diff --git a/.editorconfig b/.editorconfig index 753499f5afaf4..734314d6db6d7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -151,6 +151,19 @@ dotnet_public_api_analyzer.require_api_files = true # Workaround for https://github.com/dotnet/roslyn/issues/70570 dotnet_diagnostic.IDE0055.severity = warning +# These xUnit analyzers were disabled temporarily to let us move to the +# new xUnit and get past several component governance issues. The +# following issue tracks enabling them +# +# https://github.com/dotnet/roslyn/issues/75093 +dotnet_diagnostic.xUnit1012.severity = none +dotnet_diagnostic.xUnit1030.severity = none +dotnet_diagnostic.xUnit1031.severity = none +dotnet_diagnostic.xUnit2005.severity = none +dotnet_diagnostic.xUnit2020.severity = none +dotnet_diagnostic.xUnit2023.severity = none +dotnet_diagnostic.xUnit2029.severity = none + # CSharp code style settings: [*.cs] # Newline settings @@ -300,4 +313,4 @@ dotnet_diagnostic.RS0057.severity = error dotnet_diagnostic.RS0058.severity = error dotnet_diagnostic.RS0059.severity = error dotnet_diagnostic.RS0060.severity = error -dotnet_diagnostic.RS0061.severity = error \ No newline at end of file +dotnet_diagnostic.RS0061.severity = error diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 7bdba491ceb3f..43c22561d3b4b 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -11,7 +11,7 @@ about: Report a bug in Roslyn 2. 3. -A minimal repro, with source-code provided, is ideal. Using [sharplab](https://sharplab.io/) is preferred for compiler/language issues whenever possible. +A minimal repro, with source-code provided, is ideal. Most compiler/language issues can be distilled into a snippet that can be pasted into [sharplab](https://sharplab.io/). **Diagnostic Id**: diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml index a2e463c345e88..9d054bd460d2d 100644 --- a/.github/policies/resourceManagement.yml +++ b/.github/policies/resourceManagement.yml @@ -8,6 +8,7 @@ where: configuration: resourceManagementConfiguration: scheduledSearches: + - description: Close "Need More Info" Issues frequencies: - hourly: @@ -23,8 +24,12 @@ configuration: - closeIssue - addReply: reply: "Closing this issue as we've seen no reply to the request for more information. If you are able to get the requested information, please add it to the issue and we will retriage it. " + eventResponderTasks: - - if: + + - description: Auto-approve auto-merge PRs + triggerOnOwnActions: false + if: - payloadType: Pull_Request - isPullRequest - labelAdded: @@ -38,9 +43,10 @@ configuration: then: - approvePullRequest: comment: Auto-approval - description: Auto-approve auto-merge PRs + + - description: Auto-approve maestro PRs triggerOnOwnActions: false - - if: + if: - payloadType: Pull_Request - isPullRequest - isActivitySender: @@ -55,9 +61,10 @@ configuration: then: - approvePullRequest: comment: Auto-approve - description: Auto-approve maestro PRs - triggerOnOwnActions: false - - if: + + - description: Milestone tracking + triggerOnOwnActions: true + if: - payloadType: Pull_Request - isPullRequest - or: @@ -72,9 +79,10 @@ configuration: then: - addMilestone: milestone: Next - description: Milestone tracking - triggerOnOwnActions: true - - if: + + - description: Auto-approve OneLoc PRs + triggerOnOwnActions: false + if: - payloadType: Pull_Request - isPullRequest - isActivitySender: @@ -88,9 +96,10 @@ configuration: then: - addLabel: label: auto-merge - description: Auto-approve OneLoc PRs + + - description: Remove "Need More Info" on comment triggerOnOwnActions: false - - if: + if: - payloadType: Issue_Comment - isIssue - isOpen @@ -101,9 +110,10 @@ configuration: label: untriaged - removeLabel: label: Need More Info - description: Remove "Need More Info" on comment + + - description: Label Community Pull Requests triggerOnOwnActions: false - - if: + if: - payloadType: Pull_Request - isPullRequest - isAction: @@ -142,13 +152,45 @@ configuration: then: - addLabel: label: Community - description: Label Community Pull Requests + + - description: Adds "VSCode" tag on PRs which may affect C# extension. + triggerOnOwnActions: false + if: + - payloadType: Pull_Request + - isPullRequest + - filesMatchPattern: + pattern: 'src/(Analyzers|CodeStyle|Features|LanguageServer|Workspaces)/.*\.(cs|vb)$' + matchAny: true + - and: + - not: + isActivitySender: + user: dotnet-bot + issueAuthor: False + - not: + isActivitySender: + user: github-actions + issueAuthor: False + - or: + - isAction: + action: Opened + - isAction: + action: Synchronize + - and: + - not: + hasLabel: + label: VSCode + then: + - addLabel: + label: VSCode + + - description: Add "Needs UX Triage" on PRs triggerOnOwnActions: false - - if: + if: - payloadType: Pull_Request - isPullRequest - filesMatchPattern: - pattern: '[xX][aA][mM][lL]$' + pattern: '.*\.[xX][aA][mM][lL]$' + matchAny: true - and: - not: hasLabel: @@ -187,12 +229,15 @@ configuration: then: - addLabel: label: Needs UX Triage - description: Add "Needs UX Triage" on PRs + + - description: Adds "Needs API Review" on PRs that touch public APIs triggerOnOwnActions: false - - if: + if: - payloadType: Pull_Request + - isPullRequest - filesMatchPattern: - pattern: .*/PublicAPI\.(Shipped|Unshipped)\.txt + pattern: '.*/PublicAPI\.(Shipped|Unshipped)\.txt' + matchAny: true - not: isActivitySender: user: dotnet-bot @@ -214,9 +259,10 @@ configuration: label: Needs API Review - addReply: reply: This PR modifies public API files. Please follow the instructions at https://github.com/dotnet/roslyn/blob/main/docs/contributing/API%20Review%20Process.md for ensuring all public APIs are reviewed before merging. - description: Adds "Needs API Review" on PRs that touch public APIs + + - description: Close automatically generated PR tagger issues triggerOnOwnActions: false - - if: + if: - payloadType: Issues - isIssue - hasLabel: @@ -226,7 +272,6 @@ configuration: isRegex: False then: - closeIssue - description: Close automatically generated PR tagger issues - triggerOnOwnActions: false + onFailure: onSuccess: diff --git a/.gitignore b/.gitignore index bf020ffa52ad3..496f18e070dfe 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ .packages/ .nuget/ .complog/ +/MSBuild_Logs/ # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets !packages/*/build/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 2b4dc7d689aeb..17ea7c3b29a62 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -35,5 +35,13 @@ "azure-pipelines.customSchemaFile": ".vscode/dnceng-schema.json", "dotnet.defaultSolution": "Roslyn.sln", "dotnet.completion.showCompletionItemsFromUnimportedNamespaces": true, - "dotnet.testWindow.disableAutoDiscovery": true + "dotnet.testWindow.disableAutoDiscovery": true, + "dotnet.testWindow.disableBuildOnRefresh": true, + "cSpell.words": [ + "Nerdbank", + "NETCOREAPP", + "Unregistration", + "Unregistrations", + "Xunit" + ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 73dd695a2e492..5ac5060625cf5 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -25,22 +25,6 @@ "problemMatcher": "$msCompile", "group": "build" }, - { - "label": "build with analyzers", - "command": "./build.sh", - "type": "shell", - "args": [ - "--runAnalyzers" - ], - "windows": { - "command": "${workspaceFolder}/build.cmd", - "args": [ - "-runAnalyzers" - ], - }, - "problemMatcher": "$msCompile", - "group": "build" - }, { "label": "build csc", "command": "dotnet", @@ -49,6 +33,7 @@ "msbuild", "-p:RunAnalyzersDuringBuild=false", "-p:GenerateFullPaths=true", + "-tl:off", "src/Compilers/CSharp/csc/AnyCpu/csc.csproj" ], "problemMatcher": "$msCompile", @@ -62,6 +47,7 @@ "build", "-p:RunAnalyzersDuringBuild=false", "-p:GenerateFullPaths=true", + "-tl:off", "Compilers.slnf" ], "problemMatcher": "$msCompile", @@ -75,6 +61,21 @@ "build", "-p:RunAnalyzersDuringBuild=false", "-p:GenerateFullPaths=true", + "-tl:off", + "Roslyn.sln" + ], + "problemMatcher": "$msCompile", + "group": "build" + }, + { + "label": "build Roslyn.sln with analyzers", + "command": "dotnet", + "type": "shell", + "args": [ + "build", + "-p:RunAnalyzersDuringBuild=true", + "-p:GenerateFullPaths=true", + "-tl:off", "Roslyn.sln" ], "problemMatcher": "$msCompile", @@ -145,7 +146,7 @@ "build", "-c", "Debug", - "src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj" + "src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj" ], "problemMatcher": "$msCompile", "group": "build" diff --git a/Directory.Build.rsp b/Directory.Build.rsp index 37bf61d3487f8..d2d2d1d2f4e8e 100644 --- a/Directory.Build.rsp +++ b/Directory.Build.rsp @@ -1,2 +1 @@ -# Workaround for https://github.com/dotnet/sdk/issues/41791 --p:_IsDisjointMSBuildVersion=false +# This file intentionally left blank to avoid accidental import during build. diff --git a/README.md b/README.md index 8210dcff68ea6..ca941c7038165 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

The .NET Compiler Platform

-

Join the chat at https://gitter.im/dotnet/roslyn Chat on Discord

+

Roslyn is the open-source implementation of both the C# and Visual Basic compilers with an API surface for building code analysis tools. @@ -32,7 +32,7 @@ If you are interested in fixing issues and contributing directly to the code bas The Roslyn community can be found on [GitHub Discussions](https://github.com/dotnet/roslyn/discussions), where you can ask questions, voice ideas, and share your projects. -To chat with other community members, you can join the Roslyn [Discord](https://discord.com/invite/tGJvv88) or [Gitter](https://gitter.im/dotnet/roslyn). +To chat with other community members, you can join the Roslyn channel on the [CSharp Community Discord](https://discord.com/invite/tGJvv88). Our [Code of Conduct](CODE-OF-CONDUCT.md) applies to all Roslyn community channels and has adopted the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). @@ -55,39 +55,34 @@ Visit [Roslyn Architecture Overview](https://docs.microsoft.com/en-us/dotnet/csh |Branch|Windows Debug|Windows Release|Unix Debug| |:--:|:--:|:--:|:--:| **main**|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Build_Windows_Debug&configuration=Build_Windows_Debug&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Build_Windows_Release&configuration=Build_Windows_Release&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Build_Unix_Debug&configuration=Build_Unix_Debug&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)| -**main-vs-deps**|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Build_Windows_Debug&configuration=Build_Windows_Debug&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Build_Windows_Release&configuration=Build_Windows_Release&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Build_Unix_Debug&configuration=Build_Unix_Debug&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)| #### Desktop Unit Tests |Branch|Debug x86|Debug x64|Release x86|Release x64| |:--:|:--:|:--:|:--:|:--:| **main**|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Test_Windows_Desktop_Debug_32&configuration=Test_Windows_Desktop_Debug_32&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Test_Windows_Desktop_Debug_64&configuration=Test_Windows_Desktop_Debug_64&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Test_Windows_Desktop_Release_32&configuration=Test_Windows_Desktop_Release_32&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Test_Windows_Desktop_Release_64&configuration=Test_Windows_Desktop_Release_64&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)| -**main-vs-deps**|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Test_Windows_Desktop_Debug_32&configuration=Test_Windows_Desktop_Debug_32&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Test_Windows_Desktop_Debug_64&configuration=Test_Windows_Desktop_Debug_64&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Test_Windows_Desktop_Release_32&configuration=Test_Windows_Desktop_Release_32&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Test_Windows_Desktop_Release_64&configuration=Test_Windows_Desktop_Release_64&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)| #### CoreClr Unit Tests |Branch|Windows Debug|Windows Release|Linux| |:--:|:--:|:--:|:--:| **main**|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Test_Windows_CoreClr_Debug&configuration=Test_Windows_CoreClr_Debug&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Test_Windows_CoreClr_Release&configuration=Test_Windows_CoreClr_Release&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Test_Linux_Debug&configuration=Test_Linux_Debug&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)| -**main-vs-deps**|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Test_Windows_CoreClr_Debug&configuration=Test_Windows_CoreClr_Debug&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Test_Windows_CoreClr_Release&configuration=Test_Windows_CoreClr_Release&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Test_Linux_Debug&configuration=Test_Linux_Debug&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)| #### Integration Tests |Branch|Debug x86|Debug x64|Release x86|Release x64 |:--:|:--:|:--:|:--:|:--:| **main**|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-integration-CI?branchname=main&jobname=VS_Integration_Debug_32&configuration=VS_Integration_Debug_32&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=96&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-integration-CI?branchname=main&jobname=VS_Integration_Debug_64&configuration=VS_Integration_Debug_64&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=96&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-integration-CI?branchname=main&jobname=VS_Integration_Release_32&configuration=VS_Integration_Release_32&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=96&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-integration-CI?branchname=main&jobname=VS_Integration_Release_64&configuration=VS_Integration_Release_64&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=96&branchname=main&view=logs)| -**main-vs-deps**|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-integration-CI?branchname=main-vs-deps&jobname=VS_Integration_Debug_32&configuration=VS_Integration_Debug_32&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=96&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-integration-CI?branchname=main-vs-deps&jobname=VS_Integration_Debug_64&configuration=VS_Integration_Debug_64&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=96&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-integration-CI?branchname=main-vs-deps&jobname=VS_Integration_Release_32&configuration=VS_Integration_Release_32&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=96&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-integration-CI?branchname=main-vs-deps&jobname=VS_Integration_Release_64&configuration=VS_Integration_Release_64&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=96&branchname=main-vs-deps&view=logs)| #### Misc Tests |Branch|Determinism|Analyzers|Build Correctness|Source build|TODO/Prototype|Spanish|MacOS| |:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:| **main**|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Correctness_Determinism&configuration=Correctness_Determinism&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Correctness_Analyzers&configuration=Correctness_Analyzers&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Correctness_Build_Artifacts&configuration=Correctness_Build_Artifacts&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Source-Build+(Managed)&configuration=Source-Build+(Managed)&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Correctness_TodoCheck&configuration=Correctness_TodoCheck&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Test_Windows_Desktop_Spanish_Release_64&configuration=Test_Windows_Desktop_Spanish_Release_64&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main&jobname=Test_macOS_Debug&configuration=Test_macOS_Debug&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main&view=logs)| -**main-vs-deps**|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Correctness_Determinism&configuration=Correctness_Determinism&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Correctness_Analyzers&configuration=Correctness_Analyzers&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Correctness_Build_Artifacts&configuration=Correctness_Build_Artifacts&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Source-Build+(Managed)&configuration=Source-Build+(Managed)&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Correctness_TodoCheck&configuration=Correctness_TodoCheck&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Test_Windows_Desktop_Spanish_Release_64&configuration=Test_Windows_Desktop_Spanish_Release_64&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)|[![Build Status](https://dev.azure.com/dnceng-public/public/_apis/build/status/dotnet/roslyn/roslyn-CI?branchname=main-vs-deps&jobname=Test_macOS_Debug&configuration=Test_macOS_Debug&label=build)](https://dev.azure.com/dnceng-public/public/_build/latest?definitionId=95&branchname=main-vs-deps&view=logs)| + [//]: # (End current test results) ### .NET Foundation -This project is part of the [.NET Foundation](http://www.dotnetfoundation.org/projects) along with other -projects like [the .NET Runtime](https://github.com/dotnet/runtime/). +This project is part of the [.NET Foundation](http://www.dotnetfoundation.org/projects) along with other projects like [the .NET Runtime](https://github.com/dotnet/runtime/). diff --git a/azure-pipelines-integration-dartlab.yml b/azure-pipelines-integration-dartlab.yml index 1f6926648b39f..c9dca1e99484e 100644 --- a/azure-pipelines-integration-dartlab.yml +++ b/azure-pipelines-integration-dartlab.yml @@ -24,6 +24,14 @@ resources: trigger: - main +parameters: + - name: prNumber + type: string + default: 'None' + - name: sha + type: string + default: 'None' + variables: - name: XUNIT_LOGS value: $(Build.SourcesDirectory)\artifacts\log\$(_configuration) @@ -33,8 +41,22 @@ variables: value: true stages: +- ${{ if ne(parameters.prNumber, 'None') }}: + - stage: GitHubCommentFirst + jobs: + - job: GitHubCommentFirstJob + steps: + - checkout: none + - task: GitHubComment@0 + inputs: + gitHubConnection: 'dotnet-comment-bot-service-connection' + repositoryName: '$(Build.Repository.Name)' + id: ${{ parameters.prNumber }} + comment: 'Started DartLab pipeline [run]($(System.TeamFoundationCollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)) for ${{ parameters.sha }}' + - template: \stages\visual-studio\agent.yml@DartLabTemplates parameters: + name: VSIntegration displayName: VS Integration testLabPoolName: VS-Platform visualStudioBootstrapperURI: https://vsdrop.corp.microsoft.com/file/v1/$(VisualStudio.BuildUnderTest.ProductsDropName);bootstrappers/Enterprise/vs_enterprise.exe @@ -67,9 +89,37 @@ stages: arguments: -DropNamePrefix 'Products' -VstsDropUrlsJson '$(Pipeline.Workspace)\VisualStudioBuildUnderTest\BuildArtifacts\VstsDropUrls.json' -OutVariableName 'VisualStudio.BuildUnderTest.ProductsDropName' deployAndRunTestsStepList: - checkout: RoslynMirror + fetchDepth: 1 + fetchTags: false - template: eng/pipelines/test-integration-job.yml parameters: configuration: $(_configuration) oop64bit: $(_oop64bit) lspEditor: false skipCheckout: true + +- ${{ if ne(parameters.prNumber, 'None') }}: + - stage: GitHubCommentCompleted + condition: always() + dependsOn: VSIntegration + jobs: + - job: GitHubCommentCompletedSuccessfullyJob + condition: eq(stageDependencies.VSIntegration.result, 'Succeeded') + steps: + - checkout: none + - task: GitHubComment@0 + inputs: + gitHubConnection: 'dotnet-comment-bot-service-connection' + repositoryName: '$(Build.Repository.Name)' + id: ${{ parameters.prNumber }} + comment: 'DartLab pipeline [run]($(System.TeamFoundationCollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)) completed successfully for ${{ parameters.sha }}' + - job: GitHubCommentCompletedUnsuccessfullyJob + condition: ne(stageDependencies.VSIntegration.result, 'Succeeded') + steps: + - checkout: none + - task: GitHubComment@0 + inputs: + gitHubConnection: 'dotnet-comment-bot-service-connection' + repositoryName: '$(Build.Repository.Name)' + id: ${{ parameters.prNumber }} + comment: 'DartLab pipeline [run]($(System.TeamFoundationCollectionUri)$(System.TeamProject)/_build/results?buildId=$(Build.BuildId)) did not complete successfully for ${{ parameters.sha }}' \ No newline at end of file diff --git a/azure-pipelines-integration.yml b/azure-pipelines-integration.yml index b3945c448b11b..241c0fec59dfc 100644 --- a/azure-pipelines-integration.yml +++ b/azure-pipelines-integration.yml @@ -43,7 +43,7 @@ pr: - CONTRIBUTING.md - README.md - src/Compilers/* - - src/Features/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/README.md + - src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/README.md variables: - name: Codeql.Enabled diff --git a/azure-pipelines-official.yml b/azure-pipelines-official.yml index 4ff514dfeec51..343323ce6d2ae 100644 --- a/azure-pipelines-official.yml +++ b/azure-pipelines-official.yml @@ -37,12 +37,19 @@ parameters: type: boolean default: true -# The variables `_DotNetArtifactsCategory` and `_DotNetValidationArtifactsCategory` are required for proper publishing of build artifacts. See https://github.com/dotnet/roslyn/pull/38259 +schedules: + - cron: "0 8 23-29 * 0" + displayName: "Monthly smoke test" + branches: + include: + - main + - release/* + exclude: + - "" + always: true # Run even if there have been no source code changes since the last successful scheduled run + batch: false # Do not run the pipeline if the previously scheduled run is in-progress + variables: - - name: _DotNetArtifactsCategory - value: .NETCore - - name: _DotNetValidationArtifactsCategory - value: .NETCoreValidation - group: DotNet-Roslyn-SDLValidation-Params - name: Codeql.Enabled value: true @@ -53,6 +60,7 @@ variables: - group: DotNet-Versions-Publish - group: DotNet-VSTS-Infra-Access - group: DotNet-DevDiv-Insertion-Workflow-Variables + - group: AzureDevOps-Artifact-Feeds-Pats - name: _DevDivDropAccessToken value: $(dn-bot-devdiv-drop-rw-code-rw) - name: ArtifactServices.Drop.PAT @@ -78,6 +86,10 @@ variables: - name: Insertion.TitleSuffix value: '' + - ${{ if and(notin(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) }}: + - name: enableSourceIndex + value: true + extends: template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates parameters: @@ -92,6 +104,8 @@ extends: enabled: false suppression: suppressionFile: $(Build.SourcesDirectory)\eng\config\guardian\.gdnsuppres + policheck: + enabled: true tsa: enabled: true configFile: '$(Build.SourcesDirectory)/eng/TSAConfig.gdntsa' @@ -107,11 +121,11 @@ extends: displayName: Build and Test jobs: - - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/release/dev17.11') }}: + - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/release/dev17.12') }}: - template: /eng/common/templates-official/job/onelocbuild.yml@self parameters: MirrorRepo: roslyn - MirrorBranch: release/dev17.11 + MirrorBranch: release/dev17.12 LclSource: lclFilesfromPackage LclPackageId: 'LCL-JUNO-PROD-ROSLYN' @@ -291,8 +305,6 @@ extends: /p:RepositoryName=$(Build.Repository.Name) /p:VisualStudioDropName=$(VisualStudio.DropName) /p:DotNetSignType=$(SignType) - /p:PublishToSymbolServer=true - /p:DotNetArtifactsCategory=$(_DotNetArtifactsCategory) /p:DotnetPublishUsingPipelines=true /p:IgnoreIbcMergeErrors=true /p:GenerateSbom=true @@ -339,6 +351,15 @@ extends: name: NetCore1ESPool-Svc-Internal demands: ImageOverride -equals windows.vs2022.amd64 + - ${{ if eq(variables.enableSourceIndex, 'true') }}: + - template: /eng/common/templates-official/job/source-index-stage1.yml@self + parameters: + sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng\build.ps1 -configuration Release -prepareMachine -ci -restore -build -binaryLogName Build.binlog -skipDocumentation -msbuildEngine dotnet /p:UsingToolVSSDK=false /p:GenerateSatelliteAssemblies=false /p:PublishReadyToRun=false" + binlogPath: artifacts/log/$(BuildConfiguration)/Build.binlog + pool: + name: $(DncEngInternalBuildPool) + demands: ImageOverride -equals 1es-windows-2022 + - stage: insert dependsOn: - publish_using_darc diff --git a/azure-pipelines-pr-validation.yml b/azure-pipelines-pr-validation.yml index b47158c36063d..010ef4e297eca 100644 --- a/azure-pipelines-pr-validation.yml +++ b/azure-pipelines-pr-validation.yml @@ -26,12 +26,7 @@ parameters: type: boolean default: false -# The variables `_DotNetArtifactsCategory` and `_DotNetValidationArtifactsCategory` are required for proper publishing of build artifacts. See https://github.com/dotnet/roslyn/pull/38259 variables: - - name: _DotNetArtifactsCategory - value: .NETCore - - name: _DotNetValidationArtifactsCategory - value: .NETCoreValidation - group: DotNet-Roslyn-SDLValidation-Params - group: DotNet-Roslyn-Insertion-Variables - name: Codeql.Enabled @@ -253,8 +248,6 @@ extends: /p:RepositoryName=$(Build.Repository.Name) /p:VisualStudioDropName=$(VisualStudio.DropName) /p:DotNetSignType=$(SignType) - /p:PublishToSymbolServer=true - /p:DotNetArtifactsCategory=$(_DotNetArtifactsCategory) /p:DotnetPublishUsingPipelines=true /p:IgnoreIbcMergeErrors=true /p:GenerateSbom=true diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 177845e3afeb1..39bf2f2c610a1 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -19,7 +19,7 @@ pr: exclude: - docs/* - eng/config/PublishData.json - - src/Features/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/README.md + - src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/README.md - .vscode/* - .github/* - .devcontainer/* @@ -391,6 +391,8 @@ stages: - powershell: eng/build.ps1 -configuration Release -prepareMachine -ci -build -pack -publish -sign -binaryLogName Build.binlog /p:DotnetPublishUsingPipelines=true displayName: Build + # While this task is not executed in the official build, this serves as a PR check for whether symbol exclusions + # are properly set up. - task: PowerShell@2 displayName: Publish Symbols Dry-Run inputs: diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md index 0981e775649e0..94061fcdccf3f 100644 --- a/docs/Language Feature Status.md +++ b/docs/Language Feature Status.md @@ -10,26 +10,25 @@ efforts behind them. | Feature | Branch | State | Developer | Reviewer | IDE Buddy | LDM Champ | | ------- | ------ | ----- | --------- | -------- | --------- | --------- | -| [Overload Resolution Priority](https://github.com/dotnet/csharplang/issues/7706) | PR not yet available | [In Progress](https://github.com/dotnet/roslyn/issues/74131) | [333fred](https://github.com/333fred) | [jcouv](https://github.com/jcouv), [cston](https://github.com/cston) | Not yet assigned | [333fred](https://github.com/333fred) | | [First-class Span Types](https://github.com/dotnet/csharplang/issues/7905) | [FirstClassSpan](https://github.com/dotnet/roslyn/tree/features/FirstClassSpan) | [In Progress](https://github.com/dotnet/roslyn/issues/73445) | [jjonescz](https://github.com/jjonescz) | [cston](https://github.com/cston), [333fred](https://github.com/333fred) | | [333fred](https://github.com/333fred), [stephentoub](https://github.com/stephentoub) | -| [Semi-auto-properties](https://github.com/dotnet/csharplang/issues/140) | [semi-auto-props](https://github.com/dotnet/roslyn/tree/features/semi-auto-props) | [In Progress](https://github.com/dotnet/roslyn/issues/57012) | [Youssef1313](https://github.com/Youssef1313) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | +| [`field` keyword in properties](https://github.com/dotnet/csharplang/issues/140) | [field-keyword](https://github.com/dotnet/roslyn/tree/features/field-keyword) | [In Progress](https://github.com/dotnet/roslyn/issues/57012) | [Youssef1313](https://github.com/Youssef1313), [cston](https://github.com/cston) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | | [Default in deconstruction](https://github.com/dotnet/roslyn/pull/25562) | [decon-default](https://github.com/dotnet/roslyn/tree/features/decon-default) | [In Progress](https://github.com/dotnet/roslyn/issues/25559) | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | | [jcouv](https://github.com/jcouv) | | [Roles/Extensions](https://github.com/dotnet/csharplang/issues/5497) | [roles](https://github.com/dotnet/roslyn/tree/features/roles) | [In Progress](https://github.com/dotnet/roslyn/issues/66722) | [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs), [jjonescz](https://github.com/jjonescz) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [MadsTorgersen](https://github.com/MadsTorgersen) | -| [Ref Struct Interfaces](https://github.com/dotnet/csharplang/issues/7608) | [RefStructInterfaces](https://github.com/dotnet/roslyn/tree/features/RefStructInterfaces) | [Merged into 17.11p2](https://github.com/dotnet/roslyn/issues/72124) | [AlekseyTs](https://github.com/AlekseyTs) | [cston](https://github.com/cston), [jjonescz](https://github.com/jjonescz) | [ToddGrun](https://github.com/ToddGrun) | [agocke](https://github.com/agocke), [jaredpar](https://github.com/jaredpar) | # C# 13.0 | Feature | Branch | State | Developer | Reviewer | IDE Buddy | LDM Champ | | ------- | ------ | ----- | --------- | -------- | --------- | --------- | | [Escape character](https://github.com/dotnet/csharplang/issues/7400) | N/A | [Merged into 17.9p1](https://github.com/dotnet/roslyn/pull/70497) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv), [RikkiGibson](https://github.com/RikkiGibson) | (no IDE impact) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | -| [Method group natural type improvements](https://github.com/dotnet/csharplang/blob/main/proposals/method-group-natural-type-improvements.md) | main | [Merged into 17.9p2](https://github.com/dotnet/roslyn/issues/69432) | [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs), [cston](https://github.com/cston) | (no IDE impact) | [jcouv](https://github.com/jcouv) | +| [Method group natural type improvements](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/method-group-natural-type-improvements.md) | main | [Merged into 17.9p2](https://github.com/dotnet/roslyn/issues/69432) | [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs), [cston](https://github.com/cston) | (no IDE impact) | [jcouv](https://github.com/jcouv) | | [`Lock` object](https://github.com/dotnet/csharplang/issues/7104) | [LockObject](https://github.com/dotnet/roslyn/tree/features/LockObject) | [Merged into 17.10p2](https://github.com/dotnet/roslyn/issues/71888) | [jjonescz](https://github.com/jjonescz) | [cston](https://github.com/cston), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) (needs IDE fixer) | [stephentoub](https://github.com/stephentoub) | | Implicit indexer access in object initializers | main | [Merged into 17.9p3](https://github.com/dotnet/roslyn/pull/70649) | [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs), [cston](https://github.com/cston) | (no IDE impact) | | | [Params-collections](https://github.com/dotnet/csharplang/issues/7700) | main | [Merged to 17.10p3](https://github.com/dotnet/roslyn/issues/71137) | [AlekseyTs](https://github.com/AlekseyTs) | [RikkiGibson](https://github.com/RikkiGibson), [333fred](https://github.com/333fred) | [akhera99](https://github.com/akhera99) (needs IDE fixer) | [MadsTorgersen](https://github.com/MadsTorgersen), [AlekseyTs](https://github.com/AlekseyTs) | -| [Ref/unsafe in iterators/async](https://github.com/dotnet/csharplang/blob/main/proposals/ref-unsafe-in-iterators-async.md) | [RefInAsync](https://github.com/dotnet/roslyn/tree/features/RefInAsync) | [Merged into 17.11p2](https://github.com/dotnet/roslyn/issues/72662) | [jjonescz](https://github.com/jjonescz) | [AlekseyTs](https://github.com/AlekseyTs), [cston](https://github.com/cston) | (no IDE impact) | | -| [`allows ref struct` constraint](https://github.com/dotnet/csharplang/issues/7608) | [RefStructInterfaces](https://github.com/dotnet/roslyn/tree/features/RefStructInterfaces) | [Merged into 17.11p2](https://github.com/dotnet/roslyn/issues/72124) | [AlekseyTs](https://github.com/AlekseyTs) | [cston](https://github.com/cston), [jjonescz](https://github.com/jjonescz) | [ToddGrun](https://github.com/ToddGrun) | [agocke](https://github.com/agocke), [jaredpar](https://github.com/jaredpar) | +| [Ref/unsafe in iterators/async](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/ref-unsafe-in-iterators-async.md) | [RefInAsync](https://github.com/dotnet/roslyn/tree/features/RefInAsync) | [Merged into 17.11p2](https://github.com/dotnet/roslyn/issues/72662) | [jjonescz](https://github.com/jjonescz) | [AlekseyTs](https://github.com/AlekseyTs), [cston](https://github.com/cston) | (no IDE impact) | | | [Overload Resolution Priority](https://github.com/dotnet/csharplang/issues/7706) | main | [Merged to 17.12p1](https://github.com/dotnet/roslyn/issues/74131) | [333fred](https://github.com/333fred) | [jcouv](https://github.com/jcouv), [cston](https://github.com/cston) | Not yet assigned | [333fred](https://github.com/333fred) | | [Partial properties](https://github.com/dotnet/csharplang/issues/6420) | [partial-properties](https://github.com/dotnet/roslyn/tree/features/partial-properties) | [Merged into 17.11p3](https://github.com/dotnet/roslyn/issues/73090) | [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv), [333fred](https://github.com/333fred) | [Cosifne](https://github.com/Cosifne) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | +| [Ref Struct Interfaces/`allows ref struct` constraint](https://github.com/dotnet/csharplang/issues/7608) | [RefStructInterfaces](https://github.com/dotnet/roslyn/tree/features/RefStructInterfaces) | [Merged into 17.11p2](https://github.com/dotnet/roslyn/issues/72124) | [AlekseyTs](https://github.com/AlekseyTs) | [cston](https://github.com/cston), [jjonescz](https://github.com/jjonescz) | [ToddGrun](https://github.com/ToddGrun) | [agocke](https://github.com/agocke), [jaredpar](https://github.com/jaredpar) | +| [Collection expression better conversion from expression](https://github.com/dotnet/csharplang/issues/8374) | main | [Merged into 17.12p3](https://github.com/dotnet/roslyn/pull/74993) | [333fred](https://github.com/333fred) | [cston](https://github.com/cston), [AlekseyTs](https://github.com/AlekseyTs) | (no IDE impact) | [333fred](https://github.com/333fred), [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | # C# 12.0 diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md index 9aa9f6adb5c8a..16ff18c9ad43f 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md @@ -162,7 +162,7 @@ DoAction(action, 1); // error CS1503: Argument 1: cannot convert from ' a, int p) => a(p, new[] { p }); ``` -You can learn more about this change in the associated [proposal](https://github.com/dotnet/csharplang/blob/main/proposals/lambda-method-group-defaults.md#breaking-change). +You can learn more about this change in the associated [proposal](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/lambda-method-group-defaults.md#breaking-change). ## For the purpose of definite assignment analysis, invocations of async local functions are no longer treated as being awaited diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md index 698ae888af3c0..b1890cfa20293 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md @@ -44,3 +44,115 @@ unsafe class C // unsafe context ``` You can work around the break simply by adding the `unsafe` modifier to the local function. + +## Collection expression breaking changes with overload resolution in C# 13 and newer + +***Introduced in Visual Studio 2022 Version 17.12 and newer when using C# 13+*** + +There are a few changes in collection expression binding in C# 13. Most of these are turning ambiguities into successful compilations, +but a couple are breaking changes that either result in a new compilation error, or are a behavior breaking change. They are detailed +below. + +### Empty collection expressions no longer use whether an API is a span to tiebreak on overloads + +When an empty collection expression is provided to an overloaded method, and there isn't a clear element type, we no longer use whether +an API takes a `ReadOnlySpan` or a `Span` to decide whether to prefer that API. For example: + +```cs +class C +{ + static void M(ReadOnlySpan ros) {} + static void M(Span s) {} + + static void Main() + { + M([]); // C.M(ReadOnlySpan) in C# 12, error in C# 13. + } +} +``` + +### Exact element type is preferred over all else + +In C# 13, we prefer an exact element type match, looking at conversions from expressions. This can result in a behavior change when involving +constants: + +```cs +class C +{ + static void M1(ReadOnlySpan ros) {} + static void M1(Span s) {} + + static void M2(ReadOnlySpan ros) {} + static void M2(Span ros) {} + + static void Main() + { + M1([1]); // C.M(ReadOnlySpan) in C# 12, C.M(Span) in C# 13 + + M2([$"{1}"]); // C.M(ReadOnlySpan) in C# 12, C.M(Span) in C# 13 + } +} +``` + +## Declaration of indexers in absence of proper declaration of DefaultMemberAttribute is no longer allowed. + +***Introduced in Visual Studio 2022 version 17.13*** + +```cs +public interface I1 +{ + public I1 this[I1 args] { get; } // error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor' +} +``` + +## Default and params parameters are considered in method group natural type + +***Introduced in Visual Studio 2022 version 17.13*** + +Previously the compiler [unexpectedly](https://github.com/dotnet/roslyn/issues/71333) +inferred different delegate type depending on the order of candidates in source +when default parameter values or `params` arrays were used. Now an ambiguity error is emitted. + +```cs +using System; + +class Program +{ + static void Main() + { + var x1 = new Program().Test1; // previously Action - now error + var x2 = new Program().Test2; // previously anonymous void delegate(params long[]) - now error + + x1(); + x2(); + } +} + +static class E +{ + static public void Test1(this Program p, long[] a) => Console.Write(a.Length); + static public void Test1(this object p, params long[] a) => Console.Write(a.Length); + + static public void Test2(this object p, params long[] a) => Console.Write(a.Length); + static public void Test2(this Program p, long[] a) => Console.Write(a.Length); +} +``` + +Also in `LangVersion=12` or lower, `params` modifier must match across all methods to infer a unique delegate signature. +Note that this does not affect `LangVersion=13` and later because of [a different delegate inference algorithm](https://github.com/dotnet/csharplang/issues/7429). + +```cs +var d = new C().M; // previously inferred Action - now error CS8917: the delegate type could not be inferred + +static class E +{ + public static void M(this C c, params int[] x) { } +} + +class C +{ + public void M(int[] x) { } +} +``` + +A workaround is to use explicit delegate types instead of relying on `var` inference in those cases. diff --git a/docs/contributing/Building, Debugging, and Testing on Unix.md b/docs/contributing/Building, Debugging, and Testing on Unix.md index 0690730630dd6..5d1d326a4d610 100644 --- a/docs/contributing/Building, Debugging, and Testing on Unix.md +++ b/docs/contributing/Building, Debugging, and Testing on Unix.md @@ -12,7 +12,7 @@ Particularly for developers who aren't experienced with .NET Core development on 1. Install [VS Code](https://code.visualstudio.com/Download) - After you install VS Code, install the [C# extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) - Important tip: You can look up editor commands by name by hitting *Ctrl+Shift+P*, or by hitting *Ctrl+P* and typing a `>` character. This will help you get familiar with editor commands mentioned below. On a Mac, use *⌘* instead of *Ctrl*. -1. Install the [.NET 8.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) which matches the `sdk.version` property in [global.json](../../global.json#L3) +1. Install the [.NET 9.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/9.0) which matches the `sdk.version` property in [global.json](../../global.json#L3) 3. You can build from VS Code by running the *Run Build Task* command, then selecting an appropriate task such as *build* or *build current project* (the latter builds the containing project for the current file you're viewing in the editor). 4. You can run tests from VS Code by opening a test class in the editor, then using the *Run Tests in Context* and *Debug Tests in Context* editor commands. You may want to bind these commands to keyboard shortcuts that match their Visual Studio equivalents (**Ctrl+R, T** for *Run Tests in Context* and **Ctrl+R, Ctrl+T** for *Debug Tests in Context*). 5. You can launch a new VS Code instance with the language server from your current code by running the "launch vscode with language server" task. diff --git a/docs/contributing/Building, Debugging, and Testing on Windows.md b/docs/contributing/Building, Debugging, and Testing on Windows.md index 0482960a9d56c..87a3722a7adb5 100644 --- a/docs/contributing/Building, Debugging, and Testing on Windows.md +++ b/docs/contributing/Building, Debugging, and Testing on Windows.md @@ -20,7 +20,7 @@ The minimal required version of .NET Framework is 4.7.2. - Ensure C# and Visual Basic, MSBuild, and .NET Core are included in the selected individual components - Ensure "Use previews of the .NET Core SDK" is checked in Tools -> Options -> Environment -> Preview Features - Restart Visual Studio -1. Install the [.NET 8.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) which matches the `sdk.version` property in [global.json](../../global.json#L3) +1. Install the [.NET 9.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/9.0) which matches the `sdk.version` property in [global.json](../../global.json#L3) 1. [PowerShell 5.0 or newer](https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell). If you are on Windows 10, you are fine; you'll only need to upgrade if you're on earlier versions of Windows. The download link is under the ["Upgrading existing Windows PowerShell"](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-windows-powershell?view=powershell-6#upgrading-existing-windows-powershell) heading. 1. Run Restore.cmd 1. Open Roslyn.sln diff --git a/docs/contributing/Compiler Test Plan.md b/docs/contributing/Compiler Test Plan.md index f30047e69b4a5..72e8afa3088a1 100644 --- a/docs/contributing/Compiler Test Plan.md +++ b/docs/contributing/Compiler Test Plan.md @@ -116,6 +116,7 @@ This document provides guidance for thinking about language interactions and tes - extension based Dispose, DisposeAsync, GetEnumerator, GetAsyncEnumerator, Deconstruct, GetAwaiter etc. - UTF8 String Literals (string literals with 'u8' or 'U8' type suffix). - Inline array element access and slicing. +- Collection expressions and spread elements # Misc - reserved keywords (sometimes contextual) @@ -345,6 +346,7 @@ __makeref( x ) - Function type (in type inference comparing function types of lambdas or method groups) - UTF8 String Literal (string constant value to ```byte[]```, ```Span```, or ```ReadOnlySpan``` types) - Inline arrays (conversions to Span and ReadOnlySpan) +- Collection expression conversions ## Types diff --git a/docs/features/incremental-generators.cookbook.md b/docs/features/incremental-generators.cookbook.md index 275c3fa6ad02b..599f0f32f5dcc 100644 --- a/docs/features/incremental-generators.cookbook.md +++ b/docs/features/incremental-generators.cookbook.md @@ -544,7 +544,7 @@ Now, consider that the generator author wants to optionally allow opting in/out This value of `MyGenerator_EnableLogging` will be emitted to a generated analyzer config file, for each of the additional files in the compilation, with an item name of `build_metadata.AdditionalFiles.MyGenerator_EnableLogging`. The generator can read this value in the context of each additional file: ```cs -context.AdditionalFilesProvider +context.AdditionalTextsProvider .Combine(context.AnalyzerConfigOptionsProvider) .Select((pair, ctx) => pair.Right.GetOptions(pair.Left).TryGetValue("build_metadata.AdditionalFiles.MyGenerator_EnableLogging", out var perFileLoggingSwitch) diff --git a/docs/features/interceptors.md b/docs/features/interceptors.md index f93209462b994..c34d5294446b0 100644 --- a/docs/features/interceptors.md +++ b/docs/features/interceptors.md @@ -179,6 +179,37 @@ This allows generator authors to avoid *polluting lookup* with interceptors, hel We may also want to consider adjusting behavior of `[EditorBrowsable]` to work in the same compilation. +### Struct receiver capture + +An interceptor whose `this` parameter takes a struct by-reference can generally be used to intercept a struct instance method call, assuming the methods are compatible per [Signature matching](#signature-matching). This includes situations where the receiver must be implicitly captured to temp before the invocation, even if such capture is not permitted when the interceptor is called directly. See also [12.8.9.3 Extension method invocations](https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/expressions.md#12893-extension-method-invocations) in the standard. + + +```cs +using System.Runtime.CompilerServices; + +struct S +{ + public void Original() { } +} + +static class Program +{ + public static void Main() + { + new S().Original(); // L1: interception is valid, no errors. + new S().Interceptor(); // error CS1510: A ref or out value must be an assignable variable + } +} + +static class D +{ + [InterceptsLocation(1, "..(refers to call to 'Original()' at L1)")] + public static void Interceptor(this ref S s) +} +``` + +The reason we permit implicit receiver capture for the above intercepted call is: we want intercepting to be possible even when the interceptor author doesn't own the original receiver type. If we didn't do this, then intercepting `Original()` in the above example would only be possible by adding instance members to `struct S`. + ### Editor experience Interceptors are treated like a post-compilation step in this design. Diagnostics are given for misuse of interceptors, but some diagnostics are only given in the command-line build and not in the IDE. There is limited traceability in the editor for which calls in a compilation are actually being intercepted. If this feature is brought forward past the experimental stage, this limitation will need to be re-examined. @@ -187,12 +218,14 @@ There is an experimental public API `GetInterceptorMethod(this SemanticModel, In ### User opt-in -To use interceptors, the user project must specify the property ``. This is a list of namespaces which are allowed to contain interceptors. +To use interceptors, the user project must specify the property ``. This is a list of namespaces which are allowed to contain interceptors. ```xml -$(InterceptorsPreviewNamespaces);Microsoft.AspNetCore.Http.Generated;MyLibrary.Generated +$(InterceptorsNamespaces);Microsoft.AspNetCore.Http.Generated;MyLibrary.Generated ``` -It's expected that each entry in the `InterceptorsPreviewNamespaces` list roughly corresponds to one source generator. Well-behaved components are expected to not insert interceptors into namespaces they do not own. +It's expected that each entry in the `InterceptorsNamespaces` list roughly corresponds to one source generator. Well-behaved components are expected to not insert interceptors into namespaces they do not own. + +For compatibility, the property `` can be used as an alias for ``. If both properties have non-empty values, they will be concatenated together in the order `$(InterceptorsNamespaces);$(InterceptorsPreviewNamespaces)` when passed to the compiler. ### Implementation strategy diff --git a/docs/img/discord-mark-white.png b/docs/img/discord-mark-white.png new file mode 100644 index 0000000000000..f9f8df0dd1fe3 Binary files /dev/null and b/docs/img/discord-mark-white.png differ diff --git a/eng/Directory.Packages.props b/eng/Directory.Packages.props index bf84a2aaa4ee1..44fddbbd9b1cb 100644 --- a/eng/Directory.Packages.props +++ b/eng/Directory.Packages.props @@ -5,14 +5,14 @@ 8.0.0-preview.23468.1 1.1.3-beta1.24319.1 0.1.187-beta - <_BasicReferenceAssembliesVersion>1.7.2 + <_BasicReferenceAssembliesVersion>1.7.9 4.8.0-3.final 17.10.191 - 6.0.0-rtm.21518.12 + 9.0.0-rc.2.24462.10 6.0.0-rtm.21518.12 7.0.0-alpha.1.22060.1 - 17.5.0 + <_MicrosoftTestPlatformVersion>17.5.0 8.0.0 8.0.0 - 2.4.1 + <_xunitVersion>2.6.6 2.1.0 17.10.2079 @@ -31,21 +31,21 @@ https://github.com/dotnet/sdk/blob/main/src/Layout/redist/minimumMSBuildVersion#L1 --> - + - + - + @@ -111,8 +111,8 @@ - - + + @@ -121,7 +121,7 @@ - + @@ -142,9 +142,9 @@ --> - - - + + + + @@ -255,14 +256,11 @@ - - - @@ -278,25 +276,29 @@ - - - - - - - - + + + + + + + + - - + + + + + + diff --git a/eng/SourceBuild.props b/eng/SourceBuild.props index bdc21afbd2dc1..9004a80e28bbf 100644 --- a/eng/SourceBuild.props +++ b/eng/SourceBuild.props @@ -27,6 +27,7 @@ $(InnerBuildArgs) /p:Projects="$(InnerSourceBuildRepoRoot)Roslyn.sln" + $(InnerBuildArgs) /p:RestoreUseStaticGraphEvaluation=false diff --git a/eng/TSAConfig.gdntsa b/eng/TSAConfig.gdntsa index a3659150b8b22..755385b85c168 100644 --- a/eng/TSAConfig.gdntsa +++ b/eng/TSAConfig.gdntsa @@ -11,7 +11,5 @@ "projectName": "DevDiv", "areaPath": "DevDiv\\NET Developer Experience\\CSharp and VB IDE", "iterationPath": "DevDiv", - "tools": [ - "APIScan" - ] + "allTools": true } diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 49e3252e73c0a..7ac36a68f74f8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -2,15 +2,15 @@ - + https://github.com/dotnet/source-build-externals - 311ef7fef52828f4a70a94d13e32c394fd3292ee + fbe8f0b52ae0e083461d89db7229f6d70e874644 - + https://github.com/dotnet/source-build-reference-packages - 0b53e839fa2f09a5994cc6006533dcc3d45a4226 + 0b091fc31f5379aa6f70be1436c17fc24d4416fe @@ -122,14 +122,14 @@ - + https://github.com/dotnet/arcade - 4a7d983f833d6b86365ea1b2b4d6ee72fbdbf944 + 65260b148c869ada772a5843863c54737cd2361e - + https://github.com/dotnet/arcade - 4a7d983f833d6b86365ea1b2b4d6ee72fbdbf944 + 65260b148c869ada772a5843863c54737cd2361e @@ -156,9 +156,9 @@ https://github.com/dotnet/roslyn 5d10d428050c0d6afef30a072c4ae68776621877 - + https://github.com/dotnet/arcade - 4a7d983f833d6b86365ea1b2b4d6ee72fbdbf944 + 65260b148c869ada772a5843863c54737cd2361e https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index 758c3cfac1136..7827ede2a5cf9 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -6,7 +6,7 @@ --> 4 - 12 + 13 0 1 $(MajorVersion).$(MinorVersion).$(PatchVersion) @@ -35,7 +35,7 @@ 8.0.0 8.0.0 - 8.0.0 + 8.0.4 8.0.0 8.0.0 8.0.0 @@ -45,6 +45,7 @@ 2.0.0 8.0.0 8.0.0 + 8.0.0 8.0.0 8.0.0 8.0.0 @@ -59,12 +60,12 @@ So it's not affected by our central package management --> 4.61.3 - 1.0.803 + 1.0.865 6.34.0 13.0.3 6.34.0 - 9.0.0-beta.24076.5 + 9.0.0-beta.24076.5 4.61.3 6.34.0 @@ -83,5 +84,7 @@ --> true true + + true diff --git a/eng/build.ps1 b/eng/build.ps1 index edbcc77f9ec0e..4e1c32662de95 100644 --- a/eng/build.ps1 +++ b/eng/build.ps1 @@ -252,8 +252,8 @@ function BuildSolution() { # Workaround for some machines in the AzDO pool not allowing long paths $ibcDir = $RepoRoot - # Set DotNetBuildFromSource to 'true' if we're simulating building for source-build. - $buildFromSource = if ($sourceBuild) { "/p:DotNetBuildFromSource=true" } else { "" } + # Set DotNetBuildSourceOnly to 'true' if we're simulating building for source-build. + $buildFromSource = if ($sourceBuild) { "/p:DotNetBuildSourceOnly=true" } else { "" } $generateDocumentationFile = if ($skipDocumentation) { "/p:GenerateDocumentationFile=false" } else { "" } $roslynUseHardLinks = if ($ci) { "/p:ROSLYNUSEHARDLINKS=true" } else { "" } @@ -318,6 +318,11 @@ function GetIbcSourceBranchName() { } function GetIbcDropName() { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingConvertToSecureStringWithPlainText', + '', + Justification='$officialVisualStudioDropAccessToken is a script parameter so it needs to be plain text')] + param() if ($officialIbcDrop -and $officialIbcDrop -ne "default"){ return $officialIbcDrop @@ -627,6 +632,13 @@ function Deploy-VsixViaTool() { # Configure RemoteHostOptions.OOP64Bit for testing $oop64bitValue = [int]$oop64bit.ToBool() &$vsRegEdit set "$vsDir" $hive HKCU "Roslyn\Internal\OnOff\Features" OOP64Bit dword $oop64bitValue + + # Disable targeted notifications + if ($ci) { + # Currently does not work via vsregedit, so only apply this setting in CI + #&$vsRegEdit set "$vsDir" $hive HKCU "RemoteSettings" TurnOffSwitch dword 1 + reg add hkcu\Software\Microsoft\VisualStudio\RemoteSettings /f /t REG_DWORD /v TurnOffSwitch /d 1 + } } # Ensure that procdump is available on the machine. Returns the path to the directory that contains diff --git a/eng/build.sh b/eng/build.sh index 5a8558e054d66..49f9183bdf70d 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -169,9 +169,7 @@ while [[ $# > 0 ]]; do --warnaserror) warn_as_error=true ;; - --sourcebuild|/p:arcadebuildfromsource=true) - # Arcade specifies /p:ArcadeBuildFromSource=true instead of --sourceBuild, but that's not developer friendly so we - # have an alias. + --sourcebuild) source_build=true # RestoreUseStaticGraphEvaluation will cause prebuilts restoreUseStaticGraphEvaluation=false @@ -281,6 +279,12 @@ function BuildSolution { roslyn_use_hard_links="/p:ROSLYNUSEHARDLINKS=true" fi + local source_build_args="" + if [[ "$source_build" == true ]]; then + source_build_args="/p:DotNetBuildSourceOnly=true \ + /p:DotNetBuildRepo=true" + fi + # Setting /p:TreatWarningsAsErrors=true is a workaround for https://github.com/Microsoft/msbuild/issues/3062. # We don't pass /warnaserror to msbuild (warn_as_error is set to false by default above), but set # /p:TreatWarningsAsErrors=true so that compiler reported warnings, other than IDE0055 are treated as errors. @@ -302,7 +306,7 @@ function BuildSolution { /p:ContinuousIntegrationBuild=$ci \ /p:TreatWarningsAsErrors=true \ /p:TestRuntimeAdditionalArguments=$test_runtime_args \ - /p:ArcadeBuildFromSource=$source_build \ + $source_build_args \ $test_runtime \ $mono_tool \ $generate_documentation_file \ @@ -335,7 +339,9 @@ if [[ "$restore" == true || "$test_core_clr" == true ]]; then install=true fi InitializeDotNetCli $install -if [[ "$restore" == true && "$source_build" != true ]]; then +# Check the dev switch --source-build as well as ensure that source only switches were not passed in via extra properties +# Source only builds would not have 'dotnet' ambiently available. +if [[ "$restore" == true && "$source_build" != true && $properties != *"DotNetBuildSourceOnly=true"* ]]; then dotnet tool restore fi diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1 index 2b0a5c9e6655e..5db4ad71ee2f3 100644 --- a/eng/common/SetupNugetSources.ps1 +++ b/eng/common/SetupNugetSources.ps1 @@ -157,7 +157,7 @@ if ($dotnet31Source -ne $null) { AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v2" -Creds $creds -Username $userName -pwd $Password } -$dotnetVersions = @('5','6','7','8') +$dotnetVersions = @('5','6','7','8','9') foreach ($dotnetVersion in $dotnetVersions) { $feedPrefix = "dotnet" + $dotnetVersion; diff --git a/eng/common/SetupNugetSources.sh b/eng/common/SetupNugetSources.sh index b493479a1daf0..4604b61b0323a 100644 --- a/eng/common/SetupNugetSources.sh +++ b/eng/common/SetupNugetSources.sh @@ -99,7 +99,7 @@ if [ "$?" == "0" ]; then PackageSources+=('dotnet3.1-internal-transport') fi -DotNetVersions=('5' '6' '7' '8') +DotNetVersions=('5' '6' '7' '8' '9') for DotNetVersion in ${DotNetVersions[@]} ; do FeedPrefix="dotnet${DotNetVersion}"; diff --git a/eng/common/core-templates/job/job.yml b/eng/common/core-templates/job/job.yml index c732bee9f4a6f..ba53ebfbd5133 100644 --- a/eng/common/core-templates/job/job.yml +++ b/eng/common/core-templates/job/job.yml @@ -33,11 +33,6 @@ parameters: artifactPublishSteps: [] runAsPublic: false -# Sbom related params - enableSbom: true - PackageVersion: 9.0.0 - BuildDropPath: '$(Build.SourcesDirectory)/artifacts' - # 1es specific parameters is1ESPipeline: '' diff --git a/eng/common/core-templates/job/publish-build-assets.yml b/eng/common/core-templates/job/publish-build-assets.yml index d99a1a3b2840e..3d3356e319672 100644 --- a/eng/common/core-templates/job/publish-build-assets.yml +++ b/eng/common/core-templates/job/publish-build-assets.yml @@ -113,38 +113,19 @@ jobs: Add-Content -Path $filePath -Value "$(DefaultChannels)" Add-Content -Path $filePath -Value $(IsStableBuild) - - template: /eng/common/core-templates/steps/publish-build-artifacts.yml - parameters: - is1ESPipeline: ${{ parameters.is1ESPipeline }} - args: - displayName: Publish ReleaseConfigs Artifact - pathToPublish: '$(Build.StagingDirectory)/ReleaseConfigs' - publishLocation: Container - artifactName: ReleaseConfigs - - - task: powershell@2 - displayName: Check if SymbolPublishingExclusionsFile.txt exists - inputs: - targetType: inline - script: | $symbolExclusionfile = "$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt" - if(Test-Path -Path $symbolExclusionfile) + if (Test-Path -Path $symbolExclusionfile) { Write-Host "SymbolExclusionFile exists" - Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]true" - } - else{ - Write-Host "Symbols Exclusion file does not exist" - Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]false" + Copy-Item -Path $symbolExclusionfile -Destination "$(Build.StagingDirectory)/ReleaseConfigs" } - template: /eng/common/core-templates/steps/publish-build-artifacts.yml parameters: is1ESPipeline: ${{ parameters.is1ESPipeline }} args: - displayName: Publish SymbolPublishingExclusionsFile Artifact - condition: eq(variables['SymbolExclusionFile'], 'true') - pathToPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt' + displayName: Publish ReleaseConfigs Artifact + pathToPublish: '$(Build.StagingDirectory)/ReleaseConfigs' publishLocation: Container artifactName: ReleaseConfigs @@ -162,9 +143,10 @@ jobs: scriptType: ps scriptLocation: scriptPath scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) + arguments: > + -BuildId $(BARBuildId) -PublishingInfraVersion 3 - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -AzdoToken '$(System.AccessToken)' -WaitPublishingFinish true -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/core-templates/job/source-index-stage1.yml b/eng/common/core-templates/job/source-index-stage1.yml index 945c1c19e8249..205fb5b3a3956 100644 --- a/eng/common/core-templates/job/source-index-stage1.yml +++ b/eng/common/core-templates/job/source-index-stage1.yml @@ -34,10 +34,12 @@ jobs: pool: ${{ if eq(variables['System.TeamProject'], 'public') }}: name: $(DncEngPublicBuildPool) - image: windows.vs2022.amd64.open + image: 1es-windows-2022-open + os: windows ${{ if eq(variables['System.TeamProject'], 'internal') }}: name: $(DncEngInternalBuildPool) - image: windows.vs2022.amd64 + image: 1es-windows-2022 + os: windows steps: - ${{ if eq(parameters.is1ESPipeline, '') }}: diff --git a/eng/common/core-templates/post-build/post-build.yml b/eng/common/core-templates/post-build/post-build.yml index 20924366b8a43..454fd75c7aff1 100644 --- a/eng/common/core-templates/post-build/post-build.yml +++ b/eng/common/core-templates/post-build/post-build.yml @@ -307,9 +307,10 @@ stages: scriptType: ps scriptLocation: scriptPath scriptPath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1 - arguments: -BuildId $(BARBuildId) + arguments: > + -BuildId $(BARBuildId) -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} - -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)' + -AzdoToken '$(System.AccessToken)' -WaitPublishingFinish true -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/core-templates/steps/get-federated-access-token.yml b/eng/common/core-templates/steps/get-federated-access-token.yml index c8c49cc0e8f0f..3a4d4410c4829 100644 --- a/eng/common/core-templates/steps/get-federated-access-token.yml +++ b/eng/common/core-templates/steps/get-federated-access-token.yml @@ -3,6 +3,14 @@ parameters: type: string - name: outputVariableName type: string +- name: is1ESPipeline + type: boolean +- name: stepName + type: string + default: 'getFederatedAccessToken' +- name: condition + type: string + default: '' # Resource to get a token for. Common values include: # - '499b84ac-1321-427f-aa17-267ca6975798' for Azure DevOps # - 'https://storage.azure.com/' for storage @@ -10,10 +18,16 @@ parameters: - name: resource type: string default: '499b84ac-1321-427f-aa17-267ca6975798' +- name: isStepOutputVariable + type: boolean + default: false steps: - task: AzureCLI@2 displayName: 'Getting federated access token for feeds' + name: ${{ parameters.stepName }} + ${{ if ne(parameters.condition, '') }}: + condition: ${{ parameters.condition }} inputs: azureSubscription: ${{ parameters.federatedServiceConnection }} scriptType: 'pscore' @@ -25,4 +39,4 @@ steps: exit 1 } Write-Host "Setting '${{ parameters.outputVariableName }}' with the access token value" - Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true]$accessToken" \ No newline at end of file + Write-Host "##vso[task.setvariable variable=${{ parameters.outputVariableName }};issecret=true;isOutput=${{ parameters.isStepOutputVariable }}]$accessToken" \ No newline at end of file diff --git a/eng/common/core-templates/steps/publish-logs.yml b/eng/common/core-templates/steps/publish-logs.yml index 8c5ea77b586d2..80788c5231912 100644 --- a/eng/common/core-templates/steps/publish-logs.yml +++ b/eng/common/core-templates/steps/publish-logs.yml @@ -32,7 +32,6 @@ steps: '$(MaestroAccessToken)' '$(dn-bot-all-orgs-artifact-feeds-rw)' '$(akams-client-id)' - '$(akams-client-secret)' '$(microsoft-symbol-server-pat)' '$(symweb-symbol-server-pat)' '$(dn-bot-all-orgs-build-rw-code-rw)' diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh index eb1a908046483..4b5e8d7166bd9 100755 --- a/eng/common/cross/build-rootfs.sh +++ b/eng/common/cross/build-rootfs.sh @@ -72,7 +72,7 @@ __AlpinePackages+=" krb5-dev" __AlpinePackages+=" openssl-dev" __AlpinePackages+=" zlib-dev" -__FreeBSDBase="13.2-RELEASE" +__FreeBSDBase="13.3-RELEASE" __FreeBSDPkg="1.17.0" __FreeBSDABI="13" __FreeBSDPackages="libunwind" @@ -605,18 +605,18 @@ elif [[ "$__CodeName" == "illumos" ]]; then fi echo "Building binutils. Please wait.." if [[ "$__hasWget" == 1 ]]; then - wget -O- https://ftp.gnu.org/gnu/binutils/binutils-2.33.1.tar.bz2 | tar -xjf - + wget -O- https://ftp.gnu.org/gnu/binutils/binutils-2.42.tar.xz | tar -xJf - else - curl -SL https://ftp.gnu.org/gnu/binutils/binutils-2.33.1.tar.bz2 | tar -xjf - + curl -SL https://ftp.gnu.org/gnu/binutils/binutils-2.42.tar.xz | tar -xJf - fi mkdir build-binutils && cd build-binutils - ../binutils-2.33.1/configure --prefix="$__RootfsDir" --target="${__illumosArch}-sun-solaris2.10" --program-prefix="${__illumosArch}-illumos-" --with-sysroot="$__RootfsDir" + ../binutils-2.42/configure --prefix="$__RootfsDir" --target="${__illumosArch}-sun-solaris2.11" --program-prefix="${__illumosArch}-illumos-" --with-sysroot="$__RootfsDir" make -j "$JOBS" && make install && cd .. echo "Building gcc. Please wait.." if [[ "$__hasWget" == 1 ]]; then - wget -O- https://ftp.gnu.org/gnu/gcc/gcc-8.4.0/gcc-8.4.0.tar.xz | tar -xJf - + wget -O- https://ftp.gnu.org/gnu/gcc/gcc-13.3.0/gcc-13.3.0.tar.xz | tar -xJf - else - curl -SL https://ftp.gnu.org/gnu/gcc/gcc-8.4.0/gcc-8.4.0.tar.xz | tar -xJf - + curl -SL https://ftp.gnu.org/gnu/gcc/gcc-13.3.0/gcc-13.3.0.tar.xz | tar -xJf - fi CFLAGS="-fPIC" CXXFLAGS="-fPIC" @@ -624,7 +624,7 @@ elif [[ "$__CodeName" == "illumos" ]]; then CFLAGS_FOR_TARGET="-fPIC" export CFLAGS CXXFLAGS CXXFLAGS_FOR_TARGET CFLAGS_FOR_TARGET mkdir build-gcc && cd build-gcc - ../gcc-8.4.0/configure --prefix="$__RootfsDir" --target="${__illumosArch}-sun-solaris2.10" --program-prefix="${__illumosArch}-illumos-" --with-sysroot="$__RootfsDir" --with-gnu-as \ + ../gcc-13.3.0/configure --prefix="$__RootfsDir" --target="${__illumosArch}-sun-solaris2.11" --program-prefix="${__illumosArch}-illumos-" --with-sysroot="$__RootfsDir" --with-gnu-as \ --with-gnu-ld --disable-nls --disable-libgomp --disable-libquadmath --disable-libssp --disable-libvtv --disable-libcilkrts --disable-libada --disable-libsanitizer \ --disable-libquadmath-support --disable-shared --enable-tls make -j "$JOBS" && make install && cd .. @@ -632,7 +632,7 @@ elif [[ "$__CodeName" == "illumos" ]]; then if [[ "$__UseMirror" == 1 ]]; then BaseUrl=https://pkgsrc.smartos.skylime.net fi - BaseUrl="$BaseUrl/packages/SmartOS/trunk/${__illumosArch}/All" + BaseUrl="$BaseUrl/packages/SmartOS/2019Q4/${__illumosArch}/All" echo "Downloading manifest" if [[ "$__hasWget" == 1 ]]; then wget "$BaseUrl" diff --git a/eng/common/darc-init.ps1 b/eng/common/darc-init.ps1 index 8fda30bdce2b0..e337431056354 100644 --- a/eng/common/darc-init.ps1 +++ b/eng/common/darc-init.ps1 @@ -1,6 +1,6 @@ param ( $darcVersion = $null, - $versionEndpoint = 'https://maestro.dot.net/api/assets/darc-version?api-version=2019-01-16', + $versionEndpoint = 'https://maestro.dot.net/api/assets/darc-version?api-version=2020-02-20', $verbosity = 'minimal', $toolpath = $null ) diff --git a/eng/common/darc-init.sh b/eng/common/darc-init.sh index c305ae6bd771e..36dbd45e1ce86 100755 --- a/eng/common/darc-init.sh +++ b/eng/common/darc-init.sh @@ -2,7 +2,7 @@ source="${BASH_SOURCE[0]}" darcVersion='' -versionEndpoint='https://maestro.dot.net/api/assets/darc-version?api-version=2019-01-16' +versionEndpoint='https://maestro.dot.net/api/assets/darc-version?api-version=2020-02-20' verbosity='minimal' while [[ $# > 0 ]]; do diff --git a/eng/common/internal/Tools.csproj b/eng/common/internal/Tools.csproj index e925952d56664..32f79dfb3402c 100644 --- a/eng/common/internal/Tools.csproj +++ b/eng/common/internal/Tools.csproj @@ -4,6 +4,7 @@ net472 false + false diff --git a/eng/common/native/init-compiler.sh b/eng/common/native/init-compiler.sh index 62900e12b21c1..9a0e1f2b4567b 100644 --- a/eng/common/native/init-compiler.sh +++ b/eng/common/native/init-compiler.sh @@ -19,11 +19,9 @@ case "$compiler" in # clangx.y or clang-x.y version="$(echo "$compiler" | tr -d '[:alpha:]-=')" majorVersion="${version%%.*}" - [ -z "${version##*.*}" ] && minorVersion="${version#*.}" - if [ -z "$minorVersion" ] && [ -n "$majorVersion" ] && [ "$majorVersion" -le 6 ]; then - minorVersion=0; - fi + # LLVM based on v18 released in early 2024, with two releases per year + maxVersion="$((18 + ((($(date +%Y) - 2024) * 12 + $(date +%-m) - 3) / 6)))" compiler=clang ;; @@ -31,7 +29,9 @@ case "$compiler" in # gccx.y or gcc-x.y version="$(echo "$compiler" | tr -d '[:alpha:]-=')" majorVersion="${version%%.*}" - [ -z "${version##*.*}" ] && minorVersion="${version#*.}" + + # GCC based on v14 released in early 2024, with one release per year + maxVersion="$((14 + ((($(date +%Y) - 2024) * 12 + $(date +%-m) - 3) / 12)))" compiler=gcc ;; esac @@ -49,12 +49,10 @@ check_version_exists() { desired_version=-1 # Set up the environment to be used for building with the desired compiler. - if command -v "$compiler-$1.$2" > /dev/null; then - desired_version="-$1.$2" - elif command -v "$compiler$1$2" > /dev/null; then - desired_version="$1$2" - elif command -v "$compiler-$1$2" > /dev/null; then - desired_version="-$1$2" + if command -v "$compiler-$1" > /dev/null; then + desired_version="-$1" + elif command -v "$compiler$1" > /dev/null; then + desired_version="$1" fi echo "$desired_version" @@ -75,7 +73,7 @@ set_compiler_version_from_CC() { fi # gcc and clang often display 3 part versions. However, gcc can show only 1 part in some environments. - IFS=. read -r majorVersion minorVersion _ < /dev/null; then - echo "Error: No usable version of $compiler found." + echo "Error: No compatible version of $compiler was found within the range of $minVersion to $maxVersion. Please upgrade your toolchain or specify the compiler explicitly using CLR_CC and CLR_CXX environment variables." exit 1 fi CC="$(command -v "$compiler" 2> /dev/null)" CXX="$(command -v "$cxxCompiler" 2> /dev/null)" set_compiler_version_from_CC - else - if [ "$compiler" = "clang" ] && [ "$majorVersion" -lt 5 ] && { [ "$build_arch" = "arm" ] || [ "$build_arch" = "armel" ]; }; then - # If a major version was provided explicitly, and it was too old, find a newer compiler instead - if ! command -v "$compiler" > /dev/null; then - echo "Error: Found clang version $majorVersion which is not supported on arm/armel architectures, and there is no clang in PATH." - exit 1 - fi - - CC="$(command -v "$compiler" 2> /dev/null)" - CXX="$(command -v "$cxxCompiler" 2> /dev/null)" - set_compiler_version_from_CC - fi fi else - desired_version="$(check_version_exists "$majorVersion" "$minorVersion")" + desired_version="$(check_version_exists "$majorVersion")" if [ "$desired_version" = "-1" ]; then - echo "Error: Could not find specific version of $compiler: $majorVersion $minorVersion." + echo "Error: Could not find specific version of $compiler: $majorVersion." exit 1 fi fi diff --git a/eng/common/post-build/publish-using-darc.ps1 b/eng/common/post-build/publish-using-darc.ps1 index 4ff587ca46a99..90b58e32a87bf 100644 --- a/eng/common/post-build/publish-using-darc.ps1 +++ b/eng/common/post-build/publish-using-darc.ps1 @@ -42,6 +42,7 @@ try { --azdev-pat "$AzdoToken" ` --bar-uri "$MaestroApiEndPoint" ` --ci ` + --verbose ` @optionalParams if ($LastExitCode -ne 0) { diff --git a/eng/common/templates-official/job/job.yml b/eng/common/templates-official/job/job.yml index 0c2928d5c799e..3d16b41c78c18 100644 --- a/eng/common/templates-official/job/job.yml +++ b/eng/common/templates-official/job/job.yml @@ -1,8 +1,22 @@ +parameters: +# Sbom related params + enableSbom: true + PackageVersion: 9.0.0 + BuildDropPath: '$(Build.SourcesDirectory)/artifacts' + jobs: - template: /eng/common/core-templates/job/job.yml parameters: is1ESPipeline: true + componentGovernanceSteps: + - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.enableSbom, 'true')) }}: + - template: /eng/common/templates/steps/generate-sbom.yml + parameters: + PackageVersion: ${{ parameters.packageVersion }} + BuildDropPath: ${{ parameters.buildDropPath }} + publishArtifacts: false + # publish artifacts # for 1ES managed templates, use the templateContext.output to handle multiple outputs. templateContext: diff --git a/eng/common/templates-official/steps/execute-sdl.yml b/eng/common/templates-official/steps/execute-sdl.yml new file mode 100644 index 0000000000000..301d5c591ebd1 --- /dev/null +++ b/eng/common/templates-official/steps/execute-sdl.yml @@ -0,0 +1,86 @@ +parameters: + overrideGuardianVersion: '' + executeAllSdlToolsScript: '' + overrideParameters: '' + additionalParameters: '' + publishGuardianDirectoryToPipeline: false + sdlContinueOnError: false + condition: '' + +steps: +- task: NuGetAuthenticate@1 + +- task: NuGetToolInstaller@1 + displayName: 'Install NuGet.exe' + +- ${{ if ne(parameters.overrideGuardianVersion, '') }}: + - pwsh: | + Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl + . .\sdl.ps1 + $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts -Version ${{ parameters.overrideGuardianVersion }} + Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" + displayName: Install Guardian (Overridden) + +- ${{ if eq(parameters.overrideGuardianVersion, '') }}: + - pwsh: | + Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl + . .\sdl.ps1 + $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts + Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" + displayName: Install Guardian + +- ${{ if ne(parameters.overrideParameters, '') }}: + - powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }} + displayName: Execute SDL (Overridden) + continueOnError: ${{ parameters.sdlContinueOnError }} + condition: ${{ parameters.condition }} + +- ${{ if eq(parameters.overrideParameters, '') }}: + - powershell: ${{ parameters.executeAllSdlToolsScript }} + -GuardianCliLocation $(GuardianCliLocation) + -NugetPackageDirectory $(Build.SourcesDirectory)\.packages + -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw) + ${{ parameters.additionalParameters }} + displayName: Execute SDL + continueOnError: ${{ parameters.sdlContinueOnError }} + condition: ${{ parameters.condition }} + +- ${{ if ne(parameters.publishGuardianDirectoryToPipeline, 'false') }}: + # We want to publish the Guardian results and configuration for easy diagnosis. However, the + # '.gdn' dir is a mix of configuration, results, extracted dependencies, and Guardian default + # tooling files. Some of these files are large and aren't useful during an investigation, so + # exclude them by simply deleting them before publishing. (As of writing, there is no documented + # way to selectively exclude a dir from the pipeline artifact publish task.) + - task: DeleteFiles@1 + displayName: Delete Guardian dependencies to avoid uploading + inputs: + SourceFolder: $(Agent.BuildDirectory)/.gdn + Contents: | + c + i + condition: succeededOrFailed() + + - publish: $(Agent.BuildDirectory)/.gdn + artifact: GuardianConfiguration + displayName: Publish GuardianConfiguration + condition: succeededOrFailed() + + # Publish the SARIF files in a container named CodeAnalysisLogs to enable integration + # with the "SARIF SAST Scans Tab" Azure DevOps extension + - task: CopyFiles@2 + displayName: Copy SARIF files + inputs: + flattenFolders: true + sourceFolder: $(Agent.BuildDirectory)/.gdn/rc/ + contents: '**/*.sarif' + targetFolder: $(Build.SourcesDirectory)/CodeAnalysisLogs + condition: succeededOrFailed() + + # Use PublishBuildArtifacts because the SARIF extension only checks this case + # see microsoft/sarif-azuredevops-extension#4 + - task: PublishBuildArtifacts@1 + displayName: Publish SARIF files to CodeAnalysisLogs container + inputs: + pathToPublish: $(Build.SourcesDirectory)/CodeAnalysisLogs + artifactName: CodeAnalysisLogs + condition: succeededOrFailed() \ No newline at end of file diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml index 8da477dd69f06..07d317bf8f9a4 100644 --- a/eng/common/templates/job/job.yml +++ b/eng/common/templates/job/job.yml @@ -19,71 +19,63 @@ jobs: steps: - ${{ each step in parameters.steps }}: - ${{ step }} - + componentGovernanceSteps: - - template: /eng/common/templates/steps/component-governance.yml - parameters: - ${{ if eq(parameters.disableComponentGovernance, '') }}: - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.runAsPublic, 'false'), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/dotnet/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/microsoft/'), eq(variables['Build.SourceBranch'], 'refs/heads/main'))) }}: - disableComponentGovernance: false - ${{ else }}: - disableComponentGovernance: true + - template: /eng/common/templates/steps/component-governance.yml + parameters: + ${{ if eq(parameters.disableComponentGovernance, '') }}: + ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.runAsPublic, 'false'), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/dotnet/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/microsoft/'), eq(variables['Build.SourceBranch'], 'refs/heads/main'))) }}: + disableComponentGovernance: false ${{ else }}: - disableComponentGovernance: ${{ parameters.disableComponentGovernance }} - componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} - - - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.enableSbom, 'true')) }}: - - template: /eng/common/templates/steps/generate-sbom.yml - parameters: - PackageVersion: ${{ parameters.packageVersion }} - BuildDropPath: ${{ parameters.buildDropPath }} - publishArtifacts: false - + disableComponentGovernance: true + ${{ else }}: + disableComponentGovernance: ${{ parameters.disableComponentGovernance }} + componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }} artifactPublishSteps: - - ${{ if ne(parameters.artifacts.publish, '') }}: - - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}: - - template: /eng/common/core-templates/steps/publish-build-artifacts.yml - parameters: - is1ESPipeline: false - args: - displayName: Publish pipeline artifacts - pathToPublish: '$(Build.ArtifactStagingDirectory)/artifacts' - publishLocation: Container - artifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }} - continueOnError: true - condition: always() - - ${{ if and(ne(parameters.artifacts.publish.logs, 'false'), ne(parameters.artifacts.publish.logs, '')) }}: - - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml - parameters: - is1ESPipeline: false - args: - targetPath: '$(Build.ArtifactStagingDirectory)/artifacts/log' - artifactName: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)') }} - displayName: 'Publish logs' - continueOnError: true - condition: always() - sbomEnabled: false # we don't need SBOM for logs - - - ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}: + - ${{ if ne(parameters.artifacts.publish, '') }}: + - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}: - template: /eng/common/core-templates/steps/publish-build-artifacts.yml parameters: is1ESPipeline: false args: - displayName: Publish Logs - pathToPublish: '$(Build.ArtifactStagingDirectory)/artifacts/log/$(_BuildConfig)' + displayName: Publish pipeline artifacts + pathToPublish: '$(Build.ArtifactStagingDirectory)/artifacts' publishLocation: Container - artifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)' ) }} + artifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }} continueOnError: true condition: always() - - - ${{ if eq(parameters.enableBuildRetry, 'true') }}: + - ${{ if and(ne(parameters.artifacts.publish.logs, 'false'), ne(parameters.artifacts.publish.logs, '')) }}: - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml parameters: is1ESPipeline: false args: - targetPath: '$(Build.SourcesDirectory)\eng\common\BuildConfiguration' - artifactName: 'BuildConfiguration' - displayName: 'Publish build retry configuration' + targetPath: '$(Build.ArtifactStagingDirectory)/artifacts/log' + artifactName: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)') }} + displayName: 'Publish logs' continueOnError: true - sbomEnabled: false # we don't need SBOM for BuildConfiguration + condition: always() + sbomEnabled: false # we don't need SBOM for logs + + - ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}: + - template: /eng/common/core-templates/steps/publish-build-artifacts.yml + parameters: + is1ESPipeline: false + args: + displayName: Publish Logs + pathToPublish: '$(Build.ArtifactStagingDirectory)/artifacts/log/$(_BuildConfig)' + publishLocation: Container + artifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)' ) }} + continueOnError: true + condition: always() + + - ${{ if eq(parameters.enableBuildRetry, 'true') }}: + - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml + parameters: + is1ESPipeline: false + args: + targetPath: '$(Build.SourcesDirectory)\eng\common\BuildConfiguration' + artifactName: 'BuildConfiguration' + displayName: 'Publish build retry configuration' + continueOnError: true + sbomEnabled: false # we don't need SBOM for BuildConfiguration diff --git a/eng/common/templates/steps/execute-sdl.yml b/eng/common/templates/steps/execute-sdl.yml new file mode 100644 index 0000000000000..fe0ebf8c904eb --- /dev/null +++ b/eng/common/templates/steps/execute-sdl.yml @@ -0,0 +1,89 @@ +parameters: + overrideGuardianVersion: '' + executeAllSdlToolsScript: '' + overrideParameters: '' + additionalParameters: '' + publishGuardianDirectoryToPipeline: false + sdlContinueOnError: false + condition: '' + +steps: +- task: NuGetAuthenticate@1 + +- task: NuGetToolInstaller@1 + displayName: 'Install NuGet.exe' + +- ${{ if ne(parameters.overrideGuardianVersion, '') }}: + - pwsh: | + Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl + . .\sdl.ps1 + $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts -Version ${{ parameters.overrideGuardianVersion }} + Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" + displayName: Install Guardian (Overridden) + +- ${{ if eq(parameters.overrideGuardianVersion, '') }}: + - pwsh: | + Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl + . .\sdl.ps1 + $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts + Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" + displayName: Install Guardian + +- ${{ if ne(parameters.overrideParameters, '') }}: + - powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }} + displayName: Execute SDL (Overridden) + continueOnError: ${{ parameters.sdlContinueOnError }} + condition: ${{ parameters.condition }} + env: + GUARDIAN_DEFAULT_PACKAGE_SOURCE_SECRET: $(System.AccessToken) + +- ${{ if eq(parameters.overrideParameters, '') }}: + - powershell: ${{ parameters.executeAllSdlToolsScript }} + -GuardianCliLocation $(GuardianCliLocation) + -NugetPackageDirectory $(Build.SourcesDirectory)\.packages + ${{ parameters.additionalParameters }} + displayName: Execute SDL + continueOnError: ${{ parameters.sdlContinueOnError }} + condition: ${{ parameters.condition }} + env: + GUARDIAN_DEFAULT_PACKAGE_SOURCE_SECRET: $(System.AccessToken) + +- ${{ if ne(parameters.publishGuardianDirectoryToPipeline, 'false') }}: + # We want to publish the Guardian results and configuration for easy diagnosis. However, the + # '.gdn' dir is a mix of configuration, results, extracted dependencies, and Guardian default + # tooling files. Some of these files are large and aren't useful during an investigation, so + # exclude them by simply deleting them before publishing. (As of writing, there is no documented + # way to selectively exclude a dir from the pipeline artifact publish task.) + - task: DeleteFiles@1 + displayName: Delete Guardian dependencies to avoid uploading + inputs: + SourceFolder: $(Agent.BuildDirectory)/.gdn + Contents: | + c + i + condition: succeededOrFailed() + + - publish: $(Agent.BuildDirectory)/.gdn + artifact: GuardianConfiguration + displayName: Publish GuardianConfiguration + condition: succeededOrFailed() + + # Publish the SARIF files in a container named CodeAnalysisLogs to enable integration + # with the "SARIF SAST Scans Tab" Azure DevOps extension + - task: CopyFiles@2 + displayName: Copy SARIF files + inputs: + flattenFolders: true + sourceFolder: $(Agent.BuildDirectory)/.gdn/rc/ + contents: '**/*.sarif' + targetFolder: $(Build.SourcesDirectory)/CodeAnalysisLogs + condition: succeededOrFailed() + + # Use PublishBuildArtifacts because the SARIF extension only checks this case + # see microsoft/sarif-azuredevops-extension#4 + - task: PublishBuildArtifacts@1 + displayName: Publish SARIF files to CodeAnalysisLogs container + inputs: + pathToPublish: $(Build.SourcesDirectory)/CodeAnalysisLogs + artifactName: CodeAnalysisLogs + condition: succeededOrFailed() \ No newline at end of file diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index bdff2ce9f662e..33e27bbbb2e40 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -94,6 +94,15 @@ }, "comment-about-servicing-branches": "For a list of VS versions under servicing, see https://docs.microsoft.com/en-us/visualstudio/releases/2019/servicing#support-options-for-enterprise-and-professional-customers", "branches": { + "release/vscode": { + "nugetKind": [ + "Shipping", + "NonShipping" + ], + "vsBranch": "main", + "insertionCreateDraftPR": true, + "insertionTitlePrefix": "[Validation]" + }, "dev15.9.x-vs-deps": { "nugetKind": "PerBuildPreRelease", "vsBranch": "rel/d15.9", @@ -143,24 +152,6 @@ "vsMajorVersion": 17, "insertionTitlePrefix": "[d17.3]" }, - "release/dev17.4": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.4", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.4]" - }, - "release/dev17.5-vs-deps": { - "nugetKind": [ - "Shipping", - "NonShipping" - ], - "vsBranch": "rel/d17.5", - "vsMajorVersion": 17, - "insertionTitlePrefix": "[d17.5]" - }, "release/dev17.6": { "nugetKind": [ "Shipping", @@ -215,7 +206,7 @@ "vsMajorVersion": 17, "insertionTitlePrefix": "[d17.11]" }, - "main": { + "release/dev17.12": { "nugetKind": [ "Shipping", "NonShipping" @@ -223,7 +214,17 @@ "vsBranch": "main", "vsMajorVersion": 17, "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[d17.12 P1]" + "insertionTitlePrefix": "[d17.12 P3]" + }, + "main": { + "nugetKind": [ + "Shipping", + "NonShipping" + ], + "vsBranch": "main", + "vsMajorVersion": 17, + "insertionCreateDraftPR": true, + "insertionTitlePrefix": "[d17.13 P1]" }, "dev/andrha/telemetry": { "nugetKind": [ diff --git a/eng/config/app.manifest b/eng/config/app.manifest index 6000b933d37ea..e57d652ba650e 100644 --- a/eng/config/app.manifest +++ b/eng/config/app.manifest @@ -14,6 +14,7 @@ true + amd64 arm64 - \ No newline at end of file + diff --git a/eng/config/guardian/.gdnsuppress b/eng/config/guardian/.gdnsuppress deleted file mode 100644 index 9ccb486a7ae08..0000000000000 --- a/eng/config/guardian/.gdnsuppress +++ /dev/null @@ -1,41 +0,0 @@ -{ - "properties": { - "helpUri": "https://eng.ms/docs/microsoft-security/security/azure-security/cloudai-security-fundamentals-engineering/security-integration/guardian-wiki/microsoft-guardian/general/suppressions" - }, - "version": "1.0.0", - "suppressionSets": { - "default": { - "name": "default", - "createdDate": "2024-03-21 01:38:07Z", - "lastUpdatedDate": "2024-03-21 01:38:07Z" - } - }, - "results": { - "847ed085b811316467ddba6a5f31a5084c27c4bb1c4a7d584dc0e857018dc898": { - "signature": "847ed085b811316467ddba6a5f31a5084c27c4bb1c4a7d584dc0e857018dc898", - "alternativeSignatures": [ - "3e868456152947a1ac244bf80f7f116223d51ec35a46334f64b621b35255a1aa" - ], - "target": "eng/build.ps1", - "line": 340, - "memberOf": [ - "default" - ], - "tool": "psscriptanalyzer", - "ruleId": "PSAvoidUsingConvertToSecureStringWithPlainText", - "createdDate": "2024-03-21 01:38:07Z" - }, - "ec3b30de7f7c5fca72d402bd7f34279d378700b16d98b2f3da9922fa8db3546f": { - "signature": "ec3b30de7f7c5fca72d402bd7f34279d378700b16d98b2f3da9922fa8db3546f", - "alternativeSignatures": [], - "target": "src/EditorFeatures/CSharpTest2/EmbeddedLanguages/Json/CSharpJsonParserTests_BasicTests.cs", - "line": 4207, - "memberOf": [ - "default" - ], - "tool": "credscan", - "ruleId": "CSCAN-GENERAL0060", - "createdDate": "2024-03-21 01:38:07Z" - } - } -} \ No newline at end of file diff --git a/eng/generate-vssdk-versions.csx b/eng/generate-vssdk-versions.csx index 00418d83313e0..0a751f62c31bb 100644 --- a/eng/generate-vssdk-versions.csx +++ b/eng/generate-vssdk-versions.csx @@ -73,7 +73,7 @@ foreach (var (id, version) in properties) else if (!seenMsbuild) { Console.WriteLine($$""" - + diff --git a/eng/targets/DiaSymReaderNative.targets b/eng/targets/DiaSymReaderNative.targets index 6d52450769734..11956fb0b5233 100644 --- a/eng/targets/DiaSymReaderNative.targets +++ b/eng/targets/DiaSymReaderNative.targets @@ -18,7 +18,7 @@ package can't be referenced directly but rather has to have it's assets manually copied out. This logic is responsible for doing that. --> - + PreserveNewest false diff --git a/eng/targets/ILAsm.targets b/eng/targets/ILAsm.targets index edc2368e0ebad..9fa6580b2ce56 100644 --- a/eng/targets/ILAsm.targets +++ b/eng/targets/ILAsm.targets @@ -12,6 +12,12 @@ false false + + PreserveNewest + runtimes + false + false + PreserveNewest runtimes @@ -26,7 +32,8 @@ + - \ No newline at end of file + diff --git a/eng/targets/ILDAsm.targets b/eng/targets/ILDAsm.targets index 9e94a720804b8..2992ece5a1d44 100644 --- a/eng/targets/ILDAsm.targets +++ b/eng/targets/ILDAsm.targets @@ -11,6 +11,12 @@ false false + + PreserveNewest + runtimes + false + false + PreserveNewest runtimes @@ -25,7 +31,8 @@ + - \ No newline at end of file + diff --git a/eng/targets/Imports.BeforeArcade.targets b/eng/targets/Imports.BeforeArcade.targets index b24d5c05bc401..dae97165ac94c 100644 --- a/eng/targets/Imports.BeforeArcade.targets +++ b/eng/targets/Imports.BeforeArcade.targets @@ -14,7 +14,7 @@ - + false diff --git a/eng/targets/Imports.targets b/eng/targets/Imports.targets index 46eb0380702c3..c8696437ac702 100644 --- a/eng/targets/Imports.targets +++ b/eng/targets/Imports.targets @@ -4,6 +4,7 @@ + + + + + + diff --git a/eng/targets/Services.props b/eng/targets/Services.props index 7a1dd4ad79358..590cd0c2a1518 100644 --- a/eng/targets/Services.props +++ b/eng/targets/Services.props @@ -13,38 +13,39 @@ + + + + + - + - - - - + + + + + + - - - - - - + - + + + + + + + - - - - - - - - - + + NON_EXISTENT_FILE @@ -61,12 +61,6 @@ <_SkipUpgradeNetAnalyzersNuGetWarning>true - - false - $(CoreCompileDependsOn);ResolveKeySource @@ -160,7 +154,7 @@ - + @@ -175,7 +169,7 @@ - + @@ -255,7 +249,7 @@ - + DOTNET_BUILD_FROM_SOURCE;$(DefineConstants) DOTNET_BUILD_FROM_SOURCE diff --git a/eng/targets/TargetFrameworks.props b/eng/targets/TargetFrameworks.props index 8493c1046cb51..1132c2d08b57f 100644 --- a/eng/targets/TargetFrameworks.props +++ b/eng/targets/TargetFrameworks.props @@ -35,7 +35,7 @@ bootstrap toolset in other repos doing (1). Those can be using a NetPrevious runtime hence the toolset must support that. --> - + $(NetMinimum) @@ -50,7 +50,7 @@ - + $(NetCurrent) $(NetCurrent);$(NetPrevious) diff --git a/eng/targets/VisualStudio.targets b/eng/targets/VisualStudio.targets index 9d5b9b3fc2818..64e8116ca4adf 100644 --- a/eng/targets/VisualStudio.targets +++ b/eng/targets/VisualStudio.targets @@ -143,4 +143,35 @@ + + + + + + + + $(CreateVsixContainerDependsOn);PublishProjectReferencesForVsixCreation + + + + + <_ProjectsToPublish Include="@(ProjectReference)" Condition="$([MSBuild]::ValueOrDefault('%(ProjectReference.IncludeOutputGroupsInVSIX)', '').Contains('PublishedProjectOutputGroup'))"/> + + + + diff --git a/eng/targets/WpfWorkarounds.targets b/eng/targets/WpfWorkarounds.targets new file mode 100644 index 0000000000000..4bc46a00f1ccb --- /dev/null +++ b/eng/targets/WpfWorkarounds.targets @@ -0,0 +1,12 @@ + + + + + + + <_WindowsDesktopSDKDir>$(NuGetPackageRoot)microsoft.net.sdk.windowsdesktop\9.0.0-rc.1.24425.3\ + <_PresentationBuildTasksTfm Condition="'$(MSBuildRuntimeType)' == 'Core'">net9.0 + <_PresentationBuildTasksTfm Condition="'$(MSBuildRuntimeType)' != 'Core'">net472 + <_PresentationBuildTasksAssembly Condition="'$(_PresentationBuildTasksAssembly)'==''">$([MSBuild]::Unescape($([System.IO.Path]::GetFullPath('$(_WindowsDesktopSDKDir)tools\$(_PresentationBuildTasksTfm)\PresentationBuildTasks.dll')))) + + \ No newline at end of file diff --git a/eng/test-build-correctness.ps1 b/eng/test-build-correctness.ps1 index 9c131c1d189c4..aab81e9a89b6c 100644 --- a/eng/test-build-correctness.ps1 +++ b/eng/test-build-correctness.ps1 @@ -75,7 +75,7 @@ catch { Write-Host $_ Write-Host $_.Exception Write-Host $_.ScriptStackTrace - Write-Host "##vso[task.logissue type=error]How to investigate bootstrap failures: https://github.com/dotnet/roslyn/blob/main/docs/compilers/Bootstrap%20Builds.md#Investigating" + Write-Host "##vso[task.logissue type=error]How to investigate bootstrap failures: https://github.com/dotnet/roslyn/blob/main/docs/contributing/Bootstrap%20Builds.md#Investigating" ExitWithExitCode 1 } finally { diff --git a/global.json b/global.json index 2cd32c6ddbf19..2e5746985615d 100644 --- a/global.json +++ b/global.json @@ -1,18 +1,18 @@ { "sdk": { - "version": "9.0.100-preview.5.24307.3", + "version": "9.0.100-preview.7.24407.12", "allowPrerelease": false, "rollForward": "patch" }, "tools": { - "dotnet": "9.0.100-preview.5.24307.3", + "dotnet": "9.0.100-preview.7.24407.12", "vs": { "version": "17.8.0" } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24352.2", - "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24352.2", + "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24459.6", + "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24459.6", "Microsoft.Build.Traversal": "3.4.0" } } diff --git a/scripts/vscode-build.ps1 b/scripts/vscode-build.ps1 index 42f3c0475b9c1..4c1722c6fa927 100644 --- a/scripts/vscode-build.ps1 +++ b/scripts/vscode-build.ps1 @@ -14,7 +14,7 @@ $projectFileInfo = Get-ProjectFile $fileInfo if ($projectFileInfo) { $buildTool = InitializeBuildTool $frameworkArg = if ($framework -ne "") { " -p:TargetFramework=$framework" } else { "" } - $buildArgs = "$($buildTool.Command) -v:m -m -p:RunAnalyzersDuringBuild=false -p:GenerateFullPaths=true$frameworkArg $($projectFileInfo.FullName)" + $buildArgs = "$($buildTool.Command) -v:m -tl:off -m -p:RunAnalyzersDuringBuild=false -p:GenerateFullPaths=true$frameworkArg $($projectFileInfo.FullName)" Exec-Command $buildTool.Path $buildArgs exit 0 diff --git a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems index a13697111e9c7..5f550c427c2b5 100644 --- a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems +++ b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems @@ -82,7 +82,6 @@ - diff --git a/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.cs index cc1998d92fddc..0c301b610c1da 100644 --- a/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/InlineDeclaration/CSharpInlineDeclarationDiagnosticAnalyzer.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.Linq; using System.Linq.Expressions; @@ -30,7 +31,7 @@ namespace Microsoft.CodeAnalysis.CSharp.InlineDeclaration; /// /// [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal class CSharpInlineDeclarationDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer +internal sealed class CSharpInlineDeclarationDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer { private const string CS0165 = nameof(CS0165); // Use of unassigned local variable 's' @@ -179,10 +180,9 @@ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context, INamedTypeSymb // for references to the local to make sure that no reads/writes happen before // the out-argument. If there are any reads/writes we can't inline as those // accesses will become invalid. - if (localStatement.Parent is not BlockSyntax enclosingBlockOfLocalStatement) - { + var enclosingBlockOfLocalStatement = GetEnclosingPseudoBlock(localStatement.Parent); + if (enclosingBlockOfLocalStatement is null) return; - } if (argumentExpression.IsInExpressionTree(semanticModel, expressionType, cancellationToken)) { @@ -223,8 +223,8 @@ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context, INamedTypeSymb // See if inlining this variable would make it so that some variables were no // longer definitely assigned. - if (WouldCauseDefiniteAssignmentErrors(semanticModel, localStatement, - enclosingBlockOfLocalStatement, outLocalSymbol)) + if (WouldCauseDefiniteAssignmentErrors( + semanticModel, localStatement, enclosingBlockOfLocalStatement, outLocalSymbol)) { return; } @@ -251,10 +251,38 @@ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context, INamedTypeSymb properties: null)); } + public static SyntaxNode? GetEnclosingPseudoBlock(SyntaxNode? parent) + { + if (parent is BlockSyntax) + return parent; + + if (parent is SwitchSectionSyntax) + return parent; + + if (parent is GlobalStatementSyntax) + return parent.Parent as CompilationUnitSyntax; + + return null; + } + + private static StatementSyntax GetLastStatement(SyntaxNode enclosingBlock) + { + if (enclosingBlock is BlockSyntax block) + return block.Statements.Last(); + + if (enclosingBlock is SwitchSectionSyntax switchSection) + return switchSection.Statements.Last(); + + if (enclosingBlock is CompilationUnitSyntax compilationUnit) + return compilationUnit.Members.OfType().Last().Statement; + + throw ExceptionUtilities.Unreachable(); + } + private static bool WouldCauseDefiniteAssignmentErrors( SemanticModel semanticModel, LocalDeclarationStatementSyntax localStatement, - BlockSyntax enclosingBlock, + SyntaxNode enclosingBlock, ILocalSymbol outLocalSymbol) { // See if we have something like: @@ -272,7 +300,7 @@ private static bool WouldCauseDefiniteAssignmentErrors( var dataFlow = semanticModel.AnalyzeDataFlow( nextStatement, - enclosingBlock.Statements.Last()); + GetLastStatement(enclosingBlock)); Contract.ThrowIfNull(dataFlow); return dataFlow.DataFlowsIn.Contains(outLocalSymbol); } @@ -332,7 +360,7 @@ private static bool WouldCauseDefiniteAssignmentErrors( private static bool IsAccessed( SemanticModel semanticModel, ISymbol outSymbol, - BlockSyntax enclosingBlockOfLocalStatement, + SyntaxNode enclosingBlockOfLocalStatement, LocalDeclarationStatementSyntax localStatement, ArgumentSyntax argumentNode, CancellationToken cancellationToken) diff --git a/src/Analyzers/CSharp/Analyzers/RemoveUnusedMembers/CSharpRemoveUnusedMembersDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/RemoveUnusedMembers/CSharpRemoveUnusedMembersDiagnosticAnalyzer.cs index 2bb616b174829..55ed47da767b2 100644 --- a/src/Analyzers/CSharp/Analyzers/RemoveUnusedMembers/CSharpRemoveUnusedMembersDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/RemoveUnusedMembers/CSharpRemoveUnusedMembersDiagnosticAnalyzer.cs @@ -8,11 +8,12 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.RemoveUnusedMembers; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.RemoveUnusedMembers; [DiagnosticAnalyzer(LanguageNames.CSharp)] -internal class CSharpRemoveUnusedMembersDiagnosticAnalyzer +internal sealed class CSharpRemoveUnusedMembersDiagnosticAnalyzer : AbstractRemoveUnusedMembersDiagnosticAnalyzer< DocumentationCommentTriviaSyntax, IdentifierNameSyntax, @@ -28,4 +29,18 @@ protected override IEnumerable GetTypeDeclarations(INamed protected override SyntaxList GetMembers(TypeDeclarationSyntax typeDeclaration) => typeDeclaration.Members; + + protected override SyntaxNode GetParentIfSoleDeclarator(SyntaxNode node) + { + return node switch + { + VariableDeclaratorSyntax variableDeclarator + => variableDeclarator.Parent is VariableDeclarationSyntax + { + Parent: FieldDeclarationSyntax { Declaration.Variables.Count: 0 } or + EventFieldDeclarationSyntax { Declaration.Variables.Count: 0 } + } declaration ? declaration.GetRequiredParent() : node, + _ => node, + }; + } } diff --git a/src/Analyzers/CSharp/Analyzers/UseAutoProperty/CSharpUseAutoPropertyAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseAutoProperty/CSharpUseAutoPropertyAnalyzer.cs index 4dd854bff2926..ac65a9e833852 100644 --- a/src/Analyzers/CSharp/Analyzers/UseAutoProperty/CSharpUseAutoPropertyAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseAutoProperty/CSharpUseAutoPropertyAnalyzer.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -29,6 +30,12 @@ internal sealed class CSharpUseAutoPropertyAnalyzer : AbstractUseAutoPropertyAna protected override SyntaxKind PropertyDeclarationKind => SyntaxKind.PropertyDeclaration; + protected override bool CanExplicitInterfaceImplementationsBeFixed + => false; + + protected override bool SupportsFieldAttributesOnProperties + => true; + protected override ISemanticFacts SemanticFacts => CSharpSemanticFacts.Instance; @@ -38,15 +45,26 @@ protected override bool SupportsReadOnlyProperties(Compilation compilation) protected override bool SupportsPropertyInitializer(Compilation compilation) => compilation.LanguageVersion() >= LanguageVersion.CSharp6; - protected override bool CanExplicitInterfaceImplementationsBeFixed() - => false; + protected override bool SupportsFieldExpression(Compilation compilation) + => compilation.LanguageVersion() >= LanguageVersion.Preview; protected override ExpressionSyntax? GetFieldInitializer(VariableDeclaratorSyntax variable, CancellationToken cancellationToken) => variable.Initializer?.Value; - protected override void RegisterIneligibleFieldsAction( + protected override bool ContainsFieldExpression(PropertyDeclarationSyntax propertyDeclaration, CancellationToken cancellationToken) + { + foreach (var node in propertyDeclaration.DescendantNodes()) + { + if (node.IsKind(SyntaxKind.FieldExpression)) + return true; + } + + return false; + } + + protected override void RecordIneligibleFieldLocations( HashSet fieldNames, - ConcurrentSet ineligibleFields, + ConcurrentDictionary> ineligibleFieldUsageIfOutsideProperty, SemanticModel semanticModel, SyntaxNode codeBlock, CancellationToken cancellationToken) @@ -54,15 +72,22 @@ protected override void RegisterIneligibleFieldsAction( foreach (var argument in codeBlock.DescendantNodesAndSelf().OfType()) { // An argument will disqualify a field if that field is used in a ref/out position. - // We can't change such field references to be property references in C#. + // We can't change such field references to be property references in C#, unless we + // are converting to the `field` keyword. if (argument.RefKindKeyword.Kind() != SyntaxKind.None) AddIneligibleFieldsForExpression(argument.Expression); + + // Use of a field in a nameof(...) expression can't *ever* be converted to use `field`. + // So hard block in this case. + if (argument.Expression.IsNameOfArgumentExpression()) + AddIneligibleFieldsForExpression(argument.Expression, alwaysRestricted: true); } foreach (var refExpression in codeBlock.DescendantNodesAndSelf().OfType()) AddIneligibleFieldsForExpression(refExpression.Expression); - // Can't take the address of an auto-prop. So disallow for fields that we do `&x` on. + // Can't take the address of an auto-prop. So disallow for fields that we do `&x` on. Unless we are converting + // to the `field` keyword. foreach (var addressOfExpression in codeBlock.DescendantNodesAndSelf().OfType()) { if (addressOfExpression.Kind() == SyntaxKind.AddressOfExpression) @@ -72,9 +97,11 @@ protected override void RegisterIneligibleFieldsAction( foreach (var memberAccess in codeBlock.DescendantNodesAndSelf().OfType()) { if (CouldReferenceField(memberAccess)) - AddIneligibleFieldsIfAccessedOffNotDefinitelyAssignedValue(semanticModel, memberAccess, ineligibleFields, cancellationToken); + AddIneligibleFieldsIfAccessedOffNotDefinitelyAssignedValue(memberAccess); } + return; + bool CouldReferenceField(ExpressionSyntax expression) { // Don't bother binding if the expression isn't even referencing the name of a field we know about. @@ -82,50 +109,62 @@ bool CouldReferenceField(ExpressionSyntax expression) return rightmostName != null && fieldNames.Contains(rightmostName); } - void AddIneligibleFieldsForExpression(ExpressionSyntax expression) + void AddIneligibleFieldsForExpression(ExpressionSyntax expression, bool alwaysRestricted = false) { if (!CouldReferenceField(expression)) return; var symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken); - AddIneligibleFields(ineligibleFields, symbolInfo); + AddIneligibleFields(symbolInfo, expression, alwaysRestricted); } - } - private static void AddIneligibleFieldsIfAccessedOffNotDefinitelyAssignedValue( - SemanticModel semanticModel, MemberAccessExpressionSyntax memberAccess, ConcurrentSet ineligibleFields, CancellationToken cancellationToken) - { - // `c.x = ...` can't be converted to `c.X = ...` if `c` is a struct and isn't definitely assigned as that point. + void AddIneligibleFieldsIfAccessedOffNotDefinitelyAssignedValue( + MemberAccessExpressionSyntax memberAccess) + { + // `c.x = ...` can't be converted to `c.X = ...` if `c` is a struct and isn't definitely assigned as that point. - // only care about writes. if this was a read, then it must be def assigned and thus is safe to convert to a prop. - if (!memberAccess.IsOnlyWrittenTo()) - return; + // only care about writes. if this was a read, then it must be def assigned and thus is safe to convert to a prop. + if (!memberAccess.IsOnlyWrittenTo()) + return; - // this only matters for a field access off of a struct. They can be declared unassigned and have their - // fields directly written into. - var symbolInfo = semanticModel.GetSymbolInfo(memberAccess, cancellationToken); - if (symbolInfo.GetAnySymbol() is not IFieldSymbol { ContainingType.TypeKind: TypeKind.Struct }) - return; + // this only matters for a field access off of a struct. They can be declared unassigned and have their + // fields directly written into. + var symbolInfo = semanticModel.GetSymbolInfo(memberAccess, cancellationToken); + if (symbolInfo.GetAnySymbol() is not IFieldSymbol { ContainingType.TypeKind: TypeKind.Struct }) + return; - var exprSymbol = semanticModel.GetSymbolInfo(memberAccess.Expression, cancellationToken).GetAnySymbol(); - if (exprSymbol is not IParameterSymbol and not ILocalSymbol) - return; + var exprSymbol = semanticModel.GetSymbolInfo(memberAccess.Expression, cancellationToken).GetAnySymbol(); + if (exprSymbol is not IParameterSymbol and not ILocalSymbol) + return; - var dataFlow = semanticModel.AnalyzeDataFlow(memberAccess.Expression); - if (dataFlow != null && !dataFlow.DefinitelyAssignedOnEntry.Contains(exprSymbol)) - AddIneligibleFields(ineligibleFields, symbolInfo); - } + var dataFlow = semanticModel.AnalyzeDataFlow(memberAccess.Expression); + if (dataFlow != null && !dataFlow.DefinitelyAssignedOnEntry.Contains(exprSymbol)) + AddIneligibleFields(symbolInfo, memberAccess); + } - private static void AddIneligibleFields(ConcurrentSet ineligibleFields, SymbolInfo symbolInfo) - { - AddIneligibleField(symbolInfo.Symbol); - foreach (var symbol in symbolInfo.CandidateSymbols) - AddIneligibleField(symbol); + void AddIneligibleFields( + SymbolInfo symbolInfo, + SyntaxNode location, + bool alwaysRestricted = false) + { + AddIneligibleField(symbolInfo.Symbol, location, alwaysRestricted); + foreach (var symbol in symbolInfo.CandidateSymbols) + AddIneligibleField(symbol, location, alwaysRestricted); + } - void AddIneligibleField(ISymbol? symbol) + void AddIneligibleField( + ISymbol? symbol, + SyntaxNode location, + bool alwaysRestricted) { + // If the field is always restricted, then add the compilation unit itself to the ineligibility locations. + // that way we never think we can convert this field. if (symbol is IFieldSymbol field) - ineligibleFields.Add(field); + { + AddFieldUsage(ineligibleFieldUsageIfOutsideProperty, field, alwaysRestricted + ? location.SyntaxTree.GetRoot(cancellationToken) + : location); + } } } @@ -181,7 +220,7 @@ private static bool CheckExpressionSyntactically(ExpressionSyntax expression) => accessorDeclaration is { Body.Statements: [T statement] } ? statement : null; protected override ExpressionSyntax? GetSetterExpression( - IMethodSymbol setMethod, SemanticModel semanticModel, CancellationToken cancellationToken) + SemanticModel semanticModel, IMethodSymbol setMethod, CancellationToken cancellationToken) { // Setter has to be of the form: // @@ -213,4 +252,24 @@ protected override SyntaxNode GetFieldNode( ? fieldDeclaration : variableDeclarator; } + + protected override void AddAccessedFields( + SemanticModel semanticModel, + IMethodSymbol accessor, + HashSet fieldNames, + HashSet result, + CancellationToken cancellationToken) + { + var syntax = accessor.DeclaringSyntaxReferences[0].GetSyntax(cancellationToken); + foreach (var descendant in syntax.DescendantNodesAndSelf()) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (descendant is IdentifierNameSyntax identifierName) + { + result.AddIfNotNull(TryGetDirectlyAccessedFieldSymbol( + semanticModel, identifierName, fieldNames, cancellationToken)); + } + } + } } diff --git a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer.cs index 887b530668f8c..3e1c756b5b5d3 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer.cs @@ -13,11 +13,12 @@ using Microsoft.CodeAnalysis.Shared.CodeStyle; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.UseCollectionExpression; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UseCollectionExpression; -using static SyntaxFactory; +using static UseCollectionExpressionHelpers; [DiagnosticAnalyzer(LanguageNames.CSharp)] internal sealed partial class CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer() @@ -49,16 +50,18 @@ private void AnalyzeArrayCreationExpression(SyntaxNodeAnalysisContext context, I // Analyze the statements that follow to see if they can initialize this array. var allowSemanticsChange = option.Value is CollectionExpressionPreference.WhenTypesLooselyMatch; - var matches = TryGetMatches(semanticModel, arrayCreationExpression, expressionType, allowSemanticsChange, cancellationToken, out var changesSemantics); + var replacementExpression = CreateReplacementCollectionExpressionForAnalysis(arrayCreationExpression.Initializer); + var matches = TryGetMatches(semanticModel, arrayCreationExpression, replacementExpression, expressionType, allowSemanticsChange, cancellationToken, out var changesSemantics); if (matches.IsDefault) return; ReportArrayCreationDiagnostics(context, syntaxTree, option.Notification, arrayCreationExpression, changesSemantics); } - public static ImmutableArray> TryGetMatches( + public static ImmutableArray> TryGetMatches( SemanticModel semanticModel, ArrayCreationExpressionSyntax expression, + CollectionExpressionSyntax replacementExpression, INamedTypeSymbol? expressionType, bool allowSemanticsChange, CancellationToken cancellationToken, @@ -69,6 +72,7 @@ public static ImmutableArray> TryGetM var matches = UseCollectionExpressionHelpers.TryGetMatches( semanticModel, expression, + replacementExpression, expressionType, isSingletonInstance: false, allowSemanticsChange, @@ -79,8 +83,8 @@ public static ImmutableArray> TryGetM if (matches.IsDefault) return default; - if (!UseCollectionExpressionHelpers.CanReplaceWithCollectionExpression( - semanticModel, expression, expressionType, isSingletonInstance: false, allowSemanticsChange, skipVerificationForReplacedNode: true, cancellationToken, out changesSemantics)) + if (!CanReplaceWithCollectionExpression( + semanticModel, expression, replacementExpression, expressionType, isSingletonInstance: false, allowSemanticsChange, skipVerificationForReplacedNode: true, cancellationToken, out changesSemantics)) { return default; } @@ -101,7 +105,7 @@ public static ImmutableArray> TryGetM if (ienumerableType is null) return default; - if (!UseCollectionExpressionHelpers.IsConstructibleCollectionType( + if (!IsConstructibleCollectionType( semanticModel.Compilation, ienumerableType.TypeArguments.Single())) { return default; @@ -111,9 +115,10 @@ public static ImmutableArray> TryGetM return matches; } - public static ImmutableArray> TryGetMatches( + public static ImmutableArray> TryGetMatches( SemanticModel semanticModel, ImplicitArrayCreationExpressionSyntax expression, + CollectionExpressionSyntax replacementExpression, INamedTypeSymbol? expressionType, bool allowSemanticsChange, CancellationToken cancellationToken, @@ -121,8 +126,8 @@ public static ImmutableArray> TryGetM { // if we have `new[] { ... }` we have no subsequent matches to add to the collection. All values come // from within the initializer. - if (!UseCollectionExpressionHelpers.CanReplaceWithCollectionExpression( - semanticModel, expression, expressionType, isSingletonInstance: false, allowSemanticsChange, skipVerificationForReplacedNode: true, cancellationToken, out changesSemantics)) + if (!CanReplaceWithCollectionExpression( + semanticModel, expression, replacementExpression, expressionType, isSingletonInstance: false, allowSemanticsChange, skipVerificationForReplacedNode: true, cancellationToken, out changesSemantics)) { return default; } @@ -154,11 +159,10 @@ private void AnalyzeArrayInitializerExpression(SyntaxNodeAnalysisContext context // Have to actually examine what would happen when we do the replacement, as the replaced value may interact // with inference based on the values within. - var replacementCollectionExpression = CollectionExpression( - [.. initializer.Expressions.Select(ExpressionElement)]); + var replacementCollectionExpression = CreateReplacementCollectionExpressionForAnalysis(initializer); var allowSemanticsChange = option.Value is CollectionExpressionPreference.WhenTypesLooselyMatch; - if (!UseCollectionExpressionHelpers.CanReplaceWithCollectionExpression( + if (!CanReplaceWithCollectionExpression( semanticModel, arrayCreationExpression, replacementCollectionExpression, expressionType, isSingletonInstance: false, allowSemanticsChange, skipVerificationForReplacedNode: true, cancellationToken, out var changesSemantics)) @@ -170,8 +174,8 @@ private void AnalyzeArrayInitializerExpression(SyntaxNodeAnalysisContext context { var matches = initializer.Parent switch { - ArrayCreationExpressionSyntax arrayCreation => TryGetMatches(semanticModel, arrayCreation, expressionType, allowSemanticsChange, cancellationToken, out _), - ImplicitArrayCreationExpressionSyntax arrayCreation => TryGetMatches(semanticModel, arrayCreation, expressionType, allowSemanticsChange, cancellationToken, out _), + ArrayCreationExpressionSyntax arrayCreation => TryGetMatches(semanticModel, arrayCreation, replacementCollectionExpression, expressionType, allowSemanticsChange, cancellationToken, out _), + ImplicitArrayCreationExpressionSyntax arrayCreation => TryGetMatches(semanticModel, arrayCreation, replacementCollectionExpression, expressionType, allowSemanticsChange, cancellationToken, out _), _ => throw ExceptionUtilities.Unreachable(), }; diff --git a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForBuilderDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForBuilderDiagnosticAnalyzer.cs index ab5493c28229e..347115c0d6cb5 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForBuilderDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForBuilderDiagnosticAnalyzer.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.CodeStyle; +using Microsoft.CodeAnalysis.UseCollectionExpression; using Microsoft.CodeAnalysis.UseCollectionInitializer; using Roslyn.Utilities; @@ -159,7 +160,7 @@ void FadeOutCode(SyntaxNodeAnalysisContext context, AnalysisResult analysisResul identifier, initializedSymbol: semanticModel.GetDeclaredSymbol(declarator, cancellationToken)); - using var _ = ArrayBuilder>.GetInstance(out var matches); + using var _ = ArrayBuilder>.GetInstance(out var matches); // Now walk all the statement after the local declaration. using var enumerator = state.GetSubsequentStatements().GetEnumerator(); @@ -249,6 +250,6 @@ public readonly record struct AnalysisResult( Location DiagnosticLocation, LocalDeclarationStatementSyntax LocalDeclarationStatement, InvocationExpressionSyntax CreationExpression, - ImmutableArray> Matches, + ImmutableArray> Matches, bool ChangesSemantics); } diff --git a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForFluentDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForFluentDiagnosticAnalyzer.cs index 52084b99e4540..42f9408bd91ca 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForFluentDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForFluentDiagnosticAnalyzer.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Shared.CodeStyle; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.UseCollectionExpression; using Microsoft.CodeAnalysis.UseCollectionInitializer; using Roslyn.Utilities; @@ -133,9 +134,16 @@ private void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context, INamedTypeSy { // Because we're recursing from top to bottom in the expression tree, we build up the matches in reverse. Right // before returning them, we'll reverse them again to get the proper order. - using var _ = ArrayBuilder>.GetInstance(out var matchesInReverse); - if (!AnalyzeInvocation(text, state, invocation, addMatches ? matchesInReverse : null, out var existingInitializer, cancellationToken)) + using var _1 = ArrayBuilder>.GetInstance(out var preMatchesInReverse); + using var _2 = ArrayBuilder>.GetInstance(out var postMatchesInReverse); + if (!AnalyzeInvocation( + text, state, invocation, + addMatches ? preMatchesInReverse : null, + addMatches ? postMatchesInReverse : null, + out var existingInitializer, cancellationToken)) + { return null; + } if (!CanReplaceWithCollectionExpression( state.SemanticModel, invocation, expressionType, isSingletonInstance: false, allowSemanticsChange, skipVerificationForReplacedNode: true, cancellationToken, out var changesSemantics)) @@ -143,18 +151,23 @@ private void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context, INamedTypeSy return null; } - matchesInReverse.ReverseContents(); - return new AnalysisResult(existingInitializer, invocation, matchesInReverse.ToImmutable(), changesSemantics); + preMatchesInReverse.ReverseContents(); + postMatchesInReverse.ReverseContents(); + return new AnalysisResult(existingInitializer, invocation, preMatchesInReverse.ToImmutable(), postMatchesInReverse.ToImmutable(), changesSemantics); } private static bool AnalyzeInvocation( SourceText text, FluentState state, InvocationExpressionSyntax invocation, - ArrayBuilder>? matchesInReverse, + ArrayBuilder>? preMatchesInReverse, + ArrayBuilder>? postMatchesInReverse, out InitializerExpressionSyntax? existingInitializer, CancellationToken cancellationToken) { + var semanticModel = state.SemanticModel; + var compilation = semanticModel.Compilation; + existingInitializer = null; if (invocation.Expression is not MemberAccessExpressionSyntax memberAccess) return false; @@ -162,128 +175,141 @@ private static bool AnalyzeInvocation( // Topmost invocation must be a syntactic match for one of our collection manipulation forms. At the top level // we don't want to end with a linq method as that would be lazy, and a collection expression will eagerly // realize the collection. - if (!IsMatch(state, memberAccess, invocation, allowLinq: false, matchesInReverse, out var isAdditionMatch, cancellationToken)) + if (!IsMatch(state, memberAccess, invocation, allowLinq: false, postMatchesInReverse, out var isAdditionMatch, cancellationToken)) return false; // We don't want to offer this feature on top of some builder-type. They will commonly end with something like // `builder.ToImmutable()`. We want that case to be handled by the 'ForBuilder' analyzer instead. - var expressionType = state.SemanticModel.GetTypeInfo(memberAccess.Expression, cancellationToken).Type; + var expressionType = semanticModel.GetTypeInfo(memberAccess.Expression, cancellationToken).Type; if (expressionType is null || expressionType.Name.EndsWith("Builder", StringComparison.Ordinal)) return false; - var semanticModel = state.SemanticModel; - var compilation = semanticModel.Compilation; - - using var _1 = ArrayBuilder.GetInstance(out var stack); - stack.Push(memberAccess.Expression); + var ienumerableOfTType = compilation.IEnumerableOfTType(); + var current = memberAccess.Expression; var copiedData = false; - while (stack.TryPop(out var current)) + // Methods of the form Add(...)/AddRange(...) or `ToXXX()` count as something to continue recursing down the + // left hand side of the expression. In the inner expressions we can have things like `.Concat/.Append` + // calls as the outer expressions will realize the collection. + while (current is InvocationExpressionSyntax { Expression: MemberAccessExpressionSyntax currentMemberAccess } currentInvocation && + IsMatch(state, currentMemberAccess, currentInvocation, allowLinq: true, postMatchesInReverse, out _, cancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); + copiedData = true; + current = currentMemberAccess.Expression; + } - // Methods of the form Add(...)/AddRange(...) or `ToXXX()` count as something to continue recursing down the - // left hand side of the expression. In the inner expressions we can have things like `.Concat/.Append` - // calls as the outer expressions will realize the collection. - if (current is InvocationExpressionSyntax { Expression: MemberAccessExpressionSyntax currentMemberAccess } currentInvocation && - IsMatch(state, currentMemberAccess, currentInvocation, allowLinq: true, matchesInReverse, out _, cancellationToken)) - { - copiedData = true; - stack.Push(currentMemberAccess.Expression); - continue; - } + // `new int[] { ... }` or `new[] { ... }` is a fine base case to make a collection out of. As arrays are + // always list-like this is safe to move over. + if (current is ArrayCreationExpressionSyntax { Initializer: var initializer } arrayCreation) + { + if (initializer is null || !IsLegalInitializer(initializer)) + return false; - // `new int[] { ... }` or `new[] { ... }` is a fine base case to make a collection out of. As arrays are - // always list-like this is safe to move over. - if (current is ArrayCreationExpressionSyntax { Initializer: var initializer } arrayCreation) - { - if (initializer is null || !IsLegalInitializer(initializer)) - return false; + existingInitializer = initializer; + return true; + } - existingInitializer = initializer; - return true; - } + if (current is ImplicitArrayCreationExpressionSyntax implicitArrayCreation) + { + if (!IsLegalInitializer(implicitArrayCreation.Initializer)) + return false; - if (current is ImplicitArrayCreationExpressionSyntax implicitArrayCreation) - { - if (!IsLegalInitializer(implicitArrayCreation.Initializer)) - return false; + existingInitializer = implicitArrayCreation.Initializer; + return true; + } - existingInitializer = implicitArrayCreation.Initializer; - return true; + // Forms like `Array.Empty()` or `ImmutableArray.Empty` are fine base cases. Because the + // collection is empty, we don't have to add any matches. + if (IsCollectionEmptyAccess(semanticModel, current, cancellationToken)) + return IsListLike(current); + + // `new X()` or `new X { a, b, c}` or `new X() { a, b, c }` are fine base cases. + if (current is ObjectCreationExpressionSyntax objectCreation) + { + if (objectCreation is not + { + Initializer: null or { RawKind: (int)SyntaxKind.CollectionInitializerExpression } + }) + { + return false; } - // Forms like `Array.Empty()` or `ImmutableArray.Empty` are fine base cases. Because the - // collection is empty, we don't have to add any matches. - if (IsCollectionEmptyAccess(semanticModel, current, cancellationToken)) - return IsListLike(current); + existingInitializer = objectCreation.Initializer; - // `new X()` or `new X { a, b, c}` or `new X() { a, b, c }` are fine base cases. - if (current is ObjectCreationExpressionSyntax objectCreation) - { - if (objectCreation is not - { - ArgumentList: null or { Arguments.Count: 0 }, - Initializer: null or { RawKind: (int)SyntaxKind.CollectionInitializerExpression } - }) - { - return false; - } + if (!IsLegalInitializer(objectCreation.Initializer)) + return false; - if (!IsLegalInitializer(objectCreation.Initializer)) + if (!IsListLike(current)) + return false; + + if (objectCreation.ArgumentList is { Arguments.Count: 1 }) + { + // Can take a single argument if that argument is itself a collection. + var argumentType = semanticModel.GetTypeInfo(objectCreation.ArgumentList.Arguments[0].Expression, cancellationToken).Type; + if (argumentType is null) return false; - if (!IsListLike(current)) + if (!Equals(argumentType.OriginalDefinition, ienumerableOfTType) && + !argumentType.AllInterfaces.Any(i => Equals(i.OriginalDefinition, ienumerableOfTType))) + { return false; + } - existingInitializer = objectCreation.Initializer; + // Add the arguments to the pre-matches. They will execute before the initializer values are added. + AddArgumentsInReverse(preMatchesInReverse, objectCreation.ArgumentList.Arguments, useSpread: true); return true; } - - // Forms like `ImmutableArray.Create(...)` or `ImmutableArray.CreateRange(...)` are fine base cases. - if (current is InvocationExpressionSyntax currentInvocationExpression && - IsCollectionFactoryCreate(semanticModel, currentInvocationExpression, out var factoryMemberAccess, out var unwrapArgument, cancellationToken)) + else if (objectCreation.ArgumentList is null or { Arguments.Count: 0 }) { - if (!IsListLike(current)) - return false; - - AddArgumentsInReverse(matchesInReverse, GetArguments(currentInvocationExpression, unwrapArgument), useSpread: false); + // Otherwise, we have to have an empty argument list. return true; } - // If we're bottomed out at some different type of expression, and we started with an AsSpan, and we did not - // perform a copy of the data, then do not convert this. The above cases produce a fresh-collection (an - // rvalue), which is fine to get a span out of. However, this may be wrapping a *non-fresh* (an lvalue) - // collection. That means the user could mutate the underlying data the span wraps. Since we are - // converting to a form that will create a fresh collection, that could be noticeable. - if (memberAccess.Name.Identifier.ValueText == AsSpanName && !copiedData) + return false; + } + + // Forms like `ImmutableArray.Create(...)` or `ImmutableArray.CreateRange(...)` are fine base cases. + if (current is InvocationExpressionSyntax currentInvocationExpression && + IsCollectionFactoryCreate(semanticModel, currentInvocationExpression, out var factoryMemberAccess, out var unwrapArgument, cancellationToken)) + { + if (!IsListLike(current)) return false; - // Down to some final collection. Like `x` in `x.Concat(y).ToArray()`. If `x` is itself is something that - // can be iterated, we can convert this to `[.. x, .. y]`. Note: we only want to do this if ending with one - // of the ToXXX Methods. If we just have `x.AddRange(y)` it's preference to keep that, versus `[.. x, ..y]` - if (!isAdditionMatch && IsIterable(current)) - { - AddFinalMatch(current); - return true; - } + AddArgumentsInReverse(postMatchesInReverse, GetArguments(currentInvocationExpression, unwrapArgument), useSpread: false); + return true; + } - // Something we didn't understand. + // If we're bottomed out at some different type of expression, and we started with an AsSpan, and we did not + // perform a copy of the data, then do not convert this. The above cases produce a fresh-collection (an + // rvalue), which is fine to get a span out of. However, this may be wrapping a *non-fresh* (an lvalue) + // collection. That means the user could mutate the underlying data the span wraps. Since we are + // converting to a form that will create a fresh collection, that could be noticeable. + if (memberAccess.Name.Identifier.ValueText == AsSpanName && !copiedData) return false; + + // Down to some final collection. Like `x` in `x.Concat(y).ToArray()`. If `x` is itself is something that + // can be iterated, we can convert this to `[.. x, .. y]`. Note: we only want to do this if ending with one + // of the ToXXX Methods. If we just have `x.AddRange(y)` it's preference to keep that, versus `[.. x, ..y]` + if (!isAdditionMatch && IsIterable(current)) + { + AddFinalMatch(current); + return true; } + // Something we didn't understand. return false; void AddFinalMatch(ExpressionSyntax expression) { - if (matchesInReverse is null) + if (postMatchesInReverse is null) return; // We're only adding one item to the final collection. So we're ending up with `[.. ]`. If this // originally was wrapped over multiple lines in a fluent fashion, and we're down to just a single wrapped // line, then unwrap. - if (matchesInReverse.Count == 0 && + if (postMatchesInReverse.Count == 0 && expression is InvocationExpressionSyntax { Expression: MemberAccessExpressionSyntax memberAccess } innerInvocation && text.Lines.GetLineFromPosition(expression.SpanStart).LineNumber + 1 == text.Lines.GetLineFromPosition(expression.Span.End).LineNumber && memberAccess.Expression.GetTrailingTrivia() @@ -292,7 +318,7 @@ void AddFinalMatch(ExpressionSyntax expression) .All(static t => t.IsWhitespaceOrEndOfLine())) { // Remove any whitespace around the `.`, making the singly-wrapped fluent expression into a single line. - matchesInReverse.Add(new CollectionExpressionMatch( + postMatchesInReverse.Add(new CollectionMatch( Argument(innerInvocation.WithExpression( memberAccess.Update( memberAccess.Expression.WithoutTrailingTrivia(), @@ -302,7 +328,7 @@ void AddFinalMatch(ExpressionSyntax expression) return; } - matchesInReverse.Add(new CollectionExpressionMatch(Argument(expression), UseSpread: true)); + postMatchesInReverse.Add(new CollectionMatch(Argument(expression), UseSpread: true)); } // We only want to offer this feature when the original collection was list-like (as opposed to being something @@ -359,12 +385,13 @@ static bool IsLegalInitializer(InitializerExpressionSyntax? initializer) return false; } } + return true; } } private static void AddArgumentsInReverse( - ArrayBuilder>? matchesInReverse, + ArrayBuilder>? matchesInReverse, SeparatedSyntaxList arguments, bool useSpread) { @@ -388,7 +415,7 @@ private static bool IsMatch( MemberAccessExpressionSyntax memberAccess, InvocationExpressionSyntax invocation, bool allowLinq, - ArrayBuilder>? matchesInReverse, + ArrayBuilder>? matchesInReverse, out bool isAdditionMatch, CancellationToken cancellationToken) { @@ -467,12 +494,15 @@ static bool HasAnySuffix(string name) /// help determine the best collection expression final syntax. /// The location of the code like builder.ToImmutable() that will actually be /// replaced with the collection expression - /// The arguments being added to the collection that will be converted into elements in the - /// final collection expression. + /// The arguments being added to the collection that will be converted into elements in + /// the final collection expression *before* the existing initializer elements. + /// The arguments being added to the collection that will be converted into elements in + /// the final collection expression *after* the existing initializer elements. public readonly record struct AnalysisResult( // Location DiagnosticLocation, InitializerExpressionSyntax? ExistingInitializer, InvocationExpressionSyntax CreationExpression, - ImmutableArray> Matches, + ImmutableArray> PreMatches, + ImmutableArray> PostMatches, bool ChangesSemantics); } diff --git a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer.cs index dc8fc2a87fc37..3fea21dfca3c3 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer.cs @@ -9,9 +9,12 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Shared.CodeStyle; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.UseCollectionExpression; namespace Microsoft.CodeAnalysis.CSharp.UseCollectionExpression; +using static UseCollectionExpressionHelpers; + [DiagnosticAnalyzer(LanguageNames.CSharp)] internal sealed partial class CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer : AbstractCSharpUseCollectionExpressionDiagnosticAnalyzer @@ -117,7 +120,7 @@ private void AnalyzeExplicitStackAllocExpression(SyntaxNodeAnalysisContext conte additionalUnnecessaryLocations: additionalUnnecessaryLocations)); } - public static ImmutableArray> TryGetMatches( + public static ImmutableArray> TryGetMatches( SemanticModel semanticModel, StackAllocArrayCreationExpressionSyntax expression, INamedTypeSymbol? expressionType, @@ -127,6 +130,7 @@ public static ImmutableArray> TryGetM return UseCollectionExpressionHelpers.TryGetMatches( semanticModel, expression, + CreateReplacementCollectionExpressionForAnalysis(expression.Initializer), expressionType, isSingletonInstance: false, allowSemanticsChange, diff --git a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CollectionExpressionMatch.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CollectionExpressionMatch.cs deleted file mode 100644 index 8528791948c89..0000000000000 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/CollectionExpressionMatch.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. - -using Microsoft.CodeAnalysis.UseCollectionInitializer; - -namespace Microsoft.CodeAnalysis.CSharp.UseCollectionExpression; - -/// -internal readonly record struct CollectionExpressionMatch( - TMatchNode Node, - bool UseSpread) where TMatchNode : SyntaxNode; diff --git a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/UseCollectionExpressionHelpers.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/UseCollectionExpressionHelpers.cs index 15d93e2106889..f7fab29e21d2e 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/UseCollectionExpressionHelpers.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionExpression/UseCollectionExpressionHelpers.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.UseCollectionExpression; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UseCollectionExpression; @@ -33,11 +34,15 @@ internal static class UseCollectionExpressionHelpers distinguishRefFromOut: true, // Not relevant. We are not comparing method signatures. objectAndDynamicCompareEqually: false, + // Not relevant. We are not comparing method signatures. + arrayAndReadOnlySpanCompareEqually: false, // The value we're tweaking. tupleNamesMustMatch: false, // We do not want to ignore this. `ImmutableArray` should not be convertible to `ImmutableArray` ignoreNullableAnnotations: false); + private static readonly SymbolEquivalenceComparer s_arrayAndReadOnlySpanCompareEquallyComparer = s_tupleNamesCanDifferComparer.With(arrayAndReadOnlySpanCompareEqually: true); + public static bool CanReplaceWithCollectionExpression( SemanticModel semanticModel, ExpressionSyntax expression, @@ -147,9 +152,17 @@ public static bool CanReplaceWithCollectionExpression( // The new expression's converted type has to equal the old expressions as well. Otherwise, we're now // converting this to some different collection type unintentionally. + // + // Note: it's acceptable to be originally converting to an array, and now converting to a ROS. This occurs with + // APIs that started out just taking an array, but which now have an overload that takes a span. APIs should + // only do this when the new api has the same semantics (outside of perf), and the language and runtime strongly + // want code to call the new api. So it's desirable to change here. var replacedTypeInfo = speculationAnalyzer.SpeculativeSemanticModel.GetTypeInfo(speculationAnalyzer.ReplacedExpression, cancellationToken); - if (!originalTypeInfo.ConvertedType.Equals(replacedTypeInfo.ConvertedType)) + if (!originalTypeInfo.ConvertedType.Equals(replacedTypeInfo.ConvertedType) && + !s_arrayAndReadOnlySpanCompareEquallyComparer.Equals(originalTypeInfo.ConvertedType, replacedTypeInfo.ConvertedType)) + { return false; + } return true; @@ -802,9 +815,10 @@ private static bool ShouldReplaceExistingExpressionEntirely( return false; } - public static ImmutableArray> TryGetMatches( + public static ImmutableArray> TryGetMatches( SemanticModel semanticModel, TArrayCreationExpressionSyntax expression, + CollectionExpressionSyntax replacementExpression, INamedTypeSymbol? expressionType, bool isSingletonInstance, bool allowSemanticsChange, @@ -822,7 +836,7 @@ public static ImmutableArray> TryGetM if (getType(expression) is not ArrayTypeSyntax { RankSpecifiers: [{ Sizes: [var size] }, ..] }) return default; - using var _ = ArrayBuilder>.GetInstance(out var matches); + using var _ = ArrayBuilder>.GetInstance(out var matches); var initializer = getInitializer(expression); if (size is OmittedArraySizeExpressionSyntax) @@ -914,7 +928,7 @@ public static ImmutableArray> TryGetM } if (!CanReplaceWithCollectionExpression( - semanticModel, expression, expressionType, isSingletonInstance, allowSemanticsChange, skipVerificationForReplacedNode: true, cancellationToken, out changesSemantics)) + semanticModel, expression, replacementExpression, expressionType, isSingletonInstance, allowSemanticsChange, skipVerificationForReplacedNode: true, cancellationToken, out changesSemantics)) { return default; } @@ -1222,4 +1236,7 @@ public static SeparatedSyntaxList GetArguments(InvocationExpress : SeparatedList(initializer.Expressions.GetWithSeparators().Select( nodeOrToken => nodeOrToken.IsToken ? nodeOrToken : Argument((ExpressionSyntax)nodeOrToken.AsNode()!))); } + + public static CollectionExpressionSyntax CreateReplacementCollectionExpressionForAnalysis(InitializerExpressionSyntax? initializer) + => initializer is null ? s_emptyCollectionExpression : CollectionExpression([.. initializer.Expressions.Select(ExpressionElement)]); } diff --git a/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerAnalyzer.cs index 7c2abecc18d1f..fabc39b46613b 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerAnalyzer.cs @@ -3,10 +3,13 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.UseCollectionExpression; using Microsoft.CodeAnalysis.UseCollectionInitializer; namespace Microsoft.CodeAnalysis.CSharp.UseCollectionInitializer; @@ -42,136 +45,155 @@ protected override bool HasExistingInvalidInitializerForCollection() }; } - protected override bool ValidateMatchesForCollectionExpression( - ArrayBuilder> matches, CancellationToken cancellationToken) + protected override bool AnalyzeMatchesAndCollectionConstructorForCollectionExpression( + ArrayBuilder> preMatches, + ArrayBuilder> postMatches, + CancellationToken cancellationToken) { // Constructor wasn't called with any arguments. Nothing to validate. var argumentList = _objectCreationExpression.ArgumentList; if (argumentList is null || argumentList.Arguments.Count == 0) return true; - // Anything beyond just a single capacity argument isn't anything we can handle. - if (argumentList.Arguments.Count >= 2) + // Anything beyond just a single capacity argument (or single value to populate the collection with) isn't + // anything we can handle. + if (argumentList.Arguments.Count != 1) return false; - // must be a single `int capacity` constructor. if (this.SemanticModel.GetSymbolInfo(_objectCreationExpression, cancellationToken).Symbol is not IMethodSymbol { MethodKind: MethodKind.Constructor, - Parameters: [{ Type.SpecialType: SpecialType.System_Int32, Name: "capacity" }], + Parameters.Length: 1, } constructor) { return false; } - // The original collection could have been passed elements explicitly in its initializer. Ensure we account for - // that as well. - var individualElementCount = _objectCreationExpression.Initializer?.Expressions.Count ?? 0; - - // Walk the matches, determining what individual elements are added as-is, as well as what values are going to - // be spread into the final collection. We'll then ensure a correspondance between both and the expression the - // user is currently passing to the 'capacity' argument to make sure they're entirely congruent. - using var _1 = ArrayBuilder.GetInstance(out var spreadElements); - foreach (var match in matches) + var ienumerableOfTType = this.SemanticModel.Compilation.IEnumerableOfTType(); + var firstParameter = constructor.Parameters[0]; + if (Equals(firstParameter.Type.OriginalDefinition, ienumerableOfTType) || + firstParameter.Type.AllInterfaces.Any(i => Equals(i.OriginalDefinition, ienumerableOfTType))) { - switch (match.Statement) - { - case ExpressionStatementSyntax { Expression: InvocationExpressionSyntax invocation } expressionStatement: - // x.AddRange(y). Have to make sure we see y.Count in the capacity list. - // x.Add(y, z). Increment the total number of elements by the arg count. - if (match.UseSpread) - spreadElements.Add(invocation.ArgumentList.Arguments[0].Expression); - else - individualElementCount += invocation.ArgumentList.Arguments.Count; - - continue; - - case ForEachStatementSyntax foreachStatement: - // foreach (var v in expr) x.Add(v). Have to make sure we see expr.Count in the capacity list. - spreadElements.Add(foreachStatement.Expression); - continue; - - default: - // Something we don't support (yet). - return false; - } + // Took a single argument that implements IEnumerable. We handle this by spreading that argument as the + // first thing added to the collection. + preMatches.Add(new(argumentList.Arguments[0].Expression, UseSpread: true)); + return true; } + else if (firstParameter is { Type.SpecialType: SpecialType.System_Int32, Name: "capacity" }) + { + // is a single `int capacity` constructor. - // Now, break up an expression like `1 + x.Length + y.Count` into the parts separated by the +'s - var currentArgumentExpression = argumentList.Arguments[0].Expression; - using var _2 = ArrayBuilder.GetInstance(out var expressionPieces); + // The original collection could have been passed elements explicitly in its initializer. Ensure we account for + // that as well. + var individualElementCount = _objectCreationExpression.Initializer?.Expressions.Count ?? 0; - while (true) - { - if (currentArgumentExpression is BinaryExpressionSyntax binaryExpression) + // Walk the matches, determining what individual elements are added as-is, as well as what values are going to + // be spread into the final collection. We'll then ensure a correspondance between both and the expression the + // user is currently passing to the 'capacity' argument to make sure they're entirely congruent. + using var _1 = ArrayBuilder.GetInstance(out var spreadElements); + foreach (var match in postMatches) { - if (binaryExpression.Kind() != SyntaxKind.AddExpression) - return false; - - expressionPieces.Add(binaryExpression.Right); - currentArgumentExpression = binaryExpression.Left; + switch (match.Node) + { + case ExpressionStatementSyntax { Expression: InvocationExpressionSyntax invocation } expressionStatement: + // x.AddRange(y). Have to make sure we see y.Count in the capacity list. + // x.Add(y, z). Increment the total number of elements by the arg count. + if (match.UseSpread) + spreadElements.Add(invocation.ArgumentList.Arguments[0].Expression); + else + individualElementCount += invocation.ArgumentList.Arguments.Count; + + continue; + + case ForEachStatementSyntax foreachStatement: + // foreach (var v in expr) x.Add(v). Have to make sure we see expr.Count in the capacity list. + spreadElements.Add(foreachStatement.Expression); + continue; + + default: + // Something we don't support (yet). + return false; + } } - else + + // Now, break up an expression like `1 + x.Length + y.Count` into the parts separated by the +'s + var currentArgumentExpression = argumentList.Arguments[0].Expression; + using var _2 = ArrayBuilder.GetInstance(out var expressionPieces); + + while (true) { - expressionPieces.Add(currentArgumentExpression); - break; + if (currentArgumentExpression is BinaryExpressionSyntax binaryExpression) + { + if (binaryExpression.Kind() != SyntaxKind.AddExpression) + return false; + + expressionPieces.Add(binaryExpression.Right); + currentArgumentExpression = binaryExpression.Left; + } + else + { + expressionPieces.Add(currentArgumentExpression); + break; + } } - } - // Determine the total constant value provided in the expression. For each constant we see, remove that - // constant from the pieces list. That way the pieces list only corresponds to the values to spread. - var totalConstantValue = 0; - for (var i = expressionPieces.Count - 1; i >= 0; i--) - { - var piece = expressionPieces[i]; - var constant = this.SemanticModel.GetConstantValue(piece, cancellationToken); - if (constant.Value is int value) + // Determine the total constant value provided in the expression. For each constant we see, remove that + // constant from the pieces list. That way the pieces list only corresponds to the values to spread. + var totalConstantValue = 0; + for (var i = expressionPieces.Count - 1; i >= 0; i--) { - totalConstantValue += value; - expressionPieces.RemoveAt(i); + var piece = expressionPieces[i]; + var constant = this.SemanticModel.GetConstantValue(piece, cancellationToken); + if (constant.Value is int value) + { + totalConstantValue += value; + expressionPieces.RemoveAt(i); + } } - } - // If the constant didn't match the number of individual elements to add, we can't update this code. - if (totalConstantValue != individualElementCount) - return false; + // If the constant didn't match the number of individual elements to add, we can't update this code. + if (totalConstantValue != individualElementCount) + return false; - // After removing the constants, we should have an expression for each value we're going to spread. - if (expressionPieces.Count != spreadElements.Count) - return false; + // After removing the constants, we should have an expression for each value we're going to spread. + if (expressionPieces.Count != spreadElements.Count) + return false; - // Now make sure we have a match for each part of `x.Length + y.Length` to an element being spread - // into the collection. - foreach (var piece in expressionPieces) - { - // we support x.Length, x.Count, and x.Count() - var current = piece; - if (piece is InvocationExpressionSyntax invocationExpression) + // Now make sure we have a match for each part of `x.Length + y.Length` to an element being spread + // into the collection. + foreach (var piece in expressionPieces) { - if (invocationExpression.ArgumentList.Arguments.Count != 0) + // we support x.Length, x.Count, and x.Count() + var current = piece; + if (piece is InvocationExpressionSyntax invocationExpression) + { + if (invocationExpression.ArgumentList.Arguments.Count != 0) + return false; + + current = invocationExpression.Expression; + } + + if (current is not MemberAccessExpressionSyntax(SyntaxKind.SimpleMemberAccessExpression) { Name.Identifier.ValueText: "Length" or "Count" } memberAccess) return false; - current = invocationExpression.Expression; - } + current = memberAccess.Expression; - if (current is not MemberAccessExpressionSyntax(SyntaxKind.SimpleMemberAccessExpression) { Name.Identifier.ValueText: "Length" or "Count" } memberAccess) - return false; + // Now see if we have an item we're spreading matching 'x'. + var matchIndex = spreadElements.FindIndex(SyntaxFacts.AreEquivalent, current); + if (matchIndex < 0) + return false; - current = memberAccess.Expression; + spreadElements.RemoveAt(matchIndex); + } - // Now see if we have an item we're spreading matching 'x'. - var matchIndex = spreadElements.FindIndex(SyntaxFacts.AreEquivalent, current); - if (matchIndex < 0) + // If we had any spread elements remaining we can't proceed. + if (spreadElements.Count > 0) return false; - spreadElements.RemoveAt(matchIndex); + // We're all good. The items we found matches up precisely to the capacity provided! + return true; } - // If we had any spread elements remaining we can't proceed. - if (spreadElements.Count > 0) - return false; - - // We're all good. The items we found matches up precisely to the capacity provided! - return true; + return false; } } diff --git a/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerDiagnosticAnalyzer.cs index 9a7530ed1625c..69b943c5b43f5 100644 --- a/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseCollectionInitializer/CSharpUseCollectionInitializerDiagnosticAnalyzer.cs @@ -41,5 +41,12 @@ protected override bool AreCollectionExpressionsSupported(Compilation compilatio => compilation.LanguageVersion().SupportsCollectionExpressions(); protected override bool CanUseCollectionExpression(SemanticModel semanticModel, BaseObjectCreationExpressionSyntax objectCreationExpression, INamedTypeSymbol? expressionType, bool allowSemanticsChange, CancellationToken cancellationToken, out bool changesSemantics) - => UseCollectionExpressionHelpers.CanReplaceWithCollectionExpression(semanticModel, objectCreationExpression, expressionType, isSingletonInstance: false, allowSemanticsChange, skipVerificationForReplacedNode: true, cancellationToken, out changesSemantics); + { + // Synthesize the final collection expression we would replace this object-creation with. That will allow us to + // determine if we end up calling the right overload in cases of overloaded methods. + var replacement = UseCollectionExpressionHelpers.CreateReplacementCollectionExpressionForAnalysis(objectCreationExpression.Initializer); + + return UseCollectionExpressionHelpers.CanReplaceWithCollectionExpression( + semanticModel, objectCreationExpression, replacement, expressionType, isSingletonInstance: false, allowSemanticsChange, skipVerificationForReplacedNode: true, cancellationToken, out changesSemantics); + } } diff --git a/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaHelpers.cs b/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaHelpers.cs index bb2a81c2f53ba..f2ddccdc64584 100644 --- a/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaHelpers.cs +++ b/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaHelpers.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; @@ -112,6 +113,33 @@ internal static bool TryConvertToExpressionBody( { var body = declaration.Body as BlockSyntax; - return body.TryConvertToExpressionBody(languageVersion, conversionPreference, cancellationToken, out expression, out _); + if (!body.TryConvertToExpressionBody(languageVersion, conversionPreference, cancellationToken, out expression, out var semicolonToken)) + return false; + + // If we have directives, we have something like: + // + // X(c => + // { + // #if DEBUG + // Y(); + // #else + // Z(); + // #endif + // }); + // + // Converting this to an expression body is a little too complex for us to support currently. We'd have to grab + // out the parts of the #else/#elif blocks, grab out their expressions, and rewrite into a form like so: + // + // X(c => + // #if DEBUG + // Y() + // #else + // Z() + // #endif + // ); + if (semicolonToken.TrailingTrivia.Any(t => t.IsDirective)) + return false; + + return true; } } diff --git a/src/Analyzers/CSharp/Analyzers/UsePrimaryConstructor/CSharpUsePrimaryConstructorDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UsePrimaryConstructor/CSharpUsePrimaryConstructorDiagnosticAnalyzer.cs index 8d48275f66a5d..1bfd65102367d 100644 --- a/src/Analyzers/CSharp/Analyzers/UsePrimaryConstructor/CSharpUsePrimaryConstructorDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UsePrimaryConstructor/CSharpUsePrimaryConstructorDiagnosticAnalyzer.cs @@ -366,6 +366,9 @@ bool TryFindPrimaryConstructorCandidate( if (primaryConstructor != null) return false; + if (constructor.Parameters.Any(p => p.Type.IsRefLikeType)) + return false; + primaryConstructor = constructor; primaryConstructorDeclaration = constructorDeclaration; } diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf index 7428be3e362ba..62f46796ecfab 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + Použít System.Threading.Lock {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf index 2f2b3d8d345aa..accb3909571de 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + „System.Threading.Lock“ nutzen {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf index 9e78dfcbc6462..d7855c6a310b3 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + Usar "System.Threading.Lock" {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf index e687f353af960..e8f1a51941216 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + Utilisez 'System.Threading.Lock' {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf index 82b30413bb2a2..4568f9346ec71 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + Usare 'System.Threading.Lock' {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf index 4dc388dba7df0..40b6033cee3da 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + 'System.Threading.Lock' を使用する {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf index f8b851cd7c67d..a450fc7a71c47 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + 'System.Threading.Lock' 사용 {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf index b6e19685673fc..f4e2d9f1ce44e 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + Użyj typu „System.Threading.Lock” {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf index 5dc5dbaa3d9bd..d23edd5e0edf4 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + Usar 'System.Threading.Lock' {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf index 892b12c8e06e2..ecb6219478e28 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + Использовать "System.Threading.Lock" {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf index 6a602b643516c..1b93fd9b6ccad 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + 'System.Threading.Lock' türünü kullanın {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf index 2ffdb5f145d4b..ea18e9dbd42f5 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + 使用 'System.Threading.Lock' {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf index f6955440b60d2..ae7a62524cb9c 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf @@ -239,7 +239,7 @@ Use 'System.Threading.Lock' - Use 'System.Threading.Lock' + 使用 'System.Threading.Lock' {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. diff --git a/src/Analyzers/CSharp/CodeFixes/AddInheritdoc/AddInheritdocCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/AddInheritdoc/AddInheritdocCodeFixProvider.cs index c835f9f901206..eab69a511fc47 100644 --- a/src/Analyzers/CSharp/CodeFixes/AddInheritdoc/AddInheritdocCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/AddInheritdoc/AddInheritdocCodeFixProvider.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -89,8 +90,8 @@ protected override async Task FixAllAsync(Document document, ImmutableArray + + + + + + + + + + + + + + + + + + @@ -77,6 +95,7 @@ + diff --git a/src/Analyzers/CSharp/CodeFixes/ConvertNamespace/ConvertNamespaceCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/ConvertNamespace/ConvertNamespaceCodeFixProvider.cs index b39e9e57791f8..7bcd0962149a7 100644 --- a/src/Analyzers/CSharp/CodeFixes/ConvertNamespace/ConvertNamespaceCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/ConvertNamespace/ConvertNamespaceCodeFixProvider.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; @@ -55,8 +56,8 @@ protected override async Task FixAllAsync( var namespaceDecl = (BaseNamespaceDeclarationSyntax)diagnostic.AdditionalLocations[0].FindNode(cancellationToken); - var options = await document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); - var converted = await ConvertNamespaceTransform.ConvertAsync(document, namespaceDecl, options.GetFormattingOptions(), cancellationToken).ConfigureAwait(false); + var options = await document.GetCSharpSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); + var converted = await ConvertNamespaceTransform.ConvertAsync(document, namespaceDecl, options, cancellationToken).ConfigureAwait(false); editor.ReplaceNode( editor.OriginalRoot, diff --git a/src/Analyzers/CSharp/CodeFixes/ConvertNamespace/ConvertNamespaceTransform.cs b/src/Analyzers/CSharp/CodeFixes/ConvertNamespace/ConvertNamespaceTransform.cs index e4476ae00ee0a..4b628007a97d0 100644 --- a/src/Analyzers/CSharp/CodeFixes/ConvertNamespace/ConvertNamespaceTransform.cs +++ b/src/Analyzers/CSharp/CodeFixes/ConvertNamespace/ConvertNamespaceTransform.cs @@ -291,9 +291,9 @@ private static SyntaxNode ReplaceWithBlockScopedNamespace( } return document.Root.ReplaceSyntax( - new SyntaxNode[] { namespaceDeclaration }, + [namespaceDeclaration], (_, _) => converted.WithAdditionalAnnotations(annotation), - new SyntaxToken[] { tokenAfterNamespace }, + [tokenAfterNamespace], (_, _) => tokenAfterNamespace.WithLeadingTrivia(triviaAfterSplit), [], (_, _) => throw ExceptionUtilities.Unreachable()); diff --git a/src/Analyzers/CSharp/CodeFixes/ConvertToRecord/ConvertToRecordEngine.cs b/src/Analyzers/CSharp/CodeFixes/ConvertToRecord/ConvertToRecordEngine.cs index 6efd82df26bf0..452531f32dac9 100644 --- a/src/Analyzers/CSharp/CodeFixes/ConvertToRecord/ConvertToRecordEngine.cs +++ b/src/Analyzers/CSharp/CodeFixes/ConvertToRecord/ConvertToRecordEngine.cs @@ -239,8 +239,7 @@ await RefactorInitializersAsync(type, solutionEditor, propertiesToAssign, cancel } } - var optionsProvider = await document.GetCodeFixOptionsAsync(cancellationToken).ConfigureAwait(false); - var lineFormattingOptions = optionsProvider.GetLineFormattingOptions(); + var lineFormattingOptions = await document.GetLineFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var modifiedClassTrivia = GetModifiedClassTrivia( positionalParameterInfos, typeDeclaration, lineFormattingOptions); diff --git a/src/Features/CSharp/Portable/GenerateConstructor/CSharpGenerateConstructorService.cs b/src/Analyzers/CSharp/CodeFixes/GenerateConstructor/CSharpGenerateConstructorService.cs similarity index 100% rename from src/Features/CSharp/Portable/GenerateConstructor/CSharpGenerateConstructorService.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateConstructor/CSharpGenerateConstructorService.cs diff --git a/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/GenerateConstructor/GenerateConstructorCodeFixProvider.cs similarity index 88% rename from src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateConstructor/GenerateConstructorCodeFixProvider.cs index ec7933d35312d..e2b20ae46539f 100644 --- a/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/GenerateConstructor/GenerateConstructorCodeFixProvider.cs @@ -34,14 +34,10 @@ namespace Microsoft.CodeAnalysis.CSharp.GenerateConstructor; /// [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.GenerateConstructor), Shared] [ExtensionOrder(After = PredefinedCodeFixProviderNames.FullyQualify)] -internal class GenerateConstructorCodeFixProvider : AbstractGenerateMemberCodeFixProvider +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class GenerateConstructorCodeFixProvider() : AbstractGenerateMemberCodeFixProvider { - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public GenerateConstructorCodeFixProvider() - { - } - public override ImmutableArray FixableDiagnosticIds => GenerateConstructorDiagnosticIds.AllDiagnosticIds; protected override Task> GetCodeActionsAsync( diff --git a/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsCodeFixProvider.cs similarity index 83% rename from src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsCodeFixProvider.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsCodeFixProvider.cs index c650876bd8a11..65a8d18ad1354 100644 --- a/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsCodeFixProvider.cs @@ -13,18 +13,15 @@ namespace Microsoft.CodeAnalysis.CSharp.GenerateDefaultConstructors; [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.GenerateDefaultConstructors), Shared] -internal class CSharpGenerateDefaultConstructorsCodeFixProvider : AbstractGenerateDefaultConstructorCodeFixProvider +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpGenerateDefaultConstructorsCodeFixProvider() + : AbstractGenerateDefaultConstructorCodeFixProvider { private const string CS1729 = nameof(CS1729); // 'B' does not contain a constructor that takes 0 arguments CSharpConsoleApp3 C:\Users\cyrusn\source\repos\CSharpConsoleApp3\CSharpConsoleApp3\Program.cs 1 Active private const string CS7036 = nameof(CS7036); // There is no argument given that corresponds to the required parameter 's' of 'B.B(string)' private const string CS8983 = nameof(CS8983); // CS8983: A 'struct' with field initializers must include an explicitly declared constructor. - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpGenerateDefaultConstructorsCodeFixProvider() - { - } - public override ImmutableArray FixableDiagnosticIds { get; } = [CS1729, CS7036, CS8983]; diff --git a/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs b/src/Analyzers/CSharp/CodeFixes/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs similarity index 89% rename from src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs index 23fe06ecf003e..4f10d1692a870 100644 --- a/src/Features/CSharp/Portable/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs +++ b/src/Analyzers/CSharp/CodeFixes/GenerateDefaultConstructors/CSharpGenerateDefaultConstructorsService.cs @@ -18,14 +18,10 @@ namespace Microsoft.CodeAnalysis.CSharp.GenerateDefaultConstructors; [ExportLanguageService(typeof(IGenerateDefaultConstructorsService), LanguageNames.CSharp), Shared] -internal class CSharpGenerateDefaultConstructorsService : AbstractGenerateDefaultConstructorsService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpGenerateDefaultConstructorsService() : AbstractGenerateDefaultConstructorsService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpGenerateDefaultConstructorsService() - { - } - protected override bool TryInitializeState( SemanticDocument semanticDocument, TextSpan textSpan, CancellationToken cancellationToken, [NotNullWhen(true)] out INamedTypeSymbol? classType) diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateEnumMember/CSharpGenerateEnumMemberService.cs b/src/Analyzers/CSharp/CodeFixes/GenerateEnumMember/CSharpGenerateEnumMemberService.cs similarity index 91% rename from src/Features/CSharp/Portable/GenerateMember/GenerateEnumMember/CSharpGenerateEnumMemberService.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateEnumMember/CSharpGenerateEnumMemberService.cs index 10d3a4fd5598c..25785bb31454f 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateEnumMember/CSharpGenerateEnumMemberService.cs +++ b/src/Analyzers/CSharp/CodeFixes/GenerateEnumMember/CSharpGenerateEnumMemberService.cs @@ -14,15 +14,11 @@ namespace Microsoft.CodeAnalysis.CSharp.GenerateMember.GenerateEnumMember; [ExportLanguageService(typeof(IGenerateEnumMemberService), LanguageNames.CSharp), Shared] -internal partial class CSharpGenerateEnumMemberService : +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed partial class CSharpGenerateEnumMemberService() : AbstractGenerateEnumMemberService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpGenerateEnumMemberService() - { - } - protected override bool IsIdentifierNameGeneration(SyntaxNode node) => node is IdentifierNameSyntax; diff --git a/src/Features/CSharp/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.cs similarity index 83% rename from src/Features/CSharp/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.cs index 9c8da121dba61..0c6119fbe7905 100644 --- a/src/Features/CSharp/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.cs @@ -19,17 +19,13 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateEnumMember; [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.GenerateEnumMember), Shared] [ExtensionOrder(After = PredefinedCodeFixProviderNames.GenerateConstructor)] -internal class GenerateEnumMemberCodeFixProvider : AbstractGenerateMemberCodeFixProvider +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class GenerateEnumMemberCodeFixProvider() : AbstractGenerateMemberCodeFixProvider { private const string CS0117 = nameof(CS0117); // error CS0117: 'Color' does not contain a definition for 'Red' private const string CS1061 = nameof(CS1061); // error CS1061: 'Color' does not contain a definition for 'Red' and no accessible extension method 'Red' accepting a first argument of type 'Color' could be found - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public GenerateEnumMemberCodeFixProvider() - { - } - public override ImmutableArray FixableDiagnosticIds { get; } = [CS0117, CS1061]; diff --git a/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateConversionCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/GenerateMethod/GenerateConversionCodeFixProvider.cs similarity index 87% rename from src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateConversionCodeFixProvider.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateMethod/GenerateConversionCodeFixProvider.cs index 4bfacf947f333..af47c46976f2f 100644 --- a/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateConversionCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/GenerateMethod/GenerateConversionCodeFixProvider.cs @@ -20,17 +20,13 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateMethod; [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.GenerateConversion), Shared] [ExtensionOrder(After = PredefinedCodeFixProviderNames.GenerateEnumMember)] -internal class GenerateConversionCodeFixProvider : AbstractGenerateMemberCodeFixProvider +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class GenerateConversionCodeFixProvider() : AbstractGenerateMemberCodeFixProvider { private const string CS0029 = nameof(CS0029); // error CS0029: Cannot implicitly convert type 'type' to 'type' private const string CS0030 = nameof(CS0030); // error CS0030: Cannot convert type 'type' to 'type' - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public GenerateConversionCodeFixProvider() - { - } - public override ImmutableArray FixableDiagnosticIds { get { return [CS0029, CS0030]; } diff --git a/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateDeconstructMethodCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/GenerateMethod/GenerateDeconstructMethodCodeFixProvider.cs similarity index 100% rename from src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateDeconstructMethodCodeFixProvider.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateMethod/GenerateDeconstructMethodCodeFixProvider.cs diff --git a/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateMethodCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/GenerateMethod/GenerateMethodCodeFixProvider.cs similarity index 92% rename from src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateMethodCodeFixProvider.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateMethod/GenerateMethodCodeFixProvider.cs index 5c30027be904c..ebdc100c1d1a4 100644 --- a/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateMethodCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/GenerateMethod/GenerateMethodCodeFixProvider.cs @@ -44,14 +44,10 @@ internal static class GenerateMethodDiagnosticIds [ExtensionOrder(After = PredefinedCodeFixProviderNames.GenerateEnumMember)] [ExtensionOrder(Before = PredefinedCodeFixProviderNames.PopulateSwitch)] [ExtensionOrder(Before = PredefinedCodeFixProviderNames.GenerateVariable)] -internal sealed class GenerateMethodCodeFixProvider : AbstractGenerateMemberCodeFixProvider +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class GenerateMethodCodeFixProvider() : AbstractGenerateMemberCodeFixProvider { - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public GenerateMethodCodeFixProvider() - { - } - public override ImmutableArray FixableDiagnosticIds { get; } = GenerateMethodDiagnosticIds.FixableDiagnosticIds; diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpCommonGenerationServiceMethods.cs b/src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpCommonGenerationServiceMethods.cs similarity index 100% rename from src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpCommonGenerationServiceMethods.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpCommonGenerationServiceMethods.cs diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateConversionService.cs b/src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpGenerateConversionService.cs similarity index 95% rename from src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateConversionService.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpGenerateConversionService.cs index 674f5b2dab83b..084ccf0323348 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateConversionService.cs +++ b/src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpGenerateConversionService.cs @@ -20,15 +20,11 @@ namespace Microsoft.CodeAnalysis.CSharp.GenerateMember.GenerateParameterizedMember; [ExportLanguageService(typeof(IGenerateConversionService), LanguageNames.CSharp), Shared] -internal partial class CSharpGenerateConversionService : +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed partial class CSharpGenerateConversionService() : AbstractGenerateConversionService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpGenerateConversionService() - { - } - protected override bool IsImplicitConversionGeneration(SyntaxNode node) { return node is ExpressionSyntax && @@ -220,8 +216,8 @@ private static IMethodSymbol GenerateMethodSymbol( } protected override string GetImplicitConversionDisplayText(AbstractGenerateParameterizedMemberService.State state) - => string.Format(CSharpFeaturesResources.Generate_implicit_conversion_operator_in_0, state.TypeToGenerateIn.Name); + => string.Format(CodeFixesResources.Generate_implicit_conversion_operator_in_0, state.TypeToGenerateIn.Name); protected override string GetExplicitConversionDisplayText(AbstractGenerateParameterizedMemberService.State state) - => string.Format(CSharpFeaturesResources.Generate_explicit_conversion_operator_in_0, state.TypeToGenerateIn.Name); + => string.Format(CodeFixesResources.Generate_explicit_conversion_operator_in_0, state.TypeToGenerateIn.Name); } diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateDeconstructMethodService.cs b/src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpGenerateDeconstructMethodService.cs similarity index 94% rename from src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateDeconstructMethodService.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpGenerateDeconstructMethodService.cs index 92cb73480134c..862f7db6e3f54 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateDeconstructMethodService.cs +++ b/src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpGenerateDeconstructMethodService.cs @@ -20,15 +20,11 @@ namespace Microsoft.CodeAnalysis.CSharp.GenerateMember.GenerateMethod; [ExportLanguageService(typeof(IGenerateDeconstructMemberService), LanguageNames.CSharp), Shared] -internal sealed class CSharpGenerateDeconstructMethodService : +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpGenerateDeconstructMethodService() : AbstractGenerateDeconstructMethodService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpGenerateDeconstructMethodService() - { - } - protected override bool ContainingTypesOrSelfHasUnsafeKeyword(INamedTypeSymbol containingType) => containingType.ContainingTypesOrSelfHasUnsafeKeyword(); diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateMethodService.cs b/src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpGenerateMethodService.cs similarity index 97% rename from src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateMethodService.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpGenerateMethodService.cs index 9fa97b3e47cb2..f6986582d93d0 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateMethodService.cs +++ b/src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpGenerateMethodService.cs @@ -21,15 +21,11 @@ namespace Microsoft.CodeAnalysis.CSharp.GenerateMember.GenerateMethod; [ExportLanguageService(typeof(IGenerateParameterizedMemberService), LanguageNames.CSharp), Shared] -internal sealed class CSharpGenerateMethodService : +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpGenerateMethodService() : AbstractGenerateMethodService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpGenerateMethodService() - { - } - protected override bool IsExplicitInterfaceGeneration(SyntaxNode node) => node is MethodDeclarationSyntax; diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs b/src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs similarity index 100% rename from src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateParameterizedMember/CSharpGenerateParameterizedMemberService.cs diff --git a/src/Features/CSharp/Portable/GenerateVariable/CSharpGenerateVariableCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/GenerateVariable/CSharpGenerateVariableCodeFixProvider.cs similarity index 88% rename from src/Features/CSharp/Portable/GenerateVariable/CSharpGenerateVariableCodeFixProvider.cs rename to src/Analyzers/CSharp/CodeFixes/GenerateVariable/CSharpGenerateVariableCodeFixProvider.cs index 5c496ede5cd18..1d263364de048 100644 --- a/src/Features/CSharp/Portable/GenerateVariable/CSharpGenerateVariableCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/GenerateVariable/CSharpGenerateVariableCodeFixProvider.cs @@ -22,7 +22,9 @@ namespace Microsoft.CodeAnalysis.CSharp.GenerateVariable; [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.GenerateVariable), Shared] [ExtensionOrder(After = PredefinedCodeFixProviderNames.GenerateMethod)] -internal class CSharpGenerateVariableCodeFixProvider : AbstractGenerateMemberCodeFixProvider +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class CSharpGenerateVariableCodeFixProvider() : AbstractGenerateMemberCodeFixProvider { private const string CS1061 = nameof(CS1061); // error CS1061: 'C' does not contain a definition for 'Goo' and no extension method 'Goo' accepting a first argument of type 'C' could be found private const string CS0103 = nameof(CS0103); // error CS0103: The name 'Goo' does not exist in the current context @@ -32,12 +34,6 @@ internal class CSharpGenerateVariableCodeFixProvider : AbstractGenerateMemberCod private const string CS0120 = nameof(CS0120); // error CS0120: An object reference is required for the non-static field, method, or property 'A' private const string CS0118 = nameof(CS0118); // error CS0118: 'C' is a type but is used like a variable - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public CSharpGenerateVariableCodeFixProvider() - { - } - public override ImmutableArray FixableDiagnosticIds => [CS1061, CS0103, CS0117, CS0539, CS0246, CS0120, CS0118]; diff --git a/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.AddNewKeywordAction.cs b/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.AddNewKeywordAction.cs index c6c2aa4a1bcfe..a2de070884f44 100644 --- a/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.AddNewKeywordAction.cs +++ b/src/Analyzers/CSharp/CodeFixes/HideBase/HideBaseCodeFixProvider.AddNewKeywordAction.cs @@ -6,8 +6,10 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.OrderModifiers; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.OrderModifiers; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -28,9 +30,9 @@ private class AddNewKeywordAction(Document document, SyntaxNode node) : CodeActi protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) { var root = await _document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var options = await _document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); + var configOptions = await _document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - var newNode = GetNewNode(_node, options.PreferredModifierOrder.Value); + var newNode = GetNewNode(_node, configOptions.GetOption(CSharpCodeStyleOptions.PreferredModifierOrder).Value); var newRoot = root.ReplaceNode(_node, newNode); return _document.WithSyntaxRoot(newRoot); diff --git a/src/Features/CSharp/Portable/ImplementAbstractClass/CSharpImplementAbstractClassCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/ImplementAbstractClass/CSharpImplementAbstractClassCodeFixProvider.cs similarity index 94% rename from src/Features/CSharp/Portable/ImplementAbstractClass/CSharpImplementAbstractClassCodeFixProvider.cs rename to src/Analyzers/CSharp/CodeFixes/ImplementAbstractClass/CSharpImplementAbstractClassCodeFixProvider.cs index 89d58bf473ab2..aa7db53519afc 100644 --- a/src/Features/CSharp/Portable/ImplementAbstractClass/CSharpImplementAbstractClassCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/ImplementAbstractClass/CSharpImplementAbstractClassCodeFixProvider.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CSharp.ImplementAbstractClass; [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.ImplementAbstractClass), Shared] [ExtensionOrder(After = PredefinedCodeFixProviderNames.GenerateType)] -internal class CSharpImplementAbstractClassCodeFixProvider : +internal sealed class CSharpImplementAbstractClassCodeFixProvider : AbstractImplementAbstractClassCodeFixProvider { private const string CS0534 = nameof(CS0534); // 'Program' does not implement inherited abstract member 'Goo.bar()' diff --git a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs similarity index 100% rename from src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs rename to src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs diff --git a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceService.cs b/src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceService.cs similarity index 81% rename from src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceService.cs rename to src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceService.cs index c1d9811c90da9..8605be36ee10c 100644 --- a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceService.cs +++ b/src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceService.cs @@ -5,14 +5,16 @@ #nullable disable using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.Threading; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.ImplementInterface; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -20,13 +22,15 @@ namespace Microsoft.CodeAnalysis.CSharp.ImplementInterface; [ExportLanguageService(typeof(IImplementInterfaceService), LanguageNames.CSharp), Shared] -internal class CSharpImplementInterfaceService : AbstractImplementInterfaceService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpImplementInterfaceService() : AbstractImplementInterfaceService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpImplementInterfaceService() - { - } + protected override ISyntaxFormatting SyntaxFormatting + => CSharpSyntaxFormatting.Instance; + + protected override SyntaxGeneratorInternal SyntaxGeneratorInternal + => CSharpSyntaxGeneratorInternal.Instance; protected override string ToDisplayString(IMethodSymbol disposeImplMethod, SymbolDisplayFormat format) => SymbolDisplay.ToDisplayString(disposeImplMethod, format); @@ -90,16 +94,16 @@ protected override SyntaxNode CreateFinalizer( { // ' Do not change this code... // Dispose(false) - var disposeStatement = (StatementSyntax)AddComment(g, - string.Format(FeaturesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, disposeMethodDisplayString), + var disposeStatement = (StatementSyntax)AddComment( + string.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, disposeMethodDisplayString), g.ExpressionStatement(g.InvocationExpression( g.IdentifierName(nameof(IDisposable.Dispose)), g.Argument(DisposingName, RefKind.None, g.FalseLiteralExpression())))); var methodDecl = SyntaxFactory.DestructorDeclaration(classType.Name).AddBodyStatements(disposeStatement); - return AddComment(g, - string.Format(FeaturesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, disposeMethodDisplayString), + return AddComment( + string.Format(CodeFixesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, disposeMethodDisplayString), methodDecl); } } diff --git a/src/Analyzers/CSharp/CodeFixes/InlineDeclaration/CSharpInlineDeclarationCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/InlineDeclaration/CSharpInlineDeclarationCodeFixProvider.cs index 526ca834a7acd..934b1cc4b4b3b 100644 --- a/src/Analyzers/CSharp/CodeFixes/InlineDeclaration/CSharpInlineDeclarationCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/InlineDeclaration/CSharpInlineDeclarationCodeFixProvider.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; @@ -44,7 +45,7 @@ protected override async Task FixAllAsync( Document document, ImmutableArray diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { - var options = await document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetCSharpSimplifierOptionsAsync(cancellationToken).ConfigureAwait(false); // Gather all statements to be removed // We need this to find the statements we can safely attach trivia to @@ -92,7 +93,7 @@ private static (VariableDeclaratorSyntax declarator, IdentifierNameSyntax identi private static SyntaxNode ReplaceIdentifierWithInlineDeclaration( Document document, - CSharpCodeFixOptionsProvider options, SemanticModel semanticModel, + CSharpSimplifierOptions options, SemanticModel semanticModel, SyntaxNode currentRoot, VariableDeclaratorSyntax declarator, IdentifierNameSyntax identifier, SyntaxNode currentNode, HashSet declarationsToRemove, @@ -114,24 +115,21 @@ private static SyntaxNode ReplaceIdentifierWithInlineDeclaration( // this local statement will be moved to be above the statement containing // the out-var. var localDeclarationStatement = (LocalDeclarationStatementSyntax)declaration.Parent; - var block = (BlockSyntax)localDeclarationStatement.Parent; - var declarationIndex = block.Statements.IndexOf(localDeclarationStatement); + var block = CSharpInlineDeclarationDiagnosticAnalyzer.GetEnclosingPseudoBlock(localDeclarationStatement.Parent); + var statements = GetStatements(block); + var declarationIndex = statements.IndexOf(localDeclarationStatement); // Try to find a predecessor Statement on the same line that isn't going to be removed StatementSyntax priorStatementSyntax = null; var localDeclarationToken = localDeclarationStatement.GetFirstToken(); for (var i = declarationIndex - 1; i >= 0; i--) { - var statementSyntax = block.Statements[i]; + var statementSyntax = statements[i]; if (declarationsToRemove.Contains(statementSyntax)) - { continue; - } if (sourceText.AreOnSameLine(statementSyntax.GetLastToken(), localDeclarationToken)) - { priorStatementSyntax = statementSyntax; - } break; } @@ -157,9 +155,9 @@ private static SyntaxNode ReplaceIdentifierWithInlineDeclaration( // We initialize this to null here but we must see at least the statement // into which the declaration is going to be inlined so this will be not null StatementSyntax nextStatementSyntax = null; - for (var i = declarationIndex + 1; i < block.Statements.Count; i++) + for (var i = declarationIndex + 1; i < statements.Length; i++) { - var statement = block.Statements[i]; + var statement = statements[i]; if (!declarationsToRemove.Contains(statement)) { nextStatementSyntax = statement; @@ -174,7 +172,9 @@ private static SyntaxNode ReplaceIdentifierWithInlineDeclaration( } // The above code handled the moving of trivia. So remove the node, keeping around no trivia from it. - editor.RemoveNode(localDeclarationStatement, SyntaxRemoveOptions.KeepNoTrivia); + editor.RemoveNode(localDeclarationStatement.Parent is GlobalStatementSyntax globalStatement + ? globalStatement + : localDeclarationStatement, SyntaxRemoveOptions.KeepNoTrivia); } else { @@ -237,8 +237,22 @@ private static SyntaxNode ReplaceIdentifierWithInlineDeclaration( return editor.GetChangedRoot(); } + private static ImmutableArray GetStatements(SyntaxNode pseudoBlock) + { + if (pseudoBlock is BlockSyntax block) + return [.. block.Statements]; + + if (pseudoBlock is SwitchSectionSyntax switchSection) + return [.. switchSection.Statements]; + + if (pseudoBlock is CompilationUnitSyntax compilationUnit) + return compilationUnit.Members.OfType().Select(g => g.Statement).ToImmutableArray(); + + return []; + } + public static TypeSyntax GenerateTypeSyntaxOrVar( - ITypeSymbol symbol, CSharpCodeFixOptionsProvider options) + ITypeSymbol symbol, CSharpSimplifierOptions options) { var useVar = IsVarDesired(symbol, options); @@ -251,7 +265,7 @@ public static TypeSyntax GenerateTypeSyntaxOrVar( : symbol.GenerateTypeSyntax(); } - private static bool IsVarDesired(ITypeSymbol type, CSharpCodeFixOptionsProvider options) + private static bool IsVarDesired(ITypeSymbol type, CSharpSimplifierOptions options) { // If they want it for intrinsics, and this is an intrinsic, then use var. if (type.IsSpecialType() == true) diff --git a/src/Analyzers/CSharp/CodeFixes/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs b/src/Analyzers/CSharp/CodeFixes/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs index adfd18228e12b..bdea1f83c6eb7 100644 --- a/src/Analyzers/CSharp/CodeFixes/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs +++ b/src/Analyzers/CSharp/CodeFixes/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs @@ -165,12 +165,7 @@ public static async Task MakeLocalFunctionStaticAsync( } } -#if CODE_STYLE - var info = new CSharpCodeGenerationContextInfo( - CodeGenerationContext.Default, CSharpCodeGenerationOptions.Default, new CSharpCodeGenerationService(document.Project.GetExtendedLanguageServices().LanguageServices), root.SyntaxTree.Options.LanguageVersion()); -#else var info = await document.GetCodeGenerationInfoAsync(CodeGenerationContext.Default, cancellationToken).ConfigureAwait(false); -#endif // Updates the local function declaration with variables passed in as parameters syntaxEditor.ReplaceNode( diff --git a/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs index 6657044d72b52..706341426bd6c 100644 --- a/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs @@ -13,15 +13,18 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; namespace Microsoft.CodeAnalysis.CSharp.MisplacedUsingDirectives; @@ -57,12 +60,12 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var compilationUnit = (CompilationUnitSyntax)syntaxRoot; - var options = await document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); - var simplifierOptions = options.GetSimplifierOptions(); + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + var simplifierOptions = new CSharpSimplifierOptions(configOptions); // Read the preferred placement option and verify if it can be applied to this code file. There are cases // where we will not be able to fix the diagnostic and the user will need to resolve it manually. - var (placement, preferPreservation) = DeterminePlacement(compilationUnit, options.UsingDirectivePlacement); + var (placement, preferPreservation) = DeterminePlacement(compilationUnit, configOptions.GetOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement)); if (preferPreservation) return; diff --git a/src/Analyzers/CSharp/CodeFixes/NewLines/EmbeddedStatementPlacement/EmbeddedStatementPlacementCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/NewLines/EmbeddedStatementPlacement/EmbeddedStatementPlacementCodeFixProvider.cs index bf6a8be42bb2e..2cb1247d4ee5b 100644 --- a/src/Analyzers/CSharp/CodeFixes/NewLines/EmbeddedStatementPlacement/EmbeddedStatementPlacementCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/NewLines/EmbeddedStatementPlacement/EmbeddedStatementPlacementCodeFixProvider.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; @@ -47,7 +48,7 @@ public static async Task FixAllAsync(Document document, ImmutableArray var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, document.Project.Solution.Services); - var options = await document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetCSharpSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var endOfLineTrivia = ElasticEndOfLine(options.NewLine); diff --git a/src/Analyzers/CSharp/CodeFixes/RemoveUnusedParametersAndValues/CSharpRemoveUnusedValuesCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/RemoveUnusedParametersAndValues/CSharpRemoveUnusedValuesCodeFixProvider.cs index 434d14f295da9..b459db309e58d 100644 --- a/src/Analyzers/CSharp/CodeFixes/RemoveUnusedParametersAndValues/CSharpRemoveUnusedValuesCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/RemoveUnusedParametersAndValues/CSharpRemoveUnusedValuesCodeFixProvider.cs @@ -30,7 +30,7 @@ internal sealed class CSharpRemoveUnusedValuesCodeFixProvider() ExpressionStatementSyntax, LocalDeclarationStatementSyntax, VariableDeclaratorSyntax, ForEachStatementSyntax, SwitchSectionSyntax, SwitchLabelSyntax, CatchClauseSyntax, CatchClauseSyntax> { - protected override ISyntaxFormatting GetSyntaxFormatting() + protected override ISyntaxFormatting SyntaxFormatting => CSharpSyntaxFormatting.Instance; protected override BlockSyntax WrapWithBlockIfNecessary(IEnumerable statements) diff --git a/src/Analyzers/CSharp/CodeFixes/UseCoalesceExpression/CSharpUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseCoalesceExpression/CSharpUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.cs new file mode 100644 index 0000000000000..ebb1f88d3d23a --- /dev/null +++ b/src/Analyzers/CSharp/CodeFixes/UseCoalesceExpression/CSharpUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.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.Threading; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.UseCoalesceExpression; + +namespace Microsoft.CodeAnalysis.CSharp.UseCoalesceExpression; + +[ExtensionOrder(Before = PredefinedCodeFixProviderNames.AddBraces)] +[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.UseCoalesceExpressionForIfNullStatementCheck), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider() + : AbstractUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider +{ + protected override ITypeSymbol? TryGetExplicitCast( + SemanticModel semanticModel, SyntaxNode expressionToCoalesce, + SyntaxNode leftAssignmentPart, SyntaxNode rightAssignmentPart, + CancellationToken cancellationToken) + { + var leftPartTypeSymbol = semanticModel.GetTypeInfo(expressionToCoalesce, cancellationToken).Type; + var rightPartTypeSymbol = semanticModel.GetTypeInfo(rightAssignmentPart, cancellationToken).Type; + var finalDestinationTypeSymbol = semanticModel.GetTypeInfo(leftAssignmentPart, cancellationToken).Type; + + if (leftPartTypeSymbol == null || rightPartTypeSymbol == null || finalDestinationTypeSymbol == null) + return null; + + if (leftPartTypeSymbol.Equals(rightPartTypeSymbol)) + return null; + + if (semanticModel.Compilation.HasImplicitConversion(leftPartTypeSymbol, rightPartTypeSymbol) || + semanticModel.Compilation.HasImplicitConversion(rightPartTypeSymbol, leftPartTypeSymbol)) + { + return null; + } + + return finalDestinationTypeSymbol; + } +} diff --git a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpCollectionExpressionRewriter.cs b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpCollectionExpressionRewriter.cs index 3912db017c814..23b878b52e152 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpCollectionExpressionRewriter.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpCollectionExpressionRewriter.cs @@ -5,7 +5,10 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; +using System.Linq.Expressions; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -17,6 +20,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.UseCollectionExpression; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UseCollectionExpression; @@ -33,7 +37,8 @@ internal static class CSharpCollectionExpressionRewriter public static async Task CreateCollectionExpressionAsync( Document workspaceDocument, TParentExpression expressionToReplace, - ImmutableArray> matches, + ImmutableArray> preMatches, + ImmutableArray> postMatches, Func getInitializer, Func withInitializer, CancellationToken cancellationToken) @@ -46,12 +51,7 @@ public static async Task CreateCollectionExpressionA var document = await ParsedDocument.CreateAsync(workspaceDocument, cancellationToken).ConfigureAwait(false); -#if CODE_STYLE - var formattingOptions = CSharpSyntaxFormattingOptions.Default; -#else - var formattingOptions = (CSharpSyntaxFormattingOptions)await workspaceDocument.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); -#endif - + var formattingOptions = await workspaceDocument.GetCSharpSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var indentationOptions = new IndentationOptions(formattingOptions); var wrappingLength = formattingOptions.CollectionExpressionWrappingLength; @@ -85,22 +85,13 @@ CollectionExpressionSyntax CreateCollectionExpressionWithoutExistingElements() // Didn't have an existing initializer (or it was empty). For both cases, just create an entirely // fresh collection expression, and replace the object entirely. - if (matches is [{ Node: ExpressionSyntax expression } match]) + if (preMatches is [{ Node: ExpressionSyntax } preMatch] && postMatches.IsEmpty) { - // Specialize when we're taking some expression (like x.y.ToArray()) and converting to a spreaded - // collection expression. We just want to trivially make that `[.. x.y]` without any specialized - // behavior. In particular, we do not want to generate something like: - // - // [ - // .. x.y, - // ] - // - // For that sort of case. Single element collections should stay closely associated with the original - // expression. - return CollectionExpression([ - match.UseSpread - ? SpreadElement(expression.WithoutTrivia()) - : ExpressionElement(expression.WithoutTrivia())]).WithTriviaFrom(expressionToReplace); + return CreateSingleElementCollection(preMatch); + } + else if (preMatches.IsEmpty && postMatches is [{ Node: ExpressionSyntax } postMatch]) + { + return CreateSingleElementCollection(postMatch); } else if (makeMultiLineCollectionExpression) { @@ -133,7 +124,8 @@ CollectionExpressionSyntax CreateCollectionExpressionWithoutExistingElements() // now create the elements, following that indentation preference. using var _ = ArrayBuilder.GetInstance(out var nodesAndTokens); - CreateAndAddElements(matches, nodesAndTokens, preferredIndentation: elementIndentation, forceTrailingComma: true); + CreateAndAddElements(preMatches, nodesAndTokens, preferredIndentation: elementIndentation, forceTrailingComma: true, moreToCome: true); + CreateAndAddElements(postMatches, nodesAndTokens, preferredIndentation: elementIndentation, forceTrailingComma: true, moreToCome: false); // Add a newline between the last element and the close bracket if we don't already have one. if (nodesAndTokens.Count > 0 && nodesAndTokens.Last().GetTrailingTrivia() is [.., (kind: not SyntaxKind.EndOfLineTrivia)]) @@ -155,7 +147,8 @@ CollectionExpressionSyntax CreateCollectionExpressionWithoutExistingElements() // fresh collection expression, and do a wholesale replacement of the original object creation // expression with it. using var _ = ArrayBuilder.GetInstance(out var nodesAndTokens); - CreateAndAddElements(matches, nodesAndTokens, preferredIndentation: null, forceTrailingComma: false); + CreateAndAddElements(preMatches, nodesAndTokens, preferredIndentation: null, forceTrailingComma: false, moreToCome: true); + CreateAndAddElements(postMatches, nodesAndTokens, preferredIndentation: null, forceTrailingComma: false, moreToCome: false); // Remove any trailing whitespace from the last element/comma and the final close bracket. if (nodesAndTokens.Count > 0) @@ -201,6 +194,25 @@ CollectionExpressionSyntax CreateCollectionExpressionWithoutExistingElements() } } + CollectionExpressionSyntax CreateSingleElementCollection(CollectionMatch match) + { + // Specialize when we're taking some expression (like x.y.ToArray()) and converting to a spreaded + // collection expression. We just want to trivially make that `[.. x.y]` without any specialized + // behavior. In particular, we do not want to generate something like: + // + // [ + // .. x.y, + // ] + // + // For that sort of case. Single element collections should stay closely associated with the original + // expression. + var expression = (ExpressionSyntax)(object)match.Node; + return CollectionExpression([ + match.UseSpread + ? SpreadElement(expression.WithoutTrivia()) + : ExpressionElement(expression.WithoutTrivia())]).WithTriviaFrom(expressionToReplace); + } + CollectionExpressionSyntax CreateCollectionExpressionWithExistingElements() { // If the object creation expression had an initializer (with at least one element in it). Attempt to @@ -330,10 +342,11 @@ SeparatedSyntaxList FixLeadingAndTrailingWhitespace( // Used to we can uniformly add the items correctly with the requested (but optional) indentation. And so that // commas are added properly to the sequence. void CreateAndAddElements( - ImmutableArray> matches, + ImmutableArray> matches, ArrayBuilder nodesAndTokens, string? preferredIndentation, - bool forceTrailingComma) + bool forceTrailingComma, + bool moreToCome) { // If there's no requested indentation, then we want to produce the sequence as: `a, b, c, d`. So just // a space after any comma. If there is desired indentation for an element, then we always follow a comma @@ -349,7 +362,7 @@ void CreateAndAddElements( } if (matches.Length > 0 && forceTrailingComma) - AddCommaIfMissing(last: true); + AddCommaIfMissing(last: !moreToCome); return; @@ -384,6 +397,11 @@ CollectionExpressionSyntax AddMatchesToExistingNonEmptyCollectionExpression( string? preferredIndentation) { using var _ = ArrayBuilder.GetInstance(out var nodesAndTokens); + + // Add any pre-items before the initializer items. + CreateAndAddElements(preMatches, nodesAndTokens, preferredIndentation, forceTrailingComma: true, moreToCome: true); + + // Now add all the initializer items. nodesAndTokens.AddRange(initialCollectionExpression.Elements.GetWithSeparators()); // If there is already a trailing comma before, remove it. We'll add it back at the end. If there is no @@ -402,12 +420,15 @@ CollectionExpressionSyntax AddMatchesToExistingNonEmptyCollectionExpression( nodesAndTokens[^1] = nodesAndTokens[^1].WithTrailingTrivia(); } + // Now add all the post matches in. + // If we're wrapping to multiple lines, and we don't already have a trailing comma, then force one at the // end. This keeps every element consistent with ending the line with a comma, which makes code easier to // maintain. CreateAndAddElements( - matches, nodesAndTokens, preferredIndentation, - forceTrailingComma: preferredIndentation != null && trailingComma == default); + postMatches, nodesAndTokens, preferredIndentation, + forceTrailingComma: preferredIndentation != null && trailingComma == default, + moreToCome: false); if (trailingComma != default) { @@ -436,7 +457,7 @@ static CollectionElementSyntax CreateCollectionElement( } IEnumerable CreateElements( - CollectionExpressionMatch match, string? preferredIndentation) + CollectionMatch match, string? preferredIndentation) { var node = match.Node; @@ -706,7 +727,7 @@ bool MakeMultiLineCollectionExpression() { // If there's already an initializer, and we're not adding anything to it, then just keep the initializer // as-is. No need to convert it to be multi-line if it's currently single-line. - if (initializer != null && matches.Length == 0) + if (initializer != null && preMatches.Length == 0 && postMatches.Length == 0) return false; var totalLength = 0; @@ -716,27 +737,38 @@ bool MakeMultiLineCollectionExpression() totalLength += expression.Span.Length; } - foreach (var (node, _) in matches) + if (CheckForMultiLine(preMatches) || + CheckForMultiLine(postMatches)) { - // if the statement we're replacing has any comments on it, then we need to be multiline to give them an - // appropriate place to go. - if (node.GetLeadingTrivia().Any(static t => t.IsSingleOrMultiLineComment()) || - node.GetTrailingTrivia().Any(static t => t.IsSingleOrMultiLineComment())) - { - return true; - } + return true; + } + + return totalLength > wrappingLength; - foreach (var component in GetElementComponents(node)) + bool CheckForMultiLine(ImmutableArray> matches) + { + foreach (var (node, _) in matches) { - // if any of the expressions we're adding are multiline, then make things multiline. - if (!document.Text.AreOnSameLine(component.GetFirstToken(), component.GetLastToken())) + // if the statement we're replacing has any comments on it, then we need to be multiline to give them an + // appropriate place to go. + if (node.GetLeadingTrivia().Any(static t => t.IsSingleOrMultiLineComment()) || + node.GetTrailingTrivia().Any(static t => t.IsSingleOrMultiLineComment())) + { return true; + } - totalLength += component.Span.Length; + foreach (var component in GetElementComponents(node)) + { + // if any of the expressions we're adding are multiline, then make things multiline. + if (!document.Text.AreOnSameLine(component.GetFirstToken(), component.GetLastToken())) + return true; + + totalLength += component.Span.Length; + } } - } - return totalLength > wrappingLength; + return false; + } } static IEnumerable GetElementComponents(TMatchNode node) diff --git a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForArrayCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForArrayCodeFixProvider.cs index 6131ccff3191a..2340ebb0b3fa2 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForArrayCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForArrayCodeFixProvider.cs @@ -7,7 +7,6 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; @@ -72,6 +71,7 @@ and not ImplicitArrayCreationExpressionSyntax var collectionExpression = await CSharpCollectionExpressionRewriter.CreateCollectionExpressionAsync( document, arrayCreationExpression, + preMatches: [], matches, static e => e switch { @@ -97,17 +97,17 @@ and not ImplicitArrayCreationExpressionSyntax static bool IsOnSingleLine(SourceText sourceText, SyntaxNode node) => sourceText.AreOnSameLine(node.GetFirstToken(), node.GetLastToken()); - ImmutableArray> GetMatches( + ImmutableArray> GetMatches( SemanticModel semanticModel, ExpressionSyntax expression, INamedTypeSymbol? expressionType) => expression switch { ImplicitArrayCreationExpressionSyntax arrayCreation => CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer.TryGetMatches( - semanticModel, arrayCreation, expressionType, allowSemanticsChange: true, cancellationToken, out _), + semanticModel, arrayCreation, CreateReplacementCollectionExpressionForAnalysis(arrayCreation.Initializer), expressionType, allowSemanticsChange: true, cancellationToken, out _), ArrayCreationExpressionSyntax arrayCreation => CSharpUseCollectionExpressionForArrayDiagnosticAnalyzer.TryGetMatches( - semanticModel, arrayCreation, expressionType, allowSemanticsChange: true, cancellationToken, out _), + semanticModel, arrayCreation, CreateReplacementCollectionExpressionForAnalysis(arrayCreation.Initializer), expressionType, allowSemanticsChange: true, cancellationToken, out _), // We validated this is unreachable in the caller. _ => throw ExceptionUtilities.Unreachable(), diff --git a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForBuilderCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForBuilderCodeFixProvider.cs index 7079f10191638..65ac94dcec1bd 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForBuilderCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForBuilderCodeFixProvider.cs @@ -8,8 +8,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.UseCollectionExpression; -using Microsoft.CodeAnalysis.UseCollectionInitializer; namespace Microsoft.CodeAnalysis.CSharp.UseCollectionExpression; @@ -66,20 +65,26 @@ protected override async Task FixAsync( var collectionExpression = await CreateCollectionExpressionAsync( newDocument, dummyObjectCreation, - analysisResult.Matches.SelectAsArray(m => new CollectionExpressionMatch(m.Statement, m.UseSpread)), + preMatches: [], + analysisResult.Matches, static o => o.Initializer, static (o, i) => o.WithInitializer(i), cancellationToken).ConfigureAwait(false); var subEditor = new SyntaxEditor(root, document.Project.Solution.Services); - // Remove the actual declaration of the builder. - subEditor.RemoveNode(analysisResult.LocalDeclarationStatement); - // Remove all the nodes mutating the builder. foreach (var (statement, _) in analysisResult.Matches) subEditor.RemoveNode(statement); + // Remove the actual declaration of the builder. Keep any comments on the builder declaration in case they're + // still valid for the final statement. + var removalOptions = SyntaxRemoveOptions.KeepUnbalancedDirectives | SyntaxRemoveOptions.AddElasticMarker; + if (analysisResult.LocalDeclarationStatement.GetLeadingTrivia().Any(t => t.IsSingleOrMultiLineComment())) + removalOptions |= SyntaxRemoveOptions.KeepLeadingTrivia; + + subEditor.RemoveNode(analysisResult.LocalDeclarationStatement, removalOptions); + // Finally, replace the invocation where we convert the builder to a collection with the new collection expression. subEditor.ReplaceNode(dummyObjectCreation, collectionExpression); @@ -92,7 +97,7 @@ static AnalysisResult TrackAnalysisResult(SyntaxNode root, AnalysisResult analys => new(analysisResult.DiagnosticLocation, root.GetCurrentNode(analysisResult.LocalDeclarationStatement)!, root.GetCurrentNode(analysisResult.CreationExpression)!, - analysisResult.Matches.SelectAsArray(m => new Match(root.GetCurrentNode(m.Statement)!, m.UseSpread)), + analysisResult.Matches.SelectAsArray(m => new CollectionMatch(root.GetCurrentNode(m.Node)!, m.UseSpread)), analysisResult.ChangesSemantics); // Creates a new document with all of the relevant nodes in analysisResult tracked so that we can find them diff --git a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForCreateCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForCreateCodeFixProvider.cs index 0466efe136cb1..ff99cda43402b 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForCreateCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForCreateCodeFixProvider.cs @@ -62,11 +62,12 @@ protected override async Task FixAsync( semanticDocument.Root.ReplaceNode(invocationExpression, dummyObjectCreation), cancellationToken).ConfigureAwait(false); dummyObjectCreation = (ImplicitObjectCreationExpressionSyntax)newSemanticDocument.Root.GetAnnotatedNodes(dummyObjectAnnotation).Single(); var expressions = dummyObjectCreation.ArgumentList.Arguments.Select(a => a.Expression); - var matches = expressions.SelectAsArray(static e => new CollectionExpressionMatch(e, UseSpread: false)); + var matches = expressions.SelectAsArray(static e => new CollectionMatch(e, UseSpread: false)); var collectionExpression = await CreateCollectionExpressionAsync( newSemanticDocument.Document, dummyObjectCreation, + preMatches: [], matches, static o => o.Initializer, static (o, i) => o.WithInitializer(i), diff --git a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForFluentCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForFluentCodeFixProvider.cs index e6d5670884c6b..18e06fdfdafbb 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForFluentCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForFluentCodeFixProvider.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; @@ -68,7 +69,8 @@ protected override async Task FixAsync( var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); // Get the expressions that we're going to fill the new collection expression with. - var arguments = await GetArgumentsAsync(document, analysisResult.Matches, cancellationToken).ConfigureAwait(false); + var allMatches = analysisResult.PreMatches.Concat(analysisResult.PostMatches); + var arguments = await GetArgumentsAsync(document, allMatches, cancellationToken).ConfigureAwait(false); var argumentListTrailingTrivia = analysisResult.ExistingInitializer is null ? default @@ -85,30 +87,31 @@ protected override async Task FixAsync( semanticDocument.Root.ReplaceNode(invocationExpression, dummyObjectCreation), cancellationToken).ConfigureAwait(false); dummyObjectCreation = (ImplicitObjectCreationExpressionSyntax)newSemanticDocument.Root.GetAnnotatedNodes(dummyObjectAnnotation).Single(); - var matches = CreateMatches(dummyObjectCreation.ArgumentList.Arguments, analysisResult.Matches); + var preMatches = CreateMatches(dummyObjectCreation.ArgumentList.Arguments, analysisResult.PreMatches, index: 0); + var postMatches = CreateMatches(dummyObjectCreation.ArgumentList.Arguments, analysisResult.PostMatches, index: preMatches.Length); var collectionExpression = await CreateCollectionExpressionAsync( newSemanticDocument.Document, dummyObjectCreation, - matches, + preMatches, + postMatches, static o => o.Initializer, static (o, i) => o.WithInitializer(i), cancellationToken).ConfigureAwait(false); editor.ReplaceNode(invocationExpression, collectionExpression); - static ImmutableArray> CreateMatches( + static ImmutableArray> CreateMatches( SeparatedSyntaxList arguments, - ImmutableArray> matches) + ImmutableArray> matches, + int index) { - Contract.ThrowIfTrue(arguments.Count != matches.Length); + using var result = TemporaryArray>.Empty; - using var result = TemporaryArray>.Empty; - - for (int i = 0, n = arguments.Count; i < n; i++) + for (int i = 0, n = matches.Length; i < n; i++) { - var argument = arguments[i]; var match = matches[i]; + var argument = arguments[i + index]; // If we're going to spread a collection expression, just take the values *within* that collection expression // and make them arguments to the collection expression we're creating. @@ -137,18 +140,15 @@ static ImmutableArray> CreateMatches static async Task> GetArgumentsAsync( Document document, - ImmutableArray> matches, + ImmutableArray> matches, CancellationToken cancellationToken) { if (matches.IsEmpty) return default; var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); -#if CODE_STYLE - var formattingOptions = SyntaxFormattingOptions.CommonDefaults; -#else - var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); -#endif + var formattingOptions = await document.GetSyntaxFormattingOptionsAsync( + CSharpSyntaxFormatting.Instance, cancellationToken).ConfigureAwait(false); using var _ = ArrayBuilder.GetInstance(out var nodesAndTokens); diff --git a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForStackAllocCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForStackAllocCodeFixProvider.cs index 7774bb8c9acd4..38db892da4846 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForStackAllocCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseCollectionExpression/CSharpUseCollectionExpressionForStackAllocCodeFixProvider.cs @@ -7,7 +7,6 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; @@ -48,6 +47,7 @@ protected sealed override async Task FixAsync( var collectionExpression = await CSharpCollectionExpressionRewriter.CreateCollectionExpressionAsync( document, stackAllocExpression, + preMatches: [], matches, static e => e switch { @@ -70,7 +70,7 @@ protected sealed override async Task FixAsync( return; - ImmutableArray> GetMatches() + ImmutableArray> GetMatches() => stackAllocExpression switch { // if we have `stackalloc[] { ... }` we have no subsequent matches to add to the collection. All values come diff --git a/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider.cs index 3203bff642c22..e27000bf62d1d 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider.cs @@ -7,9 +7,9 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.UseCollectionExpression; using Microsoft.CodeAnalysis.UseCollectionInitializer; namespace Microsoft.CodeAnalysis.CSharp.UseCollectionInitializer; @@ -37,23 +37,14 @@ protected override CSharpUseCollectionInitializerAnalyzer GetAnalyzer() Document document, BaseObjectCreationExpressionSyntax objectCreation, bool useCollectionExpression, - ImmutableArray> matches, + ImmutableArray> preMatches, + ImmutableArray> postMatches, CancellationToken cancellationToken) { - var newObjectCreation = await GetNewObjectCreationAsync( - document, objectCreation, useCollectionExpression, matches, cancellationToken).ConfigureAwait(false); - return (objectCreation, newObjectCreation); - } + ExpressionSyntax newObjectCreation = useCollectionExpression + ? await CreateCollectionExpressionAsync(document, objectCreation, preMatches, postMatches, cancellationToken).ConfigureAwait(false) + : CreateObjectInitializerExpression(objectCreation, postMatches); - private static async Task GetNewObjectCreationAsync( - Document document, - BaseObjectCreationExpressionSyntax objectCreation, - bool useCollectionExpression, - ImmutableArray> matches, - CancellationToken cancellationToken) - { - return useCollectionExpression - ? await CreateCollectionExpressionAsync(document, objectCreation, matches, cancellationToken).ConfigureAwait(false) - : CreateObjectInitializerExpression(objectCreation, matches); + return (objectCreation, newObjectCreation); } } diff --git a/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider_CollectionExpression.cs b/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider_CollectionExpression.cs index f84f195875f0a..765047327066e 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider_CollectionExpression.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider_CollectionExpression.cs @@ -5,9 +5,9 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.UseCollectionExpression; +using Microsoft.CodeAnalysis.UseCollectionExpression; using Microsoft.CodeAnalysis.UseCollectionInitializer; namespace Microsoft.CodeAnalysis.CSharp.UseCollectionInitializer; @@ -21,13 +21,15 @@ internal partial class CSharpUseCollectionInitializerCodeFixProvider private static Task CreateCollectionExpressionAsync( Document document, BaseObjectCreationExpressionSyntax objectCreation, - ImmutableArray> matches, + ImmutableArray> preMatches, + ImmutableArray> postMatches, CancellationToken cancellationToken) { return CSharpCollectionExpressionRewriter.CreateCollectionExpressionAsync( document, objectCreation, - matches.SelectAsArray(m => new CollectionExpressionMatch(m.Statement, m.UseSpread)), + preMatches, + postMatches, static objectCreation => objectCreation.Initializer, static (objectCreation, initializer) => objectCreation.WithInitializer(initializer), cancellationToken); diff --git a/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider_CollectionInitializer.cs b/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider_CollectionInitializer.cs index f1d0323603ec6..c8c3ad9b1b932 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider_CollectionInitializer.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseCollectionInitializer/CSharpUseCollectionInitializerCodeFixProvider_CollectionInitializer.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.UseCollectionExpression; using Microsoft.CodeAnalysis.UseCollectionInitializer; using Roslyn.Utilities; @@ -23,7 +24,7 @@ internal partial class CSharpUseCollectionInitializerCodeFixProvider { private static BaseObjectCreationExpressionSyntax CreateObjectInitializerExpression( BaseObjectCreationExpressionSyntax objectCreation, - ImmutableArray> matches) + ImmutableArray> matches) { var expressions = CreateCollectionInitializerExpressions(); var withLineBreaks = AddLineBreaks(expressions); @@ -35,13 +36,13 @@ SeparatedSyntaxList CreateCollectionInitializerExpressions() { using var _ = ArrayBuilder.GetInstance(out var nodesAndTokens); - UseInitializerHelpers.AddExistingItems, ExpressionSyntax>( + UseInitializerHelpers.AddExistingItems, ExpressionSyntax>( objectCreation, nodesAndTokens, addTrailingComma: matches.Length > 0, static (_, expression) => expression); for (var i = 0; i < matches.Length; i++) { var match = matches[i]; - var statement = (ExpressionStatementSyntax)match.Statement; + var statement = (ExpressionStatementSyntax)match.Node; var trivia = statement.GetLeadingTrivia(); var leadingTrivia = i == 0 ? trivia.WithoutLeadingBlankLines() : trivia; diff --git a/src/Analyzers/CSharp/CodeFixes/UseConditionalExpression/CSharpUseConditionalExpressionForAssignmentCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseConditionalExpression/CSharpUseConditionalExpressionForAssignmentCodeFixProvider.cs index 39bcf0dc146c5..8fb28e7def2a0 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseConditionalExpression/CSharpUseConditionalExpressionForAssignmentCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseConditionalExpression/CSharpUseConditionalExpressionForAssignmentCodeFixProvider.cs @@ -57,6 +57,6 @@ protected override StatementSyntax WrapWithBlockIfAppropriate( protected override ExpressionSyntax ConvertToExpression(IThrowOperation throwOperation) => CSharpUseConditionalExpressionHelpers.ConvertToExpression(throwOperation); - protected override ISyntaxFormatting GetSyntaxFormatting() + protected override ISyntaxFormatting SyntaxFormatting => CSharpSyntaxFormatting.Instance; } diff --git a/src/Analyzers/CSharp/CodeFixes/UseConditionalExpression/CSharpUseConditionalExpressionForReturnCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseConditionalExpression/CSharpUseConditionalExpressionForReturnCodeFixProvider.cs index ba4a932007522..e1dca2d1db1ae 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseConditionalExpression/CSharpUseConditionalExpressionForReturnCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseConditionalExpression/CSharpUseConditionalExpressionForReturnCodeFixProvider.cs @@ -60,6 +60,6 @@ protected override ExpressionSyntax WrapReturnExpressionIfNecessary(ExpressionSy protected override ExpressionSyntax ConvertToExpression(IThrowOperation throwOperation) => CSharpUseConditionalExpressionHelpers.ConvertToExpression(throwOperation); - protected override ISyntaxFormatting GetSyntaxFormatting() + protected override ISyntaxFormatting SyntaxFormatting => CSharpSyntaxFormatting.Instance; } diff --git a/src/Analyzers/CSharp/CodeFixes/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationCodeFixProvider.cs index 6bc18e8e3d139..576f76620d1cb 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationCodeFixProvider.cs @@ -50,11 +50,8 @@ protected override async Task FixAllAsync( .OrderBy(d => d.Location.SourceSpan.End) .SelectAsArray(d => (ObjectCreationExpressionSyntax)d.AdditionalLocations[0].FindNode(getInnermostNodeForTie: true, cancellationToken)); -#if CODE_STYLE - var options = CSharpSimplifierOptions.Default; -#else - var options = (CSharpSimplifierOptions)await document.GetSimplifierOptionsAsync(cancellationToken).ConfigureAwait(false); -#endif + var options = (CSharpSimplifierOptions)await document.GetSimplifierOptionsAsync( + CSharpSimplification.Instance, cancellationToken).ConfigureAwait(false); // Bulk apply these, except at the expression level. One fix at the expression level may prevent another fix // from being valid. For example: `new List { new C() }`. If we apply the fix to the outer `List`, we diff --git a/src/Analyzers/CSharp/CodeFixes/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs index 931722e8eb838..8f731bb6e81a3 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs @@ -88,12 +88,7 @@ protected override async Task FixAllAsync( if (languageVersion >= LanguageVersion.CSharp8) { -#if CODE_STYLE - var info = new CSharpCodeGenerationContextInfo( - CodeGenerationContext.Default, CSharpCodeGenerationOptions.Default, new CSharpCodeGenerationService(document.Project.GetExtendedLanguageServices().LanguageServices), root.SyntaxTree.Options.LanguageVersion()); -#else var info = await document.GetCodeGenerationInfoAsync(CodeGenerationContext.Default, cancellationToken).ConfigureAwait(false); -#endif var options = (CSharpCodeGenerationOptions)info.Options; makeStaticIfPossible = options.PreferStaticLocalFunction.Value; diff --git a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems index 4cb24a2e90359..cb7713cf037fb 100644 --- a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems +++ b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems @@ -33,7 +33,18 @@ + + + + + + + + + + + @@ -97,6 +108,7 @@ + diff --git a/src/Features/CSharpTest/GenerateConstructor/GenerateConstructorTests.cs b/src/Analyzers/CSharp/Tests/GenerateConstructor/GenerateConstructorTests.cs similarity index 99% rename from src/Features/CSharpTest/GenerateConstructor/GenerateConstructorTests.cs rename to src/Analyzers/CSharp/Tests/GenerateConstructor/GenerateConstructorTests.cs index 3fa80c6c96c1b..2d3bdb24c3f20 100644 --- a/src/Features/CSharpTest/GenerateConstructor/GenerateConstructorTests.cs +++ b/src/Analyzers/CSharp/Tests/GenerateConstructor/GenerateConstructorTests.cs @@ -19,13 +19,9 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.GenerateConstructor; [Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] -public class GenerateConstructorTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor +public sealed class GenerateConstructorTests(ITestOutputHelper logger) + : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor(logger) { - public GenerateConstructorTests(ITestOutputHelper logger) - : base(logger) - { - } - internal override (DiagnosticAnalyzer?, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) => (null, new GenerateConstructorCodeFixProvider()); @@ -2788,74 +2784,6 @@ class D """); } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530003")] - public async Task TestAttributesWithAllValidParameters() - { - await TestInRegularAndScriptAsync( - """ - using System; - - enum A - { - A1 - } - - [AttributeUsage(AttributeTargets.Class)] - class MyAttrAttribute : Attribute - { - } - - [|[MyAttrAttribute(new int[] { 1, 2, 3 }, A.A1, true, (byte)1, 'a', (short)12, (int)1, (long)5L, 5D, 3.5F, "hello")]|] - class D - { - } - """, - """ - using System; - - enum A - { - A1 - } - - [AttributeUsage(AttributeTargets.Class)] - class MyAttrAttribute : Attribute - { - private int[] ints; - private A a1; - private bool v1; - private byte v2; - private char v3; - private short v4; - private int v5; - private long v6; - private double v7; - private float v8; - private string v9; - - public MyAttrAttribute(int[] ints, A a1, bool v1, byte v2, char v3, short v4, int v5, long v6, double v7, float v8, string v9) - { - this.ints = ints; - this.a1 = a1; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - this.v4 = v4; - this.v5 = v5; - this.v6 = v6; - this.v7 = v7; - this.v8 = v8; - this.v9 = v9; - } - } - - [MyAttrAttribute(new int[] { 1, 2, 3 }, A.A1, true, (byte)1, 'a', (short)12, (int)1, (long)5L, 5D, 3.5F, "hello")] - class D - { - } - """); - } - [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530003")] public async Task TestAttributesWithDelegation() { @@ -4575,39 +4503,6 @@ public A(int* a, int b, int c) : this(a, b) { } """); } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44708")] - public async Task TestGenerateNameFromTypeArgument() - { - await TestInRegularAndScriptAsync( -""" - using System.Collections.Generic; - - class Frog { } - - class C - { - C M() => new [||]C(new List()); - } - """, -""" - using System.Collections.Generic; - - class Frog { } - - class C - { - private List frogs; - - public C(List frogs) - { - this.frogs = frogs; - } - - C M() => new C(new List()); - } - """); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44708")] public async Task TestDoNotGenerateNameFromTypeArgumentIfNotEnumerable() { @@ -4643,39 +4538,6 @@ C M() """); } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44708")] - public async Task TestGenerateNameFromTypeArgumentForErrorType() - { - await TestInRegularAndScriptAsync( -""" - using System.Collections.Generic; - - class Frog { } - - class C - { - C M() => new [||]C(new List<>()); - } - """, -""" - using System.Collections.Generic; - - class Frog { } - - class C - { - private List ts; - - public C(List ts) - { - this.ts = ts; - } - - C M() => new C(new List<>()); - } - """); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44708")] public async Task TestGenerateNameFromTypeArgumentForTupleType() { @@ -4709,43 +4571,6 @@ public C(List<(int, string)> list) """); } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44708")] - public async Task TestGenerateNameFromTypeArgumentInNamespace() - { - await TestInRegularAndScriptAsync( -""" - using System.Collections.Generic; - - namespace N { - class Frog { } - - class C - { - C M() => new [||]C(new List()); - } - } - """, -""" - using System.Collections.Generic; - - namespace N { - class Frog { } - - class C - { - private List frogs; - - public C(List frogs) - { - this.frogs = frogs; - } - - C M() => new C(new List()); - } - } - """); - } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47928")] public async Task TestGenerateConstructorFromImplicitObjectCreation() { @@ -5144,4 +4969,179 @@ public static void Test() } """); } + +#if !CODE_STYLE + + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530003")] + public async Task TestAttributesWithAllValidParameters() + { + await TestInRegularAndScriptAsync( + """ + using System; + + enum A + { + A1 + } + + [AttributeUsage(AttributeTargets.Class)] + class MyAttrAttribute : Attribute + { + } + + [|[MyAttrAttribute(new int[] { 1, 2, 3 }, A.A1, true, (byte)1, 'a', (short)12, (int)1, (long)5L, 5D, 3.5F, "hello")]|] + class D + { + } + """, + """ + using System; + + enum A + { + A1 + } + + [AttributeUsage(AttributeTargets.Class)] + class MyAttrAttribute : Attribute + { + private int[] ints; + private A a1; + private bool v1; + private byte v2; + private char v3; + private short v4; + private int v5; + private long v6; + private double v7; + private float v8; + private string v9; + + public MyAttrAttribute(int[] ints, A a1, bool v1, byte v2, char v3, short v4, int v5, long v6, double v7, float v8, string v9) + { + this.ints = ints; + this.a1 = a1; + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + this.v4 = v4; + this.v5 = v5; + this.v6 = v6; + this.v7 = v7; + this.v8 = v8; + this.v9 = v9; + } + } + + [MyAttrAttribute(new int[] { 1, 2, 3 }, A.A1, true, (byte)1, 'a', (short)12, (int)1, (long)5L, 5D, 3.5F, "hello")] + class D + { + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44708")] + public async Task TestGenerateNameFromTypeArgument() + { + await TestInRegularAndScriptAsync( +""" + using System.Collections.Generic; + + class Frog { } + + class C + { + C M() => new [||]C(new List()); + } + """, +""" + using System.Collections.Generic; + + class Frog { } + + class C + { + private List frogs; + + public C(List frogs) + { + this.frogs = frogs; + } + + C M() => new C(new List()); + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44708")] + public async Task TestGenerateNameFromTypeArgumentForErrorType() + { + await TestInRegularAndScriptAsync( +""" + using System.Collections.Generic; + + class Frog { } + + class C + { + C M() => new [||]C(new List<>()); + } + """, +""" + using System.Collections.Generic; + + class Frog { } + + class C + { + private List ts; + + public C(List ts) + { + this.ts = ts; + } + + C M() => new C(new List<>()); + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44708")] + public async Task TestGenerateNameFromTypeArgumentInNamespace() + { + await TestInRegularAndScriptAsync( +""" + using System.Collections.Generic; + + namespace N { + class Frog { } + + class C + { + C M() => new [||]C(new List()); + } + } + """, +""" + using System.Collections.Generic; + + namespace N { + class Frog { } + + class C + { + private List frogs; + + public C(List frogs) + { + this.frogs = frogs; + } + + C M() => new C(new List()); + } + } + """); + } + +#endif } diff --git a/src/Features/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs b/src/Analyzers/CSharp/Tests/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs similarity index 99% rename from src/Features/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs rename to src/Analyzers/CSharp/Tests/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs index d2cbb3b3b2f76..8eec2a263228e 100644 --- a/src/Features/CSharpTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs +++ b/src/Analyzers/CSharp/Tests/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.cs @@ -18,12 +18,15 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.GenerateDefaultConstruc EmptyDiagnosticAnalyzer, CSharpGenerateDefaultConstructorsCodeFixProvider>; +#if !CODE_STYLE using VerifyRefactoring = CSharpCodeRefactoringVerifier< GenerateDefaultConstructorsCodeRefactoringProvider>; +#endif [UseExportProvider] public class GenerateDefaultConstructorsTests { +#if !CODE_STYLE private static async Task TestRefactoringAsync(string source, string fixedSource, int index = 0) { await TestRefactoringOnlyAsync(source, fixedSource, index); @@ -40,6 +43,7 @@ private static async Task TestRefactoringOnlyAsync(string source, string fixedSo LanguageVersion = LanguageVersion.CSharp10, }.RunAsync(); } +#endif private static async Task TestCodeFixAsync(string source, string fixedSource, int index = 0) { @@ -51,9 +55,12 @@ private static async Task TestCodeFixAsync(string source, string fixedSource, in LanguageVersion = LanguageVersion.CSharp10, }.RunAsync(); +#if !CODE_STYLE await TestRefactoringMissingAsync(source); +#endif } +#if !CODE_STYLE private static async Task TestRefactoringMissingAsync(string source) { await new VerifyRefactoring.Test @@ -63,6 +70,7 @@ private static async Task TestRefactoringMissingAsync(string source) LanguageVersion = LanguageVersion.CSharp10, }.RunAsync(); } +#endif private static async Task TestCodeFixMissingAsync(string source) { @@ -174,24 +182,6 @@ internal B(int x) """); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - public async Task TestPrivateBase() - { - await TestRefactoringMissingAsync( - """ - class {|CS1729:C|} : [||]B - { - } - - class B - { - private B(int x) - { - } - } - """); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] public async Task TestRefOutParams() { @@ -434,29 +424,18 @@ public B(bool x) index: 3); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - public async Task TestFixAll2() + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors), CompilerTrait(CompilerFeature.Tuples)] + public async Task Tuple() { - await TestRefactoringAsync( + await TestCodeFixAsync( """ - class C : [||]B + class {|CS7036:C|} : [||]B { - public {|CS1729:C|}(bool x) - { - } } class B { - internal B(int x) - { - } - - protected B(string x) - { - } - - public B(bool x) + public B((int, string) x) { } } @@ -464,60 +443,32 @@ public B(bool x) """ class C : B { - public {|CS1729:C|}(bool x) - { - } - - protected C(string x) : base(x) - { - } - - internal C(int x) : base(x) + public C((int, string) x) : base(x) { } } class B { - internal B(int x) - { - } - - protected B(string x) - { - } - - public B(bool x) + public B((int, string) x) { } } - """, -index: 2); + """); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - public async Task TestFixAll_WithTuples() + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors), CompilerTrait(CompilerFeature.Tuples)] + public async Task TupleWithNames() { - await TestRefactoringAsync( + await TestCodeFixAsync( """ - class C : [||]B + class {|CS7036:C|} : [||]B { - public {|CS1729:C|}((bool, bool) x) - { - } } class B { - internal B((int, int) x) - { - } - - protected B((string, string) x) - { - } - - public B((bool, bool) x) + public B((int a, string b) x) { } } @@ -525,52 +476,82 @@ public B((bool, bool) x) """ class C : B { - public {|CS1729:C|}((bool, bool) x) + public C((int a, string b) x) : base(x) { } + } - protected C((string, string) x) : base(x) + class B + { + public B((int a, string b) x) { } + } + """); + } - internal C((int, int) x) : base(x) + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] + [WorkItem("https://github.com/dotnet/Roslyn/issues/6541")] + public async Task TestGenerateFromDerivedClass() + { + await TestCodeFixAsync( + """ + class Base + { + public Base(string value) { } } - class B + class [||]{|CS7036:Derived|} : Base { - internal B((int, int) x) + } + """, + """ + class Base + { + public Base(string value) { } + } - protected B((string, string) x) + class Derived : Base + { + public Derived(string value) : base(value) { } + } + """); + } - public B((bool, bool) x) + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] + [WorkItem("https://github.com/dotnet/Roslyn/issues/6541")] + public async Task TestGenerateFromDerivedClass2() + { + await TestCodeFixAsync( + """ + class Base + { + public Base(int a, string value = null) { } } - """, -index: 2); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - public async Task TestMissing1() - { - await TestRefactoringMissingAsync( + class [||]{|CS7036:Derived|} : Base + { + } + """, """ - class C : [||]B + class Base { - public {|CS7036:C|}(int x) + public Base(int a, string value = null) { } } - class B + class Derived : Base { - internal B(int x) + public Derived(int a, string value = null) : base(a, value) { } } @@ -578,40 +559,33 @@ internal B(int x) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/889349")] - public async Task TestDefaultConstructorGeneration_1() + [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] + public async Task TestGenerateConstructorFromProtectedConstructor() { - await TestRefactoringAsync( + await TestCodeFixAsync( """ - class C : [||]B + abstract class {|CS7036:C|} : [||]B { - public {|CS7036:C|}(int y) - { - } } - class B + abstract class B { - internal B(int x) + protected B(int x) { } } """, """ - class C : B + abstract class C : B { - public {|CS7036:C|}(int y) - { - } - - internal {|CS0111:C|}(int x) : base(x) + protected C(int x) : base(x) { } } - class B + abstract class B { - internal B(int x) + protected B(int x) { } } @@ -619,21 +593,18 @@ internal B(int x) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/889349")] - public async Task TestDefaultConstructorGeneration_2() + [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] + public async Task TestGenerateConstructorFromProtectedConstructor2() { - await TestRefactoringAsync( + await TestCodeFixAsync( """ - class C : [||]B + class {|CS7036:C|} : [||]B { - private {|CS7036:C|}(int y) - { - } } - class B + abstract class B { - internal B(int x) + protected B(int x) { } } @@ -641,18 +612,14 @@ internal B(int x) """ class C : B { - internal C(int x) : base(x) - { - } - - private {|CS0111:{|CS7036:C|}|}(int y) + public C(int x) : base(x) { } } - class B + abstract class B { - internal B(int x) + protected B(int x) { } } @@ -660,145 +627,68 @@ internal B(int x) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544070")] - public async Task TestException1() + [WorkItem("https://github.com/dotnet/roslyn/issues/35208")] + [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] + public async Task TestGenerateConstructorInAbstractClassFromPublicConstructor() { - await TestRefactoringAsync( + await TestCodeFixAsync( """ - using System; - class Program : Excep[||]tion + abstract class {|CS7036:C|} : [||]B { } - """, - """ - using System; - using System.Runtime.Serialization; - class Program : Exception - { - public Program() - { - } - public Program(string message) : base(message) + abstract class B + { + public B(int x) { } - - public Program(string message, Exception innerException) : base(message, innerException) + } + """, + """ + abstract class C : B + { + protected C(int x) : base(x) { } + } - protected Program(SerializationInfo info, StreamingContext context) : base(info, context) + abstract class B + { + public B(int x) { } } - """, -index: 4); + """); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - public async Task TestException2() + [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] + public async Task TestGenerateConstructorFromPublicConstructor2() { - await TestRefactoringAsync( + await TestCodeFixAsync( """ - using System; - using System.Collections.Generic; - using System.Linq; + class {|CS7036:C|} : [||]B + { + } - class Program : [||]Exception + abstract class B { - public Program() - { - } - - static void Main(string[] args) - { - } - } - """, - """ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Runtime.Serialization; - - class Program : Exception - { - public Program() - { - } - - public Program(string message) : base(message) - { - } - - public Program(string message, Exception innerException) : base(message, innerException) - { - } - - protected Program(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - - static void Main(string[] args) + public B(int x) { } } """, -index: 3); - } - - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - public async Task TestException3() - { - await TestRefactoringAsync( """ - using System; - using System.Collections.Generic; - using System.Linq; - - class Program : [||]Exception + class C : B { - public Program(string message) : base(message) - { - } - - public Program(string message, Exception innerException) : base(message, innerException) - { - } - - protected Program(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) - { - } - - static void Main(string[] args) + public C(int x) : base(x) { } } - """, - """ - using System; - using System.Collections.Generic; - using System.Linq; - class Program : Exception + abstract class B { - public Program() - { - } - - public Program(string message) : base(message) - { - } - - public Program(string message, Exception innerException) : base(message, innerException) - { - } - - protected Program(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) - { - } - - static void Main(string[] args) + public B(int x) { } } @@ -806,62 +696,42 @@ static void Main(string[] args) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - public async Task TestException4() + [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] + public async Task TestGenerateConstructorFromInternalConstructor() { - await TestRefactoringAsync( + await TestCodeFixAsync( """ - using System; - using System.Collections.Generic; - using System.Linq; - - class Program : [||]Exception + abstract class {|CS7036:C|} : [||]B { - public Program(string message, Exception innerException) : base(message, innerException) - { - } - - protected Program(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) - { - } + } - static void Main(string[] args) + abstract class B + { + internal B(int x) { } } """, """ - using System; - using System.Collections.Generic; - using System.Linq; - - class Program : Exception + abstract class C : B { - public Program() - { - } - - public Program(string message) : base(message) - { - } - - public Program(string message, Exception innerException) : base(message, innerException) - { - } - - protected Program(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) + internal C(int x) : base(x) { } + } - static void Main(string[] args) + abstract class B + { + internal B(int x) { } } - """, -index: 2); + """); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors), CompilerTrait(CompilerFeature.Tuples)] - public async Task Tuple() + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] + [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] + public async Task TestGenerateConstructorFromInternalConstructor2() { await TestCodeFixAsync( """ @@ -869,9 +739,9 @@ class {|CS7036:C|} : [||]B { } - class B + abstract class B { - public B((int, string) x) + internal B(int x) { } } @@ -879,161 +749,150 @@ public B((int, string) x) """ class C : B { - public C((int, string) x) : base(x) + public C(int x) : base(x) { } } - class B + abstract class B { - public B((int, string) x) + internal B(int x) { } } """); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors), CompilerTrait(CompilerFeature.Tuples)] - public async Task TupleWithNames() + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] + [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] + public async Task TestGenerateConstructorFromProtectedInternalConstructor() { await TestCodeFixAsync( """ - class {|CS7036:C|} : [||]B + abstract class {|CS7036:C|} : [||]B { } - class B + abstract class B { - public B((int a, string b) x) + protected internal B(int x) { } } """, """ - class C : B + abstract class C : B { - public C((int a, string b) x) : base(x) + protected internal C(int x) : base(x) { } } - class B + abstract class B { - public B((int a, string b) x) + protected internal B(int x) { } } """); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] - [WorkItem("https://github.com/dotnet/Roslyn/issues/6541")] - public async Task TestGenerateFromDerivedClass() + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] + [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] + public async Task TestGenerateConstructorFromProtectedInternalConstructor2() { await TestCodeFixAsync( """ - class Base + class {|CS7036:C|} : [||]B { - public Base(string value) - { - } } - class [||]{|CS7036:Derived|} : Base + abstract class B { + protected internal B(int x) + { + } } """, """ - class Base + class C : B { - public Base(string value) + public C(int x) : base(x) { } } - class Derived : Base + abstract class B { - public Derived(string value) : base(value) + protected internal B(int x) { } } """); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] - [WorkItem("https://github.com/dotnet/Roslyn/issues/6541")] - public async Task TestGenerateFromDerivedClass2() + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] + [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] + public async Task TestGenerateConstructorFromPrivateProtectedConstructor() { await TestCodeFixAsync( """ - class Base + abstract class {|CS7036:C|} : [||]B { - public Base(int a, string value = null) - { - } } - class [||]{|CS7036:Derived|} : Base + abstract class B { + private protected B(int x) + { + } } """, """ - class Base + abstract class C : B { - public Base(int a, string value = null) + private protected C(int x) : base(x) { } } - class Derived : Base + abstract class B { - public Derived(int a, string value = null) : base(a, value) + private protected B(int x) { } } """); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/19953")] - public async Task TestNotOnEnum() - { - await TestRefactoringMissingAsync( - """ - enum [||]E - { - } - """); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] - public async Task TestGenerateConstructorFromProtectedConstructor() + public async Task TestGenerateConstructorFromPrivateProtectedConstructor2() { await TestCodeFixAsync( """ - abstract class {|CS7036:C|} : [||]B + class {|CS7036:C|} : [||]B { } abstract class B { - protected B(int x) + private protected internal {|CS0107:B|}(int x) { } } """, """ - abstract class C : B + class C : B { - protected C(int x) : base(x) + public C(int x) : base(x) { } } abstract class B { - protected B(int x) + private protected internal {|CS0107:B|}(int x) { } } @@ -1041,70 +900,103 @@ protected B(int x) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] - public async Task TestGenerateConstructorFromProtectedConstructor2() + public async Task TestRecord() { await TestCodeFixAsync( """ - class {|CS7036:C|} : [||]B + record {|CS1729:C|} : [||]B { } - abstract class B + record B { - protected B(int x) + public B(int x) { } } """, """ - class C : B + record C : B { public C(int x) : base(x) { } } - abstract class B + record B { - protected B(int x) + public B(int x) { } } - """); + """, index: 1); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/48318")] - public async Task TestGenerateConstructorFromProtectedConstructorCursorAtTypeOpening() + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] + [WorkItem("https://github.com/dotnet/roslyn/issues/58593")] + public async Task TestStructWithFieldInitializer() { - await TestRefactoringOnlyAsync( - """ - class {|CS7036:C|} : B + var source = """ + struct [||]{|CS8983:S|} { - - [||] - + object X = 1; } - - abstract class B + """; + var fixedSource = """ + struct S { - protected B(int x) + object X = 1; + + public S() { } } - """, + """; + + await new VerifyCodeFix.Test + { + TestCode = source.Replace("[||]", ""), + FixedCode = fixedSource, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); + +#if !CODE_STYLE + await TestRefactoringMissingAsync(source); +#endif + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] + [WorkItem("https://github.com/dotnet/roslyn/issues/58593")] + public async Task TestMissingInStructWithoutFieldInitializer() + { + var source = """ + struct [||]S + { + object X; + } + """; + + await TestCodeFixMissingAsync(source); + +#if !CODE_STYLE + await TestRefactoringMissingAsync(source); +#endif + } + +#if !CODE_STYLE + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] + public async Task TestPrivateBase() + { + await TestRefactoringMissingAsync( """ - class C : B + class {|CS1729:C|} : [||]B { - public C(int x) : base(x) - { - } } - abstract class B + class B { - protected B(int x) + private B(int x) { } } @@ -1112,21 +1004,28 @@ protected B(int x) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/48318")] - public async Task TestGenerateConstructorFromProtectedConstructorCursorBetweenTypeMembers() + public async Task TestFixAll2() { - await TestRefactoringOnlyAsync( + await TestRefactoringAsync( """ - class {|CS7036:C|} : B + class C : [||]B { - int X; - [||] - int Y; + public {|CS1729:C|}(bool x) + { + } } - abstract class B + class B { - protected B(int x) + internal B(int x) + { + } + + protected B(string x) + { + } + + public B(bool x) { } } @@ -1134,53 +1033,113 @@ protected B(int x) """ class C : B { - int X; + public {|CS1729:C|}(bool x) + { + } - int Y; + protected C(string x) : base(x) + { + } - public C(int x) : base(x) + internal C(int x) : base(x) { } } - abstract class B + class B { - protected B(int x) + internal B(int x) + { + } + + protected B(string x) + { + } + + public B(bool x) { } } - """); + """, +index: 2); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/35208")] - [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] - public async Task TestGenerateConstructorInAbstractClassFromPublicConstructor() + public async Task TestFixAll_WithTuples() { - await TestCodeFixAsync( + await TestRefactoringAsync( """ - abstract class {|CS7036:C|} : [||]B + class C : [||]B { + public {|CS1729:C|}((bool, bool) x) + { + } } - abstract class B + class B { - public B(int x) + internal B((int, int) x) + { + } + + protected B((string, string) x) + { + } + + public B((bool, bool) x) { } } """, """ - abstract class C : B + class C : B { - protected C(int x) : base(x) + public {|CS1729:C|}((bool, bool) x) + { + } + + protected C((string, string) x) : base(x) + { + } + + internal C((int, int) x) : base(x) { } } - abstract class B + class B { - public B(int x) + internal B((int, int) x) + { + } + + protected B((string, string) x) + { + } + + public B((bool, bool) x) + { + } + } + """, +index: 2); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] + public async Task TestMissing1() + { + await TestRefactoringMissingAsync( + """ + class C : [||]B + { + public {|CS7036:C|}(int x) + { + } + } + + class B + { + internal B(int x) { } } @@ -1188,18 +1147,21 @@ public B(int x) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] - public async Task TestGenerateConstructorFromPublicConstructor2() + [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/889349")] + public async Task TestDefaultConstructorGeneration_1() { - await TestCodeFixAsync( + await TestRefactoringAsync( """ - class {|CS7036:C|} : [||]B + class C : [||]B { + public {|CS7036:C|}(int y) + { + } } - abstract class B + class B { - public B(int x) + internal B(int x) { } } @@ -1207,14 +1169,18 @@ public B(int x) """ class C : B { - public C(int x) : base(x) + public {|CS7036:C|}(int y) + { + } + + internal {|CS0111:C|}(int x) : base(x) { } } - abstract class B + class B { - public B(int x) + internal B(int x) { } } @@ -1222,16 +1188,19 @@ public B(int x) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] - public async Task TestGenerateConstructorFromInternalConstructor() + [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/889349")] + public async Task TestDefaultConstructorGeneration_2() { - await TestCodeFixAsync( + await TestRefactoringAsync( """ - abstract class {|CS7036:C|} : [||]B + class C : [||]B { + private {|CS7036:C|}(int y) + { + } } - abstract class B + class B { internal B(int x) { @@ -1239,14 +1208,18 @@ internal B(int x) } """, """ - abstract class C : B + class C : B { internal C(int x) : base(x) { } + + private {|CS0111:{|CS7036:C|}|}(int y) + { + } } - abstract class B + class B { internal B(int x) { @@ -1256,67 +1229,145 @@ internal B(int x) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] - public async Task TestGenerateConstructorFromInternalConstructor2() + [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544070")] + public async Task TestException1() { - await TestCodeFixAsync( + await TestRefactoringAsync( """ - class {|CS7036:C|} : [||]B + using System; + class Program : Excep[||]tion { } + """, + """ + using System; + using System.Runtime.Serialization; + class Program : Exception + { + public Program() + { + } - abstract class B + public Program(string message) : base(message) + { + } + + public Program(string message, Exception innerException) : base(message, innerException) + { + } + + protected Program(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } + """, +index: 4); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] + public async Task TestException2() + { + await TestRefactoringAsync( + """ + using System; + using System.Collections.Generic; + using System.Linq; + + class Program : [||]Exception { - internal B(int x) + public Program() + { + } + + static void Main(string[] args) { } } """, """ - class C : B + using System; + using System.Collections.Generic; + using System.Linq; + using System.Runtime.Serialization; + + class Program : Exception { - public C(int x) : base(x) + public Program() + { + } + + public Program(string message) : base(message) + { + } + + public Program(string message, Exception innerException) : base(message, innerException) + { + } + + protected Program(SerializationInfo info, StreamingContext context) : base(info, context) { } - } - abstract class B - { - internal B(int x) + static void Main(string[] args) { } } - """); + """, +index: 3); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] - public async Task TestGenerateConstructorFromProtectedInternalConstructor() + public async Task TestException3() { - await TestCodeFixAsync( + await TestRefactoringAsync( """ - abstract class {|CS7036:C|} : [||]B - { - } + using System; + using System.Collections.Generic; + using System.Linq; - abstract class B + class Program : [||]Exception { - protected internal B(int x) + public Program(string message) : base(message) + { + } + + public Program(string message, Exception innerException) : base(message, innerException) + { + } + + protected Program(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) + { + } + + static void Main(string[] args) { } } """, """ - abstract class C : B + using System; + using System.Collections.Generic; + using System.Linq; + + class Program : Exception { - protected internal C(int x) : base(x) + public Program() { } - } - abstract class B - { - protected internal B(int x) + public Program(string message) : base(message) + { + } + + public Program(string message, Exception innerException) : base(message, innerException) + { + } + + protected Program(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) + { + } + + static void Main(string[] args) { } } @@ -1324,86 +1375,88 @@ protected internal B(int x) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] - public async Task TestGenerateConstructorFromProtectedInternalConstructor2() + public async Task TestException4() { - await TestCodeFixAsync( + await TestRefactoringAsync( """ - class {|CS7036:C|} : [||]B - { - } + using System; + using System.Collections.Generic; + using System.Linq; - abstract class B + class Program : [||]Exception { - protected internal B(int x) + public Program(string message, Exception innerException) : base(message, innerException) + { + } + + protected Program(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) + { + } + + static void Main(string[] args) { } } """, """ - class C : B + using System; + using System.Collections.Generic; + using System.Linq; + + class Program : Exception { - public C(int x) : base(x) + public Program() { } - } - abstract class B - { - protected internal B(int x) + public Program(string message) : base(message) { } - } - """); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] - public async Task TestGenerateConstructorFromPrivateProtectedConstructor() - { - await TestCodeFixAsync( - """ - abstract class {|CS7036:C|} : [||]B - { - } + public Program(string message, Exception innerException) : base(message, innerException) + { + } - abstract class B - { - private protected B(int x) + protected Program(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { } - } - """, - """ - abstract class C : B - { - private protected C(int x) : base(x) + + static void Main(string[] args) { } } + """, +index: 2); + } - abstract class B + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] + [WorkItem("https://github.com/dotnet/roslyn/issues/19953")] + public async Task TestNotOnEnum() + { + await TestRefactoringMissingAsync( + """ + enum [||]E { - private protected B(int x) - { - } } """); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/25238")] - public async Task TestGenerateConstructorFromPrivateProtectedConstructor2() + [WorkItem("https://github.com/dotnet/roslyn/issues/48318")] + public async Task TestGenerateConstructorFromProtectedConstructorCursorAtTypeOpening() { - await TestCodeFixAsync( + await TestRefactoringOnlyAsync( """ - class {|CS7036:C|} : [||]B + class {|CS7036:C|} : B { + + [||] + } abstract class B { - private protected internal {|CS0107:B|}(int x) + protected B(int x) { } } @@ -1418,7 +1471,7 @@ public C(int x) : base(x) abstract class B { - private protected internal {|CS0107:B|}(int x) + protected B(int x) { } } @@ -1426,33 +1479,40 @@ abstract class B } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - [WorkItem("https://github.com/dotnet/roslyn/issues/40586")] - public async Task TestGeneratePublicConstructorInSealedClassForProtectedBase() + [WorkItem("https://github.com/dotnet/roslyn/issues/48318")] + public async Task TestGenerateConstructorFromProtectedConstructorCursorBetweenTypeMembers() { - await TestRefactoringAsync( + await TestRefactoringOnlyAsync( """ - class Base + class {|CS7036:C|} : B { - protected Base() - { - } + int X; + [||] + int Y; } - sealed class Program : [||]Base + abstract class B { + protected B(int x) + { + } } """, """ - class Base + class C : B { - protected Base() + int X; + + int Y; + + public C(int x) : base(x) { } } - sealed class Program : Base + abstract class B { - public Program() + protected B(int x) { } } @@ -1528,81 +1588,38 @@ internal Program() } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors)] - public async Task TestRecord() + [WorkItem("https://github.com/dotnet/roslyn/issues/40586")] + public async Task TestGeneratePublicConstructorInSealedClassForProtectedBase() { - await TestCodeFixAsync( + await TestRefactoringAsync( """ - record {|CS1729:C|} : [||]B + class Base { + protected Base() + { + } } - record B + sealed class Program : [||]Base { - public B(int x) - { - } } """, """ - record C : B - { - public C(int x) : base(x) - { - } - } - - record B + class Base { - public B(int x) + protected Base() { } } - """, index: 1); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] - [WorkItem("https://github.com/dotnet/roslyn/issues/58593")] - public async Task TestStructWithFieldInitializer() - { - var source = """ - struct [||]{|CS8983:S|} - { - object X = 1; - } - """; - var fixedSource = """ - struct S + sealed class Program : Base { - object X = 1; - - public S() + public Program() { } } - """; - - await new VerifyCodeFix.Test - { - TestCode = source.Replace("[||]", ""), - FixedCode = fixedSource, - LanguageVersion = LanguageVersion.CSharp12, - }.RunAsync(); - - await TestRefactoringMissingAsync(source); + """); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)] - [WorkItem("https://github.com/dotnet/roslyn/issues/58593")] - public async Task TestMissingInStructWithoutFieldInitializer() - { - var source = """ - struct [||]S - { - object X; - } - """; - - await TestCodeFixMissingAsync(source); - await TestRefactoringMissingAsync(source); - } +#endif } diff --git a/src/Features/CSharpTest/GenerateEnumMember/GenerateEnumMemberTests.cs b/src/Analyzers/CSharp/Tests/GenerateEnumMember/GenerateEnumMemberTests.cs similarity index 99% rename from src/Features/CSharpTest/GenerateEnumMember/GenerateEnumMemberTests.cs rename to src/Analyzers/CSharp/Tests/GenerateEnumMember/GenerateEnumMemberTests.cs index 8434f60dd792c..ef4531bb9b3f2 100644 --- a/src/Features/CSharpTest/GenerateEnumMember/GenerateEnumMemberTests.cs +++ b/src/Analyzers/CSharp/Tests/GenerateEnumMember/GenerateEnumMemberTests.cs @@ -16,13 +16,9 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.GenerateEnumMember; [Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEnumMember)] -public class GenerateEnumMemberTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor +public sealed class GenerateEnumMemberTests(ITestOutputHelper logger) + : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor(logger) { - public GenerateEnumMemberTests(ITestOutputHelper logger) - : base(logger) - { - } - internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) => (null, new GenerateEnumMemberCodeFixProvider()); diff --git a/src/Features/CSharpTest/GenerateMethod/GenerateConversionTests.cs b/src/Analyzers/CSharp/Tests/GenerateMethod/GenerateConversionTests.cs similarity index 96% rename from src/Features/CSharpTest/GenerateMethod/GenerateConversionTests.cs rename to src/Analyzers/CSharp/Tests/GenerateMethod/GenerateConversionTests.cs index de2ec8843bf82..65a5634332887 100644 --- a/src/Features/CSharpTest/GenerateMethod/GenerateConversionTests.cs +++ b/src/Analyzers/CSharp/Tests/GenerateMethod/GenerateConversionTests.cs @@ -17,13 +17,9 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.GenerateMethod; [Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)] -public class GenerateConversionTest : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor +public sealed class GenerateConversionTests(ITestOutputHelper logger) + : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor(logger) { - public GenerateConversionTest(ITestOutputHelper logger) - : base(logger) - { - } - internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) => (null, new GenerateConversionCodeFixProvider()); diff --git a/src/Features/CSharpTest/GenerateMethod/GenerateDeconstructMethodTests.cs b/src/Analyzers/CSharp/Tests/GenerateMethod/GenerateDeconstructMethodTests.cs similarity index 97% rename from src/Features/CSharpTest/GenerateMethod/GenerateDeconstructMethodTests.cs rename to src/Analyzers/CSharp/Tests/GenerateMethod/GenerateDeconstructMethodTests.cs index 0462179ffd750..ea95b0f287d11 100644 --- a/src/Features/CSharpTest/GenerateMethod/GenerateDeconstructMethodTests.cs +++ b/src/Analyzers/CSharp/Tests/GenerateMethod/GenerateDeconstructMethodTests.cs @@ -16,13 +16,9 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.GenerateDeconstructMethod; [Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)] -public class GenerateDeconstructMethodTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor +public sealed class GenerateDeconstructMethodTests(ITestOutputHelper logger) + : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor(logger) { - public GenerateDeconstructMethodTests(ITestOutputHelper logger) - : base(logger) - { - } - internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) => (null, new GenerateDeconstructMethodCodeFixProvider()); diff --git a/src/Features/CSharpTest/GenerateMethod/GenerateMethodTests.cs b/src/Analyzers/CSharp/Tests/GenerateMethod/GenerateMethodTests.cs similarity index 99% rename from src/Features/CSharpTest/GenerateMethod/GenerateMethodTests.cs rename to src/Analyzers/CSharp/Tests/GenerateMethod/GenerateMethodTests.cs index 8ca11d1c34efc..11377189c98f5 100644 --- a/src/Features/CSharpTest/GenerateMethod/GenerateMethodTests.cs +++ b/src/Analyzers/CSharp/Tests/GenerateMethod/GenerateMethodTests.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateMethod; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -5300,7 +5301,7 @@ internal static void Test(global::Outer.Inner inner) } } """, -new TestParameters(Options.Regular)); +new TestParameters(new CSharpParseOptions(kind: SourceCodeKind.Regular))); } [Theory] diff --git a/src/Features/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs b/src/Analyzers/CSharp/Tests/ImplementAbstractClass/ImplementAbstractClassTests.cs similarity index 99% rename from src/Features/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs rename to src/Analyzers/CSharp/Tests/ImplementAbstractClass/ImplementAbstractClassTests.cs index ed3df972d2c97..bc4c5048dcc2b 100644 --- a/src/Features/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs +++ b/src/Analyzers/CSharp/Tests/ImplementAbstractClass/ImplementAbstractClassTests.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.ImplementType; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -1713,7 +1712,7 @@ void Goo() { } public override int Prop => throw new System.NotImplementedException(); } - """, globalOptions: options); + """, options: options); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17274")] @@ -1910,7 +1909,7 @@ class C : AbstractClass public override int ReadWriteProp { get; set; } public override int WriteOnlyProp { set => throw new System.NotImplementedException(); } } - """, parameters: new TestParameters(globalOptions: options)); + """, parameters: new TestParameters(options: options)); } [Theory, CombinatorialData] diff --git a/src/Features/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests_FixAllTests.cs b/src/Analyzers/CSharp/Tests/ImplementAbstractClass/ImplementAbstractClassTests_FixAllTests.cs similarity index 100% rename from src/Features/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests_FixAllTests.cs rename to src/Analyzers/CSharp/Tests/ImplementAbstractClass/ImplementAbstractClassTests_FixAllTests.cs diff --git a/src/Features/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests_ThroughMember.cs b/src/Analyzers/CSharp/Tests/ImplementAbstractClass/ImplementAbstractClassTests_ThroughMember.cs similarity index 90% rename from src/Features/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests_ThroughMember.cs rename to src/Analyzers/CSharp/Tests/ImplementAbstractClass/ImplementAbstractClassTests_ThroughMember.cs index 72af868c1c1a3..8a4ed151f3ccc 100644 --- a/src/Features/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests_ThroughMember.cs +++ b/src/Analyzers/CSharp/Tests/ImplementAbstractClass/ImplementAbstractClassTests_ThroughMember.cs @@ -72,7 +72,7 @@ abstract class Base class [|Derived|] : Base { } - """, [FeaturesResources.Implement_abstract_class]); + """, [AnalyzersResources.Implement_abstract_class]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -93,7 +93,7 @@ abstract class Middle : Base class [|Derived|] : Base { } - """, [FeaturesResources.Implement_abstract_class]); + """, [AnalyzersResources.Implement_abstract_class]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -126,7 +126,7 @@ public override void Method() inner.Method(); } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact] @@ -159,7 +159,7 @@ public override void Method(int a, ref int b, in int c, ref readonly int d, out inner.Method(a, ref b, c, in d, out e); } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact] @@ -189,7 +189,7 @@ class Derived : Base public override int this[int a, in int b, ref readonly int c, out int d] => inner[a, b, in c, out d]; } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -224,7 +224,7 @@ public override void Method1() inner.Method1(); } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -247,7 +247,7 @@ public override void Method1() inner.Method1(); } } - """, new string[] { FeaturesResources.Implement_abstract_class }); + """, [AnalyzersResources.Implement_abstract_class]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -288,7 +288,7 @@ public override void Method() class DerivedAgain : Derived { } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -321,7 +321,7 @@ public override void Method() inner.Method(); } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -347,9 +347,9 @@ class [|Derived|] : Base, IInterface } """, [ - FeaturesResources.Implement_abstract_class, - string.Format(FeaturesResources.Implement_through_0, "Inner"), - string.Format(FeaturesResources.Implement_through_0, "IInterface.Inner"), + AnalyzersResources.Implement_abstract_class, + string.Format(AnalyzersResources.Implement_through_0, "Inner"), + string.Format(AnalyzersResources.Implement_through_0, "IInterface.Inner"), ]); } @@ -367,7 +367,7 @@ class [|Derived|] : Base { dynamic inner; } - """, [FeaturesResources.Implement_abstract_class]); + """, [AnalyzersResources.Implement_abstract_class]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -400,7 +400,7 @@ public override void Method() inner.Method(); } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -430,7 +430,7 @@ class Derived : Base public override int Property { get => inner.Property; set => inner.Property = value; } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -505,7 +505,7 @@ class Derived : Base public override int SetOnly { set => inner.SetOnly = value; } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -596,7 +596,7 @@ public override event Action Event } } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -633,7 +633,7 @@ public override void Method() inner.Method(); } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -650,7 +650,7 @@ class [|Derived|] : Base { Base inner; } - """, [FeaturesResources.Implement_abstract_class]); + """, [AnalyzersResources.Implement_abstract_class]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -683,7 +683,7 @@ protected override void Method() inner.Method(); } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -716,7 +716,7 @@ protected internal override void Method() inner.Method(); } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -749,7 +749,7 @@ internal override void Method() inner.Method(); } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -766,7 +766,7 @@ class [|Derived|] : Base { Base inner; } - """, [FeaturesResources.Implement_abstract_class]); + """, [AnalyzersResources.Implement_abstract_class]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -799,7 +799,7 @@ private protected override void Method() inner.Method(); } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41420")] @@ -832,7 +832,7 @@ class Derived : Base public override int InternalGet { internal get => inner.InternalGet; set => inner.InternalGet = value; } public override int InternalSet { get => inner.InternalSet; internal set => inner.InternalSet = value; } } - """, index: 1, title: string.Format(FeaturesResources.Implement_through_0, "inner")); + """, index: 1, title: string.Format(AnalyzersResources.Implement_through_0, "inner")); } [Fact] @@ -935,7 +935,7 @@ class [|Program|](Base base1) : Base { private Base _base = base1; } - """, [FeaturesResources.Implement_abstract_class, string.Format(FeaturesResources.Implement_through_0, "_base")]); + """, [AnalyzersResources.Implement_abstract_class, string.Format(AnalyzersResources.Implement_through_0, "_base")]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69177")] @@ -953,7 +953,7 @@ class [|Program|](Base base1) : Base { private Base _base = (base1); } - """, [FeaturesResources.Implement_abstract_class, string.Format(FeaturesResources.Implement_through_0, "_base")]); + """, [AnalyzersResources.Implement_abstract_class, string.Format(AnalyzersResources.Implement_through_0, "_base")]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69177")] @@ -971,7 +971,7 @@ class [|Program|](Base base1) : Base { private Base B { get; } = base1; } - """, [FeaturesResources.Implement_abstract_class, string.Format(FeaturesResources.Implement_through_0, "B")]); + """, [AnalyzersResources.Implement_abstract_class, string.Format(AnalyzersResources.Implement_through_0, "B")]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69177")] @@ -989,7 +989,7 @@ class [|Program|](Base base1) : Base { private Base B { get; } = (base1); } - """, [FeaturesResources.Implement_abstract_class, string.Format(FeaturesResources.Implement_through_0, "B")]); + """, [AnalyzersResources.Implement_abstract_class, string.Format(AnalyzersResources.Implement_through_0, "B")]); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69177")] diff --git a/src/EditorFeatures/CSharpTest/CodeActions/ImplementInterface/ImplementInterfaceTests.cs b/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests.cs similarity index 93% rename from src/EditorFeatures/CSharpTest/CodeActions/ImplementInterface/ImplementInterfaceTests.cs rename to src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests.cs index 3a8f14b625acc..1fcfb16183639 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/ImplementInterface/ImplementInterfaceTests.cs +++ b/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests.cs @@ -377,7 +377,7 @@ class Class : IInterface } } """, -codeAction: ("True;False;False:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, CompilerTrait(CompilerFeature.Tuples)] @@ -560,7 +560,7 @@ public void M(string? s1, string s2) """, }, }, - CodeActionEquivalenceKey = "False;False;True:global::IInterface;Assembly1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;False;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }; @@ -1017,7 +1017,7 @@ public void Method1() } } """, -codeAction: ("False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", 1)); +codeAction: ("False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", 1)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69177")] @@ -1048,7 +1048,7 @@ public void Method1() } } """, -codeAction: ("False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", 1)); +codeAction: ("False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", 1)); } [Fact] @@ -1097,7 +1097,7 @@ public void Method1() } } """, -codeAction: ("False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", 1)); +codeAction: ("False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", 1)); } [Fact] @@ -1146,7 +1146,7 @@ public void Method1() } } """, -codeAction: ("False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", 1)); +codeAction: ("False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", 1)); } [Fact] @@ -1199,7 +1199,7 @@ class D : {|CS0535:I|} MarkupHandling = MarkupMode.Allow, }, CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne, - CodeActionEquivalenceKey = "False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", + CodeActionEquivalenceKey = "False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", CodeActionIndex = 1, }; @@ -1246,7 +1246,7 @@ public int this[int x] } } """, -codeAction: ("False;False;False:global::IGoo;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;f", 1)); +codeAction: ("False;False;False:global::IGoo;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;f", 1)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/472")] @@ -1274,7 +1274,7 @@ public int Compare(object x, object y) } } """, -codeAction: ("False;False;False:global::System.Collections.IComparer;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;x", 1)); +codeAction: ("False;False;False:global::System.Collections.IComparer;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;x", 1)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/472")] @@ -1302,7 +1302,7 @@ public int Compare(object x, object y) } } """, -codeAction: ("False;False;False:global::System.Collections.IComparer;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", 1)); +codeAction: ("False;False;False:global::System.Collections.IComparer;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", 1)); } [Fact] @@ -1330,7 +1330,7 @@ abstract class C : I public abstract void Method1(); } """, -codeAction: ("False;True;True:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("False;True;True:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact] @@ -1371,7 +1371,7 @@ interface I int Method2(); } """, -codeAction: ("False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;goo", 1)); +codeAction: ("False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;goo", 1)); } [Fact] @@ -2180,7 +2180,7 @@ int i1.p } } """, -codeAction: ("True;False;False:global::i1;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::i1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541981")] @@ -2220,7 +2220,7 @@ public void Method1() """, Options = { AllOptionsOff }, CodeActionsVerifier = codeActions => Assert.Equal(3, codeActions.Length), - CodeActionEquivalenceKey = "False;False;True:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;False;True:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); @@ -2245,7 +2245,7 @@ public void Method1() """, Options = { AllOptionsOff }, CodeActionsVerifier = codeActions => Assert.Equal(3, codeActions.Length), - CodeActionEquivalenceKey = "False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", + CodeActionEquivalenceKey = "False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;i", CodeActionIndex = 1, }.RunAsync(); @@ -2270,7 +2270,7 @@ void I.Method1() """, Options = { AllOptionsOff }, CodeActionsVerifier = codeActions => Assert.Equal(3, codeActions.Length), - CodeActionEquivalenceKey = "True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 2, }.RunAsync(); } @@ -2322,7 +2322,7 @@ IEnumerator IEnumerable.GetEnumerator() } } """, -codeAction: ("False;False;False:global::System.Collections.Generic.IReadOnlyList;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;field", 1)); +codeAction: ("False;False;False:global::System.Collections.Generic.IReadOnlyList;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;field", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/768799")] @@ -2372,7 +2372,7 @@ IEnumerator IEnumerable.GetEnumerator() } } """, -codeAction: ("False;False;False:global::System.Collections.Generic.IReadOnlyList;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;field", 1)); +codeAction: ("False;False;False:global::System.Collections.Generic.IReadOnlyList;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;field", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/768799")] @@ -2422,7 +2422,7 @@ public int M() } } """, -codeAction: ("False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", 1)); +codeAction: ("False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/768799")] @@ -2504,7 +2504,7 @@ public int M() CodeActionsVerifier = codeActions => Assert.Equal(3, codeActions.Length), DiagnosticSelector = diagnostics => diagnostics[0], CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne, - CodeActionEquivalenceKey = "False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", + CodeActionEquivalenceKey = "False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", CodeActionIndex = 1, }.RunAsync(); @@ -2584,7 +2584,7 @@ public int M2() CodeActionsVerifier = codeActions => Assert.Equal(3, codeActions.Length), DiagnosticSelector = diagnostics => diagnostics[1], CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne, - CodeActionEquivalenceKey = "False;False;False:global::I2;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", + CodeActionEquivalenceKey = "False;False;False:global::I2;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", CodeActionIndex = 1, }.RunAsync(); } @@ -2648,7 +2648,7 @@ public int M() }, Options = { AllOptionsOff }, CodeActionsVerifier = codeActions => Assert.Equal(4, codeActions.Length), - CodeActionEquivalenceKey = "False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", + CodeActionEquivalenceKey = "False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", CodeActionIndex = 1, }.RunAsync(); @@ -2708,7 +2708,7 @@ public int M() }, Options = { AllOptionsOff }, CodeActionsVerifier = codeActions => Assert.Equal(4, codeActions.Length), - CodeActionEquivalenceKey = "False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;aa", + CodeActionEquivalenceKey = "False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;aa", CodeActionIndex = 2, }.RunAsync(); } @@ -2800,7 +2800,7 @@ public int M() CodeActionsVerifier = codeActions => Assert.Equal(3, codeActions.Length), DiagnosticSelector = diagnostics => diagnostics[0], CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne, - CodeActionEquivalenceKey = "False;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", + CodeActionEquivalenceKey = "False;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;a", CodeActionIndex = 1, }.RunAsync(); @@ -2888,7 +2888,7 @@ public int M2() CodeActionsVerifier = codeActions => Assert.Equal(3, codeActions.Length), DiagnosticSelector = diagnostics => diagnostics[1], CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne, - CodeActionEquivalenceKey = "False;False;False:global::I2;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;b", + CodeActionEquivalenceKey = "False;False;False:global::I2;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;b", CodeActionIndex = 1, }.RunAsync(); } @@ -2933,7 +2933,7 @@ public int M() """, Options = { AllOptionsOff }, CodeActionsVerifier = codeActions => Assert.Equal(3, codeActions.Length), - CodeActionEquivalenceKey = "False;False;False:global::IB;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;IA.B", + CodeActionEquivalenceKey = "False;False;False:global::IB;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;IA.B", CodeActionIndex = 1, }.RunAsync(); } @@ -3113,7 +3113,7 @@ public event EventHandler E } } } - """, codeAction: ("False;False;False:global::IGoo;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;canGoo", 1)); + """, codeAction: ("False;False;False:global::IGoo;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;canGoo", 1)); } [Fact] @@ -3140,7 +3140,7 @@ public event EventHandler E } } """, -codeAction: ("False;False;False:global::IGoo;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;canGoo", 1)); +codeAction: ("False;False;False:global::IGoo;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;canGoo", 1)); } [Fact] @@ -3170,7 +3170,7 @@ abstract class Goo : IGoo public event EventHandler E; } """, -codeAction: ("False;False;True:global::IGoo;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 0)); +codeAction: ("False;False;True:global::IGoo;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 0)); } [Fact] @@ -3200,7 +3200,7 @@ abstract class Goo : IGoo public abstract event EventHandler E; } """, -codeAction: ("False;True;True:global::IGoo;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("False;True;True:global::IGoo;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact] @@ -3241,7 +3241,7 @@ event EventHandler IGoo.E } } """, -codeAction: ("True;False;False:global::IGoo;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 2)); +codeAction: ("True;False;False:global::IGoo;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 2)); } [Fact] @@ -3427,7 +3427,7 @@ int ISomeInterface.this[int index] } } """, -codeAction: ("True;False;False:global::ISomeInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::ISomeInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact] @@ -3521,7 +3521,7 @@ void I.Goo() } } """, -codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542357")] @@ -3660,7 +3660,7 @@ void I.Goo() } } """, -codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542587")] @@ -3751,7 +3751,7 @@ void I.Goo() } } """, -codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542587")] @@ -4220,7 +4220,7 @@ void I.Goo(S x, IList list) } } """, -codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542505")] @@ -4303,7 +4303,7 @@ void I.Goo(A x, B y, IList list1, IList list2) } } """, -codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542506")] @@ -4467,7 +4467,7 @@ abstract class Goo : IGoo public abstract int Gibberish { get; set; } } """, -codeAction: ("False;True;True:global::IGoo;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("False;True;True:global::IGoo;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544210")] @@ -4546,7 +4546,7 @@ int IOptional.Goo(int g) } } """, -codeAction: ("True;False;False:global::IOptional;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::IOptional;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact] @@ -4737,7 +4737,7 @@ void IGoo.Goo(DateTime x) } } """, -codeAction: ("True;False;False:global::IGoo;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::IGoo;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545477")] @@ -4824,7 +4824,7 @@ void IGoo.Goo2(object x) } } """, -codeAction: ("True;False;False:global::IGoo;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::IGoo;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545464")] @@ -4947,7 +4947,7 @@ void d.m(b? x, b? y) throw new System.NotImplementedException(); } } - """, codeAction: ("True;False;False:global::d;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); + """, codeAction: ("True;False;False:global::d;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/916114")] @@ -6074,7 +6074,7 @@ public void Dispose() } } - """, codeAction: ("False;False;True:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 0)); + """, codeAction: ("False;False;True:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 0)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/958699")] @@ -6093,7 +6093,7 @@ class C : IDisposable {DisposePattern("protected virtual ", "C", "public void ")} }} -", codeAction: ("False;False;True:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 1)); +", codeAction: ("False;False;True:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/958699")] @@ -6115,7 +6115,7 @@ void IDisposable.Dispose() } } - """, codeAction: ("True;False;False:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 2)); + """, codeAction: ("True;False;False:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 2)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/941469")] @@ -6142,7 +6142,7 @@ class IDisposable }} {DisposePattern("protected virtual ", "C", "void System.IDisposable.")} -}}", codeAction: ("True;False;False:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 3)); +}}", codeAction: ("True;False;False:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 3)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/958699")] @@ -6161,7 +6161,7 @@ abstract class C : IDisposable public abstract void Dispose(); } - """, codeAction: ("False;True;True:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 2)); + """, codeAction: ("False;True;True:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 2)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/958699")] @@ -6187,7 +6187,7 @@ public void Dispose() goo.Dispose(); } } - """, codeAction: ("False;False;False:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;goo", 2)); + """, codeAction: ("False;False;False:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;goo", 2)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/941469")] @@ -6203,7 +6203,7 @@ public async Task TestImplementIDisposableExplicitly_NoNamespaceImportForSystem( {DisposePattern("protected virtual ", "C", "void System.IDisposable.", gcPrefix: "System.")} }} ", - CodeActionEquivalenceKey = "True;False;False:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", CodeActionIndex = 3, // 🐛 generated QualifiedName where SimpleMemberAccessExpression was expected @@ -6243,7 +6243,7 @@ public void F() throw new NotImplementedException(); } } - """, codeAction: ("False;False;True:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 0)); + """, codeAction: ("False;False;True:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 0)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/951968")] @@ -6275,7 +6275,7 @@ public void F() }} {DisposePattern("protected virtual ", "C", "public void ")} -}}", codeAction: ("False;False;True:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 1)); +}}", codeAction: ("False;False;True:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/951968")] @@ -6307,7 +6307,7 @@ void I.F() }} {DisposePattern("protected virtual ", "C", "void IDisposable.")} -}}", codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 3)); +}}", codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 3)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/941469")] @@ -6341,7 +6341,7 @@ void IDisposable.Dispose() } } } - """, codeAction: ("True;False;False:global::System.IDisposable;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); + """, codeAction: ("True;False;False:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact] @@ -6383,7 +6383,7 @@ void IDisposable.Dispose() } } - """, codeAction: ("True;False;False:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); + """, codeAction: ("True;False;False:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545924")] @@ -6732,7 +6732,7 @@ bool I.Goo(bool x) } } """, -codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); +codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546443")] @@ -6879,7 +6879,7 @@ void I.M() throw new System.NotImplementedException(); } } - """, codeAction: ("True;False;False:global::N.I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); + """, codeAction: ("True;False;False:global::N.I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/847464")] @@ -6917,7 +6917,7 @@ void I.Goo() throw new System.NotImplementedException(); } } - """, codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); + """, codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/847464")] @@ -6955,7 +6955,7 @@ void I.Goo() partial class C { } - """, codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); + """, codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/847464")] @@ -7014,7 +7014,7 @@ partial class C : {|CS0535:I2|} }, Options = { AllOptionsOff }, CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne, - CodeActionEquivalenceKey = "True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -7073,7 +7073,7 @@ void IGoo.set_IndexProp(int p1, string Value) """, }, }, - CodeActionEquivalenceKey = "True;False;False:global::IGoo;Assembly1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::IGoo;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }; @@ -7136,7 +7136,7 @@ public void set_P(int x, object Value) """, }, }, - CodeActionEquivalenceKey = "False;False;True:global::I;Assembly1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;False;True:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); } @@ -7205,7 +7205,7 @@ public string this[int i] """, }, }, - CodeActionEquivalenceKey = "False;False;True:global::I;Assembly1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;False;True:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }; @@ -7245,7 +7245,7 @@ class Program : IDisposable private bool disposedValue; {DisposePattern("protected virtual ", "Program", "public void ")} -}}", codeAction: ("False;False;True:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 1)); +}}", codeAction: ("False;False;True:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 1)); } [Fact] @@ -7268,7 +7268,7 @@ class Program : IDisposable private bool disposedValue; {DisposePattern("protected virtual ", "Program", "void IDisposable.")} -}}", codeAction: ("True;False;False:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 3)); +}}", codeAction: ("True;False;False:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 3)); } [Fact] @@ -7295,7 +7295,7 @@ public void Dispose() throw new NotImplementedException(); } } - """, codeAction: ("False;False;True:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 0)); + """, codeAction: ("False;False;True:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 0)); } [Fact] @@ -7326,7 +7326,7 @@ public void Dispose() throw new NotImplementedException(); } } - """, codeAction: ("False;False;True:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 0)); + """, codeAction: ("False;False;True:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 0)); } [Fact] @@ -7347,7 +7347,7 @@ sealed class Program : IDisposable private bool disposedValue; {DisposePattern("private ", "Program", "void IDisposable.")} -}}", codeAction: ("True;False;False:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 3)); +}}", codeAction: ("True;False;False:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 3)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/9760")] @@ -7370,7 +7370,7 @@ class Program : IDisposable private bool disposedValue1; {DisposePattern("protected virtual ", "Program", "public void ", disposeField: "disposedValue1")} -}}", codeAction: ("False;False;True:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 1)); +}}", codeAction: ("False;False;True:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 1)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/9760")] @@ -7397,7 +7397,7 @@ class Program : IDisposable { _options.FieldNamesAreCamelCaseWithUnderscorePrefix, }, - CodeActionEquivalenceKey = "False;False;True:global::System.IDisposable;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", + CodeActionEquivalenceKey = "False;False;True:global::System.IDisposable;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -7544,7 +7544,30 @@ public void M1() [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/994328")] public async Task TestDisposePatternWhenAdditionalUsingsAreIntroduced1() { - //CSharpFeaturesResources.DisposePattern +#if NET9_0_OR_GREATER + var extraUsing = """ + + using System.Diagnostics.CodeAnalysis; + """; + + var equalsMethod = """ + public bool Equals([AllowNull] int other) + { + throw new NotImplementedException(); + } + """; +#else + var extraUsing = ""; + + var equalsMethod = """ + public bool Equals(int other) + { + throw new NotImplementedException(); + } + """; +#endif + + //CSharpCodeFixesResources.DisposePattern await TestWithAllCodeStyleOptionsOffAsync( """ interface I : System.IDisposable, System.IEquatable where U : T @@ -7561,40 +7584,39 @@ partial class C : {|CS0535:{|CS0535:{|CS0535:I : System.IDisposable, System.IEquatable where U : T -{{ - System.Collections.Generic.List M(System.Collections.Generic.Dictionary> a, T b, U c); - System.Collections.Generic.List M(System.Collections.Generic.Dictionary> a, TT b, UU c) where UU : TT; -}} + $$""" + using System; + using System.Collections.Generic;{{extraUsing}} -partial class C -{{ -}} + interface I : System.IDisposable, System.IEquatable where U : T + { + System.Collections.Generic.List M(System.Collections.Generic.Dictionary> a, T b, U c); + System.Collections.Generic.List M(System.Collections.Generic.Dictionary> a, TT b, UU c) where UU : TT; + } -partial class C : I, System.IDisposable -{{ - private bool disposedValue; + partial class C + { + } - public bool Equals(int other) - {{ - throw new NotImplementedException(); - }} + partial class C : I, System.IDisposable + { + private bool disposedValue; + + {{equalsMethod}} - public List M(Dictionary> a, Exception b, AggregateException c) - {{ - throw new NotImplementedException(); - }} + public List M(Dictionary> a, Exception b, AggregateException c) + { + throw new NotImplementedException(); + } - public List M(Dictionary> a, TT b, UU c) where UU : TT - {{ - throw new NotImplementedException(); - }} + public List M(Dictionary> a, TT b, UU c) where UU : TT + { + throw new NotImplementedException(); + } -{DisposePattern("protected virtual ", "C", "public void ")} -}}", codeAction: ("False;False;True:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 1)); + {{DisposePattern("protected virtual ", "C", "public void ")}} + } + """, codeAction: ("False;False;True:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 1)); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/994328")] @@ -7616,40 +7638,42 @@ partial class C { } """, -$@"using System; -using System.Collections.Generic; + $$""" + using System; + using System.Collections.Generic; -interface I : System.IDisposable, System.IEquatable where U : T -{{ - System.Collections.Generic.List M(System.Collections.Generic.Dictionary> a, T b, U c); - System.Collections.Generic.List M(System.Collections.Generic.Dictionary> a, TT b, UU c) where UU : TT; -}} + interface I : System.IDisposable, System.IEquatable where U : T + { + System.Collections.Generic.List M(System.Collections.Generic.Dictionary> a, T b, U c); + System.Collections.Generic.List M(System.Collections.Generic.Dictionary> a, TT b, UU c) where UU : TT; + } -partial class C : I, System.IDisposable -{{ - private bool disposedValue; + partial class C : I, System.IDisposable + { + private bool disposedValue; - bool IEquatable.Equals(int other) - {{ - throw new NotImplementedException(); - }} + bool IEquatable.Equals(int other) + { + throw new NotImplementedException(); + } - List I.M(Dictionary> a, Exception b, AggregateException c) - {{ - throw new NotImplementedException(); - }} + List I.M(Dictionary> a, Exception b, AggregateException c) + { + throw new NotImplementedException(); + } - List I.M(Dictionary> a, TT b, UU c) - {{ - throw new NotImplementedException(); - }} + List I.M(Dictionary> a, TT b, UU c) + { + throw new NotImplementedException(); + } -{DisposePattern("protected virtual ", "C", "void IDisposable.")} -}} + {{DisposePattern("protected virtual ", "C", "void IDisposable.")}} + } -partial class C -{{ -}}", codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 3)); + partial class C + { + } + """, codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction;", 3)); } private static string DisposePattern( @@ -7659,34 +7683,36 @@ private static string DisposePattern( string disposeField = "disposedValue", string gcPrefix = "") { - return $@" {disposeVisibility}void Dispose(bool disposing) - {{ - if (!{disposeField}) - {{ - if (disposing) - {{ - // {FeaturesResources.TODO_colon_dispose_managed_state_managed_objects} - }} - - // {FeaturesResources.TODO_colon_free_unmanaged_resources_unmanaged_objects_and_override_finalizer} - // {FeaturesResources.TODO_colon_set_large_fields_to_null} - {disposeField} = true; - }} - }} + return $$""" + {{disposeVisibility}}void Dispose(bool disposing) + { + if (!{{disposeField}}) + { + if (disposing) + { + // {{CodeFixesResources.TODO_colon_dispose_managed_state_managed_objects}} + } - // // {string.Format(FeaturesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, "Dispose(bool disposing)")} - // ~{className}() - // {{ - // // {string.Format(FeaturesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(bool disposing)")} - // Dispose(disposing: false); - // }} + // {{CodeFixesResources.TODO_colon_free_unmanaged_resources_unmanaged_objects_and_override_finalizer}} + // {{CodeFixesResources.TODO_colon_set_large_fields_to_null}} + {{disposeField}} = true; + } + } - {implementationVisibility}Dispose() - {{ - // {string.Format(FeaturesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(bool disposing)")} - Dispose(disposing: true); - {gcPrefix}GC.SuppressFinalize(this); - }}"; + // // {{string.Format(CodeFixesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, "Dispose(bool disposing)")}} + // ~{{className}}() + // { + // // {{string.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(bool disposing)")}} + // Dispose(disposing: false); + // } + + {{implementationVisibility}}Dispose() + { + // {{string.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(bool disposing)")}} + Dispose(disposing: true); + {{gcPrefix}}GC.SuppressFinalize(this); + } + """; } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1132014")] @@ -7843,7 +7869,7 @@ IEnumerator IEnumerable.GetEnumerator() } } """, -codeAction: ("False;False;False:global::System.Collections.Generic.IList;mscorlib;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;innerList", 1)); +codeAction: ("False;False;False:global::System.Collections.Generic.IList;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;innerList", 1)); } [Fact, CompilerTrait(CompilerFeature.Tuples)] @@ -8007,10 +8033,13 @@ void M() { } public int Prop => throw new System.NotImplementedException(); } """, - CodeActionOptions = (CodeActionOptions.Default with + Options = { - ImplementTypeOptions = new() { InsertionBehavior = ImplementTypeInsertionBehavior.AtTheEnd } - }).CreateProvider() + new OptionsCollection(LanguageNames.CSharp) + { + { ImplementTypeOptionsStorage.InsertionBehavior, ImplementTypeInsertionBehavior.AtTheEnd } + } + } }.RunAsync(); } @@ -8189,10 +8218,13 @@ class Class : IInterface public int WriteOnlyProp { set => throw new System.NotImplementedException(); } } """, - CodeActionOptions = (CodeActionOptions.Default with + Options = { - ImplementTypeOptions = new() { PropertyGenerationBehavior = ImplementTypePropertyGenerationBehavior.PreferAutoProperties } - }).CreateProvider() + new OptionsCollection(LanguageNames.CSharp) + { + { ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties } + } + } }.RunAsync(); } @@ -8470,7 +8502,7 @@ void IInterface.Method1() } """, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "True;False;False:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -8509,7 +8541,7 @@ abstract class Class : IInterface } """, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "False;True;True:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;True;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -8558,7 +8590,7 @@ public void Method1() MarkupHandling = MarkupMode.Allow, }, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "False;False;True:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;False;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", }.RunAsync(); } @@ -8612,7 +8644,7 @@ void IInterface.M1() Options = { AllOptionsOff }, DiagnosticSelector = diagnostics => diagnostics[1], CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne, - CodeActionEquivalenceKey = "True;False;False:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); } @@ -8658,7 +8690,7 @@ abstract class Class : {|CS0535:{|CS0535:IInterface|}|} MarkupHandling = MarkupMode.Allow, }, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "False;True;True:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;True;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", }.RunAsync(); } @@ -8706,7 +8738,7 @@ public void Method1() MarkupHandling = MarkupMode.Allow, }, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "False;False;True:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;False;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", }.RunAsync(); } @@ -8771,7 +8803,7 @@ int IInterface.P2 MarkupHandling = MarkupMode.Allow, }, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "True;False;False:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); } @@ -8817,7 +8849,7 @@ abstract class Class : {|CS0535:{|CS0535:IInterface|}|} MarkupHandling = MarkupMode.Allow, }, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "False;True;True:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;True;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", }.RunAsync(); } @@ -8898,7 +8930,7 @@ void IInterface.Method1() } """, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "True;False;False:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -8937,7 +8969,7 @@ abstract class Class : IInterface } """, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "False;True;True:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;True;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -8996,7 +9028,7 @@ public void Method1() Options = { AllOptionsOff }, // Specify the code action by equivalence key only to avoid trying to implement the interface explicitly with a second code fix pass. - CodeActionEquivalenceKey = "False;False;True:global::IInterface;Assembly1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;False;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", }.RunAsync(); } @@ -9052,7 +9084,7 @@ void IInterface.Method1() MarkupHandling = MarkupMode.Allow, }, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "True;False;False:global::IInterface;Assembly1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -9108,7 +9140,7 @@ abstract class Class : {|CS0535:{|CS0535:IInterface|}|} Options = { AllOptionsOff }, // Specify the code action by equivalence key only to avoid trying to execute a second code fix pass with a different action - CodeActionEquivalenceKey = "False;True;True:global::IInterface;Assembly1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;True;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", }.RunAsync(); } @@ -9608,7 +9640,7 @@ public void Method1() Options = { AllOptionsOff }, // Specify the code action by equivalence key only to avoid trying to implement the interface explicitly with a second code fix pass. - CodeActionEquivalenceKey = "False;False;True:global::IInterface;Assembly1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;False;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", }.RunAsync(); } @@ -9664,7 +9696,7 @@ void IInterface.Method1() MarkupHandling = MarkupMode.Allow, }, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "True;False;False:global::IInterface;Assembly1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -9720,7 +9752,7 @@ abstract class Class : {|CS0535:{|CS0535:IInterface|}|} Options = { AllOptionsOff }, // Specify the code action by equivalence key only to avoid trying to execute a second code fix pass with a different action - CodeActionEquivalenceKey = "False;True;True:global::IInterface;Assembly1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;True;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", }.RunAsync(); } @@ -9801,7 +9833,7 @@ void IInterface.Method1() } """, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "True;False;False:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -9840,7 +9872,7 @@ abstract class Class : IInterface } """, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "False;True;True:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;True;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -9930,7 +9962,7 @@ void IInterface.Method1() } """, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "True;False;False:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "True;False;False:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -9973,7 +10005,7 @@ abstract class Class : IInterface } """, Options = { AllOptionsOff }, - CodeActionEquivalenceKey = "False;True;True:global::IInterface;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionEquivalenceKey = "False;True;True:global::IInterface;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -10011,7 +10043,7 @@ public async Task TestWithNullableProperty() { await TestInRegularAndScriptAsync( """ - #nullable enable + #nullable enable public interface ITest { @@ -10022,7 +10054,7 @@ public class Test : {|CS0535:ITest|} } """, """ - #nullable enable + #nullable enable public interface ITest { @@ -10040,7 +10072,7 @@ public async Task TestWithNullablePropertyAlreadyImplemented() { var code = """ - #nullable enable + #nullable enable public interface ITest { @@ -10059,7 +10091,7 @@ public async Task TestWithNullableMethod() { await TestInRegularAndScriptAsync( """ - #nullable enable + #nullable enable public interface ITest { @@ -10070,7 +10102,7 @@ public class Test : {|CS0535:ITest|} } """, """ - #nullable enable + #nullable enable public interface ITest { @@ -10093,7 +10125,7 @@ public async Task TestWithNullableEvent() // see https://github.com/dotnet/roslyn/issues/36673 await TestInRegularAndScriptAsync( """ - #nullable enable + #nullable enable using System; @@ -10106,7 +10138,7 @@ public class Test : {|CS0535:ITest|} } """, """ - #nullable enable + #nullable enable using System; @@ -10126,7 +10158,7 @@ public async Task TestWithNullableDisabled() { await TestInRegularAndScriptAsync( """ - #nullable enable + #nullable enable public interface ITest { @@ -10140,7 +10172,7 @@ public class Test : {|CS0535:ITest|} } """, """ - #nullable enable + #nullable enable public interface ITest { @@ -10163,7 +10195,7 @@ public async Task GenericInterfaceNotNull1() { ReferenceAssemblies = ReferenceAssemblies.Net.Net50, TestCode = """ - #nullable enable + #nullable enable using System.Diagnostics.CodeAnalysis; @@ -10181,7 +10213,7 @@ class A : {|CS0535:{|CS0535:IFoo|}|} } """, FixedCode = """ - #nullable enable + #nullable enable using System.Diagnostics.CodeAnalysis; @@ -10283,7 +10315,7 @@ void I.M2() throw new System.NotImplementedException(); } } - """, codeAction: ("True;False;True:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 2)); + """, codeAction: ("True;False;True:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 2)); } [Fact] @@ -10409,7 +10441,7 @@ void I.M2() throw new System.NotImplementedException(); } } - """, codeAction: ("True;False;True:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); + """, codeAction: ("True;False;True:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/48295")] @@ -10853,7 +10885,7 @@ void I.M(T1? a, T2 b, T1? c, T3? d) throw new System.NotImplementedException(); } } - """, codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); + """, codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/53012")] @@ -10889,7 +10921,7 @@ void I.M(T1? a, T2 b, T1? c, T3? d) throw new System.NotImplementedException(); } } - """, codeAction: ("True;False;False:global::I;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); + """, codeAction: ("True;False;False:global::I;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", 1)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/51779")] @@ -10969,8 +11001,8 @@ public static void M1() } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface, codeAction.Title), - CodeActionEquivalenceKey = "False;False;True:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_interface, codeAction.Title), + CodeActionEquivalenceKey = "False;False;True:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); } @@ -11006,8 +11038,8 @@ static void ITest.M1() } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_all_members_explicitly, codeAction.Title), - CodeActionEquivalenceKey = "True;False;False:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_all_members_explicitly, codeAction.Title), + CodeActionEquivalenceKey = "True;False;False:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -11043,8 +11075,8 @@ public static void M1() } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface_abstractly, codeAction.Title), - CodeActionEquivalenceKey = "False;True;True:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_interface_abstractly, codeAction.Title), + CodeActionEquivalenceKey = "False;True;True:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -11078,8 +11110,8 @@ class C : ITest } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_all_members_explicitly, codeAction.Title), - CodeActionEquivalenceKey = "True;False;False:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_all_members_explicitly, codeAction.Title), + CodeActionEquivalenceKey = "True;False;False:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); } @@ -11113,8 +11145,8 @@ class C : ITest } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_all_members_explicitly, codeAction.Title), - CodeActionEquivalenceKey = "True;False;False:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_all_members_explicitly, codeAction.Title), + CodeActionEquivalenceKey = "True;False;False:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); } @@ -11155,8 +11187,8 @@ class C : ITest } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface, codeAction.Title), - CodeActionEquivalenceKey = "False;False;True:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_interface, codeAction.Title), + CodeActionEquivalenceKey = "False;False;True:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); } @@ -11190,8 +11222,8 @@ class C : ITest } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface, codeAction.Title), - CodeActionEquivalenceKey = "False;False;True:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_interface, codeAction.Title), + CodeActionEquivalenceKey = "False;False;True:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); } @@ -11225,8 +11257,8 @@ class C : ITest } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_all_members_explicitly, codeAction.Title), - CodeActionEquivalenceKey = "True;False;False:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_all_members_explicitly, codeAction.Title), + CodeActionEquivalenceKey = "True;False;False:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -11260,8 +11292,8 @@ abstract class C : ITest } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface_abstractly, codeAction.Title), - CodeActionEquivalenceKey = "False;True;True:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_interface_abstractly, codeAction.Title), + CodeActionEquivalenceKey = "False;True;True:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); @@ -11296,8 +11328,8 @@ static int ITest.M(ITest x) } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_all_members_explicitly, codeAction.Title), - CodeActionEquivalenceKey = "True;False;False:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_all_members_explicitly, codeAction.Title), + CodeActionEquivalenceKey = "True;False;False:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); @@ -11332,8 +11364,8 @@ public static int M(ITest x) } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface, codeAction.Title), - CodeActionEquivalenceKey = "False;False;True:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_interface, codeAction.Title), + CodeActionEquivalenceKey = "False;False;True:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); @@ -11368,8 +11400,8 @@ public static int M(C x) } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface, codeAction.Title), - CodeActionEquivalenceKey = "False;False;True:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_interface, codeAction.Title), + CodeActionEquivalenceKey = "False;False;True:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); @@ -11404,8 +11436,8 @@ static int ITest.M(C x) } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_all_members_explicitly, codeAction.Title), - CodeActionEquivalenceKey = "True;False;False:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_all_members_explicitly, codeAction.Title), + CodeActionEquivalenceKey = "True;False;False:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); @@ -11440,8 +11472,8 @@ public static int M(C x) } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface_abstractly, codeAction.Title), - CodeActionEquivalenceKey = "False;True;True:global::ITest;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_interface_abstractly, codeAction.Title), + CodeActionEquivalenceKey = "False;True;True:global::ITest;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); @@ -11517,8 +11549,8 @@ public static explicit operator string(C3 x) } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_all_members_explicitly, codeAction.Title), - CodeActionEquivalenceKey = "True;False;False:global::I1;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_all_members_explicitly, codeAction.Title), + CodeActionEquivalenceKey = "True;False;False:global::I1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -11593,8 +11625,8 @@ public static explicit operator string(C3 x) } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface, codeAction.Title), - CodeActionEquivalenceKey = "False;False;True:global::I1;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_interface, codeAction.Title), + CodeActionEquivalenceKey = "False;False;True:global::I1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 0, }.RunAsync(); } @@ -11669,8 +11701,8 @@ public static explicit operator string(C3 x) } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_interface_abstractly, codeAction.Title), - CodeActionEquivalenceKey = "False;True;True:global::I1;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_interface_abstractly, codeAction.Title), + CodeActionEquivalenceKey = "False;True;True:global::I1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", CodeActionIndex = 1, }.RunAsync(); } @@ -11811,7 +11843,7 @@ static void I.M() } } """, - CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Implement_all_members_explicitly, codeAction.Title), + CodeActionVerifier = (codeAction, verifier) => verifier.Equal(CodeFixesResources.Implement_all_members_explicitly, codeAction.Title), }.RunAsync(); } diff --git a/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.cs b/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.cs new file mode 100644 index 0000000000000..ede09df35995f --- /dev/null +++ b/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.cs @@ -0,0 +1,696 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.ImplementInterface; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ImplementInterface; + +using VerifyCS = CSharpCodeFixVerifier< + EmptyDiagnosticAnalyzer, + CSharpImplementInterfaceCodeFixProvider>; + +public class ImplementInterfaceTests_FixAllTests +{ + #region "Fix all occurrences tests" + + [Fact] + [Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] + [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task TestFixAllInDocument() + { + await new VerifyCS.Test + { + TestState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C1 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + """ + class B2 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C2 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + AdditionalProjects = + { + ["Assembly1"] = + { + Sources = + { + """ + class B3 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C3 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + AdditionalProjectReferences = { "TestProject" }, + }, + }, + }, + FixedState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : I1, I2 + { + public void F1() + { + throw new System.NotImplementedException(); + } + + class C1 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + """ + class B2 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C2 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + MarkupHandling = MarkupMode.Allow, + }, + BatchFixedState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : I1, I2 + { + public void F1() + { + throw new System.NotImplementedException(); + } + + class C1 : I1, I2 + { + public void F1() + { + throw new System.NotImplementedException(); + } + } + } + """, + """ + class B2 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C2 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + MarkupHandling = MarkupMode.Allow, + }, + CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipFixAllInProjectCheck | CodeFixTestBehaviors.SkipFixAllInSolutionCheck, + CodeActionEquivalenceKey = "False;False;True:global::I1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionIndex = 0, + }.RunAsync(); + } + + [Fact] + [Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] + [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task TestFixAllInProject() + { + await new VerifyCS.Test + { + TestState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C1 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + """ + class B2 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C2 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + AdditionalProjects = + { + ["Assembly1"] = + { + Sources = + { + """ + class B3 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C3 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + AdditionalProjectReferences = { "TestProject" }, + }, + }, + }, + FixedState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : I1, I2 + { + public void F1() + { + throw new System.NotImplementedException(); + } + + class C1 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + """ + class B2 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C2 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + MarkupHandling = MarkupMode.Allow, + }, + BatchFixedState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : I1, I2 + { + public void F1() + { + throw new System.NotImplementedException(); + } + + class C1 : I1, I2 + { + public void F1() + { + throw new System.NotImplementedException(); + } + } + } + """, + """ + class B2 : I1, I2 + { + public void F1() + { + throw new System.NotImplementedException(); + } + + class C2 : I1, I2 + { + public void F1() + { + throw new System.NotImplementedException(); + } + } + } + """, + }, + MarkupHandling = MarkupMode.Allow, + }, + CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipFixAllInDocumentCheck | CodeFixTestBehaviors.SkipFixAllInSolutionCheck, + CodeActionEquivalenceKey = "False;False;True:global::I1;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionIndex = 0, + }.RunAsync(); + } + + [Fact] + [Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] + [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task TestFixAllInSolution() + { + await new VerifyCS.Test + { + TestState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C1 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + """ + class B2 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C2 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + AdditionalProjects = + { + ["Assembly1"] = + { + Sources = + { + """ + class B3 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C3 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + AdditionalProjectReferences = { "TestProject" }, + }, + }, + }, + FixedState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + + class C1 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + """ + class B2 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C2 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + MarkupHandling = MarkupMode.Allow, + }, + BatchFixedState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + + class C1 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + } + } + """, + """ + class B2 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + + class C2 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + } + } + """, + }, + AdditionalProjects = + { + ["Assembly1"] = + { + Sources = + { + """ + class B3 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + + class C3 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + } + } + """, + }, + AdditionalProjectReferences = { "TestProject" }, + }, + }, + MarkupHandling = MarkupMode.Allow, + }, + CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipFixAllInDocumentCheck | CodeFixTestBehaviors.SkipFixAllInProjectCheck, + DiagnosticSelector = diagnostics => diagnostics[1], + CodeActionEquivalenceKey = "True;False;False:global::I2;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionIndex = 1, + }.RunAsync(); + } + + [Fact] + [Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] + [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task TestFixAllInSolution_DifferentAssemblyWithSameTypeName() + { + await new VerifyCS.Test + { + TestState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C1 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + """ + class B2 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C2 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + AdditionalProjects = + { + ["Assembly1"] = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B3 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C3 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + }, + }, + }, + FixedState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + + class C1 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + """ + class B2 : {|CS0535:I1|}, {|CS0535:I2|} + { + class C2 : {|CS0535:I1|}, {|CS0535:I2|} + { + } + } + """, + }, + MarkupHandling = MarkupMode.Allow, + }, + BatchFixedState = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B1 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + + class C1 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + } + } + """, + """ + class B2 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + + class C2 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + } + } + """, + }, + MarkupHandling = MarkupMode.Allow, + AdditionalProjects = + { + ["Assembly1"] = + { + Sources = + { + """ + public interface I1 + { + void F1(); + } + + public interface I2 + { + void F1(); + } + + class B3 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + + class C3 : {|CS0535:I1|}, I2 + { + void I2.F1() + { + throw new System.NotImplementedException(); + } + } + } + """, + }, + }, + }, + }, + CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipFixAllInDocumentCheck | CodeFixTestBehaviors.SkipFixAllInProjectCheck, + DiagnosticSelector = diagnostics => diagnostics[1], + CodeActionEquivalenceKey = "True;False;False:global::I2;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", + CodeActionIndex = 1, + }.RunAsync(); + } + + #endregion +} diff --git a/src/Analyzers/CSharp/Tests/InlineDeclaration/CSharpInlineDeclarationTests.cs b/src/Analyzers/CSharp/Tests/InlineDeclaration/CSharpInlineDeclarationTests.cs index 97f431170bbe6..fffaef75f7d51 100644 --- a/src/Analyzers/CSharp/Tests/InlineDeclaration/CSharpInlineDeclarationTests.cs +++ b/src/Analyzers/CSharp/Tests/InlineDeclaration/CSharpInlineDeclarationTests.cs @@ -18,13 +18,9 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.InlineDeclaration; [Trait(Traits.Feature, Traits.Features.CodeActionsInlineDeclaration)] -public partial class CSharpInlineDeclarationTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor +public sealed partial class CSharpInlineDeclarationTests(ITestOutputHelper logger) + : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor(logger) { - public CSharpInlineDeclarationTests(ITestOutputHelper logger) - : base(logger) - { - } - internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) => (new CSharpInlineDeclarationDiagnosticAnalyzer(), new CSharpInlineDeclarationCodeFixProvider()); @@ -2433,15 +2429,21 @@ void M(out C c2) """); } - [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44429")] + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/44429")] + [WorkItem("https://github.com/dotnet/roslyn/issues/74736")] public async Task TopLevelStatement() { - await TestMissingAsync(""" + await TestAsync(""" [|int|] i; if (int.TryParse(v, out i)) { } - """, new TestParameters(TestOptions.Regular)); + """, """ + if (int.TryParse(v, out int i)) + { + } + """, CSharpParseOptions.Default); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47041")] @@ -2512,4 +2514,41 @@ private void TestMethod(out int hello) } """); } + + [Fact] + public async Task TestInSwitchSection() + { + await TestInRegularAndScript1Async( + """ + class C + { + void M(object o) + { + switch (o) + { + case string s: + [|int|] i; + if (int.TryParse(v, out i)) + { + } + } + } + } + """, + """ + class C + { + void M(object o) + { + switch (o) + { + case string s: + if (int.TryParse(v, out int i)) + { + } + } + } + } + """); + } } diff --git a/src/Analyzers/CSharp/Tests/OrderModifiers/OrderModifiersTests.cs b/src/Analyzers/CSharp/Tests/OrderModifiers/OrderModifiersTests.cs index 626e1f7038727..f3db59b1473d7 100644 --- a/src/Analyzers/CSharp/Tests/OrderModifiers/OrderModifiersTests.cs +++ b/src/Analyzers/CSharp/Tests/OrderModifiers/OrderModifiersTests.cs @@ -558,4 +558,22 @@ file abstract class C } """); } + + [Fact, WorkItem("https://github.com/dotnet/vscode-csharp/issues/7553")] + public async Task TestEmptySelection() + { + await TestInRegularAndScript1Async( + """ + namespace M; + [||]static internal class C + { + } + """, + """ + namespace M; + internal static class C + { + } + """, TestParameters.Default.WithIncludeDiagnosticsOutsideSelection(false)); + } } diff --git a/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs b/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs index 3418d1e2e4205..ca6f3fe43ab08 100644 --- a/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs +++ b/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs @@ -10047,8 +10047,8 @@ public async Task DoNotRemoveForNullWithMultipleMatchingParameterTypes() using System; public class TestClass { - public TestClass(object? value) { } - public TestClass(Func value) { } + public TestClass(object? value) { } + public TestClass(Func value) { } public TestClass Create1() => new ((object?)null); } @@ -10070,7 +10070,7 @@ public async Task DoNotRemoveForNintPointerToVoidPointer() using System; public class TestClass { - unsafe void M(nint** ptr) + unsafe void M(nint** ptr) { nint value = (nint)(void*)*ptr; } @@ -12527,39 +12527,39 @@ public async Task DoNotRemoveNecessaryCastWithOverloadedNegationAndImplicitConve namespace WrongRedundantCastWarning { - struct Flag - { - public Flag(int value) => this.Value = value; + struct Flag + { + public Flag(int value) => this.Value = value; - public int Value { get; } + public int Value { get; } - // This cast is wrongly reported as redundant - public static FlagSet operator ~(Flag flag) => ~(FlagSet)flag; - } + // This cast is wrongly reported as redundant + public static FlagSet operator ~(Flag flag) => ~(FlagSet)flag; + } - struct FlagSet - { - public FlagSet(int value) => this.Value = value; + struct FlagSet + { + public FlagSet(int value) => this.Value = value; - public int Value { get; } + public int Value { get; } - public static implicit operator FlagSet(Flag flag) => new FlagSet(flag.Value); + public static implicit operator FlagSet(Flag flag) => new FlagSet(flag.Value); - public static FlagSet operator ~(FlagSet flagSet) => new FlagSet(~flagSet.Value); - } + public static FlagSet operator ~(FlagSet flagSet) => new FlagSet(~flagSet.Value); + } - class Program - { - static readonly Flag One = new Flag(1); - static readonly Flag Two = new Flag(2); + class Program + { + static readonly Flag One = new Flag(1); + static readonly Flag Two = new Flag(2); - static void Main(string[] args) - { - var flipped = ~Two; + static void Main(string[] args) + { + var flipped = ~Two; - Console.WriteLine(flipped.Value); - } - } + Console.WriteLine(flipped.Value); + } + } } """; await new VerifyCS.Test @@ -12742,7 +12742,7 @@ class C { protected sbyte ExtractInt8(object data) { - return (data is sbyte value) ? value : (sbyte)0; + return (data is sbyte value) ? value : (sbyte)0; } } """; @@ -13835,4 +13835,160 @@ void X() LanguageVersion = LanguageVersion.CSharp12, }.RunAsync(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75145")] + public async Task UnnecessaryInterpolationCast1() + { + await new VerifyCS.Test + { + TestCode = """ + #nullable enable + + using System; + + public class C + { + public static void Main() + { + string s = $"{[|(object?)|]null}"; + Console.WriteLine(s); + } + } + """, + FixedCode = """ + #nullable enable + + using System; + + public class C + { + public static void Main() + { + string s = $"{null}"; + Console.WriteLine(s); + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75145")] + public async Task UnnecessaryInterpolationCast2() + { + await new VerifyCS.Test + { + TestCode = """ + #nullable enable + + using System.Runtime.CompilerServices; + + public class IssueClass + { + public object? Test() + { + return InterpolateMe($"{[|(object?)|]null}"); + } + + public static object? InterpolateMe([InterpolatedStringHandlerArgument] ref TestInterpolatedStringHandler handler) + { + return null; + } + + [InterpolatedStringHandler] + public ref struct TestInterpolatedStringHandler(int literalLength, int formattedCount) + { + public readonly void AppendLiteral(string s) + { + } + + public void AppendFormatted(T value) + { + } + + public void AppendFormatted(object? value) + { + } + } + } + """, + FixedCode = """ + #nullable enable + + using System.Runtime.CompilerServices; + + public class IssueClass + { + public object? Test() + { + return InterpolateMe($"{null}"); + } + + public static object? InterpolateMe([InterpolatedStringHandlerArgument] ref TestInterpolatedStringHandler handler) + { + return null; + } + + [InterpolatedStringHandler] + public ref struct TestInterpolatedStringHandler(int literalLength, int formattedCount) + { + public readonly void AppendLiteral(string s) + { + } + + public void AppendFormatted(T value) + { + } + + public void AppendFormatted(object? value) + { + } + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75145")] + public async Task NecessaryInterpolationCast() + { + await new VerifyCS.Test + { + TestCode = """ + #nullable enable + + using System.Runtime.CompilerServices; + + public class IssueClass + { + public object? Test() + { + return InterpolateMe($"{(object?)null}"); + } + + public static object? InterpolateMe([InterpolatedStringHandlerArgument] ref TestInterpolatedStringHandler handler) + { + return null; + } + + [InterpolatedStringHandler] + public ref struct TestInterpolatedStringHandler(int literalLength, int formattedCount) + { + public readonly void AppendLiteral(string s) + { + } + + public void AppendFormatted(T value) + { + } + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } } diff --git a/src/Analyzers/CSharp/Tests/RemoveUnusedMembers/RemoveUnusedMembersTests.cs b/src/Analyzers/CSharp/Tests/RemoveUnusedMembers/RemoveUnusedMembersTests.cs index 2bcf767b9dfeb..c06801cfe9adc 100644 --- a/src/Analyzers/CSharp/Tests/RemoveUnusedMembers/RemoveUnusedMembersTests.cs +++ b/src/Analyzers/CSharp/Tests/RemoveUnusedMembers/RemoveUnusedMembersTests.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.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; @@ -16,6 +15,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.RemoveUnusedMembers; +using static Microsoft.CodeAnalysis.CSharp.UsePatternCombinators.AnalyzedPattern; using VerifyCS = CSharpCodeFixVerifier< CSharpRemoveUnusedMembersDiagnosticAnalyzer, CSharpRemoveUnusedMembersCodeFixProvider>; @@ -30,19 +30,20 @@ public void TestStandardProperty(AnalyzerProperty property) [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31582")] public async Task FieldReadViaSuppression() { - var code = """ - #nullable enable - class MyClass - { - string? _field = null; - public void M() + await new VerifyCS.Test + { + TestCode = """ + #nullable enable + class MyClass { - _field!.ToString(); + string? _field = null; + public void M() + { + _field!.ToString(); + } } - } - """; - - await VerifyCS.VerifyCodeFixAsync(code, code); + """ + }.RunAsync(); } [Theory] @@ -53,14 +54,16 @@ public void M() [InlineData("private protected")] public async Task NonPrivateField(string accessibility) { - var code = $$""" - class MyClass - { - {{accessibility}} int _goo; - } - """; + await new VerifyCS.Test + { + TestCode = $$""" + class MyClass + { + {{accessibility}} int _goo; + } + """, + }.RunAsync(); - await VerifyCS.VerifyCodeFixAsync(code, code); } [Theory] @@ -71,14 +74,15 @@ class MyClass [InlineData("private protected")] public async Task NonPrivateFieldWithConstantInitializer(string accessibility) { - var code = $$""" - class MyClass - { - {{accessibility}} int _goo = 0; - } - """; - - await VerifyCS.VerifyCodeFixAsync(code, code); + await new VerifyCS.Test + { + TestCode = $$""" + class MyClass + { + {{accessibility}} int _goo = 0; + } + """, + }.RunAsync(); } [Theory] @@ -89,15 +93,16 @@ class MyClass [InlineData("private protected")] public async Task NonPrivateFieldWithNonConstantInitializer(string accessibility) { - var code = $$""" - class MyClass - { - {{accessibility}} int _goo = _goo2; - private static readonly int _goo2 = 0; - } - """; - - await VerifyCS.VerifyCodeFixAsync(code, code); + await new VerifyCS.Test + { + TestCode = $$""" + class MyClass + { + {{accessibility}} int _goo = _goo2; + private static readonly int _goo2 = 0; + } + """, + }.RunAsync(); } [Theory] @@ -1462,30 +1467,26 @@ public void M() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33994")] public async Task PropertyIsOnlyWritten() { - var source = - """ - class MyClass - { - private int {|#0:P|} { get; set; } - public void M() - { - P = 0; - } - } - """; - - var descriptor = new CSharpRemoveUnusedMembersDiagnosticAnalyzer().SupportedDiagnostics.First(x => x.Id == "IDE0052"); - var expectedMessage = string.Format(AnalyzersResources.Private_property_0_can_be_converted_to_a_method_as_its_get_accessor_is_never_invoked, "MyClass.P"); - await new VerifyCS.Test { - TestCode = source, + TestCode = """ + class MyClass + { + private int {|#0:P|} { get; set; } + public void M() + { + P = 0; + } + } + """, ExpectedDiagnostics = { // Test0.cs(3,17): info IDE0052: Private property 'MyClass.P' can be converted to a method as its get accessor is never invoked. - VerifyCS.Diagnostic(descriptor).WithMessage(expectedMessage).WithLocation(0), + VerifyCS + .Diagnostic(new CSharpRemoveUnusedMembersDiagnosticAnalyzer().SupportedDiagnostics.First(x => x.Id == "IDE0052")) + .WithMessage(string.Format(AnalyzersResources.Private_property_0_can_be_converted_to_a_method_as_its_get_accessor_is_never_invoked, "MyClass.P")) + .WithLocation(0), }, - FixedCode = source, }.RunAsync(); } @@ -1745,20 +1746,21 @@ class MyClass } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43191")] - public async Task PropertyIsIncrementedAndValueDropped_VerifyAnalizerMessage() + public async Task PropertyIsIncrementedAndValueDropped_VerifyAnalyzerMessage() { var code = """ class MyClass { - private int P { get; set; } + private int {|#0:P|} { get; set; } public void M1() { ++P; } } """; await VerifyCS.VerifyAnalyzerAsync(code, new DiagnosticResult( CSharpRemoveUnusedMembersDiagnosticAnalyzer.s_removeUnreadMembersRule) - .WithSpan(3, 17, 3, 18) - .WithArguments("MyClass.P")); + .WithLocation(0) + .WithArguments("MyClass.P") + .WithOptions(DiagnosticOptions.IgnoreAdditionalLocations)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43191")] @@ -1805,20 +1807,19 @@ class MyClass } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43191")] - public async Task IndexerIsIncrementedAndValueDropped_VerifyAnalizerMessage() + public async Task IndexerIsIncrementedAndValueDropped_VerifyAnalyzerMessage() { - var code = """ + await VerifyCS.VerifyAnalyzerAsync(""" class MyClass { - private int this[int x] { get { return 0; } set { } } + private int {|#0:this|}[int x] { get { return 0; } set { } } public void M1(int x) => ++this[x]; } - """; - - await VerifyCS.VerifyAnalyzerAsync(code, new DiagnosticResult( - CSharpRemoveUnusedMembersDiagnosticAnalyzer.s_removeUnreadMembersRule) - .WithSpan(3, 17, 3, 21) - .WithArguments("MyClass.this")); + """, new DiagnosticResult( + CSharpRemoveUnusedMembersDiagnosticAnalyzer.s_removeUnreadMembersRule) + .WithLocation(0) + .WithArguments("MyClass.this") + .WithOptions(DiagnosticOptions.IgnoreAdditionalLocations)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43191")] @@ -1921,20 +1922,21 @@ class MyClass } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43191")] - public async Task PropertyIsTargetOfCompoundAssignmentAndValueDropped_VerifyAnalizerMessage() + public async Task PropertyIsTargetOfCompoundAssignmentAndValueDropped_VerifyAnalyzerMessage() { var code = """ class MyClass { - private int P { get; set; } + private int {|#0:P|} { get; set; } public void M1(int x) { P += x; } } """; await VerifyCS.VerifyAnalyzerAsync(code, new DiagnosticResult( CSharpRemoveUnusedMembersDiagnosticAnalyzer.s_removeUnreadMembersRule) - .WithSpan(3, 17, 3, 18) - .WithArguments("MyClass.P")); + .WithLocation(0) + .WithArguments("MyClass.P") + .WithOptions(DiagnosticOptions.IgnoreAdditionalLocations)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43191")] @@ -1986,15 +1988,16 @@ public async Task IndexerIsTargetOfCompoundAssignmentAndValueDropped_VerifyAnaly var code = """ class MyClass { - private int this[int x] { get { return 0; } set { } } + private int {|#0:this|}[int x] { get { return 0; } set { } } public void M1(int x, int y) => this[x] += y; } """; await VerifyCS.VerifyAnalyzerAsync(code, new DiagnosticResult( CSharpRemoveUnusedMembersDiagnosticAnalyzer.s_removeUnreadMembersRule) - .WithSpan(3, 17, 3, 21) - .WithArguments("MyClass.this")); + .WithLocation(0) + .WithArguments("MyClass.this") + .WithOptions(DiagnosticOptions.IgnoreAdditionalLocations)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43191")] @@ -3173,15 +3176,18 @@ await VerifyCS.VerifyAnalyzerAsync( """ class C { - private C(int i) { } + private {|#0:C|}(int i) { } } """, -// /0/Test0.cs(3,13): info IDE0051: Private member 'C.C' is unused -VerifyCS.Diagnostic("IDE0051").WithSpan(3, 13, 3, 14).WithArguments("C.C")); + // /0/Test0.cs(3,13): info IDE0051: Private member 'C.C' is unused + VerifyCS.Diagnostic("IDE0051") + .WithLocation(0) + .WithArguments("C.C") + .WithOptions(DiagnosticOptions.IgnoreAdditionalLocations)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/62856")] - public async Task DontWarnForAwaiterMethods() + public async Task DoNotWarnForAwaiterMethods() { const string code = """ using System; diff --git a/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedParametersTests.cs b/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedParametersTests.cs index d609103963861..c5dfbd10f2c03 100644 --- a/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedParametersTests.cs +++ b/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedParametersTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; @@ -1920,4 +1921,141 @@ void M(int [|x|]) } """, Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId)); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58168")] + public async Task TestInterpolatedStringHandler_TwoIntParameters_FirstParameter() + { + await TestDiagnosticMissingAsync(""" + + + using System.Runtime.CompilerServices; + + [InterpolatedStringHandler] + public struct MyInterpolatedStringHandler + { + public MyInterpolatedStringHandler(int [|literalLength|], int formattedCount) + { + } + } + + + + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58168")] + public async Task TestInterpolatedStringHandler_TwoIntParameters_SecondParameter() + { + await TestDiagnosticMissingAsync(""" + + + using System.Runtime.CompilerServices; + + [InterpolatedStringHandler] + public struct MyInterpolatedStringHandler + { + public MyInterpolatedStringHandler(int literalLength, int [|formattedCount|]) + { + } + } + + + + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/58168")] + [MemberData(nameof(NonIntTypes))] + public async Task TestInterpolatedStringHandler_TwoParameters_FirstNonIntParameter(string nonIntType) + { + await TestDiagnosticsAsync($$""" + + + using System.Runtime.CompilerServices; + + [InterpolatedStringHandler] + public struct MyInterpolatedStringHandler + { + public MyInterpolatedStringHandler({{nonIntType}} [|literalLength|], int formattedCount) + { + } + } + + + + """, Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId)); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/58168")] + [MemberData(nameof(NonIntTypes))] + public async Task TestInterpolatedStringHandler_TwoParameters_SecondNonIntParameter(string nonIntType) + { + await TestDiagnosticsAsync($$""" + + + using System.Runtime.CompilerServices; + + [InterpolatedStringHandler] + public struct MyInterpolatedStringHandler + { + public MyInterpolatedStringHandler(int literalLength, {{nonIntType}} [|formattedCount|]) + { + } + } + + + + """, Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58168")] + public async Task TestInterpolatedStringHandler_OneIntParameter() + { + await TestDiagnosticMissingAsync(""" + + + using System.Runtime.CompilerServices; + + [InterpolatedStringHandler] + public struct MyInterpolatedStringHandler + { + public MyInterpolatedStringHandler(int [|literalLength|]) + { + } + } + + + + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/58168")] + [MemberData(nameof(NonIntTypes))] + public async Task TestInterpolatedStringHandler_OneNonIntParameter(string nonIntType) + { + await TestDiagnosticsAsync($$""" + + + using System.Runtime.CompilerServices; + + [InterpolatedStringHandler] + public struct MyInterpolatedStringHandler + { + public MyInterpolatedStringHandler({{nonIntType}} [|p|]) + { + } + } + + + + """, Diagnostic(IDEDiagnosticIds.UnusedParameterDiagnosticId)); + } + + public static IEnumerable NonIntTypes() + { + yield return ["byte"]; + yield return ["long"]; + yield return ["object"]; + yield return ["string"]; + } } diff --git a/src/Analyzers/CSharp/Tests/SimplifyInterpolation/SimplifyInterpolationTests.cs b/src/Analyzers/CSharp/Tests/SimplifyInterpolation/SimplifyInterpolationTests.cs index 5c30b9c4c1e95..9ca2c201de088 100644 --- a/src/Analyzers/CSharp/Tests/SimplifyInterpolation/SimplifyInterpolationTests.cs +++ b/src/Analyzers/CSharp/Tests/SimplifyInterpolation/SimplifyInterpolationTests.cs @@ -44,9 +44,9 @@ void M(string someValue) var diagnostics = await GetDiagnosticsWorkerAsync(workspace, parameters); Assert.Equal( - new[] { + [ ("IDE0071", DiagnosticSeverity.Info), - }, + ], diagnostics.Select(d => (d.Descriptor.Id, d.Severity))); } diff --git a/src/Analyzers/CSharp/Tests/UseAutoProperty/UseAutoPropertyTests.cs b/src/Analyzers/CSharp/Tests/UseAutoProperty/UseAutoPropertyTests.cs index e8fc58427100c..c819c4aad6ad3 100644 --- a/src/Analyzers/CSharp/Tests/UseAutoProperty/UseAutoPropertyTests.cs +++ b/src/Analyzers/CSharp/Tests/UseAutoProperty/UseAutoPropertyTests.cs @@ -18,9 +18,11 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseAutoProperty; [Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)] -public sealed class UseAutoPropertyTests(ITestOutputHelper logger) +public sealed partial class UseAutoPropertyTests(ITestOutputHelper logger) : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest_NoEditor(logger) { + private readonly ParseOptions CSharp12 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp12); + internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) => (new CSharpUseAutoPropertyAnalyzer(), GetCSharpUseAutoPropertyCodeFixProvider()); @@ -667,7 +669,7 @@ class Class } [Fact] - public async Task TestGetterWithMutipleStatements() + public async Task TestGetterWithMultipleStatements_CSharp12() { await TestMissingInRegularAndScriptAsync( """ @@ -684,11 +686,11 @@ int P } } } - """); + """, new TestParameters(parseOptions: CSharp12)); } [Fact] - public async Task TestSetterWithMutipleStatements() + public async Task TestSetterWithMultipleStatements_CSharp12() { await TestMissingInRegularAndScriptAsync( """ @@ -731,7 +733,7 @@ int P } } } - """); + """, new TestParameters(parseOptions: CSharp12)); } [Fact] @@ -1153,9 +1155,9 @@ partial class Class } [Fact] - public async Task TestNotWithFieldWithAttribute() + public async Task TestWithFieldWithAttribute() { - await TestMissingInRegularAndScriptAsync( + await TestInRegularAndScriptAsync( """ class Class { @@ -1170,6 +1172,13 @@ int P } } } + """, + """ + class Class + { + [field: A] + int P { get; } + } """); } diff --git a/src/Analyzers/CSharp/Tests/UseAutoProperty/UseAutoPropertyTests_Field.cs b/src/Analyzers/CSharp/Tests/UseAutoProperty/UseAutoPropertyTests_Field.cs new file mode 100644 index 0000000000000..41b95d6f61dd5 --- /dev/null +++ b/src/Analyzers/CSharp/Tests/UseAutoProperty/UseAutoPropertyTests_Field.cs @@ -0,0 +1,1399 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseAutoProperty; + +[Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)] +public sealed partial class UseAutoPropertyTests +{ + private readonly ParseOptions CSharp13 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp13); + private readonly ParseOptions Preview = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview); + + [Fact] + public async Task TestNotInCSharp13() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P + { + get + { + return s.Trim(); + } + } + } + """, new(parseOptions: CSharp13)); + } + + [Fact] + public async Task TestFieldSimplestCase() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P + { + get + { + return s.Trim(); + } + } + } + """, + """ + class Class + { + string P + { + get + { + return field.Trim(); + } + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestFieldAccessOffOfThis() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P + { + get + { + return this.s.Trim(); + } + } + } + """, + """ + class Class + { + string P + { + get + { + return field.Trim(); + } + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestStaticField() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|static string s|]; + + static string P + { + get + { + return s.Trim(); + } + } + } + """, + """ + class Class + { + static string P + { + get + { + return field.Trim(); + } + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestGetterWithMultipleStatements_Field() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + int P + { + get + { + ; + return i; + } + } + } + """, + """ + class Class + { + int P + { + get + { + ; + return field; + } + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestSetterWithMultipleStatementsAndGetterWithSingleStatement_Field() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + int P + { + get + { + return i; + } + + set + { + ; + i = value; + } + } + } + """, + """ + class Class + { + int P + { + get; + + set + { + ; + field = value; + } + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestSetterWithMultipleStatementsAndGetterWithSingleStatement_Field2() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + int P + { + get => i; + + set + { + ; + i = value; + } + } + } + """, + """ + class Class + { + int P + { + get; + + set + { + ; + field = value; + } + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestSimpleFieldInExpressionBody() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P => s.Trim(); + } + """, + """ + class Class + { + string P => field.Trim(); + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestMultipleFields_NoClearChoice() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + int [|x|], y; + + int Total => x + y; + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestMultipleFields_NoClearChoice2() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + int [|x|], y; + + int Total + { + get => x + y; + set + { + x = value; + y = value; + } + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestMultipleFields_ClearChoice() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + int [|x|], y; + + int Total + { + get => x + y; + set + { + x = value; + } + } + } + """, + """ + class Class + { + int y; + + int Total + { + get => field + y; + set; + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestMultipleFields_PickByName1() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + int [|x|], y; + + int X => x + y; + } + """, + """ + class Class + { + int y; + + int X => field + y; + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestMultipleFields_PickByName2() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + int [|_x|], y; + + int X => _x + y; + } + """, + """ + class Class + { + int y; + + int X => field + y; + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestNotWhenAlreadyUsingField() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P + { + get + { + var v = field.Trim(); + return s.Trim(); + } + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestNotWhenUsingNameof1() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P + { + get + { + if (s is null) + throw new ArgumentNullException(nameof(s)); + return s.Trim(); + } + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestNotWhenUsingNameof2() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P + { + get + { + if (s is null) + throw new ArgumentNullException(nameof(this.s)); + return s.Trim(); + } + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestNotWhenUsingNameof3() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P + { + get + { + return s.Trim(); + } + } + + void M() + { + if (s is null) + throw new ArgumentNullException(nameof(s)); + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestNotWhenUsingNameof4() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P + { + get + { + return s.Trim(); + } + } + + void M() + { + if (s is null) + throw new ArgumentNullException(nameof(this.s)); + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestNotWhenUsingNameof5() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|string s = nameof(s)|]; + + string P => s; + } + """, new(parseOptions: CSharp13)); + } + + [Fact] + public async Task TestWithRefArgumentUseInside() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P => Init(ref s); + + void Init(ref string s) + { + } + } + """, + """ + class Class + { + string P => Init(ref field); + + void Init(ref string s) + { + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestNotWithRefArgumentUseOutside() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P => s.Trim(); + + void M() + { + Init(ref s); + } + + void Init(ref string s) + { + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestWithRefUseInside() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P + { + get + { + ref string s1 = ref s; + return s.Trim(); + } + } + } + """, + """ + class Class + { + string P + { + get + { + ref string s1 = ref field; + return field.Trim(); + } + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestNotWithRefUseOutside() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + string P + { + get + { + return s.Trim(); + } + } + + void M() + { + ref string s1 = ref s; + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestWithAddressOfInside() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|int s|]; + + int P + { + get + { + unsafe + { + int* p = &s; + return s; + } + } + } + } + """, + """ + class Class + { + int P + { + get + { + unsafe + { + int* p = &field; + return field; + } + } + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestNotWithAddressOfOutside() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|int s|]; + + int P + { + get + { + unsafe + { + return s; + } + } + } + + unsafe void M() + { + int* p = &s; + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestNotChainedPattern1() + { + await TestInRegularAndScriptAsync( + """ + class Builder + { + [|private bool _strictMode;|] + private Builder _builder; + + public bool StrictMode + { + get { return _strictMode ?? _builder.StrictMode; } + set { this._strictMode = value; } + } + } + """, + """ + class Builder + { + private Builder _builder; + + public bool StrictMode + { + get { return field ?? _builder.StrictMode; } + set; + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestLazyInit1() + { + await TestInRegularAndScriptAsync( + """ + using System.Collections.Generic; + + class Builder + { + [|private List? _list|] + + public List List => _list ??= new(); + } + """, + """ + using System.Collections.Generic; + + class Builder + { + public List List => field ??= new(); + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestRefSetAccessor1() + { + await TestInRegularAndScriptAsync( + """ + class Builder + { + [|private int prop;|] + public int Prop { get => prop; set => Set(ref prop, value); } + + void Set(ref int a, int b) { } + } + """, + """ + class Builder + { + public int Prop { get; set => Set(ref field, value); } + + void Set(ref int a, int b) { } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestRefSetAccessor2() + { + await TestInRegularAndScriptAsync( + """ + class Builder + { + [|private int prop;|] + + public int Prop + { + get => prop; + set + { + if (!Set(ref prop, value)) return; + OnPropChanged(); + } + } + + void Set(ref int a, int b) { } + void OnPropChanged() { } + } + """, + """ + class Builder + { + public int Prop + { + get; + set + { + if (!Set(ref field, value)) return; + OnPropChanged(); + } + } + + void Set(ref int a, int b) { } + void OnPropChanged() { } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestAttributesOnField() + { + await TestInRegularAndScriptAsync( + """ + class C + { + [Something] + [|private int prop;|] + public int Prop { get => prop; set => prop = value; } + } + """, + """ + class C + { + [field: Something] + public int Prop { get; set; } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestAttributesOnField2() + { + await TestInRegularAndScriptAsync( + """ + class C + { + [Something] + [|private string prop;|] + public string Prop => prop.Trim(); + } + """, + """ + class C + { + [field: Something] + public string Prop => field.Trim(); + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestAttributesOnField3() + { + await TestInRegularAndScriptAsync( + """ + class C + { + [Something] + [|private string prop;|] + + [PropAttribute] + public string Prop => prop.Trim(); + } + """, + """ + class C + { + [field: Something] + [PropAttribute] + public string Prop => field.Trim(); + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestAttributesOnField4() + { + await TestInRegularAndScriptAsync( + """ + class C + { + [Something] + [|private string prop;|] + + /// Docs + [PropAttribute] + public string Prop => prop.Trim(); + } + """, + """ + class C + { + /// Docs + [field: Something] + [PropAttribute] + public string Prop => field.Trim(); + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestAttributesOnField5() + { + await TestInRegularAndScriptAsync( + """ + class C + { + [Something] + [|private string prop;|] + + /// Docs + [PropAttribute][PropAttribute2] + public string Prop => prop.Trim(); + } + """, + """ + class C + { + /// Docs + [field: Something] + [PropAttribute][PropAttribute2] + public string Prop => field.Trim(); + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestAttributesOnField6() + { + await TestInRegularAndScriptAsync( + """ + class C + { + [Something] + [|private string prop;|] + + /// Docs + public string Prop => prop.Trim(); + } + """, + """ + class C + { + /// Docs + [field: Something] + public string Prop => field.Trim(); + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestAttributesOnField7() + { + await TestInRegularAndScriptAsync( + """ + class C + { + /// FieldDocs + [Something] + [|private string prop;|] + + /// Docs + public string Prop => prop.Trim(); + } + """, + """ + class C + { + /// Docs + [field: Something] + public string Prop => field.Trim(); + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestFieldUsedInObjectInitializer() + { + await TestInRegularAndScriptAsync( + """ + class C + { + [|private string prop;|] + + public string Prop + { + get + { + var v = new C { prop = "" }; + return prop.Trim(); + } + } + } + """, + """ + class C + { + public string Prop + { + get + { + var v = new C { Prop = "" }; + return field.Trim(); + } + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestSimpleFieldInExpressionBody_FieldWrittenElsewhere1() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + public string P => s.Trim(); + + void M() + { + s = ""; + } + } + """, + """ + class Class + { + public string P { get => field.Trim(); private set; } + + void M() + { + P = ""; + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestSimpleFieldInExpressionBody_FieldWrittenElsewhere2() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + public string P => s ??= ""; + + void M() + { + s = ""; + } + } + """, + """ + class Class + { + public string P { get => field ??= ""; private set; } + + void M() + { + P = ""; + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestSimpleFieldInExpressionBody_FieldWrittenElsewhere3() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + public string P + { + get => s ??= ""; + } + + void M() + { + s = ""; + } + } + """, + """ + class Class + { + public string P + { + get => field ??= ""; private set; + } + + void M() + { + P = ""; + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestSimpleFieldInExpressionBody_FieldWrittenElsewhere4() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|string s|]; + + public string P + { + get + { + return s ??= ""; + } + } + + void M() + { + s = ""; + } + } + """, + """ + class Class + { + public string P + { + get + { + return field ??= ""; + } + + private set; + } + + void M() + { + P = ""; + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestNonTrivialGetterWithExternalRead1() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + public int I => i / 2; + + void M() + { + Console.WriteLine(i); + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestNonTrivialGetterWithExternalRead2() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + public int I => i / 2; + + void M() + { + Console.WriteLine(this.i); + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestNonTrivialSetterWithExternalWrite1() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + public int I { get => i; set => value = i / 2; } + + void M() + { + i = 1; + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestNonTrivialSetterWithExternalWrite2() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + public int I { get => i; set => value = i / 2; } + + void M() + { + this.i = 1; + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestNonTrivialSetterWithNoExternalWrite1() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + public int I { get => i; set => i = value / 2; } + } + """, + """ + class Class + { + public int I { get; set => field = value / 2; } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestNonTrivialGetterWithExternalReadWrite1() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + public int I => i / 2; + + void M() + { + Console.WriteLine(this.i++); + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestNonTrivialSetterWithExternalReadWrite1() + { + await TestMissingInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + public int I { get => i; set => i = value / 2; } + + void M() + { + Console.WriteLine(this.i++); + } + } + """, new(parseOptions: Preview)); + } + + [Fact] + public async Task TestTrivialGetterWithExternalRead1() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + public int I => i; + + void M() + { + Console.WriteLine(i); + } + } + """, + """ + class Class + { + public int I { get; } + + void M() + { + Console.WriteLine(I); + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestNoSetterWithExternalWrite1() + { + await TestInRegularAndScriptAsync( + """ + class Class + { + [|int i|]; + + public int I => i; + + void M() + { + i = 1; + } + } + """, + """ + class Class + { + public int I { get; private set; } + + void M() + { + I = 1; + } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestFormatString() + { + await TestInRegularAndScriptAsync( + """ + class C + { + [|private string prop;|] + public string Prop => $"{prop:prop}"; + } + """, + """ + class C + { + public string Prop => $"{field:prop}"; + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestNoSetterButWrittenOutside() + { + await TestInRegularAndScriptAsync( + """ + class C + { + [|private string prop;|] + public string Prop => prop ?? ""; + + void M() { prop = "..."; } + } + """, + """ + class C + { + public string Prop { get => field ?? ""; private set; } + + void M() { Prop = "..."; } + } + """, parseOptions: Preview); + } + + [Fact] + public async Task TestNotWithNameofInAttribute() + { + await TestMissingInRegularAndScriptAsync( + """ + class C + { + [|private string prop;|] + [ThisIsMyBackingField(nameof(prop))] + public string Prop { get => prop; set => prop = value; } + } + """, new(parseOptions: Preview)); + } +} diff --git a/src/Analyzers/CSharp/Tests/UseCoalesceExpression/UseCoalesceExpressionForIfNullStatementCheckTests.cs b/src/Analyzers/CSharp/Tests/UseCoalesceExpression/UseCoalesceExpressionForIfNullStatementCheckTests.cs index 82209e6409b9f..b90c9f295ab96 100644 --- a/src/Analyzers/CSharp/Tests/UseCoalesceExpression/UseCoalesceExpressionForIfNullStatementCheckTests.cs +++ b/src/Analyzers/CSharp/Tests/UseCoalesceExpression/UseCoalesceExpressionForIfNullStatementCheckTests.cs @@ -4,16 +4,17 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Analyzers.UseCoalesceExpression; +using Microsoft.CodeAnalysis.CSharp.UseCoalesceExpression; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.UseCoalesceExpression; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.Analyzers.UnitTests.UseCoalesceExpression; using VerifyCS = CSharpCodeFixVerifier< CSharpUseCoalesceExpressionForIfNullStatementCheckDiagnosticAnalyzer, - UseCoalesceExpressionForIfNullStatementCheckCodeFixProvider>; + CSharpUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider>; [Trait(Traits.Feature, Traits.Features.CodeActionsUseCoalesceExpression)] public class UseCoalesceExpressionForIfNullStatementCheckTests @@ -458,4 +459,236 @@ void M() LanguageVersion = LanguageVersion.CSharp9, }.RunAsync(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74460")] + public async Task TestLocalDeclaration_CastWithParenthesizedExpression() + { + await new VerifyCS.Test + { + TestCode = + """ + interface I + { + } + + class C : I + { + void M(object o) + { + I item = o as C; + [|if|] (item == null) + { + item = o as D; + } + } + } + + class D : I + { + } + """, + FixedCode = + """ + interface I + { + } + + class C : I + { + void M(object o) + { + I item = (I)(o as C) ?? o as D; + } + } + + class D : I + { + } + """ + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74460")] + public async Task TestLocalDeclaration_CastWithoutParenthesizedExpression() + { + await new VerifyCS.Test + { + TestCode = + """ + interface I + { + } + + class C : I + { + void M(C c, D d) + { + I item = c; + [|if|] (item == null) + { + item = d; + } + } + } + + class D : I + { + } + """, + FixedCode = + """ + interface I + { + } + + class C : I + { + void M(C c, D d) + { + I item = (I)c ?? d; + } + } + + class D : I + { + } + """ + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74460")] + public async Task TestLocalDeclaration_NoCastWhenEqualSymbol() + { + await new VerifyCS.Test + { + TestCode = + """ + interface I + { + } + + class C : I + { + void M(C c1, C c2) + { + I item = c1; + [|if|] (item == null) + { + item = c2; + } + } + } + """, + FixedCode = + """ + interface I + { + } + + class C : I + { + void M(C c1, C c2) + { + I item = c1 ?? c2; + } + } + """ + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74460")] + public async Task TestLocalDeclaration_NoCastWhenDerivedClass() + { + await new VerifyCS.Test + { + TestCode = + """ + interface I + { + } + + class C : I + { + void M(C c, D d) + { + I item = c; + [|if|] (item == null) + { + item = d; + } + } + } + + class D : C + { + } + """, + FixedCode = + """ + interface I + { + } + + class C : I + { + void M(C c, D d) + { + I item = c ?? d; + } + } + + class D : C + { + } + """ + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74460")] + public async Task TestLocalDeclaration_NoCastWhenDerivedClassReversed() + { + await new VerifyCS.Test + { + TestCode = + """ + interface I + { + } + + class C : D + { + void M(C c, D d) + { + I item = c; + [|if|] (item == null) + { + item = d; + } + } + } + + class D : I + { + } + """, + FixedCode = + """ + interface I + { + } + + class C : D + { + void M(C c, D d) + { + I item = c ?? d; + } + } + + class D : I + { + } + """ + }.RunAsync(); + } } diff --git a/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForArrayTests.cs b/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForArrayTests.cs index 1d727b5957f43..863c202e575e3 100644 --- a/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForArrayTests.cs +++ b/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForArrayTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.UseCollectionExpression; @@ -1177,6 +1178,66 @@ public XAttribute(int[] values) { } }.RunAsync(); } + [Fact] + public async Task TestNonTargetTypedAttributeArgument1() + { + await new VerifyCS.Test + { + TestCode = """ + [X(new string[] { })] + class C + { + } + + public class XAttribute : System.Attribute + { + public XAttribute(object values) { } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); + } + + [Fact] + public async Task TestNonTargetTypedAttributeArgument2() + { + await new VerifyCS.Test + { + TestCode = """ + [X(new string[] { "" })] + class C + { + } + + public class XAttribute : System.Attribute + { + public XAttribute(object values) { } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); + } + + [Fact] + public async Task TestNonTargetTypedAttributeArgument3() + { + await new VerifyCS.Test + { + TestCode = """ + [X(new[] { "" })] + class C + { + } + + public class XAttribute : System.Attribute + { + public XAttribute(object values) { } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); + } + [Fact] public async Task TestTargetTypedReturn1() { @@ -5698,4 +5759,130 @@ class C LanguageVersion = LanguageVersion.CSharp12, }.RunAsync(); } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/74931")] + public async Task AllowSwitchToReadOnlySpanCSharp12(bool implicitType, bool whenTypesLooselyMatch) + { + await new VerifyCS.Test + { + TestCode = $$""" + using System; + + class C + { + void M(char c) + { + Split([|[|new|]{{(implicitType ? "" : " char")}}[]|] { c }); + } + + void Split(char[] p) { } + void Split(ReadOnlySpan p) { } + } + """, + FixedCode = """ + using System; + + class C + { + void M(char c) + { + Split([c]); + } + + void Split(char[] p) { } + void Split(ReadOnlySpan p) { } + } + """, + EditorConfig = $$""" + [*] + dotnet_style_prefer_collection_expression={{(whenTypesLooselyMatch ? "when_types_loosely_match" : "when_types_exactly_match")}} + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/74931")] + public async Task AllowSwitchToReadOnlySpanCSharp13(bool implicitType, bool whenTypesLooselyMatch) + { + await new VerifyCS.Test + { + TestCode = $$""" + using System; + + class C + { + void M(char c) + { + Split([|[|new|]{{(implicitType ? "" : " char")}}[]|] { c }); + } + + void Split(char[] p) { } + void Split(ReadOnlySpan p) { } + } + """, + FixedCode = """ + using System; + + class C + { + void M(char c) + { + Split([c]); + } + + void Split(char[] p) { } + void Split(ReadOnlySpan p) { } + } + """, + EditorConfig = $$""" + [*] + dotnet_style_prefer_collection_expression={{(whenTypesLooselyMatch ? "when_types_loosely_match" : "when_types_exactly_match")}} + """, + LanguageVersion = LanguageVersion.CSharp13, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/74931")] + public async Task AllowSwitchToReadOnlySpanGeneric1(bool implicitType, bool whenTypesLooselyMatch) + { + await new VerifyCS.Test + { + TestCode = $$""" + using System; + + class C + { + void M(char c) + { + Split([|[|new|]{{(implicitType ? "" : " char")}}[]|] { c }); + } + + void Split(T[] p) { } + void Split(ReadOnlySpan p) { } + } + """, + FixedCode = """ + using System; + + class C + { + void M(char c) + { + Split([c]); + } + + void Split(T[] p) { } + void Split(ReadOnlySpan p) { } + } + """, + EditorConfig = $$""" + [*] + dotnet_style_prefer_collection_expression={{(whenTypesLooselyMatch ? "when_types_loosely_match" : "when_types_exactly_match")}} + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } } diff --git a/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForBuilderTests.cs b/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForBuilderTests.cs index b4552f98d0246..b29ad478b0a7e 100644 --- a/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForBuilderTests.cs +++ b/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForBuilderTests.cs @@ -1589,4 +1589,41 @@ IEnumerable M() """ }.RunAsync(); } + + [Theory, MemberData(nameof(SuccessCreationPatterns))] + [WorkItem("https://github.com/dotnet/roslyn/issues/74208")] + public async Task TestComment(string pattern) + { + await new VerifyCS.Test + { + TestCode = $$""" + using System.Collections.Immutable; + + class C + { + ImmutableArray M() + { + // Comment to keep + {{pattern}} + [|builder.Add(|]0); + return builder.ToImmutable(); + } + } + """ + s_arrayBuilderApi, + FixedCode = """ + using System.Collections.Immutable; + + class C + { + ImmutableArray M() + { + // Comment to keep + return [0]; + } + } + """ + s_arrayBuilderApi, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } } diff --git a/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForFluentTests.cs b/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForFluentTests.cs index 406b13eaa34f1..b3413c13b4dba 100644 --- a/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForFluentTests.cs +++ b/src/Analyzers/CSharp/Tests/UseCollectionExpression/UseCollectionExpressionForFluentTests.cs @@ -2930,4 +2930,140 @@ void M(int[] x) ReferenceAssemblies = ReferenceAssemblies.Net.Net80, }.RunAsync(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72699")] + public async Task TestObjectCreationArgument1() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values) + { + List list = new List(values).[|ToList|](); + } + } + """, + FixedCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values) + { + List list = [.. values]; + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72699")] + public async Task TestObjectCreationArgument2() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values) + { + List list = new List(values) { 1, 2, 3 }.[|ToList|](); + } + } + """, + FixedCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values) + { + List list = [.. values, 1, 2, 3]; + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72699")] + public async Task TestObjectCreationArgument3() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values, int[] x) + { + List list = new List(values).Concat(x).[|ToList|](); + } + } + """, + FixedCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values, int[] x) + { + List list = [.. values, .. x]; + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72699")] + public async Task TestObjectCreationArgument4() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values, int[] x) + { + List list = new List(values) { 1, 2, 3 }.Concat(x).[|ToList|](); + } + } + """, + FixedCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values, int[] x) + { + List list = [.. values, 1, 2, 3, .. x]; + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } } diff --git a/src/Analyzers/CSharp/Tests/UseCollectionInitializer/UseCollectionInitializerTests.cs b/src/Analyzers/CSharp/Tests/UseCollectionInitializer/UseCollectionInitializerTests.cs index 089e6809d03e6..5d9f3f4dcd37c 100644 --- a/src/Analyzers/CSharp/Tests/UseCollectionInitializer/UseCollectionInitializerTests.cs +++ b/src/Analyzers/CSharp/Tests/UseCollectionInitializer/UseCollectionInitializerTests.cs @@ -1786,4 +1786,45 @@ void M() LanguageVersion = LanguageVersion.CSharp12, }.RunAsync(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75214")] + public async Task TestComplexForeach() + { + await new VerifyCS.Test + { + TestCode = """ + #nullable enable + + using System.Collections.Generic; + using System.Linq; + + class C + { + void M(List? list1) + { + foreach (var (value, sort) in (list1 ?? [|new|] List()).Select((val, i) => (val, i))) + { + } + } + } + """, + FixedCode = """ + #nullable enable + + using System.Collections.Generic; + using System.Linq; + + class C + { + void M(List? list1) + { + foreach (var (value, sort) in (list1 ?? []).Select((val, i) => (val, i))) + { + } + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); + } } diff --git a/src/Analyzers/CSharp/Tests/UseCollectionInitializer/UseCollectionInitializerTests_CollectionExpression.cs b/src/Analyzers/CSharp/Tests/UseCollectionInitializer/UseCollectionInitializerTests_CollectionExpression.cs index 4a89e0458efa5..7a19fa362e961 100644 --- a/src/Analyzers/CSharp/Tests/UseCollectionInitializer/UseCollectionInitializerTests_CollectionExpression.cs +++ b/src/Analyzers/CSharp/Tests/UseCollectionInitializer/UseCollectionInitializerTests_CollectionExpression.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.Diagnostics.CodeAnalysis; -using System.Linq.Expressions; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.UseCollectionInitializer; @@ -198,13 +196,19 @@ class C [Fact] public async Task TestInField4() { - await TestMissingInRegularAndScriptAsync( - """ + await TestInRegularAndScriptAsync(""" using System.Collections.Generic; class C { - List c = new List(new[] { 1, 2, 3 }); + List c = [|new|] List(new[] { 1, 2, 3 }); + } + """, """ + using System.Collections.Generic; + + class C + { + List c = [.. new[] { 1, 2, 3 }]; } """); } @@ -2361,8 +2365,7 @@ static void M() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17823")] public async Task TestWhenReferencedInInitializer_LocalVar2() { - await TestMissingInRegularAndScriptAsync( - """ + await TestInRegularAndScriptAsync(""" using System.Collections.Generic; using System.Linq; @@ -2370,7 +2373,19 @@ class C { void M() { - List t = new List(new int[] { 1, 2, 3 }); + List t = [|new|] List(new int[] { 1, 2, 3 }); + t.Add(t.Min() - 1); + } + } + """, """ + using System.Collections.Generic; + using System.Linq; + + class C + { + void M() + { + List t = [.. new int[] { 1, 2, 3 }]; t.Add(t.Min() - 1); } } @@ -2416,7 +2431,7 @@ static void M() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18260")] public async Task TestWhenReferencedInInitializer_Assignment2() { - await TestMissingInRegularAndScriptAsync( + await TestInRegularAndScriptAsync( """ using System.Collections.Generic; using System.Linq; @@ -2426,7 +2441,21 @@ class C void M() { List t = null; - t = new List(new int[] { 1, 2, 3 }); + t = [|new|] List(new int[] { 1, 2, 3 }); + t.Add(t.Min() - 1); + } + } + """, + """ + using System.Collections.Generic; + using System.Linq; + + class C + { + void M() + { + List t = null; + t = [.. new int[] { 1, 2, 3 }]; t.Add(t.Min() - 1); } } @@ -4936,7 +4965,7 @@ void M(int[] x, int[] y) { List c = [|new|] List(x); [|c.Add(|]0); - c.AddRange(y); + [|c.AddRange(|]y); } } """, @@ -4947,11 +4976,7 @@ class C { void M(int[] x, int[] y) { - List c = new List(x) - { - 0 - }; - c.AddRange(y); + List c = [.. x, 0, .. y]; } } """); @@ -5719,4 +5744,126 @@ void M() ReferenceAssemblies = ReferenceAssemblies.Net.Net80, }.RunAsync(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72699")] + public async Task TestObjectCreationArgument1() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values) + { + List list = [|new|] List(values); + } + } + """, + FixedCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values) + { + List list = [.. values]; + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72699")] + public async Task TestObjectCreationArgument2() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values) + { + List list = [|new|] List(values) { 1, 2, 3 }; + } + } + """, + FixedCode = """ + using System.Linq; + using System.Collections.Generic; + + class C + { + void M(int[] values) + { + List list = [.. values, 1, 2, 3]; + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73362")] + public async Task TestWithOverloadResolution1() + { + await new VerifyCS.Test + { + TestCode = """ + using System.Collections.Generic; + + class C + { + public void Test(Class1 param1, Class1 param2) + { + MethodTakingEnumerable([|new|] List { param1, param2 }); + } + + public void MethodTakingEnumerable(IEnumerable param) + { + } + + public void MethodTakingEnumerable(IEnumerable param) + { + } + + public class Class1 { } + public class Class2 { } + } + """, + FixedCode = """ + using System.Collections.Generic; + + class C + { + public void Test(Class1 param1, Class1 param2) + { + MethodTakingEnumerable([param1, param2]); + } + + public void MethodTakingEnumerable(IEnumerable param) + { + } + + public void MethodTakingEnumerable(IEnumerable param) + { + } + + public class Class1 { } + public class Class2 { } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } } diff --git a/src/Analyzers/CSharp/Tests/UseObjectInitializer/UseObjectInitializerTests.cs b/src/Analyzers/CSharp/Tests/UseObjectInitializer/UseObjectInitializerTests.cs index 8a81aa0efa2b9..252322bd3d60e 100644 --- a/src/Analyzers/CSharp/Tests/UseObjectInitializer/UseObjectInitializerTests.cs +++ b/src/Analyzers/CSharp/Tests/UseObjectInitializer/UseObjectInitializerTests.cs @@ -20,17 +20,6 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseObjectInitializer; [Trait(Traits.Feature, Traits.Features.CodeActionsUseObjectInitializer)] public partial class UseObjectInitializerTests { - private static async Task TestInRegularAndScriptAsync(string testCode, string fixedCode, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary) - { - await new VerifyCS.Test - { - TestCode = testCode, - FixedCode = fixedCode, - LanguageVersion = LanguageVersion.CSharp12, - TestState = { OutputKind = outputKind } - }.RunAsync(); - } - private static async Task TestMissingInRegularAndScriptAsync(string testCode, LanguageVersion? languageVersion = null) { var test = new VerifyCS.Test @@ -48,20 +37,19 @@ private static async Task TestMissingInRegularAndScriptAsync(string testCode, La [Fact] public async Task TestOnVariableDeclarator() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; void M() { - var c = [|new|] C(); - [|c.|]i = 1; + var c = {|#1:{|#0:new|} C()|}; + {|#2:c.|}i = 1{|#3:;|} } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -74,7 +62,19 @@ void M() }; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(6,19): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact] @@ -142,21 +142,20 @@ class C [Fact] public async Task TestDoNotUpdateAssignmentThatReferencesInitializedValue1Async() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; void M() { - var c = [|new|] C(); - [|c.|]i = 1; + var c = {|#1:{|#0:new|} C()|}; + {|#2:c.|}i = 1{|#3:;|} c.i = c.i + 1; } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -170,7 +169,19 @@ void M() c.i = c.i + 1; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(7,17): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact] @@ -194,8 +205,7 @@ void M() [Fact] public async Task TestDoNotUpdateAssignmentThatReferencesInitializedValue3Async() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; @@ -203,13 +213,13 @@ class C void M() { C c; - c = [|new|] C(); - [|c.|]i = 1; + c = {|#1:{|#0:new|} C()|}; + {|#2:c.|}i = 1{|#3:;|} c.i = c.i + 1; } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -224,7 +234,19 @@ void M() c.i = c.i + 1; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(6,19): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact] @@ -249,8 +271,7 @@ void M() [Fact] public async Task TestOnAssignmentExpression() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; @@ -258,12 +279,12 @@ class C void M() { C c = null; - c = [|new|] C(); - [|c.|]i = 1; + c = {|#1:{|#0:new|} C()|}; + {|#2:c.|}i = 1{|#3:;|} } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -277,27 +298,38 @@ void M() }; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(8,13): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact] public async Task TestStopOnDuplicateMember() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; void M() { - var c = [|new|] C(); - [|c.|]i = 1; + var c = {|#1:{|#0:new|} C()|}; + {|#2:c.|}i = 1{|#3:;|} c.i = 2; } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -311,14 +343,25 @@ void M() c.i = 2; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(7,17): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact] public async Task TestComplexInitializer() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; @@ -326,13 +369,13 @@ class C void M(C[] array) { - array[0] = [|new|] C(); - [|array[0].|]i = 1; - [|array[0].|]j = 2; + array[0] = {|#1:{|#0:new|} C()|}; + {|#2:array[0].|}i = 1{|#3:;|} + {|#4:array[0].|}j = 2{|#5:;|} } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -347,14 +390,25 @@ void M(C[] array) }; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(8,20): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3).WithLocation(4).WithLocation(5), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact] public async Task TestNotOnCompoundAssignment() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; @@ -362,13 +416,13 @@ class C void M() { - var c = [|new|] C(); - [|c.|]i = 1; + var c = {|#1:{|#0:new|} C()|}; + {|#2:c.|}i = 1{|#3:;|} c.j += 1; } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -383,14 +437,25 @@ void M() c.j += 1; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(8,17): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39146")] public async Task TestWithExistingInitializer() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; @@ -398,12 +463,12 @@ class C void M() { - var c = [|new|] C() { i = 1 }; - [|c.|]j = 1; + var c = {|#1:{|#0:new|} C() { i = 1 }|}; + {|#2:c.|}j = 1{|#3:;|} } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -411,21 +476,32 @@ class C void M() { - var c = [||]new C + var c = new C { i = 1, j = 1 }; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(8,17): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39146")] public async Task TestWithExistingInitializerComma() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; @@ -433,15 +509,15 @@ class C void M() { - var c = [|new|] C() + var c = {|#1:{|#0:new|} C() { i = 1, - }; - [|c.|]j = 1; + }|}; + {|#2:c.|}j = 1{|#3:;|} } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -449,21 +525,32 @@ class C void M() { - var c = [||]new C + var c = new C { i = 1, j = 1 }; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(8,17): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39146")] public async Task TestWithExistingInitializerNotIfAlreadyInitialized() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; @@ -471,16 +558,16 @@ class C void M() { - var c = [|new|] C() + var c = {|#1:{|#0:new|} C() { i = 1, - }; - [|c.|]j = 1; + }|}; + {|#2:c.|}j = 1{|#3:;|} c.i = 2; } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -488,7 +575,7 @@ class C void M() { - var c = [||]new C + var c = new C { i = 1, j = 1 @@ -496,7 +583,19 @@ void M() c.i = 2; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(8,17): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact] @@ -521,8 +620,7 @@ void M() [Fact] public async Task TestFixAllInDocument1() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; @@ -533,15 +631,15 @@ public C(System.Action a) { } void M() { - var v = [|new|] C(() => { - var v2 = [|new|] C(); - [|v2.|]i = 1; - }); - [|v.|]j = 2; + var v = {|#1:{|#0:new|} C(() => { + var v2 = {|#5:{|#4:new|} C()|}; + {|#6:v2.|}i = 1{|#7:;|} + })|}; + {|#2:v.|}j = 2{|#3:;|} } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -564,14 +662,27 @@ void M() }; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(11,17): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + // /0/Test0.cs(12,22): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(4).WithLocation(5).WithLocation(6).WithLocation(7), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact] public async Task TestFixAllInDocument2() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; @@ -579,15 +690,15 @@ class C void M() { - var v = [|new|] C(); - [|v.|]j = () => { - var v2 = [|new|] C(); - [|v2.|]i = 1; - }; + var v = {|#1:{|#0:new|} C()|}; + {|#2:v.|}j = () => { + var v2 = {|#5:{|#4:new|} C()|}; + {|#6:v2.|}i = 1{|#7:;|} + }{|#3:;|} } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -607,14 +718,27 @@ void M() }; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(8,17): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + // /0/Test0.cs(10,22): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(4).WithLocation(5).WithLocation(6).WithLocation(7), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact] public async Task TestFixAllInDocument3() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; @@ -622,16 +746,16 @@ class C void M(C[] array) { - array[0] = [|new|] C(); - [|array[0].|]i = 1; - [|array[0].|]j = 2; - array[1] = [|new|] C(); - [|array[1].|]i = 3; - [|array[1].|]j = 4; + array[0] = {|#1:{|#0:new|} C()|}; + {|#2:array[0].|}i = 1{|#3:;|} + {|#4:array[0].|}j = 2{|#5:;|} + array[1] = {|#7:{|#6:new|} C()|}; + {|#8:array[1].|}i = 3{|#9:;|} + {|#10:array[1].|}j = 4{|#11:;|} } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -651,27 +775,40 @@ void M(C[] array) }; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(8,20): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3).WithLocation(4).WithLocation(5), + // /0/Test0.cs(11,20): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(6).WithLocation(7).WithLocation(8).WithLocation(9).WithLocation(10).WithLocation(11), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact] public async Task TestTrivia1() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; int j; void M() { - var c = [|new|] C(); - [|c.|]i = 1; // Goo - [|c.|]j = 2; // Bar + var c = {|#1:{|#0:new|} C()|}; + {|#2:c.|}i = 1{|#3:;|} // Goo + {|#4:c.|}j = 2{|#5:;|} // Bar } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -685,31 +822,42 @@ void M() }; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(7,17): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3).WithLocation(4).WithLocation(5), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/46670")] public async Task TestTriviaRemoveLeadingBlankLinesForFirstProperty() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; int j; void M() { - var c = [|new|] C(); + var c = {|#1:{|#0:new|} C()|}; //Goo - [|c.|]i = 1; + {|#2:c.|}i = 1{|#3:;|} //Bar - [|c.|]j = 2; + {|#4:c.|}j = 2{|#5:;|} } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -726,7 +874,19 @@ void M() }; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(7,17): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3).WithLocation(4).WithLocation(5), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/15459")] @@ -786,22 +946,21 @@ public void M() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17953")] public async Task TestAvailableInsidePreprocessorDirective() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ public class Goo { public void M() { #if true - var goo = [|new|] Goo(); - [|goo.|]Value = ""; + var goo = {|#1:{|#0:new|} Goo()|}; + {|#2:goo.|}Value = ""{|#3:;|} #endif } public string Value { get; set; } } - """, - """ + """; + var fixedCode = """ public class Goo { public void M() @@ -816,14 +975,25 @@ public void M() public string Value { get; set; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(6,19): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19253")] public async Task TestKeepBlankLinesAfter() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class Goo { public int Bar { get; set; } @@ -833,14 +1003,14 @@ class MyClass { public void Main() { - var goo = [|new|] Goo(); - [|goo.|]Bar = 1; + var goo = {|#1:{|#0:new|} Goo()|}; + {|#2:goo.|}Bar = 1{|#3:;|} int horse = 1; } } - """, - """ + """; + var fixedCode = """ class Goo { public int Bar { get; set; } @@ -858,7 +1028,19 @@ public void Main() int horse = 1; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(6,19): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23368")] @@ -915,8 +1097,7 @@ public void Main() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23368")] public async Task TestWithExplicitImplementedInterfaceMembers3() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ interface IExample { string Name { get; set; } string LastName { get; set; } @@ -931,13 +1112,13 @@ class MyClass { public void Main() { - IExample e = [|new|] C(); - [|e.|]LastName = string.Empty; + IExample e = {|#1:{|#0:new|} C()|}; + {|#2:e.|}LastName = string.Empty{|#3:;|} e.Name = string.Empty; } } - """, - """ + """; + var fixedCode = """ interface IExample { string Name { get; set; } string LastName { get; set; } @@ -959,7 +1140,19 @@ public void Main() e.Name = string.Empty; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(15,22): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37675")] @@ -987,20 +1180,19 @@ public void Dispose() [Fact] public async Task TestImplicitObject() { - await TestInRegularAndScriptAsync( - """ + var testCode = """ class C { int i; void M() { - C c = [|new|](); - [|c.|]i = 1; + C c = {|#1:{|#0:new|}()|}; + {|#2:c.|}i = 1{|#3:;|} } } - """, - """ + """; + var fixedCode = """ class C { int i; @@ -1013,23 +1205,34 @@ void M() }; } } - """); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(6,19): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + }.RunAsync(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/61066")] public async Task TestInTopLevelStatements() { - await TestInRegularAndScriptAsync( - """ - MyClass cl = [|new|](); - [|cl.|]MyProperty = 5; + var testCode = """ + MyClass cl = {|#1:{|#0:new|}()|}; + {|#2:cl.|}MyProperty = 5{|#3:;|} class MyClass { public int MyProperty { get; set; } } - """, - """ + """; + var fixedCode = """ MyClass cl = new() { MyProperty = 5 @@ -1039,19 +1242,29 @@ class MyClass { public int MyProperty { get; set; } } - """, OutputKind.ConsoleApplication); + """; + + await new VerifyCS.Test + { + TestCode = testCode, + ExpectedDiagnostics = + { + // /0/Test0.cs(6,19): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, + FixedCode = fixedCode, + LanguageVersion = LanguageVersion.CSharp12, + TestState = { OutputKind = OutputKind.ConsoleApplication }, + }.RunAsync(); } [Theory] - [InlineData(8.0)] - [InlineData(9.0)] + [CombinatorialData] [WorkItem("https://github.com/dotnet/roslyn/issues/72094")] - public async Task TestWithConflictingSeverityConfigurationEntries(double analysisLevel) + public async Task TestWithConflictingSeverityConfigurationEntries(bool enabled) { - var expectFix = analysisLevel >= 9.0; - string testCode, fixedCode; - if (expectFix) + if (enabled) { testCode = """ @@ -1061,8 +1274,8 @@ class C void M() { - var c = [|new|] C(); - c.i = 1; + var c = {|#1:{|#0:new|} C()|}; + {|#2:c.|}i = 1{|#3:;|} } } """; @@ -1108,7 +1321,75 @@ void M() dotnet_style_object_initializer = true:suggestion dotnet_diagnostic.IDE0017.severity = none - build_property.EffectiveAnalysisLevelStyle = {analysisLevel} + build_property.EnableCodeStyleSeverity = {enabled} + """; + + var test = new VerifyCS.Test + { + TestState = + { + Sources = { testCode }, + AnalyzerConfigFiles = + { + ("/.globalconfig", globalConfig), + } + }, + FixedState = { Sources = { fixedCode } }, + LanguageVersion = LanguageVersion.CSharp12, + }; + + if (enabled) + { + test.ExpectedDiagnostics.Add( + // /0/Test0.cs(7,17): info IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3)); + } + + await test.RunAsync(); + } + + [Theory] + [CombinatorialData] + public async Task TestFallbackSeverityConfiguration(bool enabled) + { + var testCode = + """ + class C + { + int i; + + void M() + { + var c = {|#1:{|#0:new|} C()|}; + {|#2:c.|}i = 1{|#3:;|} + } + } + """; + + var fixedCode = + """ + class C + { + int i; + + void M() + { + var c = new C + { + i = 1 + }; + } + } + """; + + var globalConfig = + $""" + is_global = true + + dotnet_style_object_initializer = true + dotnet_diagnostic.IDE0017.severity = warning + + build_property.EnableCodeStyleSeverity = {enabled} """; await new VerifyCS.Test @@ -1116,6 +1397,11 @@ void M() TestState = { Sources = { testCode }, + ExpectedDiagnostics = + { + // /0/Test0.cs(7,17): warning IDE0017: Object initialization can be simplified + VerifyCS.Diagnostic().WithSeverity(DiagnosticSeverity.Warning).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3), + }, AnalyzerConfigFiles = { ("/.globalconfig", globalConfig), diff --git a/src/Analyzers/CSharp/Tests/UsePrimaryConstructor/UsePrimaryConstructorTests.cs b/src/Analyzers/CSharp/Tests/UsePrimaryConstructor/UsePrimaryConstructorTests.cs index 5fb52d431a110..b2ebe728c5c55 100644 --- a/src/Analyzers/CSharp/Tests/UsePrimaryConstructor/UsePrimaryConstructorTests.cs +++ b/src/Analyzers/CSharp/Tests/UsePrimaryConstructor/UsePrimaryConstructorTests.cs @@ -4100,4 +4100,31 @@ class C() LanguageVersion = LanguageVersion.CSharp12, }.RunAsync(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73614")] + public async Task TestNotWithRefStruct() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + ref struct Sample + { + private ReadOnlySpan _str; + + public Sample(ReadOnlySpan str) + { + _str = str; + } + + public void MoveNext() + { + var span = _str; + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } } diff --git a/src/Analyzers/Core/Analyzers/Analyzers.projitems b/src/Analyzers/Core/Analyzers/Analyzers.projitems index 845981b50d1b3..ea81bd2ba5653 100644 --- a/src/Analyzers/Core/Analyzers/Analyzers.projitems +++ b/src/Analyzers/Core/Analyzers/Analyzers.projitems @@ -33,8 +33,6 @@ - - @@ -77,9 +75,13 @@ + + + + diff --git a/src/Analyzers/Core/Analyzers/AnalyzersResources.resx b/src/Analyzers/Core/Analyzers/AnalyzersResources.resx index df9dabaf42ade..34ab80d6e554e 100644 --- a/src/Analyzers/Core/Analyzers/AnalyzersResources.resx +++ b/src/Analyzers/Core/Analyzers/AnalyzersResources.resx @@ -397,4 +397,13 @@ Simplify check - + + Base classes contain inaccessible unimplemented members + + + Implement abstract class + + + Implement through '{0}' + + \ No newline at end of file diff --git a/src/Analyzers/Core/Analyzers/FileHeaders/AbstractFileHeaderHelper.cs b/src/Analyzers/Core/Analyzers/FileHeaders/AbstractFileHeaderHelper.cs index 7baa27f92252f..4941049b418d4 100644 --- a/src/Analyzers/Core/Analyzers/FileHeaders/AbstractFileHeaderHelper.cs +++ b/src/Analyzers/Core/Analyzers/FileHeaders/AbstractFileHeaderHelper.cs @@ -71,7 +71,7 @@ public FileHeader ParseFileHeader(SyntaxNode root) fileHeaderStart = Math.Min(trivia.FullSpan.Start, fileHeaderStart); fileHeaderEnd = trivia.FullSpan.End; -#if NETCOREAPP +#if NET sb.Append(commentText).AppendLine(); #else sb.AppendLine(commentText.ToString()); diff --git a/src/Analyzers/Core/Analyzers/Formatting/AbstractFormattingAnalyzer.cs b/src/Analyzers/Core/Analyzers/Formatting/AbstractFormattingAnalyzer.cs index 82238c1b92d24..7d4f8392dff2c 100644 --- a/src/Analyzers/Core/Analyzers/Formatting/AbstractFormattingAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/Formatting/AbstractFormattingAnalyzer.cs @@ -4,6 +4,8 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeStyle; @@ -41,7 +43,63 @@ private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context, CompilationOpt if (ShouldSkipAnalysis(context, compilationOptions, notification: null)) return; - var options = context.GetAnalyzerOptions().GetSyntaxFormattingOptions(SyntaxFormatting); - FormattingAnalyzerHelper.AnalyzeSyntaxTree(context, SyntaxFormatting, Descriptor, options); + var tree = context.Tree; + var cancellationToken = context.CancellationToken; + + var oldText = tree.GetText(cancellationToken); + var root = tree.GetRoot(cancellationToken); + var span = context.FilterSpan.HasValue ? context.FilterSpan.GetValueOrDefault() : root.FullSpan; + var spans = SpecializedCollections.SingletonEnumerable(span); + var formattingOptions = context.GetAnalyzerOptions().GetSyntaxFormattingOptions(SyntaxFormatting); + var formattingChanges = SyntaxFormatting.GetFormattingResult(root, spans, formattingOptions, rules: default, cancellationToken).GetTextChanges(cancellationToken); + + // formattingChanges could include changes that impact a larger section of the original document than + // necessary. Before reporting diagnostics, process the changes to minimize the span of individual + // diagnostics. + foreach (var formattingChange in formattingChanges) + { + var change = formattingChange; + Contract.ThrowIfNull(change.NewText); + + if (change.NewText.Length > 0 && !change.Span.IsEmpty) + { + // Handle cases where the change is a substring removal from the beginning. In these cases, we want + // the diagnostic span to cover the unwanted leading characters (which should be removed), and + // nothing more. + var offset = change.Span.Length - change.NewText.Length; + if (offset >= 0) + { + if (oldText.GetSubText(new TextSpan(change.Span.Start + offset, change.NewText.Length)).ContentEquals(SourceText.From(change.NewText))) + { + change = new TextChange(new TextSpan(change.Span.Start, offset), ""); + } + else + { + // Handle cases where the change is a substring removal from the end. In these cases, we want + // the diagnostic span to cover the unwanted trailing characters (which should be removed), and + // nothing more. + if (oldText.GetSubText(new TextSpan(change.Span.Start, change.NewText.Length)).ContentEquals(SourceText.From(change.NewText))) + { + change = new TextChange(new TextSpan(change.Span.Start + change.NewText.Length, offset), ""); + } + } + } + } + + Contract.ThrowIfNull(change.NewText); + if (change.NewText.Length == 0 && change.Span.IsEmpty) + { + // No actual change (allows for the formatter to report a NOP change without triggering a + // diagnostic that can't be fixed). + continue; + } + + var location = Location.Create(tree, change.Span); + context.ReportDiagnostic(Diagnostic.Create( + Descriptor, + location, + additionalLocations: null, + properties: null)); + } } } diff --git a/src/Analyzers/Core/Analyzers/Formatting/FormatterHelper.cs b/src/Analyzers/Core/Analyzers/Formatting/FormatterHelper.cs deleted file mode 100644 index ad221cea502b9..0000000000000 --- a/src/Analyzers/Core/Analyzers/Formatting/FormatterHelper.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Threading; -using Microsoft.CodeAnalysis.Formatting.Rules; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; -using static Microsoft.CodeAnalysis.Formatting.FormattingExtensions; - -namespace Microsoft.CodeAnalysis.Formatting; - -/// -/// Formats whitespace in documents or syntax trees. -/// -internal static class FormatterHelper -{ - /// - /// Gets the formatting rules that would be applied if left unspecified. - /// - internal static IEnumerable GetDefaultFormattingRules(ISyntaxFormatting syntaxFormattingService) - => syntaxFormattingService.GetDefaultFormattingRules(); - - /// - /// Formats the whitespace of a syntax tree. - /// - /// The root node of a syntax tree to format. - /// An optional set of formatting options. If these options are not supplied the current set of options from the workspace will be used. - /// An optional cancellation token. - /// The formatted tree's root node. - public static SyntaxNode Format(SyntaxNode node, ISyntaxFormatting syntaxFormattingService, SyntaxFormattingOptions options, CancellationToken cancellationToken) - => Format(node, [node.FullSpan], syntaxFormattingService, options, rules: default, cancellationToken: cancellationToken); - - public static SyntaxNode Format(SyntaxNode node, TextSpan spanToFormat, ISyntaxFormatting syntaxFormattingService, SyntaxFormattingOptions options, CancellationToken cancellationToken) - => Format(node, [spanToFormat], syntaxFormattingService, options, rules: default, cancellationToken: cancellationToken); - - /// - /// Formats the whitespace of a syntax tree. - /// - /// The root node of a syntax tree. - /// The descendant nodes of the root to format. - /// An optional set of formatting options. If these options are not supplied the current set of options from the workspace will be used. - /// An optional cancellation token. - /// The formatted tree's root node. - public static SyntaxNode Format(SyntaxNode node, SyntaxAnnotation annotation, ISyntaxFormatting syntaxFormattingService, SyntaxFormattingOptions options, IEnumerable? rules, CancellationToken cancellationToken) - => Format(node, GetAnnotatedSpans(node, annotation), syntaxFormattingService, options, rules.AsImmutableOrNull(), cancellationToken: cancellationToken); - - internal static SyntaxNode Format(SyntaxNode node, IEnumerable spans, ISyntaxFormatting syntaxFormattingService, SyntaxFormattingOptions options, ImmutableArray rules, CancellationToken cancellationToken) - => GetFormattingResult(node, spans, syntaxFormattingService, options, rules, cancellationToken).GetFormattedRoot(cancellationToken); - - internal static IList GetFormattedTextChanges(SyntaxNode node, IEnumerable spans, ISyntaxFormatting syntaxFormattingService, SyntaxFormattingOptions options, ImmutableArray rules, CancellationToken cancellationToken) - => GetFormattingResult(node, spans, syntaxFormattingService, options, rules, cancellationToken).GetTextChanges(cancellationToken); - - internal static IFormattingResult GetFormattingResult(SyntaxNode node, IEnumerable spans, ISyntaxFormatting syntaxFormattingService, SyntaxFormattingOptions options, ImmutableArray rules, CancellationToken cancellationToken) - => syntaxFormattingService.GetFormattingResult(node, spans, options, rules, cancellationToken); - - /// - /// Determines the changes necessary to format the whitespace of a syntax tree. - /// - /// The root node of a syntax tree to format. - /// An optional set of formatting options. If these options are not supplied the current set of options from the workspace will be used. - /// An optional cancellation token. - /// The changes necessary to format the tree. - public static IList GetFormattedTextChanges(SyntaxNode node, ISyntaxFormatting syntaxFormattingService, SyntaxFormattingOptions options, CancellationToken cancellationToken) - => GetFormattedTextChanges(node, [node.FullSpan], syntaxFormattingService, options, rules: default, cancellationToken: cancellationToken); -} diff --git a/src/Analyzers/Core/Analyzers/Formatting/FormattingAnalyzerHelper.cs b/src/Analyzers/Core/Analyzers/Formatting/FormattingAnalyzerHelper.cs deleted file mode 100644 index 7eb990634811a..0000000000000 --- a/src/Analyzers/Core/Analyzers/Formatting/FormattingAnalyzerHelper.cs +++ /dev/null @@ -1,75 +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 Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; -using Formatter = Microsoft.CodeAnalysis.Formatting.FormatterHelper; -using FormattingProvider = Microsoft.CodeAnalysis.Formatting.ISyntaxFormatting; - -namespace Microsoft.CodeAnalysis.CodeStyle; - -internal static class FormattingAnalyzerHelper -{ - internal static void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context, FormattingProvider formattingProvider, DiagnosticDescriptor descriptor, SyntaxFormattingOptions options) - { - var tree = context.Tree; - var cancellationToken = context.CancellationToken; - - var oldText = tree.GetText(cancellationToken); - var root = tree.GetRoot(cancellationToken); - var span = context.FilterSpan.HasValue ? context.FilterSpan.GetValueOrDefault() : root.FullSpan; - var spans = SpecializedCollections.SingletonEnumerable(span); - var formattingChanges = Formatter.GetFormattedTextChanges(root, spans, formattingProvider, options, rules: default, cancellationToken); - - // formattingChanges could include changes that impact a larger section of the original document than - // necessary. Before reporting diagnostics, process the changes to minimize the span of individual - // diagnostics. - foreach (var formattingChange in formattingChanges) - { - var change = formattingChange; - if (change.NewText.Length > 0 && !change.Span.IsEmpty) - { - // Handle cases where the change is a substring removal from the beginning. In these cases, we want - // the diagnostic span to cover the unwanted leading characters (which should be removed), and - // nothing more. - var offset = change.Span.Length - change.NewText.Length; - if (offset >= 0) - { - if (oldText.GetSubText(new TextSpan(change.Span.Start + offset, change.NewText.Length)).ContentEquals(SourceText.From(change.NewText))) - { - change = new TextChange(new TextSpan(change.Span.Start, offset), ""); - } - else - { - // Handle cases where the change is a substring removal from the end. In these cases, we want - // the diagnostic span to cover the unwanted trailing characters (which should be removed), and - // nothing more. - if (oldText.GetSubText(new TextSpan(change.Span.Start, change.NewText.Length)).ContentEquals(SourceText.From(change.NewText))) - { - change = new TextChange(new TextSpan(change.Span.Start + change.NewText.Length, offset), ""); - } - } - } - } - - if (change.NewText.Length == 0 && change.Span.IsEmpty) - { - // No actual change (allows for the formatter to report a NOP change without triggering a - // diagnostic that can't be fixed). - continue; - } - - var location = Location.Create(tree, change.Span); - context.ReportDiagnostic(Diagnostic.Create( - descriptor, - location, - additionalLocations: null, - properties: null)); - } - } -} diff --git a/src/Analyzers/Core/Analyzers/Helpers/DiagnosticHelper.cs b/src/Analyzers/Core/Analyzers/Helpers/DiagnosticHelper.cs index 151a02031558b..6429b6c763d3f 100644 --- a/src/Analyzers/Core/Analyzers/Helpers/DiagnosticHelper.cs +++ b/src/Analyzers/Core/Analyzers/Helpers/DiagnosticHelper.cs @@ -47,21 +47,22 @@ public static Diagnostic Create( params object[] messageArgs) { if (descriptor == null) - { throw new ArgumentNullException(nameof(descriptor)); - } - LocalizableString message; + var message = CreateMessage(descriptor, messageArgs); + return CreateWithMessage(descriptor, location, notificationOption, analyzerOptions, additionalLocations, properties, message); + } + + private static LocalizableString CreateMessage(DiagnosticDescriptor descriptor, object[] messageArgs) + { if (messageArgs == null || messageArgs.Length == 0) { - message = descriptor.MessageFormat; + return descriptor.MessageFormat; } else { - message = new LocalizableStringWithArguments(descriptor.MessageFormat, messageArgs); + return new LocalizableStringWithArguments(descriptor.MessageFormat, messageArgs); } - - return CreateWithMessage(descriptor, location, notificationOption, analyzerOptions, additionalLocations, properties, message); } /// @@ -92,11 +93,28 @@ public static Diagnostic CreateWithLocationTags( ImmutableArray additionalLocations, ImmutableArray additionalUnnecessaryLocations, params object[] messageArgs) + { + return CreateWithLocationTags( + descriptor, + location, + notificationOption, + analyzerOptions, + CreateMessage(descriptor, messageArgs), + additionalLocations, + additionalUnnecessaryLocations); + } + + private static Diagnostic CreateWithLocationTags( + DiagnosticDescriptor descriptor, + Location location, + NotificationOption2 notificationOption, + AnalyzerOptions analyzerOptions, + LocalizableString message, + ImmutableArray additionalLocations, + ImmutableArray additionalUnnecessaryLocations) { if (additionalUnnecessaryLocations.IsEmpty) - { - return Create(descriptor, location, notificationOption, analyzerOptions, additionalLocations, ImmutableDictionary.Empty, messageArgs); - } + return CreateWithMessage(descriptor, location, notificationOption, analyzerOptions, additionalLocations, ImmutableDictionary.Empty, message); var tagIndices = ImmutableDictionary>.Empty .Add(WellKnownDiagnosticTags.Unnecessary, Enumerable.Range(additionalLocations.Length, additionalUnnecessaryLocations.Length)); @@ -105,10 +123,10 @@ public static Diagnostic CreateWithLocationTags( location, notificationOption, analyzerOptions, + message, additionalLocations.AddRange(additionalUnnecessaryLocations), tagIndices, - ImmutableDictionary.Empty, - messageArgs); + ImmutableDictionary.Empty); } /// @@ -144,11 +162,30 @@ public static Diagnostic CreateWithLocationTags( ImmutableArray additionalUnnecessaryLocations, ImmutableDictionary? properties, params object[] messageArgs) + { + return CreateWithLocationTags( + descriptor, + location, + notificationOption, + analyzerOptions, + CreateMessage(descriptor, messageArgs), + additionalLocations, + additionalUnnecessaryLocations, + properties); + } + + public static Diagnostic CreateWithLocationTags( + DiagnosticDescriptor descriptor, + Location location, + NotificationOption2 notificationOption, + AnalyzerOptions analyzerOptions, + LocalizableString message, + ImmutableArray additionalLocations, + ImmutableArray additionalUnnecessaryLocations, + ImmutableDictionary? properties) { if (additionalUnnecessaryLocations.IsEmpty) - { - return Create(descriptor, location, notificationOption, analyzerOptions, additionalLocations, properties, messageArgs); - } + return CreateWithMessage(descriptor, location, notificationOption, analyzerOptions, additionalLocations, properties, message); var tagIndices = ImmutableDictionary>.Empty .Add(WellKnownDiagnosticTags.Unnecessary, Enumerable.Range(additionalLocations.Length, additionalUnnecessaryLocations.Length)); @@ -157,41 +194,21 @@ public static Diagnostic CreateWithLocationTags( location, notificationOption, analyzerOptions, + message, additionalLocations.AddRange(additionalUnnecessaryLocations), tagIndices, - properties, - messageArgs); + properties); } - /// - /// Create a diagnostic that adds properties specifying a tag for a set of locations. - /// - /// A describing the diagnostic. - /// An optional primary location of the diagnostic. If null, will return . - /// Notification option for the diagnostic. - /// - /// An optional set of additional locations related to the diagnostic. - /// Typically, these are locations of other items referenced in the message. - /// - /// - /// a map of location tag to index in additional locations. - /// "AbstractRemoveUnnecessaryParenthesesDiagnosticAnalyzer" for an example of usage. - /// - /// - /// An optional set of name-value pairs by means of which the analyzer that creates the diagnostic - /// can convey more detailed information to the fixer. - /// - /// Arguments to the message of the diagnostic. - /// The instance. private static Diagnostic CreateWithLocationTags( DiagnosticDescriptor descriptor, Location location, NotificationOption2 notificationOption, AnalyzerOptions analyzerOptions, + LocalizableString message, IEnumerable additionalLocations, IDictionary> tagIndices, - ImmutableDictionary? properties, - params object[] messageArgs) + ImmutableDictionary? properties) { Contract.ThrowIfTrue(additionalLocations.IsEmpty()); Contract.ThrowIfTrue(tagIndices.IsEmpty()); @@ -199,7 +216,7 @@ private static Diagnostic CreateWithLocationTags( properties ??= ImmutableDictionary.Empty; properties = properties.AddRange(tagIndices.Select(kvp => new KeyValuePair(kvp.Key, EncodeIndices(kvp.Value, additionalLocations.Count())))); - return Create(descriptor, location, notificationOption, analyzerOptions, additionalLocations, properties, messageArgs); + return CreateWithMessage(descriptor, location, notificationOption, analyzerOptions, additionalLocations, properties, message); static string EncodeIndices(IEnumerable indices, int additionalLocationsLength) { @@ -269,8 +286,8 @@ public static Diagnostic CreateWithMessage( static IEnumerable GetEffectiveCustomTags(DiagnosticDescriptor descriptor, NotificationOption2 notificationOption, AnalyzerOptions analyzerOptions) { - // 'CustomSeverityConfigurable' is only enabled when AnalysisLevel >= 9. - var skipCustomConfiguration = !analyzerOptions.AnalyzerConfigOptionsProvider.GlobalOptions.IsAnalysisLevelGreaterThanOrEquals(9); + // 'CustomSeverityConfigurable' is only enabled when EnableCodeStyleSeverity is true. + var skipCustomConfiguration = !analyzerOptions.AnalyzerConfigOptionsProvider.GlobalOptions.IsCodeStyleSeverityEnabled(); if (skipCustomConfiguration) { foreach (var customTag in descriptor.CustomTags) diff --git a/src/Analyzers/Core/Analyzers/MatchFolderAndNamespace/AbstractMatchFolderAndNamespaceDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/MatchFolderAndNamespace/AbstractMatchFolderAndNamespaceDiagnosticAnalyzer.cs index 7d34ecafb885b..8604bd596e5a0 100644 --- a/src/Analyzers/Core/Analyzers/MatchFolderAndNamespace/AbstractMatchFolderAndNamespaceDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/MatchFolderAndNamespace/AbstractMatchFolderAndNamespaceDiagnosticAnalyzer.cs @@ -148,7 +148,7 @@ private bool IsFileAndNamespaceMismatch( var relativeDirectoryPath = PathUtilities.GetRelativePath( projectDir, PathUtilities.GetDirectoryName(namespaceDeclaration.SyntaxTree.FilePath)!); - var folders = relativeDirectoryPath.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); + var folders = relativeDirectoryPath.Split([Path.DirectorySeparatorChar], StringSplitOptions.RemoveEmptyEntries); var expectedNamespace = PathMetadataUtilities.TryBuildNamespaceFromFolders(folders, GetSyntaxFacts(), rootNamespace); diff --git a/src/Analyzers/Core/Analyzers/OrderModifiers/AbstractOrderModifiersDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/OrderModifiers/AbstractOrderModifiersDiagnosticAnalyzer.cs index 43f8f18668bcb..bb06e5be77d96 100644 --- a/src/Analyzers/Core/Analyzers/OrderModifiers/AbstractOrderModifiersDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/OrderModifiers/AbstractOrderModifiersDiagnosticAnalyzer.cs @@ -48,7 +48,13 @@ private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context, CompilationOpt return; } - Recurse(context, preferredOrder, option.Notification, context.GetAnalysisRoot(findInTrivia: false)); + var analysisRoot = context.GetAnalysisRoot(findInTrivia: false); + + // Check the root node first to see if it has any modifiers that need reordering. + CheckModifiers(context, preferredOrder, option.Notification, analysisRoot); + + // Recurse to check the child nodes. + Recurse(context, preferredOrder, option.Notification, analysisRoot); } protected abstract void Recurse( diff --git a/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/AbstractRemoveUnnecessaryPragmaSuppressionsDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/AbstractRemoveUnnecessaryPragmaSuppressionsDiagnosticAnalyzer.cs index f7e43a6d2853e..195d145731738 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/AbstractRemoveUnnecessaryPragmaSuppressionsDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/AbstractRemoveUnnecessaryPragmaSuppressionsDiagnosticAnalyzer.cs @@ -745,7 +745,9 @@ private async Task ProcessSuppressMessageAttributesAsync( return false; } - var declarationNodes = SyntaxFacts.GetTopLevelAndMethodLevelMembers(root); + using var pooledDeclarationNodes = SyntaxFacts.GetTopLevelAndMethodLevelMembers(root); + var declarationNodes = pooledDeclarationNodes.Object; + using var _ = PooledHashSet.GetInstance(out var processedPartialSymbols); if (declarationNodes.Count > 0) { diff --git a/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/SuppressMessageAttributeState.cs b/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/SuppressMessageAttributeState.cs index ea9ce47b6e8fc..72af7310791af 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/SuppressMessageAttributeState.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/SuppressMessageAttributeState.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics; -internal partial class SuppressMessageAttributeState(Compilation compilation, INamedTypeSymbol suppressMessageAttributeType) +internal sealed partial class SuppressMessageAttributeState(Compilation compilation, INamedTypeSymbol suppressMessageAttributeType) { internal const string SuppressMessageScope = "Scope"; internal const string SuppressMessageTarget = "Target"; diff --git a/src/Analyzers/Core/Analyzers/RemoveUnusedMembers/AbstractRemoveUnusedMembersDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnusedMembers/AbstractRemoveUnusedMembersDiagnosticAnalyzer.cs index 7dcd15beb0c86..814efb24c087c 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnusedMembers/AbstractRemoveUnusedMembersDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnusedMembers/AbstractRemoveUnusedMembersDiagnosticAnalyzer.cs @@ -64,6 +64,7 @@ protected AbstractRemoveUnusedMembersDiagnosticAnalyzer() protected abstract IEnumerable GetTypeDeclarations(INamedTypeSymbol namedType, CancellationToken cancellationToken); protected abstract SyntaxList GetMembers(TTypeDeclarationSyntax typeDeclaration); + protected abstract SyntaxNode GetParentIfSoleDeclarator(SyntaxNode declaration); // We need to analyze the whole document even for edits within a method body, // because we might add or remove references to members in executable code. @@ -428,6 +429,7 @@ private void AnalyzeObjectCreationOperation(OperationAnalysisContext operationCo private void OnSymbolEnd(SymbolAnalysisContext symbolEndContext, bool hasUnsupportedOperation) { + var cancellationToken = symbolEndContext.CancellationToken; if (hasUnsupportedOperation) { return; @@ -445,7 +447,7 @@ private void OnSymbolEnd(SymbolAnalysisContext symbolEndContext, bool hasUnsuppo using var _1 = PooledHashSet.GetInstance(out var symbolsReferencedInDocComments); using var _2 = ArrayBuilder.GetInstance(out var debuggerDisplayAttributeArguments); - var entryPoint = symbolEndContext.Compilation.GetEntryPoint(symbolEndContext.CancellationToken); + var entryPoint = symbolEndContext.Compilation.GetEntryPoint(cancellationToken); var namedType = (INamedTypeSymbol)symbolEndContext.Symbol; foreach (var member in namedType.GetMembers()) @@ -467,7 +469,7 @@ private void OnSymbolEnd(SymbolAnalysisContext symbolEndContext, bool hasUnsuppo { // Bail out if there are syntax errors in any of the declarations of the containing type. // Note that we check this only for the first time that we report an unused or unread member for the containing type. - if (HasSyntaxErrors(namedType, symbolEndContext.CancellationToken)) + if (HasSyntaxErrors(namedType, cancellationToken)) { return; } @@ -475,7 +477,7 @@ private void OnSymbolEnd(SymbolAnalysisContext symbolEndContext, bool hasUnsuppo // Compute the set of candidate symbols referenced in all the documentation comments within the named type declarations. // This set is computed once and used for all the iterations of the loop. AddCandidateSymbolsReferencedInDocComments( - namedType, symbolEndContext.Compilation, symbolsReferencedInDocComments, symbolEndContext.CancellationToken); + namedType, symbolEndContext.Compilation, symbolsReferencedInDocComments, cancellationToken); // Compute the set of string arguments to DebuggerDisplay attributes applied to any symbol within the named type declaration. // These strings may have an embedded reference to the symbol. @@ -509,50 +511,64 @@ member is IPropertySymbol property && continue; } + // We change the message only if both 'get' and 'set' accessors are present and + // there are no shadow 'get' accessor usages. Otherwise the message will be confusing + var isConvertibleProperty = + member is IPropertySymbol { GetMethod: not null, SetMethod: not null } property2 && + !_propertiesWithShadowGetAccessorUsages.Contains(property2); + + var diagnosticLocation = GetDiagnosticLocation(member); + var fadingLocation = member.DeclaringSyntaxReferences.FirstOrDefault( + r => r.SyntaxTree == diagnosticLocation.SourceTree && r.Span.Contains(diagnosticLocation.SourceSpan)); + + var fadingNode = fadingLocation?.GetSyntax(cancellationToken) ?? diagnosticLocation.FindNode(cancellationToken); + fadingNode = fadingNode != null ? this._analyzer.GetParentIfSoleDeclarator(fadingNode) : null; + + var additionalUnnecessaryLocations = !isConvertibleProperty && fadingNode is not null + ? [fadingNode.GetLocation()] + : ImmutableArray.Empty; + // Most of the members should have a single location, except for partial methods. // We report the diagnostic on the first location of the member. - var diagnostic = DiagnosticHelper.CreateWithMessage( + symbolEndContext.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags( rule, - GetDiagnosticLocation(member), + diagnosticLocation, NotificationOption2.ForSeverity(rule.DefaultSeverity), symbolEndContext.Options, - additionalLocations: null, - properties: null, - GetMessage(rule, member)); - symbolEndContext.ReportDiagnostic(diagnostic); + message: GetMessage(rule, member, isConvertibleProperty), + additionalLocations: [], + additionalUnnecessaryLocations: additionalUnnecessaryLocations, + properties: null)); } } } - private LocalizableString GetMessage( + private static LocalizableString GetMessage( DiagnosticDescriptor rule, - ISymbol member) + ISymbol member, + bool isConvertibleProperty) { - var messageFormat = rule.MessageFormat; + var memberString = member.ToDisplayString(ContainingTypeAndNameOnlyFormat); + if (rule == s_removeUnreadMembersRule) { // IDE0052 has a different message for method and property symbols. switch (member) { case IMethodSymbol: - messageFormat = AnalyzersResources.Private_method_0_can_be_removed_as_it_is_never_invoked; - break; - - case IPropertySymbol property: - // We change the message only if both 'get' and 'set' accessors are present and - // there are no shadow 'get' accessor usages. Otherwise the message will be confusing - if (property.GetMethod != null && property.SetMethod != null && - !_propertiesWithShadowGetAccessorUsages.Contains(property)) - { - messageFormat = AnalyzersResources.Private_property_0_can_be_converted_to_a_method_as_its_get_accessor_is_never_invoked; - } - - break; + return new DiagnosticHelper.LocalizableStringWithArguments( + AnalyzersResources.Private_method_0_can_be_removed_as_it_is_never_invoked, + memberString); + + case IPropertySymbol when isConvertibleProperty: + return new DiagnosticHelper.LocalizableStringWithArguments( + AnalyzersResources.Private_property_0_can_be_converted_to_a_method_as_its_get_accessor_is_never_invoked, + memberString); } } return new DiagnosticHelper.LocalizableStringWithArguments( - messageFormat, member.ToDisplayString(ContainingTypeAndNameOnlyFormat)); + rule.MessageFormat, memberString); } private static bool HasSyntaxErrors(INamedTypeSymbol namedTypeSymbol, CancellationToken cancellationToken) diff --git a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.BlockAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.BlockAnalyzer.cs index ee5c031247f99..1b75719ebc718 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.BlockAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.BlockAnalyzer.cs @@ -485,6 +485,8 @@ private void AnalyzeUnusedValueAssignments( hasBlockWithAllUsedSymbolWrites = false; hasUnknownOperationNoneDescendant = false; + var interpolatedStringHandlerAttribute = context.Compilation.InterpolatedStringHandlerAttributeType(); + foreach (var operationBlock in context.OperationBlocks) { if (!ShouldAnalyze(operationBlock, context.OwningSymbol, ref hasUnknownOperationNoneDescendant)) @@ -559,7 +561,7 @@ private void AnalyzeUnusedValueAssignments( if (shouldReport) { - _symbolStartAnalyzer.ReportUnusedParameterDiagnostic(unusedParameter, hasReference, context.ReportDiagnostic, context.Options, cancellationToken: context.CancellationToken); + _symbolStartAnalyzer.ReportUnusedParameterDiagnostic(unusedParameter, hasReference, context.ReportDiagnostic, context.Options, interpolatedStringHandlerAttribute, context.CancellationToken); } } diff --git a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs index 3b52cf46647e9..3093a98c3c2eb 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -24,19 +22,19 @@ internal abstract partial class AbstractRemoveUnusedParametersAndValuesDiagnosti { private sealed partial class SymbolStartAnalyzer( AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer compilationAnalyzer, - INamedTypeSymbol eventArgsTypeOpt, + INamedTypeSymbol? eventArgsType, ImmutableHashSet attributeSetForMethodsToIgnore, DeserializationConstructorCheck deserializationConstructorCheck, - INamedTypeSymbol iCustomMarshaler, + INamedTypeSymbol? iCustomMarshaler, SymbolStartAnalysisContext symbolStartAnalysisContext) { private readonly AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer _compilationAnalyzer = compilationAnalyzer; - private readonly INamedTypeSymbol _eventArgsTypeOpt = eventArgsTypeOpt; + private readonly INamedTypeSymbol? _eventArgsType = eventArgsType; private readonly ImmutableHashSet _attributeSetForMethodsToIgnore = attributeSetForMethodsToIgnore; private readonly DeserializationConstructorCheck _deserializationConstructorCheck = deserializationConstructorCheck; private readonly ConcurrentDictionary _methodsUsedAsDelegates = []; - private readonly INamedTypeSymbol _iCustomMarshaler = iCustomMarshaler; + private readonly INamedTypeSymbol? _iCustomMarshaler = iCustomMarshaler; private readonly SymbolStartAnalysisContext _symbolStartAnalysisContext = symbolStartAnalysisContext; /// @@ -110,9 +108,11 @@ private void OnMethodReference(OperationAnalysisContext context) private void OnSymbolEnd(SymbolAnalysisContext context) { + var interpolatedStringHandlerAttribute = context.Compilation.InterpolatedStringHandlerAttributeType(); + foreach (var (parameter, hasReference) in _unusedParameters) { - ReportUnusedParameterDiagnostic(parameter, hasReference, context.ReportDiagnostic, context.Options, context.CancellationToken); + ReportUnusedParameterDiagnostic(parameter, hasReference, context.ReportDiagnostic, context.Options, interpolatedStringHandlerAttribute, context.CancellationToken); } } @@ -121,15 +121,16 @@ private void ReportUnusedParameterDiagnostic( bool hasReference, Action reportDiagnostic, AnalyzerOptions analyzerOptions, + INamedTypeSymbol? interpolatedStringHandlerAttributeType, CancellationToken cancellationToken) { - if (!IsUnusedParameterCandidate(parameter, cancellationToken)) + if (!IsUnusedParameterCandidate(parameter, interpolatedStringHandlerAttributeType, cancellationToken)) { return; } var location = parameter.Locations[0]; - var option = analyzerOptions.GetAnalyzerOptions(location.SourceTree).UnusedParameters; + var option = analyzerOptions.GetAnalyzerOptions(location.SourceTree!).UnusedParameters; if (option.Notification.Severity == ReportDiagnostic.Suppress || !ShouldReportUnusedParameters(parameter.ContainingSymbol, option.Value, option.Notification.Severity)) { @@ -173,7 +174,7 @@ private static LocalizableString GetMessageForUnusedParameterDiagnostic( return new DiagnosticHelper.LocalizableStringWithArguments(messageFormat, parameterName); } - private static IEnumerable GetAttributesForMethodsToIgnore(Compilation compilation) + private static IEnumerable GetAttributesForMethodsToIgnore(Compilation compilation) { // Ignore conditional methods (One conditional will often call another conditional method as its only use of a parameter) yield return compilation.ConditionalAttribute(); @@ -192,7 +193,7 @@ private static IEnumerable GetAttributesForMethodsToIgnore(Com yield return compilation.SystemComponentModelCompositionImportingConstructorAttribute(); } - private bool IsUnusedParameterCandidate(IParameterSymbol parameter, CancellationToken cancellationToken) + private bool IsUnusedParameterCandidate(IParameterSymbol parameter, INamedTypeSymbol? interpolatedStringHandlerAttributeType, CancellationToken cancellationToken) { // Ignore certain special parameters/methods. // Note that "method.ExplicitOrImplicitInterfaceImplementations" check below is not a complete check, @@ -228,16 +229,16 @@ parameter.ContainingSymbol is not IMethodSymbol method || // Ignore event handler methods "Handler(object, MyEventArgs)" // as event handlers are required to match this signature // regardless of whether or not the parameters are used. - if (_eventArgsTypeOpt != null && + if (_eventArgsType != null && method.Parameters is [{ Type.SpecialType: SpecialType.System_Object }, var secondParam] && - secondParam.Type.InheritsFromOrEquals(_eventArgsTypeOpt)) + secondParam.Type.InheritsFromOrEquals(_eventArgsType)) { return false; } // Ignore flagging parameters for methods with certain well-known attributes, // which are known to have unused parameters in real world code. - if (method.GetAttributes().Any(static (a, self) => self._attributeSetForMethodsToIgnore.Contains(a.AttributeClass), this)) + if (method.GetAttributes().Any(static (a, self) => a.AttributeClass is { } attributeClass && self._attributeSetForMethodsToIgnore.Contains(attributeClass), this)) { return false; } @@ -265,16 +266,51 @@ parameter.ContainingSymbol is not IMethodSymbol method || return false; } - // Don't report on valid GetInstance method of ICustomMarshaler. - // See https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.icustommarshaler#implementing-the-getinstance-method - if (method is { MetadataName: "GetInstance", IsStatic: true, Parameters.Length: 1, ContainingType: { } containingType } methodSymbol && - methodSymbol.Parameters[0].Type.SpecialType == SpecialType.System_String && - containingType.AllInterfaces.Any((@interface, marshaler) => @interface.Equals(marshaler), _iCustomMarshaler)) + if (method.ContainingType is { } containingType) { - return false; + // Don't report on valid GetInstance method of ICustomMarshaler. + // See https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.icustommarshaler#implementing-the-getinstance-method + if (method is { MetadataName: "GetInstance", IsStatic: true, Parameters: [{ Type.SpecialType: SpecialType.System_String }] } && + containingType.AllInterfaces.Any((@interface, marshaler) => @interface.Equals(marshaler), _iCustomMarshaler)) + { + return false; + } + + // 2 first `int` parameters of an interpolated string handler + // constructor are mandatory. Therefore, do not report them as unused + if (IsInterpolatedStringHandlerMandatoryConstructorParameter(parameter, method, containingType, interpolatedStringHandlerAttributeType)) + { + return false; + } } return true; + + static bool IsInterpolatedStringHandlerMandatoryConstructorParameter( + IParameterSymbol parameter, + IMethodSymbol method, + ITypeSymbol containingType, + INamedTypeSymbol? interpolatedStringHandlerAttributeType) + { + if (parameter.Type.SpecialType != SpecialType.System_Int32) + return false; + + if (method.MethodKind != MethodKind.Constructor) + return false; + + if (!(method.Parameters is [var firstParameter, ..] && firstParameter == parameter)) + { + if (!(method.Parameters is [_, var secondParameter, ..] && secondParameter == parameter)) + { + return false; + } + } + + if (!containingType.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, interpolatedStringHandlerAttributeType))) + return false; + + return true; + } } } } diff --git a/src/Analyzers/Core/Analyzers/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs b/src/Analyzers/Core/Analyzers/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs index 317cd825e603b..da4741a6aac68 100644 --- a/src/Analyzers/Core/Analyzers/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs +++ b/src/Analyzers/Core/Analyzers/SimplifyTypeNames/SimplifyTypeNamesDiagnosticAnalyzerBase.cs @@ -193,7 +193,7 @@ internal static Diagnostic CreateDiagnostic(SemanticModel model, TSimplifierOpti public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; - private class AnalyzerImpl(SimplifyTypeNamesDiagnosticAnalyzerBase analyzer) + private sealed class AnalyzerImpl(SimplifyTypeNamesDiagnosticAnalyzerBase analyzer) { private readonly SimplifyTypeNamesDiagnosticAnalyzerBase _analyzer = analyzer; diff --git a/src/Analyzers/Core/Analyzers/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs index 34f7e41e03429..c883b8bb26085 100644 --- a/src/Analyzers/Core/Analyzers/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs @@ -6,18 +6,22 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.UseAutoProperty; -internal abstract class AbstractUseAutoPropertyAnalyzer< +using static UseAutoPropertiesHelpers; + +internal abstract partial class AbstractUseAutoPropertyAnalyzer< TSyntaxKind, TPropertyDeclaration, TConstructorDeclaration, @@ -37,11 +41,9 @@ internal abstract class AbstractUseAutoPropertyAnalyzer< /// ConcurrentStack as that's the only concurrent collection that supports 'Clear' in netstandard2. /// private static readonly ObjectPool> s_analysisResultPool = new(() => new()); - private static readonly ObjectPool> s_fieldSetPool = new(() => []); private static readonly ObjectPool> s_nodeSetPool = new(() => []); - private static readonly ObjectPool>> s_fieldWriteLocationPool = new(() => []); - private static readonly Func> s_createFieldWriteNodeSet = _ => s_nodeSetPool.Allocate(); + private static readonly ObjectPool>> s_fieldToUsageLocationPool = new(() => []); /// /// Not static as this has different semantics around case sensitivity for C# and VB. @@ -58,8 +60,16 @@ protected AbstractUseAutoPropertyAnalyzer() _fieldNamesPool = new(() => new(this.SyntaxFacts.StringComparer)); } - protected static void AddFieldWrite(ConcurrentDictionary> fieldWrites, IFieldSymbol field, SyntaxNode node) - => fieldWrites.GetOrAdd(field, s_createFieldWriteNodeSet).Add(node); + protected static void AddFieldUsage(ConcurrentDictionary> fieldWrites, IFieldSymbol field, SyntaxNode location) + => fieldWrites.GetOrAdd(field, static _ => s_nodeSetPool.Allocate()).Add(location); + + private static void ClearAndFree(ConcurrentDictionary> multiMap) + { + foreach (var (_, nodeSet) in multiMap) + s_nodeSetPool.ClearAndFree(nodeSet); + + s_fieldToUsageLocationPool.ClearAndFree(multiMap); + } /// /// A method body edit anywhere in a type will force us to reanalyze the whole type. @@ -72,16 +82,25 @@ public override DiagnosticAnalyzerCategory GetAnalyzerCategory() protected ISyntaxFacts SyntaxFacts => this.SemanticFacts.SyntaxFacts; protected abstract TSyntaxKind PropertyDeclarationKind { get; } + + protected abstract bool CanExplicitInterfaceImplementationsBeFixed { get; } + protected abstract bool SupportsFieldAttributesOnProperties { get; } + protected abstract bool SupportsReadOnlyProperties(Compilation compilation); protected abstract bool SupportsPropertyInitializer(Compilation compilation); - protected abstract bool CanExplicitInterfaceImplementationsBeFixed(); + protected abstract bool SupportsFieldExpression(Compilation compilation); + + protected abstract bool ContainsFieldExpression(TPropertyDeclaration propertyDeclaration, CancellationToken cancellationToken); + protected abstract TExpression? GetFieldInitializer(TVariableDeclarator variable, CancellationToken cancellationToken); protected abstract TExpression? GetGetterExpression(IMethodSymbol getMethod, CancellationToken cancellationToken); - protected abstract TExpression? GetSetterExpression(IMethodSymbol setMethod, SemanticModel semanticModel, CancellationToken cancellationToken); + protected abstract TExpression? GetSetterExpression(SemanticModel semanticModel, IMethodSymbol setMethod, CancellationToken cancellationToken); protected abstract SyntaxNode GetFieldNode(TFieldDeclaration fieldDeclaration, TVariableDeclarator variableDeclarator); + protected abstract void AddAccessedFields( + SemanticModel semanticModel, IMethodSymbol accessor, HashSet fieldNames, HashSet result, CancellationToken cancellationToken); - protected abstract void RegisterIneligibleFieldsAction( - HashSet fieldNames, ConcurrentSet ineligibleFields, SemanticModel semanticModel, SyntaxNode codeBlock, CancellationToken cancellationToken); + protected abstract void RecordIneligibleFieldLocations( + HashSet fieldNames, ConcurrentDictionary> ineligibleFieldUsageIfOutsideProperty, SemanticModel semanticModel, SyntaxNode codeBlock, CancellationToken cancellationToken); protected sealed override void InitializeWorker(AnalysisContext context) => context.RegisterSymbolStartAction(context => @@ -90,44 +109,73 @@ protected sealed override void InitializeWorker(AnalysisContext context) if (!ShouldAnalyze(context, namedType)) return; - var fieldNames = _fieldNamesPool.Allocate(); + // Results of our analysis pass that we will use to determine which fields and properties to offer to fixup. var analysisResults = s_analysisResultPool.Allocate(); - var ineligibleFields = s_fieldSetPool.Allocate(); - var nonConstructorFieldWrites = s_fieldWriteLocationPool.Allocate(); - // Record the names of all the fields in this type. We can use this to greatly reduce the amount of + // Fields whose usage may disqualify them from being removed (depending on the usage location). For example, + // a field taken by ref normally can't be converted (as a property can't be taken by ref). However, this + // doesn't apply within the property itself (as it can refer to `field` after the rewrite). + var ineligibleFieldUsageIfOutsideProperty = s_fieldToUsageLocationPool.Allocate(); + + // Locations where this field is read or written. If it is read or written outside of hte property being + // changed, and the property getter/setter is non-trivial, then we cannot use 'field' for it, as that would + // change the semantics in those locations. + var fieldReads = s_fieldToUsageLocationPool.Allocate(); + var fieldWrites = s_fieldToUsageLocationPool.Allocate(); + + // Record the names of all the private fields in this type. We can use this to greatly reduce the amount of // binding we need to perform when looking for restrictions in the type. + var fieldNames = _fieldNamesPool.Allocate(); foreach (var member in namedType.GetMembers()) { - if (member is IFieldSymbol field) + if (member is IFieldSymbol + { + // Can only convert fields that are private, as otherwise we don't know how they may be used + // outside of this type. + DeclaredAccessibility: Accessibility.Private, + // Only care about actual user-defined fields, not compiler generated ones. + CanBeReferencedByName: true, + // Will never convert a constant into an auto-prop + IsConst: false, + // Can't preserve volatile semantics on a property. + IsVolatile: false, + // To make processing later on easier, limit to well-behaved fields (versus having multiple + // fields merged together in error recoery scenarios). + DeclaringSyntaxReferences.Length: 1, + } field) + { fieldNames.Add(field.Name); + } } - context.RegisterSyntaxNodeAction(context => AnalyzePropertyDeclaration(context, namedType, analysisResults), PropertyDeclarationKind); + // Examine each property-declaration we find within this named type to see if it looks like it can be converted. + context.RegisterSyntaxNodeAction( + context => AnalyzePropertyDeclaration(context, namedType, fieldNames, analysisResults), + PropertyDeclarationKind); + + // Concurrently, examine the usages of the fields of this type within itself to see how those may impact if + // a field/prop pair can actually be converted. context.RegisterCodeBlockStartAction(context => { - RegisterIneligibleFieldsAction(fieldNames, ineligibleFields, context.SemanticModel, context.CodeBlock, context.CancellationToken); - RegisterNonConstructorFieldWrites(fieldNames, nonConstructorFieldWrites, context.SemanticModel, context.CodeBlock, context.CancellationToken); + RecordIneligibleFieldLocations(fieldNames, ineligibleFieldUsageIfOutsideProperty, context.SemanticModel, context.CodeBlock, context.CancellationToken); + RecordAllFieldReferences(fieldNames, fieldReads, fieldWrites, context.SemanticModel, context.CodeBlock, context.CancellationToken); }); context.RegisterSymbolEndAction(context => { try { - Process(analysisResults, ineligibleFields, nonConstructorFieldWrites, context); + Process(analysisResults, ineligibleFieldUsageIfOutsideProperty, fieldReads, fieldWrites, context); } finally { // Cleanup after doing all our work. _fieldNamesPool.ClearAndFree(fieldNames); - s_analysisResultPool.ClearAndFree(analysisResults); - s_fieldSetPool.ClearAndFree(ineligibleFields); - foreach (var (_, nodeSet) in nonConstructorFieldWrites) - s_nodeSetPool.ClearAndFree(nodeSet); - - s_fieldWriteLocationPool.ClearAndFree(nonConstructorFieldWrites); + ClearAndFree(ineligibleFieldUsageIfOutsideProperty); + ClearAndFree(fieldReads); + ClearAndFree(fieldWrites); } }); @@ -136,6 +184,11 @@ bool ShouldAnalyze(SymbolStartAnalysisContext context, INamedTypeSymbol namedTyp if (namedType.TypeKind is not TypeKind.Class and not TypeKind.Struct and not TypeKind.Module) return false; + // Serializable types can depend on fields (and their order). Don't report these + // properties in that case. + if (namedType.IsSerializable) + return false; + // Don't bother running on this type unless at least one of its parts has the 'prefer auto props' option // on, and the diagnostic is not suppressed. if (!namedType.DeclaringSyntaxReferences.Select(d => d.SyntaxTree).Distinct().Any(tree => @@ -171,16 +224,14 @@ bool ShouldAnalyze(SymbolStartAnalysisContext context, INamedTypeSymbol namedTyp } }, SymbolKind.NamedType); - private void RegisterNonConstructorFieldWrites( + private void RecordAllFieldReferences( HashSet fieldNames, + ConcurrentDictionary> fieldReads, ConcurrentDictionary> fieldWrites, SemanticModel semanticModel, SyntaxNode codeBlock, CancellationToken cancellationToken) { - if (codeBlock.FirstAncestorOrSelf() != null) - return; - var semanticFacts = this.SemanticFacts; var syntaxFacts = this.SyntaxFacts; foreach (var identifierName in codeBlock.DescendantNodesAndSelf().OfType()) @@ -192,16 +243,97 @@ private void RegisterNonConstructorFieldWrites( if (semanticModel.GetSymbolInfo(identifierName, cancellationToken).Symbol is not IFieldSymbol field) continue; - if (!semanticFacts.IsWrittenTo(semanticModel, identifierName, cancellationToken)) - continue; + if (semanticFacts.IsOnlyWrittenTo(semanticModel, identifierName, cancellationToken)) + { + AddFieldUsage(fieldWrites, field, identifierName); + } + else if (semanticFacts.IsWrittenTo(semanticModel, identifierName, cancellationToken)) + { + AddFieldUsage(fieldWrites, field, identifierName); + AddFieldUsage(fieldReads, field, identifierName); + } + else + { + AddFieldUsage(fieldReads, field, identifierName); + } + } + } + + private AccessedFields GetGetterFields( + SemanticModel semanticModel, + IMethodSymbol getMethod, + HashSet fieldNames, + CancellationToken cancellationToken) + { + var trivialFieldExpression = GetGetterExpression(getMethod, cancellationToken); + if (trivialFieldExpression != null) + return new(CheckFieldAccessExpression(semanticModel, trivialFieldExpression, fieldNames, cancellationToken)); + + if (!this.SupportsFieldExpression(semanticModel.Compilation)) + return AccessedFields.Empty; + + using var _ = PooledHashSet.GetInstance(out var set); + AddAccessedFields(semanticModel, getMethod, fieldNames, set, cancellationToken); - AddFieldWrite(fieldWrites, field, identifierName); + return new(TrivialField: null, set.ToImmutableArray()); + } + + private AccessedFields GetSetterFields( + SemanticModel semanticModel, IMethodSymbol setMethod, HashSet fieldNames, CancellationToken cancellationToken) + { + var trivialFieldExpression = GetSetterExpression(semanticModel, setMethod, cancellationToken); + if (trivialFieldExpression != null) + return new(CheckFieldAccessExpression(semanticModel, trivialFieldExpression, fieldNames, cancellationToken)); + + if (!this.SupportsFieldExpression(semanticModel.Compilation)) + return AccessedFields.Empty; + + using var _ = PooledHashSet.GetInstance(out var set); + AddAccessedFields(semanticModel, setMethod, fieldNames, set, cancellationToken); + + return new(TrivialField: null, set.ToImmutableArray()); + } + + private IFieldSymbol? CheckFieldAccessExpression( + SemanticModel semanticModel, + TExpression? expression, + HashSet fieldNames, + CancellationToken cancellationToken) + { + if (expression == null) + return null; + + // needs to be of the form `x` or `this.x`. + var syntaxFacts = this.SyntaxFacts; + var name = expression; + if (syntaxFacts.IsMemberAccessExpression(expression)) + name = (TExpression)SyntaxFacts.GetNameOfMemberAccessExpression(expression); + + return TryGetDirectlyAccessedFieldSymbol(semanticModel, name as TIdentifierName, fieldNames, cancellationToken); + } + + private static bool TryGetSyntax( + IFieldSymbol field, + [NotNullWhen(true)] out TFieldDeclaration? fieldDeclaration, + [NotNullWhen(true)] out TVariableDeclarator? variableDeclarator, + CancellationToken cancellationToken) + { + if (field.DeclaringSyntaxReferences is [var fieldReference]) + { + variableDeclarator = fieldReference.GetSyntax(cancellationToken) as TVariableDeclarator; + fieldDeclaration = variableDeclarator?.Parent?.Parent as TFieldDeclaration; + return fieldDeclaration != null && variableDeclarator != null; } + + fieldDeclaration = null; + variableDeclarator = null; + return false; } private void AnalyzePropertyDeclaration( SyntaxNodeAnalysisContext context, INamedTypeSymbol containingType, + HashSet fieldNames, ConcurrentStack analysisResults) { var cancellationToken = context.CancellationToken; @@ -209,9 +341,15 @@ private void AnalyzePropertyDeclaration( var compilation = semanticModel.Compilation; var propertyDeclaration = (TPropertyDeclaration)context.Node; + if (semanticModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken) is not IPropertySymbol property) return; + // To make processing later on easier, limit to well-behaved properties (versus having multiple + // properties merged together in error recovery scenarios). + if (property.DeclaringSyntaxReferences.Length != 1) + return; + if (!containingType.Equals(property.ContainingType)) return; @@ -233,12 +371,7 @@ private void AnalyzePropertyDeclaration( if (property.GetMethod == null) return; - if (!CanExplicitInterfaceImplementationsBeFixed() && property.ExplicitInterfaceImplementations.Length != 0) - return; - - // Serializable types can depend on fields (and their order). Don't report these - // properties in that case. - if (containingType.IsSerializable) + if (!CanExplicitInterfaceImplementationsBeFixed && property.ExplicitInterfaceImplementations.Length != 0) return; var preferAutoProps = context.GetAnalyzerOptions().PreferAutoProperties; @@ -251,106 +384,179 @@ private void AnalyzePropertyDeclaration( if (notification.Severity == ReportDiagnostic.Suppress) return; - var getterField = GetGetterField(semanticModel, property.GetMethod, cancellationToken); - if (getterField == null) + // If the property already contains a `field` expression, then we can't do anything more here. + if (SupportsFieldExpression(compilation) && ContainsFieldExpression(propertyDeclaration, cancellationToken)) return; - // Only support this for private fields. It limits the scope of hte program - // we have to analyze to make sure this is safe to do. - if (getterField.DeclaredAccessibility != Accessibility.Private) - return; + var getterFields = GetGetterFields(semanticModel, property.GetMethod, fieldNames, cancellationToken); + getterFields = getterFields.Where( + static (getterField, args) => + { + var (@this, compilation, containingType, property, cancellationToken) = args; - // If the user made the field readonly, we only want to convert it to a property if we - // can keep it readonly. - if (getterField.IsReadOnly && !SupportsReadOnlyProperties(compilation)) - return; + // Only support this for private fields. It limits the scope of hte program + // we have to analyze to make sure this is safe to do. + if (getterField.DeclaredAccessibility != Accessibility.Private) + return false; - // Field and property have to be in the same type. - if (!containingType.Equals(getterField.ContainingType)) - return; + // Don't want to remove constants and volatile fields. + if (getterField.IsConst || getterField.IsVolatile) + return false; - // Property and field have to agree on type. - if (!property.Type.Equals(getterField.Type)) - return; + // If the user made the field readonly, we only want to convert it to a property if we + // can keep it readonly. + if (getterField.IsReadOnly && !@this.SupportsReadOnlyProperties(compilation)) + return false; - // Mutable value type fields are mutable unless they are marked read-only - if (!getterField.IsReadOnly && getterField.Type.IsMutableValueType() != false) - return; + // Mutable value type fields are mutable unless they are marked read-only + if (!getterField.IsReadOnly && getterField.Type.IsMutableValueType() != false) + return false; - // Don't want to remove constants and volatile fields. - if (getterField.IsConst || getterField.IsVolatile) - return; + // Field and property have to be in the same type. + if (!containingType.Equals(getterField.ContainingType)) + return false; - // Field and property should match in static-ness - if (getterField.IsStatic != property.IsStatic) - return; + // Field and property should match in static-ness + if (getterField.IsStatic != property.IsStatic) + return false; - var fieldReference = getterField.DeclaringSyntaxReferences[0]; - if (fieldReference.GetSyntax(cancellationToken) is not TVariableDeclarator { Parent.Parent: TFieldDeclaration fieldDeclaration } variableDeclarator) + // Property and field have to agree on type. + if (!property.Type.Equals(getterField.Type)) + return false; + + if (!TryGetSyntax(getterField, out _, out var variableDeclarator, cancellationToken)) + return false; + + var initializer = @this.GetFieldInitializer(variableDeclarator, cancellationToken); + if (initializer != null && !@this.SupportsPropertyInitializer(compilation)) + return false; + + if (!@this.CanConvert(property)) + return false; + + // Can't remove the field if it has attributes on it. + var attributes = getterField.GetAttributes(); + if (attributes.Length > 0 && !@this.SupportsFieldAttributesOnProperties) + return false; + + return true; + }, + (this, compilation, containingType, property, cancellationToken)); + + if (getterFields.IsEmpty) return; + var isTrivialSetAccessor = false; + // A setter is optional though. - var setMethod = property.SetMethod; - if (setMethod != null) + if (property.SetMethod != null) { - var setterField = GetSetterField(semanticModel, setMethod, cancellationToken); - // If there is a getter and a setter, they both need to agree on which field they are - // writing to. - if (setterField != getterField) + // Figure out all the fields written to in the setter. + var setterFields = GetSetterFields(semanticModel, property.SetMethod, fieldNames, cancellationToken); + + // Intersect these to determine which fields both the getter and setter write to. + getterFields = getterFields.Where( + static (field, setterFields) => setterFields.Contains(field), + setterFields); + + // If there is a getter and a setter, they both need to agree on which field they are writing to. + if (getterFields.IsEmpty) return; - } - var initializer = GetFieldInitializer(variableDeclarator, cancellationToken); - if (initializer != null && !SupportsPropertyInitializer(compilation)) - return; + isTrivialSetAccessor = setterFields.TrivialField != null; + } - // Can't remove the field if it has attributes on it. - var attributes = getterField.GetAttributes(); - var suppressMessageAttributeType = compilation.SuppressMessageAttributeType(); - foreach (var attribute in attributes) + if (getterFields.Count > 1) { - if (attribute.AttributeClass != suppressMessageAttributeType) - return; + // Multiple fields we could convert here. Check if any of the fields end with the property name. If + // so, it's likely that that's the field to use. + getterFields = getterFields.Where( + static (field, property) => field.Name.EndsWith(property.Name, StringComparison.OrdinalIgnoreCase), + property); } - if (!CanConvert(property)) + // If we have multiple fields that could be converted, don't offer. We don't know which field/prop pair would + // be best. + if (getterFields.Count != 1) return; - // Looks like a viable property/field to convert into an auto property. - analysisResults.Push(new AnalysisResult(property, getterField, propertyDeclaration, fieldDeclaration, variableDeclarator, notification)); + var getterField = getterFields.TrivialField ?? getterFields.NonTrivialFields.Single(); + var isTrivialGetAccessor = getterFields.TrivialField == getterField; + + Contract.ThrowIfFalse(TryGetSyntax(getterField, out var fieldDeclaration, out var variableDeclarator, cancellationToken)); + + analysisResults.Push(new AnalysisResult( + property, getterField, + propertyDeclaration, fieldDeclaration, variableDeclarator, + notification, + isTrivialGetAccessor, + isTrivialSetAccessor)); } protected virtual bool CanConvert(IPropertySymbol property) => true; - private IFieldSymbol? GetSetterField(SemanticModel semanticModel, IMethodSymbol setMethod, CancellationToken cancellationToken) - => CheckFieldAccessExpression(semanticModel, GetSetterExpression(setMethod, semanticModel, cancellationToken), cancellationToken); + protected IFieldSymbol? TryGetDirectlyAccessedFieldSymbol( + SemanticModel semanticModel, + TIdentifierName? identifierName, + HashSet fieldNames, + CancellationToken cancellationToken) + { + if (identifierName is null) + return null; - private IFieldSymbol? GetGetterField(SemanticModel semanticModel, IMethodSymbol getMethod, CancellationToken cancellationToken) - => CheckFieldAccessExpression(semanticModel, GetGetterExpression(getMethod, cancellationToken), cancellationToken); + var syntaxFacts = this.SyntaxFacts; - private static IFieldSymbol? CheckFieldAccessExpression(SemanticModel semanticModel, TExpression? expression, CancellationToken cancellationToken) - { - if (expression == null) + // Quick check to avoid costly binding. Only look at identifiers that match the name of a private field in + // the containing type. + if (!fieldNames.Contains(syntaxFacts.GetIdentifierOfIdentifierName(identifierName).ValueText)) + return null; + + TExpression expression = identifierName; + if (this.SyntaxFacts.IsNameOfAnyMemberAccessExpression(expression)) + expression = (TExpression)expression.GetRequiredParent(); + + var operation = semanticModel.GetOperation(expression, cancellationToken); + if (operation is not IFieldReferenceOperation + { + // Instance has to be 'null' (a static reference) or through `this.` Anything else is not a direct + // reference that can be updated to `field`. + Instance: null or IInstanceReferenceOperation + { + ReferenceKind: InstanceReferenceKind.ContainingTypeInstance, + }, + Field.DeclaringSyntaxReferences.Length: 1, + } fieldReference) + { return null; + } - var symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken); - return symbolInfo.Symbol is IFieldSymbol { DeclaringSyntaxReferences.Length: 1 } field - ? field - : null; + return fieldReference.Field; } private void Process( ConcurrentStack analysisResults, - ConcurrentSet ineligibleFields, - ConcurrentDictionary> nonConstructorFieldWrites, + ConcurrentDictionary> ineligibleFieldUsageIfOutsideProperty, + ConcurrentDictionary> fieldReads, + ConcurrentDictionary> fieldWrites, SymbolAnalysisContext context) { + using var _1 = PooledHashSet.GetInstance(out var reportedFields); + using var _2 = PooledHashSet.GetInstance(out var reportedProperties); + foreach (var result in analysisResults) { - // C# specific check. - if (ineligibleFields.Contains(result.Field)) - continue; + // Check If we had any invalid field usage outside of the property we're converting. + if (ineligibleFieldUsageIfOutsideProperty.TryGetValue(result.Field, out var ineligibleFieldUsages)) + { + if (!ineligibleFieldUsages.All(loc => loc.Ancestors().Contains(result.PropertyDeclaration))) + continue; + + // All the usages were inside the property. This is ok if we support the `field` keyword as those + // usages will be updated to that form. + if (!this.SupportsFieldExpression(context.Compilation)) + continue; + } // VB specific check. // @@ -362,65 +568,110 @@ private void Process( { if (result.Property.DeclaredAccessibility != Accessibility.Private && result.Property.SetMethod is null && - nonConstructorFieldWrites.TryGetValue(result.Field, out var writeLocations1) && - writeLocations1.Any(loc => !loc.Ancestors().Contains(result.PropertyDeclaration))) + fieldWrites.TryGetValue(result.Field, out var writeLocations1) && + NonConstructorLocations(writeLocations1).Any(loc => !loc.Ancestors().Contains(result.PropertyDeclaration))) { continue; } } - // If this was an `init` property, and there was a write to the field, then we can't support this. - // That's because we can't still keep this `init` as that write will not be allowed, and we can't make - // it a `setter` as that would allow arbitrary writing outside the type, despite the original `init` - // semantics. + // C# specific check. + // + // If this was an `init` property, and there was a write to the field, then we can't support this. That's + // because we can't still keep this `init` as that write will not be allowed, and we can't make it a + // `setter` as that would allow arbitrary writing outside the type, despite the original `init` semantics. if (result.Property.SetMethod is { IsInitOnly: true } && - nonConstructorFieldWrites.TryGetValue(result.Field, out var writeLocations2) && - writeLocations2.Any(loc => !loc.Ancestors().Contains(result.PropertyDeclaration))) + fieldWrites.TryGetValue(result.Field, out var writeLocations2) && + NonConstructorLocations(writeLocations2).Any(loc => !loc.Ancestors().Contains(result.PropertyDeclaration))) + { + continue; + } + + // If we have a non-trivial getter, then we can't convert this if the field is read outside of the property. + // The read will go through the property getter now, which may change semantics. + if (!result.IsTrivialGetAccessor && + fieldReads.TryGetValue(result.Field, out var specificFieldReads) && + NotWithinProperty(specificFieldReads, result.PropertyDeclaration)) + { + continue; + } + + // If we have a non-trivial getter, then we can't convert this if the field is written outside of the + // property. The write will go through the property setter now, which may change semantics. + if (result.Property.SetMethod != null && + !result.IsTrivialSetAccessor && + fieldWrites.TryGetValue(result.Field, out var specificFieldWrites) && + NotWithinProperty(specificFieldWrites, result.PropertyDeclaration)) { continue; } - Process(result, context); + // Only report a use-auto-prop message at most once for any field or property. Note: we could be smarter + // here. The set of fields and properties form a bipartite graph. In an ideal world, we'd determine the + // maximal matching between those two bipartite sets (see + // https://en.wikipedia.org/wiki/Hopcroft%E2%80%93Karp_algorithm) and use that to offer the most matches as + // possible. + // + // We can see if the simple greedy approach of just taking the matches as we find them and returning those + // is insufficient in the future. + if (reportedFields.Contains(result.Field) || reportedProperties.Contains(result.Property)) + continue; + + reportedFields.Add(result.Field); + reportedProperties.Add(result.Property); + + ReportDiagnostics(result); } - } - private void Process(AnalysisResult result, SymbolAnalysisContext context) - { - var propertyDeclaration = result.PropertyDeclaration; - var variableDeclarator = result.VariableDeclarator; - var fieldNode = GetFieldNode(result.FieldDeclaration, variableDeclarator); - - // Now add diagnostics to both the field and the property saying we can convert it to - // an auto property. For each diagnostic store both location so we can easily retrieve - // them when performing the code fix. - var additionalLocations = ImmutableArray.Create( - propertyDeclaration.GetLocation(), - variableDeclarator.GetLocation()); - - // Place the appropriate marker on the field depending on the user option. - var diagnostic1 = DiagnosticHelper.Create( - Descriptor, - fieldNode.GetLocation(), - result.Notification, - context.Options, - additionalLocations: additionalLocations, - properties: null); - - // Also, place a hidden marker on the property. If they bring up a lightbulb - // there, they'll be able to see that they can convert it to an auto-prop. - var diagnostic2 = Diagnostic.Create( - Descriptor, propertyDeclaration.GetLocation(), - additionalLocations: additionalLocations); - - context.ReportDiagnostic(diagnostic1); - context.ReportDiagnostic(diagnostic2); - } + static bool NotWithinProperty(IEnumerable nodes, TPropertyDeclaration propertyDeclaration) + { + foreach (var node in nodes) + { + if (!node.AncestorsAndSelf().Contains(propertyDeclaration)) + return true; + } + + return false; + } - private sealed record AnalysisResult( - IPropertySymbol Property, - IFieldSymbol Field, - TPropertyDeclaration PropertyDeclaration, - TFieldDeclaration FieldDeclaration, - TVariableDeclarator VariableDeclarator, - NotificationOption2 Notification); + static IEnumerable NonConstructorLocations(IEnumerable nodes) + => nodes.Where(n => n.FirstAncestorOrSelf() is null); + + void ReportDiagnostics(AnalysisResult result) + { + var propertyDeclaration = result.PropertyDeclaration; + var variableDeclarator = result.VariableDeclarator; + var fieldNode = GetFieldNode(result.FieldDeclaration, variableDeclarator); + + // Now add diagnostics to both the field and the property saying we can convert it to + // an auto property. For each diagnostic store both location so we can easily retrieve + // them when performing the code fix. + var additionalLocations = ImmutableArray.Create( + propertyDeclaration.GetLocation(), + variableDeclarator.GetLocation()); + + var properties = ImmutableDictionary.Empty; + if (result.IsTrivialGetAccessor) + properties = properties.Add(IsTrivialGetAccessor, IsTrivialGetAccessor); + + if (result.IsTrivialSetAccessor) + properties = properties.Add(IsTrivialSetAccessor, IsTrivialSetAccessor); + + // Place the appropriate marker on the field depending on the user option. + context.ReportDiagnostic(DiagnosticHelper.Create( + Descriptor, + fieldNode.GetLocation(), + result.Notification, + context.Options, + additionalLocations, + properties)); + + // Also, place a hidden marker on the property. If they bring up a lightbulb there, they'll be able to see that + // they can convert it to an auto-prop. + context.ReportDiagnostic(Diagnostic.Create( + Descriptor, propertyDeclaration.GetLocation(), + additionalLocations, + properties)); + } + } } diff --git a/src/Analyzers/Core/Analyzers/UseAutoProperty/AccessedFields.cs b/src/Analyzers/Core/Analyzers/UseAutoProperty/AccessedFields.cs new file mode 100644 index 0000000000000..ce4fa40d42f0e --- /dev/null +++ b/src/Analyzers/Core/Analyzers/UseAutoProperty/AccessedFields.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; + +namespace Microsoft.CodeAnalysis.UseAutoProperty; + +/// The single field accessed, when the get/set-accessor is of a trivial form similar to +/// get => fieldName; or set => fieldName = value;. If we see these forms, we'll want to convert them to +/// get;/set;. +/// Any fields we saw accessed in more complex expressions. These can be converted to use +/// the field expression form if we think we can still convert this field/property pair to an auto-prop. +internal readonly record struct AccessedFields( + IFieldSymbol? TrivialField, + ImmutableArray NonTrivialFields) +{ + public static readonly AccessedFields Empty = new(null, []); + + public AccessedFields(IFieldSymbol? trivialField) : this(trivialField, []) + { + } + + public int Count => (TrivialField != null ? 1 : 0) + NonTrivialFields.Length; + public bool IsEmpty => Count == 0; + + public AccessedFields Where(Func predicate, TArg arg) + => new(TrivialField != null && predicate(TrivialField, arg) ? TrivialField : null, + NonTrivialFields.WhereAsArray(predicate, arg)); + + public bool Contains(IFieldSymbol field) + => Equals(TrivialField, field) || NonTrivialFields.Contains(field); +} diff --git a/src/Analyzers/Core/Analyzers/UseAutoProperty/AnalysisResult.cs b/src/Analyzers/Core/Analyzers/UseAutoProperty/AnalysisResult.cs new file mode 100644 index 0000000000000..e38aa38ee311e --- /dev/null +++ b/src/Analyzers/Core/Analyzers/UseAutoProperty/AnalysisResult.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 Microsoft.CodeAnalysis.CodeStyle; + +namespace Microsoft.CodeAnalysis.UseAutoProperty; + +internal abstract partial class AbstractUseAutoPropertyAnalyzer< + TSyntaxKind, + TPropertyDeclaration, + TConstructorDeclaration, + TFieldDeclaration, + TVariableDeclarator, + TExpression, + TIdentifierName> +{ + /// The property we will make into an auto-property. + /// The field we are removing. + /// The single declaration that has. + /// The single containing declaration that has. + /// The single containing declarator that has. + /// The option value/severity at this particular analysis location. + /// If the get-accessor is of a trivial form like get => fieldName;. Such + /// an accessor is a simple 'read through to the field' accessor. As such, reads of the field can be replaced with + /// calls to this accessor as it will have the same semantics. + /// Same as . Such an accessor is a simple + /// 'write through to the field' accessor. As such, writes of the field can be replaced with calls to this accessor + /// as it will have the same semantics. + internal sealed record AnalysisResult( + IPropertySymbol Property, + IFieldSymbol Field, + TPropertyDeclaration PropertyDeclaration, + TFieldDeclaration FieldDeclaration, + TVariableDeclarator VariableDeclarator, + NotificationOption2 Notification, + bool IsTrivialGetAccessor, + bool IsTrivialSetAccessor); +} diff --git a/src/Analyzers/Core/Analyzers/UseAutoProperty/UseAutoPropertiesHelpers.cs b/src/Analyzers/Core/Analyzers/UseAutoProperty/UseAutoPropertiesHelpers.cs new file mode 100644 index 0000000000000..19679570faf23 --- /dev/null +++ b/src/Analyzers/Core/Analyzers/UseAutoProperty/UseAutoPropertiesHelpers.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.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.UseAutoProperty; + +internal static class UseAutoPropertiesHelpers +{ + public const string IsTrivialGetAccessor = nameof(IsTrivialGetAccessor); + public const string IsTrivialSetAccessor = nameof(IsTrivialSetAccessor); +} diff --git a/src/Analyzers/Core/Analyzers/UseCollectionExpression/CollectionExpressionMatch.cs b/src/Analyzers/Core/Analyzers/UseCollectionExpression/CollectionExpressionMatch.cs new file mode 100644 index 0000000000000..db6671311ed8f --- /dev/null +++ b/src/Analyzers/Core/Analyzers/UseCollectionExpression/CollectionExpressionMatch.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. + +namespace Microsoft.CodeAnalysis.UseCollectionExpression; + +/// +/// Represents statements following an initializer that should be converted into collection-initializer/expression +/// elements. +/// +/// The statement that follows that contains the values to add to the new collection-initializer or +/// collection-expression. Or the expression directly to add. +/// Whether or not a spread (.. x) element should be created for this statement. This +/// is needed as the statement could be cases like expr.Add(x) vs. expr.AddRange(x). This property +/// indicates that the latter should become a spread, without the consumer having to reexamine the statement to see +/// what form it is. +internal readonly record struct CollectionMatch( + TMatchNode Node, + bool UseSpread) where TMatchNode : SyntaxNode; diff --git a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractObjectCreationExpressionAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractObjectCreationExpressionAnalyzer.cs index e1cb4dc271488..5dee730834d73 100644 --- a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractObjectCreationExpressionAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractObjectCreationExpressionAnalyzer.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.UseCollectionExpression; namespace Microsoft.CodeAnalysis.UseCollectionInitializer; @@ -34,6 +35,10 @@ internal abstract class AbstractObjectCreationExpressionAnalyzer< TMatch, TAnalyzer>, new() { + public readonly record struct AnalysisResult( + ImmutableArray PreMatches, + ImmutableArray PostMatches); + protected UpdateExpressionState State; protected TObjectCreationExpressionSyntax _objectCreationExpression = null!; @@ -43,7 +48,7 @@ internal abstract class AbstractObjectCreationExpressionAnalyzer< protected SemanticModel SemanticModel => this.State.SemanticModel; protected abstract bool ShouldAnalyze(CancellationToken cancellationToken); - protected abstract bool TryAddMatches(ArrayBuilder matches, CancellationToken cancellationToken); + protected abstract bool TryAddMatches(ArrayBuilder preMatches, ArrayBuilder postMatches, CancellationToken cancellationToken); protected abstract bool IsInitializerOfLocalDeclarationStatement( TLocalDeclarationStatementSyntax localDeclarationStatement, TObjectCreationExpressionSyntax rootExpression, [NotNullWhen(true)] out TVariableDeclaratorSyntax? variableDeclarator); @@ -75,16 +80,17 @@ protected void Clear() _analyzeForCollectionExpression = false; } - protected ImmutableArray AnalyzeWorker(CancellationToken cancellationToken) + protected AnalysisResult AnalyzeWorker(CancellationToken cancellationToken) { if (!ShouldAnalyze(cancellationToken)) return default; - using var _ = ArrayBuilder.GetInstance(out var matches); - if (!TryAddMatches(matches, cancellationToken)) + using var _1 = ArrayBuilder.GetInstance(out var preMatches); + using var _2 = ArrayBuilder.GetInstance(out var postMatches); + if (!TryAddMatches(preMatches, postMatches, cancellationToken)) return default; - return matches.ToImmutableAndClear(); + return new(preMatches.ToImmutableAndClear(), postMatches.ToImmutableAndClear()); } protected UpdateExpressionState? TryInitializeState( diff --git a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs index 207b25ed408eb..1a8d7140e317b 100644 --- a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerAnalyzer.cs @@ -2,12 +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.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.UseCollectionExpression; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.UseCollectionInitializer; @@ -27,7 +27,7 @@ internal abstract class AbstractUseCollectionInitializerAnalyzer< TObjectCreationExpressionSyntax, TLocalDeclarationStatementSyntax, TVariableDeclaratorSyntax, - Match, TAnalyzer> + CollectionMatch, TAnalyzer> where TExpressionSyntax : SyntaxNode where TStatementSyntax : SyntaxNode where TObjectCreationExpressionSyntax : TExpressionSyntax @@ -49,11 +49,12 @@ internal abstract class AbstractUseCollectionInitializerAnalyzer< { protected abstract bool IsComplexElementInitializer(SyntaxNode expression); protected abstract bool HasExistingInvalidInitializerForCollection(); - protected abstract bool ValidateMatchesForCollectionExpression(ArrayBuilder> matches, CancellationToken cancellationToken); + protected abstract bool AnalyzeMatchesAndCollectionConstructorForCollectionExpression( + ArrayBuilder> preMatches, ArrayBuilder> postMatches, CancellationToken cancellationToken); protected abstract IUpdateExpressionSyntaxHelper SyntaxHelper { get; } - public ImmutableArray> Analyze( + public AnalysisResult Analyze( SemanticModel semanticModel, ISyntaxFacts syntaxFacts, TObjectCreationExpressionSyntax objectCreationExpression, @@ -65,10 +66,10 @@ public ImmutableArray> Analyze( return default; this.Initialize(state.Value, objectCreationExpression, analyzeForCollectionExpression); - var result = this.AnalyzeWorker(cancellationToken); + var (preMatches, postMatches) = this.AnalyzeWorker(cancellationToken); // If analysis failed entirely, immediately bail out. - if (result.IsDefault) + if (preMatches.IsDefault || postMatches.IsDefault) return default; // Analysis succeeded, but the result may be empty or non empty. @@ -80,14 +81,14 @@ public ImmutableArray> Analyze( // other words, we don't want to suggest changing `new List()` to `new List() { }` as that's just // noise. So convert empty results to an invalid result here. if (analyzeForCollectionExpression) - return result; + return new(preMatches, postMatches); // Downgrade an empty result to a failure for the normal collection-initializer case. - return result.IsEmpty ? default : result; + return postMatches.IsEmpty ? default : new(preMatches, postMatches); } protected sealed override bool TryAddMatches( - ArrayBuilder> matches, CancellationToken cancellationToken) + ArrayBuilder> preMatches, ArrayBuilder> postMatches, CancellationToken cancellationToken) { var seenInvocation = false; var seenIndexAssignment = false; @@ -121,17 +122,17 @@ protected sealed override bool TryAddMatches( if (match is null) break; - matches.Add(match.Value); + postMatches.Add(match.Value); } } if (_analyzeForCollectionExpression) - return ValidateMatchesForCollectionExpression(matches, cancellationToken); + return AnalyzeMatchesAndCollectionConstructorForCollectionExpression(preMatches, postMatches, cancellationToken); return true; } - private Match? TryAnalyzeStatement( + private CollectionMatch? TryAnalyzeStatement( TStatementSyntax statement, ref bool seenInvocation, ref bool seenIndexAssignment, CancellationToken cancellationToken) { return _analyzeForCollectionExpression @@ -139,7 +140,7 @@ protected sealed override bool TryAddMatches( : TryAnalyzeStatementForCollectionInitializer(statement, ref seenInvocation, ref seenIndexAssignment, cancellationToken); } - private Match? TryAnalyzeStatementForCollectionInitializer( + private CollectionMatch? TryAnalyzeStatementForCollectionInitializer( TStatementSyntax statement, ref bool seenInvocation, ref bool seenIndexAssignment, CancellationToken cancellationToken) { // At least one of these has to be false. @@ -161,7 +162,7 @@ protected sealed override bool TryAddMatches( this.State.ValuePatternMatches(instance)) { seenInvocation = true; - return new Match(expressionStatement, UseSpread: false); + return new(expressionStatement, UseSpread: false); } } @@ -171,7 +172,7 @@ protected sealed override bool TryAddMatches( this.State.ValuePatternMatches(instance)) { seenIndexAssignment = true; - return new Match(expressionStatement, UseSpread: false); + return new(expressionStatement, UseSpread: false); } } diff --git a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs index a663612d196d2..6b84494d3acfc 100644 --- a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/AbstractUseCollectionInitializerDiagnosticAnalyzer.cs @@ -11,23 +11,10 @@ using Microsoft.CodeAnalysis.Shared.CodeStyle; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.UseCollectionExpression; namespace Microsoft.CodeAnalysis.UseCollectionInitializer; -/// -/// Represents statements following an object initializer that should be converted into -/// collection-initializer/expression elements. -/// -/// The statement that follows that contains the values to add to the new -/// collection-initializer or collection-expression -/// Whether or not a spread (.. x) element should be created for this statement. This -/// is needed as the statement could be cases like expr.Add(x) vs. expr.AddRange(x). This property -/// indicates that the latter should become a spread, without the consumer having to reexamine the statement to see -/// what form it is. -internal readonly record struct Match( - TStatementSyntax Statement, - bool UseSpread) where TStatementSyntax : SyntaxNode; - internal abstract partial class AbstractUseCollectionInitializerDiagnosticAnalyzer< TSyntaxKind, TExpressionSyntax, @@ -182,7 +169,7 @@ private void AnalyzeNode( var nodes = containingStatement is null ? ImmutableArray.Empty : [containingStatement]; - nodes = nodes.AddRange(matches.Select(static m => m.Statement)); + nodes = nodes.AddRange(matches.Select(static m => m.Node)); if (syntaxFacts.ContainsInterleavedDirective(nodes, cancellationToken)) return; @@ -205,7 +192,7 @@ private void AnalyzeNode( return; - (ImmutableArray> matches, bool shouldUseCollectionExpression, bool changesSemantics)? GetCollectionInitializerMatches() + (ImmutableArray> matches, bool shouldUseCollectionExpression, bool changesSemantics)? GetCollectionInitializerMatches() { if (containingStatement is null) return null; @@ -213,7 +200,7 @@ private void AnalyzeNode( if (!preferInitializerOption.Value) return null; - var matches = analyzer.Analyze(semanticModel, syntaxFacts, objectCreationExpression, analyzeForCollectionExpression: false, cancellationToken); + var (_, matches) = analyzer.Analyze(semanticModel, syntaxFacts, objectCreationExpression, analyzeForCollectionExpression: false, cancellationToken); // If analysis failed, we can't change this, no matter what. if (matches.IsDefault) @@ -222,7 +209,7 @@ private void AnalyzeNode( return (matches, shouldUseCollectionExpression: false, changesSemantics: false); } - (ImmutableArray> matches, bool shouldUseCollectionExpression, bool changesSemantics)? GetCollectionExpressionMatches() + (ImmutableArray> matches, bool shouldUseCollectionExpression, bool changesSemantics)? GetCollectionExpressionMatches() { if (preferExpressionOption.Value == CollectionExpressionPreference.Never) return null; @@ -231,7 +218,7 @@ private void AnalyzeNode( if (!this.AreCollectionExpressionsSupported(context.Compilation)) return null; - var matches = analyzer.Analyze(semanticModel, syntaxFacts, objectCreationExpression, analyzeForCollectionExpression: true, cancellationToken); + var (_, matches) = analyzer.Analyze(semanticModel, syntaxFacts, objectCreationExpression, analyzeForCollectionExpression: true, cancellationToken); // If analysis failed, we can't change this, no matter what. if (matches.IsDefault) @@ -248,7 +235,7 @@ private void AnalyzeNode( private void FadeOutCode( SyntaxNodeAnalysisContext context, - ImmutableArray> matches, + ImmutableArray> matches, ImmutableArray locations, ImmutableDictionary? properties) { diff --git a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UpdateExpressionState.cs b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UpdateExpressionState.cs index d93969a9f41db..48a993be1f27a 100644 --- a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UpdateExpressionState.cs +++ b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UpdateExpressionState.cs @@ -9,6 +9,7 @@ using System.Threading; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.UseCollectionExpression; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.UseCollectionInitializer; @@ -337,7 +338,7 @@ private bool TryAnalyzeInvocation( /// includes calls to .Add and .AddRange, as well as foreach statements that update the /// collection, and if statements that conditionally add items to the collection-expression. /// - public Match? TryAnalyzeStatementForCollectionExpression( + public CollectionMatch? TryAnalyzeStatementForCollectionExpression( IUpdateExpressionSyntaxHelper syntaxHelper, TStatementSyntax statement, CancellationToken cancellationToken) @@ -355,7 +356,7 @@ private bool TryAnalyzeInvocation( return null; - Match? TryAnalyzeExpressionStatement(TStatementSyntax expressionStatement) + CollectionMatch? TryAnalyzeExpressionStatement(TStatementSyntax expressionStatement) { var expression = (TExpressionSyntax)@this.SyntaxFacts.GetExpressionOfExpressionStatement(expressionStatement); @@ -363,13 +364,13 @@ private bool TryAnalyzeInvocation( if (@this.TryAnalyzeInvocationForCollectionExpression(expression, allowLinq: false, cancellationToken, out var instance, out var useSpread) && @this.ValuePatternMatches(instance)) { - return new Match(expressionStatement, useSpread); + return new(expressionStatement, useSpread); } return null; } - Match? TryAnalyzeForeachStatement(TStatementSyntax foreachStatement) + CollectionMatch? TryAnalyzeForeachStatement(TStatementSyntax foreachStatement) { syntaxHelper.GetPartsOfForeachStatement(foreachStatement, out var awaitKeyword, out var identifier, out _, out var foreachStatements); if (awaitKeyword != default) @@ -393,13 +394,13 @@ private bool TryAnalyzeInvocation( @this.ValuePatternMatches(instance)) { // `foreach` will become `..expr` when we make it into a collection expression. - return new Match(foreachStatement, UseSpread: true); + return new(foreachStatement, UseSpread: true); } return null; } - Match? TryAnalyzeIfStatement(TStatementSyntax ifStatement) + CollectionMatch? TryAnalyzeIfStatement(TStatementSyntax ifStatement) { // look for the form: // @@ -430,7 +431,7 @@ private bool TryAnalyzeInvocation( { // add the form `.. x ? [y] : []` to the result return @this.SyntaxFacts.SupportsCollectionExpressionNaturalType(ifStatement.SyntaxTree.Options) - ? new Match(ifStatement, UseSpread: true) + ? new(ifStatement, UseSpread: true) : null; } @@ -446,7 +447,7 @@ private bool TryAnalyzeInvocation( @this.ValuePatternMatches(instance)) { // add the form `x ? y : z` to the result - return new Match(ifStatement, UseSpread: false); + return new(ifStatement, UseSpread: false); } } diff --git a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UseCollectionInitializerHelpers.cs b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UseCollectionInitializerHelpers.cs index 0860a10ea6eed..48c478b9b0ff1 100644 --- a/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UseCollectionInitializerHelpers.cs +++ b/src/Analyzers/Core/Analyzers/UseCollectionInitializer/UseCollectionInitializerHelpers.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.UseCollectionExpression; namespace Microsoft.CodeAnalysis.UseCollectionInitializer; @@ -18,12 +19,11 @@ internal static class UseCollectionInitializerHelpers public static readonly ImmutableDictionary UseCollectionExpressionProperties = ImmutableDictionary.Empty.Add(UseCollectionExpressionName, UseCollectionExpressionName); - public static ImmutableArray GetLocationsToFade( + public static ImmutableArray GetLocationsToFade( ISyntaxFacts syntaxFacts, - Match matchInfo) - where TStatementSyntax : SyntaxNode + CollectionMatch matchInfo) { - var match = matchInfo.Statement; + var match = matchInfo.Node; var syntaxTree = match.SyntaxTree; if (syntaxFacts.IsExpressionStatement(match)) { diff --git a/src/Analyzers/Core/Analyzers/UseExplicitTupleName/UseExplicitTupleNameDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseExplicitTupleName/UseExplicitTupleNameDiagnosticAnalyzer.cs index 0d23347c5b0ac..ceb62d1deebb7 100644 --- a/src/Analyzers/Core/Analyzers/UseExplicitTupleName/UseExplicitTupleNameDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseExplicitTupleName/UseExplicitTupleNameDiagnosticAnalyzer.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.UseExplicitTupleName; [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] -internal class UseExplicitTupleNameDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer +internal sealed class UseExplicitTupleNameDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer { public const string ElementName = nameof(ElementName); diff --git a/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs index aabbb18b1eb49..74d6e02d130d5 100644 --- a/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseObjectInitializer/AbstractUseObjectInitializerDiagnosticAnalyzer.cs @@ -49,14 +49,6 @@ internal abstract partial class AbstractUseObjectInitializerDiagnosticAnalyzer< new LocalizableResourceString(nameof(AnalyzersResources.Object_initialization_can_be_simplified), AnalyzersResources.ResourceManager, typeof(AnalyzersResources)), isUnnecessary: false); - private static readonly DiagnosticDescriptor s_unnecessaryCodeDescriptor = CreateDescriptorWithId( - IDEDiagnosticIds.UseObjectInitializerDiagnosticId, - EnforceOnBuildValues.UseObjectInitializer, - hasAnyCodeStyleOption: true, - new LocalizableResourceString(nameof(AnalyzersResources.Simplify_object_initialization), AnalyzersResources.ResourceManager, typeof(AnalyzersResources)), - new LocalizableResourceString(nameof(AnalyzersResources.Object_initialization_can_be_simplified), AnalyzersResources.ResourceManager, typeof(AnalyzersResources)), - isUnnecessary: true); - protected abstract bool FadeOutOperatorToken { get; } protected abstract TAnalyzer GetAnalyzer(); @@ -130,25 +122,25 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context) var locations = ImmutableArray.Create(objectCreationExpression.GetLocation()); - context.ReportDiagnostic(DiagnosticHelper.Create( + var unnecessaryLocations = FadeOutCode(context, matches); + + context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags( s_descriptor, objectCreationExpression.GetFirstToken().GetLocation(), option.Notification, context.Options, locations, - properties: null)); - - FadeOutCode(context, matches, locations); + additionalUnnecessaryLocations: unnecessaryLocations)); } - private void FadeOutCode( + private ImmutableArray FadeOutCode( SyntaxNodeAnalysisContext context, - ImmutableArray> matches, - ImmutableArray locations) + ImmutableArray> matches) { var syntaxTree = context.Node.SyntaxTree; var syntaxFacts = GetSyntaxFacts(); + using var locations = TemporaryArray.Empty; foreach (var match in matches) { @@ -158,23 +150,15 @@ private void FadeOutCode( var location1 = Location.Create(syntaxTree, TextSpan.FromBounds( match.MemberAccessExpression.SpanStart, end)); + locations.Add(location1); if (match.Statement.Span.End > match.Initializer.FullSpan.End) { - context.ReportDiagnostic(DiagnosticHelper.CreateWithLocationTags( - s_unnecessaryCodeDescriptor, - location1, - NotificationOption2.ForSeverity(s_unnecessaryCodeDescriptor.DefaultSeverity), - context.Options, - additionalLocations: locations, - additionalUnnecessaryLocations: [syntaxTree.GetLocation(TextSpan.FromBounds(match.Initializer.FullSpan.End, match.Statement.Span.End))])); - } - else - { - context.ReportDiagnostic(Diagnostic.Create( - s_unnecessaryCodeDescriptor, location1, additionalLocations: locations)); + locations.Add(syntaxTree.GetLocation(TextSpan.FromBounds(match.Initializer.FullSpan.End, match.Statement.Span.End))); } } + + return locations.ToImmutableAndClear(); } public sealed override DiagnosticAnalyzerCategory GetAnalyzerCategory() diff --git a/src/Analyzers/Core/Analyzers/UseObjectInitializer/UseNamedMemberInitializerAnalyzer.cs b/src/Analyzers/Core/Analyzers/UseObjectInitializer/UseNamedMemberInitializerAnalyzer.cs index b9ad90458a74b..1564a3a2d687b 100644 --- a/src/Analyzers/Core/Analyzers/UseObjectInitializer/UseNamedMemberInitializerAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/UseObjectInitializer/UseNamedMemberInitializerAnalyzer.cs @@ -57,7 +57,7 @@ public ImmutableArray> matches, + ArrayBuilder> preMatches, + ArrayBuilder> postMatches, CancellationToken cancellationToken) { using var _1 = PooledHashSet.GetInstance(out var seenNames); @@ -163,7 +164,7 @@ protected sealed override bool TryAddMatches( if (!seenNames.Add(identifier.ValueText)) break; - matches.Add(new Match( + postMatches.Add(new Match( statement, leftMemberAccess, rightExpression, typeMember?.Name ?? identifier.ValueText)); } diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf index 783b82502cec7..d0248fe8779b0 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf @@ -96,6 +96,11 @@ Vyhněte se v kódu nepoužitým parametrům. Pokud parametr nelze odebrat, změňte jeho název tak, aby začínal podtržítkem, za kterým volitelně následuje celé číslo, například _, _1, _2 atd. Tyto řetězce se považují za názvy speciálních symbolů pro vyřazení. + + Base classes contain inaccessible unimplemented members + Základní třídy obsahují nepřístupné nenaimplementované členy. + + Blank line required between block and subsequent statement Mezi blokem a následným příkazem se vyžaduje prázdný řádek. @@ -146,6 +151,16 @@ Implementace GetHashCode může být zjednodušená. + + Implement abstract class + Implementovat abstraktní třídu + + + + Implement through '{0}' + Implementovat přes {0} + + Interpolation can be simplified Interpolace může být zjednodušená. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf index ad65305a6d402..c486b28641859 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf @@ -96,6 +96,11 @@ Vermeiden Sie nicht verwendete Parameter in Ihrem Code. Wenn der Parameter nicht entfernt werden kann, ändern Sie dessen Namen so, dass er mit einem Unterstrich beginnt, dem optional eine Zahl angefügt wird. Beispiel: "_", "_1", "_2" usw. Diese werden als spezielle Symbolnamen für Ausschussparameter behandelt. + + Base classes contain inaccessible unimplemented members + Basisklassen enthalten nicht implementierte Member, auf die nicht zugegriffen werden kann. + + Blank line required between block and subsequent statement Zwischen dem Block und der nachfolgenden Anweisung ist eine leere Zeile erforderlich. @@ -146,6 +151,16 @@ Die Implementierung von "GetHashCode" kann vereinfacht werden. + + Implement abstract class + Abstrakte Klasse implementieren + + + + Implement through '{0}' + Über "{0}" implementieren + + Interpolation can be simplified Die Interpolation kann vereinfacht werden diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf index b0f143d75f44e..bbda0137154b4 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf @@ -96,6 +96,11 @@ Evite los parámetros sin usar en el código. Si el parámetro no se puede quitar, cámbielo de nombre para que empiece por un carácter de subrayado, seguido opcionalmente por un entero, como "_", "_1", "_2", etc. Estos se tratan como nombres de símbolos de descarte especiales. + + Base classes contain inaccessible unimplemented members + Las clases base contienen miembros no implementados que son inaccesibles. + + Blank line required between block and subsequent statement Se requiere una línea en blanco entre el bloque y la instrucción subsiguiente @@ -146,6 +151,16 @@ La implementación de "GetHashCode" se puede simplificar. + + Implement abstract class + Implementar clase abstracta + + + + Implement through '{0}' + Implementar a través de "{0}" + + Interpolation can be simplified La interpolación se puede simplificar diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf index a104342f0da5b..62df8a0e61ef6 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf @@ -96,6 +96,11 @@ Évitez les paramètres inutilisés dans votre code. Évitez les paramètres inutilisés dans votre code. Si vous ne pouvez pas supprimer un paramètre, changez son nom en le faisant commencer par un trait de soulignement éventuellement suivi d'un entier, par exemple '_', '_1', '_2', etc. Ces types d'élément sont traités en tant que noms de symboles discard spéciaux. + + Base classes contain inaccessible unimplemented members + Les classes de base contiennent des membres non implémentés inaccessibles + + Blank line required between block and subsequent statement Ligne vide nécessaire entre le bloc et l'instruction qui suit @@ -146,6 +151,16 @@ L'implémentation de 'GetHashCode' peut être simplifiée + + Implement abstract class + Implémenter une classe abstraite + + + + Implement through '{0}' + Implémenter via '{0}' + + Interpolation can be simplified L'interpolation peut être simplifiée diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf index 3dd221c998368..c209161779bf2 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf @@ -96,6 +96,11 @@ Evitare parametri inutilizzati nel codice. Se non è possibile rimuovere il parametro, modificarne il nome in modo che inizi con un carattere di sottolineatura e, facoltativamente, sia seguito da un numero intero, ad esempio '_', '_1', '_2' e così via. Questi vengono considerati come nomi di simboli speciali di rimozione. + + Base classes contain inaccessible unimplemented members + Le classi di base contengono membri non implementati inaccessibili + + Blank line required between block and subsequent statement È richiesta una riga vuota tra il blocco e l'istruzione successiva @@ -146,6 +151,16 @@ L'implementazione di 'GetHashCode' può essere semplificata + + Implement abstract class + Implementa la classe astratta + + + + Implement through '{0}' + Implementa tramite '{0}' + + Interpolation can be simplified L'interpolazione può essere semplificata diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf index 187e5e137d9f7..5722141523a15 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf @@ -97,6 +97,11 @@ コードに未使用のパラメーターを指定しないでください。パラメーターを削除できない場合は、パラメーターの名前をアンダースコアの後にオプションで整数が続く名前 ('_'、'_1'、'_2' など) に変更してください。これらは、特別なディスカード シンボル名として扱われます。 + + Base classes contain inaccessible unimplemented members + アクセス不可能な未実装のメンバーが基底クラスに含まれています + + Blank line required between block and subsequent statement ブロックと後続のステートメントの間に空白行が必要です @@ -147,6 +152,16 @@ 'GetHashCode' の実装を簡素化できます + + Implement abstract class + 抽象クラスの実装 + + + + Implement through '{0}' + '{0}' を通じて実装します + + Interpolation can be simplified 補間を簡素化することができます diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf index bf7482fa9dac3..5e9e27116dab6 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf @@ -96,6 +96,11 @@ 코드에 사용되지 않는 매개 변수를 사용하지 않도록 합니다. 매개 변수를 제거할 수 없는 경우 이름을 변경하여 밑줄로 시작하고 필요에 따라 뒤에 정수가 있도록 합니다(예: '_', '_1', '_2' 등). 해당 이름은 특수 무시 기호 이름으로 처리됩니다. + + Base classes contain inaccessible unimplemented members + 기본 클래스에 구현되지 않아 액세스할 수 없는 멤버가 포함되어 있습니다. + + Blank line required between block and subsequent statement 블록과 후속 문 사이에 빈 줄이 필요함 @@ -146,6 +151,16 @@ 'GetHashCode' 구현을 단순화할 수 있습니다. + + Implement abstract class + 추상 클래스 구현 + + + + Implement through '{0}' + '{0}'을(를) 통해 구현 + + Interpolation can be simplified 보간을 단순화할 수 있습니다. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf index 48f6db3801bcf..dbd0d8a7e6498 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf @@ -96,6 +96,11 @@ Unikaj nieużywanych parametrów w kodzie. Jeśli nie można usunąć parametru, zmień jego nazwę, tak aby rozpoczynała się od znaku podkreślenia, a opcjonalnie następowała po niej liczba całkowita, na przykład „_”, „_1”, „_2” itp. Są one traktowane jako specjalne nazwy symboli odrzucenia. + + Base classes contain inaccessible unimplemented members + Klasy podstawowe zawierają niedostępne niezaimplementowane składowe + + Blank line required between block and subsequent statement Wymagany jest pusty wiersz między blokiem a kolejną instrukcją @@ -146,6 +151,16 @@ Implementację „GetHashCode” można uprościć + + Implement abstract class + Implementuj klasę abstrakcyjną + + + + Implement through '{0}' + Implementuj za pomocą elementu „{0}” + + Interpolation can be simplified Interpolację można uprościć diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf index 6bc52c076ab6f..51e2a0e7acd64 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf @@ -96,6 +96,11 @@ Evite parâmetros não usados no seu código. Se o parâmetro não puder ser removido, altere o nome para que ele comece com um sublinhado e seja seguido opcionalmente por um inteiro, como '_', '_1', '_2' etc. Esses nomes são tratados como nomes de símbolo de descarte especiais. + + Base classes contain inaccessible unimplemented members + As classes base contêm membros não implementados inacessíveis + + Blank line required between block and subsequent statement Linha em branco necessária entre o bloco e a próxima instrução @@ -146,6 +151,16 @@ A implementação de 'GetHashCode' pode ser simplificada + + Implement abstract class + Implementar classe abstrata + + + + Implement through '{0}' + Implementar por meio de '{0}' + + Interpolation can be simplified A interpolação pode ser simplificada diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf index 4e8b7cd4df423..1e0cea3951856 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf @@ -96,6 +96,11 @@ Избегайте неиспользуемых параметров в коде. Если удалить параметр невозможно, измените его имя так, чтобы оно начиналось с символа подчеркивания, за которым при необходимости следует целое число, например, "_", "_1", "_2" и т. д. Эти имена считаются особыми пустыми именами символов. + + Base classes contain inaccessible unimplemented members + Базовые классы содержат недоступные нереализованные члены + + Blank line required between block and subsequent statement Необходима пустая линия между блоком и следующим оператором. @@ -146,6 +151,16 @@ Реализацию GetHashCode можно упростить. + + Implement abstract class + Реализовать абстрактный класс + + + + Implement through '{0}' + Реализовать через "{0}" + + Interpolation can be simplified Вы можете упростить интерполяцию. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf index cb77bb7ac663e..5ffcc4f3c7fc8 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf @@ -96,6 +96,11 @@ Kodunuzda kullanılmayan parametreler bulundurmamaya çalışın. Parametre kaldırılamıyorsa adını, bir alt çizgiyle başlayacak ve ardından isteğe bağlı olarak bir tamsayı gelecek ('_', '_1', '_2' gibi) şekilde değiştirin. Bu değerler özel atılabilir sembol adı olarak işlenir. + + Base classes contain inaccessible unimplemented members + Temel sınıflarda erişilemeyen, uygulanmamış üyeler var + + Blank line required between block and subsequent statement Blok ve sonraki ifade arasında boş satır gerekir @@ -146,6 +151,16 @@ 'GetHashCode' uygulaması basitleştirilebilir + + Implement abstract class + Soyut sınıfı uygula + + + + Implement through '{0}' + '{0}' aracılığıyla uygula + + Interpolation can be simplified İlişkilendirme basitleştirilebilir diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf index f5d7fc08b5ef2..6d60cb626c2ce 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf @@ -96,6 +96,11 @@ 请避免在代码中使用未使用的参数。如果无法删除该参数,请更改其名称,使其以下划线开头,也可在下划线后面跟一个整数(如 "_"、"_1"、"_2" 等)。这些被视为特殊丢弃符号名。 + + Base classes contain inaccessible unimplemented members + 基类包含无法访问的未实现成员 + + Blank line required between block and subsequent statement 块与后续语句之间需要有空白行 @@ -146,6 +151,16 @@ 可简化 "GetHashCode" 实现 + + Implement abstract class + 实现抽象类 + + + + Implement through '{0}' + 通过“{0}”实现 + + Interpolation can be simplified 内插可以简化 diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf index b69c3d9e738ad..968c91af7e239 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf @@ -96,6 +96,11 @@ 請避免在您的程式碼中使用參數。如果無法移除參數,請變更其名稱,使其以底線開頭,並可選擇在後面接著整數,例如 '_'、'_1'、'_2' 等。這些會視為特殊的捨棄符號名稱。 + + Base classes contain inaccessible unimplemented members + 基底類別包含無法存取的未實作成員 + + Blank line required between block and subsequent statement 區塊與後續陳述式之間必須有空白行 @@ -146,6 +151,16 @@ 'GetHashCode' 實作可簡化 + + Implement abstract class + 實作抽象類別 + + + + Implement through '{0}' + 透過 '{0}' 實作 + + Interpolation can be simplified 可簡化內插補點 diff --git a/src/Analyzers/Core/CodeFixes/AddParameter/RegisterFixData.cs b/src/Analyzers/Core/CodeFixes/AddParameter/RegisterFixData.cs index 033a326a6a5bc..9204d08cc5540 100644 --- a/src/Analyzers/Core/CodeFixes/AddParameter/RegisterFixData.cs +++ b/src/Analyzers/Core/CodeFixes/AddParameter/RegisterFixData.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.AddParameter; -internal class RegisterFixData(SeparatedSyntaxList arguments, ImmutableArray methodCandidates, bool isConstructorInitializer) +internal sealed class RegisterFixData(SeparatedSyntaxList arguments, ImmutableArray methodCandidates, bool isConstructorInitializer) where TArgumentSyntax : SyntaxNode { public RegisterFixData() : this([], [], false) diff --git a/src/Analyzers/Core/CodeFixes/AddRequiredParentheses/AddRequiredParenthesesCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/AddRequiredParentheses/AddRequiredParenthesesCodeFixProvider.cs index 0e0eb0e65c4bf..97ccef4d02f49 100644 --- a/src/Analyzers/Core/CodeFixes/AddRequiredParentheses/AddRequiredParenthesesCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/AddRequiredParentheses/AddRequiredParenthesesCodeFixProvider.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.AddRequiredParentheses; [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.AddRequiredParentheses), Shared] [method: ImportingConstructor] [method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] -internal class AddRequiredParenthesesCodeFixProvider() : SyntaxEditorBasedCodeFixProvider +internal sealed class AddRequiredParenthesesCodeFixProvider() : SyntaxEditorBasedCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => [IDEDiagnosticIds.AddRequiredParenthesesDiagnosticId]; diff --git a/src/Analyzers/Core/CodeFixes/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs index 9a471eb13795c..841a9a77dc4c9 100644 --- a/src/Analyzers/Core/CodeFixes/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs @@ -48,7 +48,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var syntaxGenerator = document.GetRequiredLanguageService(); var compilation = semanticModel.Compilation; - var placementOption = await document.GetAddImportPlacementOptionsAsync(addImportService, cancellationToken).ConfigureAwait(false); + var placementOption = await document.GetAddImportPlacementOptionsAsync(cancellationToken).ConfigureAwait(false); using var _ = ArrayBuilder.GetInstance(out var actions); foreach (var symbol in Sort(symbolInfo.CandidateSymbols.Cast(), placementOption.PlaceSystemNamespaceFirst)) diff --git a/src/Analyzers/Core/CodeFixes/CodeFixes.projitems b/src/Analyzers/Core/CodeFixes/CodeFixes.projitems index 82fd681da3329..4bd44bf11c75d 100644 --- a/src/Analyzers/Core/CodeFixes/CodeFixes.projitems +++ b/src/Analyzers/Core/CodeFixes/CodeFixes.projitems @@ -10,7 +10,9 @@ - + + Designer + @@ -36,8 +38,64 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -48,6 +106,8 @@ + + @@ -71,7 +131,7 @@ - + diff --git a/src/Analyzers/Core/CodeFixes/CodeFixesResources.resx b/src/Analyzers/Core/CodeFixes/CodeFixesResources.resx index 996617169b118..187f356cea199 100644 --- a/src/Analyzers/Core/CodeFixes/CodeFixesResources.resx +++ b/src/Analyzers/Core/CodeFixes/CodeFixesResources.resx @@ -213,4 +213,109 @@ {0} (may change semantics) + + Generate constructor in '{0}' + + + Generate constructor in '{0}' (with fields) + + + Generate constructor in '{0}' (with properties) + + + Generate constructor '{0}({1})' + + + Generate all + + + Generate field assigning constructor '{0}({1})' + + + Implement interface abstractly + + + Implement interface through '{0}' + + + Implement interface with Dispose pattern + + + Implement interface explicitly with Dispose pattern + + + Implement remaining members explicitly + + + Implement interface + + + Implement all members explicitly + + + TODO: dispose managed state (managed objects) + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + + + TODO: set large fields to null + + + Do not change this code. Put cleanup code in '{0}' method + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + + + Generate constant '{0}' + + + Generate read-only field '{0}' + + + Generate read-only property '{0}' + + + Generate field '{0}' + + + Generate local '{0}' + + + Generate parameter '{0}' + + + Generate parameter '{0}' (and overrides/implementations) + + + Generate variable '{0}' + + + Generate enum member '{0}' + + + Generate abstract method '{0}' + + + Generate abstract property '{0}' + + + Generate method '{0}' + + + Generate property '{0}' + + + Generate narrowing conversion in '{0}' + + + Generate widening conversion in '{0}' + + + Generate implicit conversion operator in '{0}' + + + Generate explicit conversion operator in '{0}' + \ No newline at end of file diff --git a/src/Analyzers/Core/CodeFixes/DocumentationComments/AbstractAddDocCommentNodesCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/DocumentationComments/AbstractAddDocCommentNodesCodeFixProvider.cs index 0305ba86a6e61..f246df1c44541 100644 --- a/src/Analyzers/Core/CodeFixes/DocumentationComments/AbstractAddDocCommentNodesCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/DocumentationComments/AbstractAddDocCommentNodesCodeFixProvider.cs @@ -94,7 +94,7 @@ protected async Task AddParamTagAsync( nodeBeforeNewParamNode ??= summaryNode; newDocComment = newDocComment.InsertNodesAfter(nodeBeforeNewParamNode!, - new[] { GetNewNode(parameterName, isFirstNodeInComment: false) }); + [GetNewNode(parameterName, isFirstNodeInComment: false)]); continue; } diff --git a/src/Analyzers/Core/CodeFixes/FileHeaders/AbstractFileHeaderCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/FileHeaders/AbstractFileHeaderCodeFixProvider.cs index f2996a7356445..40061d4fb71dd 100644 --- a/src/Analyzers/Core/CodeFixes/FileHeaders/AbstractFileHeaderCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/FileHeaders/AbstractFileHeaderCodeFixProvider.cs @@ -48,7 +48,7 @@ private async Task GetTransformedDocumentAsync(Document document, Canc private async Task GetTransformedSyntaxRootAsync(Document document, CancellationToken cancellationToken) { - var options = await document.GetCodeFixOptionsAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetLineFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var generator = document.GetRequiredLanguageService(); var newLineTrivia = generator.EndOfLine(options.NewLine); diff --git a/src/Analyzers/Core/CodeFixes/ForEachCast/AbstractForEachCastCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/ForEachCast/AbstractForEachCastCodeFixProvider.cs index 21055abecac29..87cff8def721e 100644 --- a/src/Analyzers/Core/CodeFixes/ForEachCast/AbstractForEachCastCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/ForEachCast/AbstractForEachCastCodeFixProvider.cs @@ -96,7 +96,7 @@ private SyntaxNode GetRewrittenCollection( collection, generator.GenericName( nameof(Enumerable.Cast), - new[] { iterationVariableType }))); + [iterationVariableType]))); } else { diff --git a/src/Analyzers/Core/CodeFixes/Formatting/FormattingCodeFixHelper.cs b/src/Analyzers/Core/CodeFixes/Formatting/FormattingCodeFixHelper.cs deleted file mode 100644 index a20c0646ab33c..0000000000000 --- a/src/Analyzers/Core/CodeFixes/Formatting/FormattingCodeFixHelper.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Text; - -using Formatter = Microsoft.CodeAnalysis.Formatting.FormatterHelper; -using FormattingProvider = Microsoft.CodeAnalysis.Formatting.ISyntaxFormatting; - -namespace Microsoft.CodeAnalysis; - -internal static class FormattingCodeFixHelper -{ - internal static async Task FixOneAsync(SyntaxTree syntaxTree, FormattingProvider formattingProvider, SyntaxFormattingOptions options, Diagnostic diagnostic, CancellationToken cancellationToken) - { - // The span to format is the full line(s) containing the diagnostic - var text = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); - var diagnosticSpan = diagnostic.Location.SourceSpan; - var diagnosticLinePositionSpan = text.Lines.GetLinePositionSpan(diagnosticSpan); - var spanToFormat = TextSpan.FromBounds( - text.Lines[diagnosticLinePositionSpan.Start.Line].Start, - text.Lines[diagnosticLinePositionSpan.End.Line].End); - - var root = await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); - var formattedRoot = Formatter.Format(root, spanToFormat, formattingProvider, options, cancellationToken); - - return syntaxTree.WithRootAndOptions(formattedRoot, syntaxTree.Options); - } -} diff --git a/src/Analyzers/Core/CodeFixes/Formatting/FormattingCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/Formatting/FormattingCodeFixProvider.cs index 15d5ceb71cbd3..65b24aaac1ae2 100644 --- a/src/Analyzers/Core/CodeFixes/Formatting/FormattingCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/Formatting/FormattingCodeFixProvider.cs @@ -11,8 +11,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; - -using Formatter = Microsoft.CodeAnalysis.Formatting.FormatterHelper; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CodeStyle; @@ -62,18 +61,26 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) private async Task FixOneAsync(CodeFixContext context, Diagnostic diagnostic, CancellationToken cancellationToken) { - var options = await context.Document.GetCodeFixOptionsAsync(cancellationToken).ConfigureAwait(false); - var formattingOptions = options.GetFormattingOptions(SyntaxFormatting); - var tree = await context.Document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var updatedTree = await FormattingCodeFixHelper.FixOneAsync(tree, SyntaxFormatting, formattingOptions, diagnostic, cancellationToken).ConfigureAwait(false); - return context.Document.WithText(await updatedTree.GetTextAsync(cancellationToken).ConfigureAwait(false)); + var root = await context.Document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var text = root.GetText(); + + // The span to format is the full line(s) containing the diagnostic + var diagnosticSpan = diagnostic.Location.SourceSpan; + var diagnosticLinePositionSpan = text.Lines.GetLinePositionSpan(diagnosticSpan); + var spanToFormat = TextSpan.FromBounds( + text.Lines[diagnosticLinePositionSpan.Start.Line].Start, + text.Lines[diagnosticLinePositionSpan.End.Line].End); + + var formattingOptions = await context.Document.GetSyntaxFormattingOptionsAsync(SyntaxFormatting, cancellationToken).ConfigureAwait(false); + var formattedRoot = SyntaxFormatting.GetFormattingResult(root, [spanToFormat], formattingOptions, rules: default, cancellationToken: cancellationToken).GetFormattedRoot(cancellationToken); + + return context.Document.WithSyntaxRoot(formattedRoot); } protected override async Task FixAllAsync(Document document, ImmutableArray diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { - var options = await document.GetCodeFixOptionsAsync(cancellationToken).ConfigureAwait(false); - var formattingOptions = options.GetFormattingOptions(SyntaxFormatting); - var updatedRoot = Formatter.Format(editor.OriginalRoot, SyntaxFormatting, formattingOptions, cancellationToken); + var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(SyntaxFormatting, cancellationToken).ConfigureAwait(false); + var updatedRoot = SyntaxFormatting.GetFormattingResult(editor.OriginalRoot, [editor.OriginalRoot.FullSpan], formattingOptions, rules: default, cancellationToken).GetFormattedRoot(cancellationToken); editor.ReplaceNode(editor.OriginalRoot, updatedRoot); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs b/src/Analyzers/Core/CodeFixes/GenerateConstructor/AbstractGenerateConstructorService.State.cs similarity index 95% rename from src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateConstructor/AbstractGenerateConstructorService.State.cs index 0f8c62b9c2bba..9a00831f60ba2 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateConstructor/AbstractGenerateConstructorService.State.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -20,11 +21,17 @@ using Microsoft.CodeAnalysis.Utilities; using Roslyn.Utilities; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor; internal abstract partial class AbstractGenerateConstructorService { - protected internal class State + protected internal sealed class State { private readonly TService _service; private readonly SemanticDocument _document; @@ -230,11 +237,14 @@ private bool TryInitializeDelegatedConstructor(CancellationToken cancellationTok return null; } + private TLanguageService GetRequiredLanguageService(string language) where TLanguageService : ILanguageService + => _document.Project.Solution.Workspace.Services.GetExtendedLanguageServices(language).GetRequiredService(); + private bool ClashesWithExistingConstructor() { Contract.ThrowIfNull(TypeToGenerateIn); - var syntaxFacts = _document.Project.Solution.Services.GetRequiredLanguageService(TypeToGenerateIn.Language); + var syntaxFacts = GetRequiredLanguageService(TypeToGenerateIn.Language); return TypeToGenerateIn.InstanceConstructors.Any(static (c, arg) => arg.self.Matches(c, arg.syntaxFacts), (self: this, syntaxFacts)); } @@ -574,10 +584,9 @@ public async Task GetChangedDocumentAsync( Contract.ThrowIfNull(TypeToGenerateIn); - var provider = document.Project.Solution.Services.GetLanguageServices(TypeToGenerateIn.Language); var (members, assignments) = await GenerateMembersAndAssignmentsAsync(document, withFields, withProperties, cancellationToken).ConfigureAwait(false); var isThis = _delegatedConstructor.ContainingType.OriginalDefinition.Equals(TypeToGenerateIn.OriginalDefinition); - var delegatingArguments = provider.GetService().CreateArguments(_delegatedConstructor.Parameters); + var delegatingArguments = this.GetRequiredLanguageService(TypeToGenerateIn.Language).CreateArguments(_delegatedConstructor.Parameters); var newParameters = _delegatedConstructor.Parameters.Concat(_parameters); var generateUnsafe = !IsContainedInUnsafeType && newParameters.Any(static p => p.RequiresUnsafeModifier()); @@ -596,7 +605,7 @@ public async Task GetChangedDocumentAsync( document.Project.Solution, new CodeGenerationContext(Token.GetLocation())); - return await provider.GetRequiredService().AddMembersAsync( + return await CodeGenerator.AddMemberDeclarationsAsync( context, TypeToGenerateIn, members.Concat(constructor), @@ -608,8 +617,6 @@ public async Task GetChangedDocumentAsync( { Contract.ThrowIfNull(TypeToGenerateIn); - var provider = document.Project.Solution.Services.GetLanguageServices(TypeToGenerateIn.Language); - var members = withFields ? SyntaxGeneratorExtensions.CreateFieldsForParameters(_parameters, ParameterToNewFieldMap, IsContainedInUnsafeType) : withProperties ? SyntaxGeneratorExtensions.CreatePropertiesForParameters(_parameters, ParameterToNewPropertyMap, IsContainedInUnsafeType) : []; @@ -617,7 +624,8 @@ public async Task GetChangedDocumentAsync( var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var assignments = !withFields && !withProperties ? [] - : provider.GetRequiredService().CreateAssignmentStatements( + : GetRequiredLanguageService(TypeToGenerateIn.Language).CreateAssignmentStatements( + GetRequiredLanguageService(TypeToGenerateIn.Language), semanticModel, _parameters, _parameterToExistingMemberMap, withFields ? ParameterToNewFieldMap : ParameterToNewPropertyMap, @@ -631,7 +639,6 @@ private async Task GenerateMemberDelegatingConstructorAsync( { Contract.ThrowIfNull(TypeToGenerateIn); - var provider = document.Project.Solution.Services.GetLanguageServices(TypeToGenerateIn.Language); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var newMemberMap = @@ -639,12 +646,13 @@ private async Task GenerateMemberDelegatingConstructorAsync( withProperties ? ParameterToNewPropertyMap : ImmutableDictionary.Empty; - return await provider.GetRequiredService().AddMembersAsync( + return await CodeGenerator.AddMemberDeclarationsAsync( new CodeGenerationSolutionContext( document.Project.Solution, new CodeGenerationContext(Token.GetLocation())), TypeToGenerateIn, - provider.GetRequiredService().CreateMemberDelegatingConstructor( + GetRequiredLanguageService(TypeToGenerateIn.Language).CreateMemberDelegatingConstructor( + GetRequiredLanguageService(TypeToGenerateIn.Language), semanticModel, TypeToGenerateIn.Name, TypeToGenerateIn, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs b/src/Analyzers/Core/CodeFixes/GenerateConstructor/AbstractGenerateConstructorService.cs similarity index 92% rename from src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs rename to src/Analyzers/Core/CodeFixes/GenerateConstructor/AbstractGenerateConstructorService.cs index c5d6f26dec73d..c57d0c9e3af9b 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateConstructor/AbstractGenerateConstructorService.cs @@ -92,25 +92,25 @@ public async Task> GenerateConstructorAsync(Document if (state.ParameterToNewFieldMap.Count > 0) { result.Add(CodeAction.Create( - string.Format(FeaturesResources.Generate_constructor_in_0_with_fields, state.TypeToGenerateIn.Name), + string.Format(CodeFixesResources.Generate_constructor_in_0_with_fields, state.TypeToGenerateIn.Name), c => state.GetChangedDocumentAsync(document, withFields: true, withProperties: false, c), - nameof(FeaturesResources.Generate_constructor_in_0_with_fields) + "_" + state.TypeToGenerateIn.Name)); + nameof(CodeFixesResources.Generate_constructor_in_0_with_fields) + "_" + state.TypeToGenerateIn.Name)); } // Same with a version that generates properties instead. if (state.ParameterToNewPropertyMap.Count > 0) { result.Add(CodeAction.Create( - string.Format(FeaturesResources.Generate_constructor_in_0_with_properties, state.TypeToGenerateIn.Name), + string.Format(CodeFixesResources.Generate_constructor_in_0_with_properties, state.TypeToGenerateIn.Name), c => state.GetChangedDocumentAsync(document, withFields: false, withProperties: true, c), - nameof(FeaturesResources.Generate_constructor_in_0_with_properties) + "_" + state.TypeToGenerateIn.Name)); + nameof(CodeFixesResources.Generate_constructor_in_0_with_properties) + "_" + state.TypeToGenerateIn.Name)); } // Always offer to just generate the constructor and nothing else. result.Add(CodeAction.Create( - string.Format(FeaturesResources.Generate_constructor_in_0, state.TypeToGenerateIn.Name), + string.Format(CodeFixesResources.Generate_constructor_in_0, state.TypeToGenerateIn.Name), c => state.GetChangedDocumentAsync(document, withFields: false, withProperties: false, c), - nameof(FeaturesResources.Generate_constructor_in_0) + "_" + state.TypeToGenerateIn.Name)); + nameof(CodeFixesResources.Generate_constructor_in_0) + "_" + state.TypeToGenerateIn.Name)); return result.ToImmutableAndClear(); } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/Argument.cs b/src/Analyzers/Core/CodeFixes/GenerateConstructor/Argument.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateConstructor/Argument.cs rename to src/Analyzers/Core/CodeFixes/GenerateConstructor/Argument.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/GenerateConstructorHelpers.cs b/src/Analyzers/Core/CodeFixes/GenerateConstructor/GenerateConstructorHelpers.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateConstructor/GenerateConstructorHelpers.cs rename to src/Analyzers/Core/CodeFixes/GenerateConstructor/GenerateConstructorHelpers.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/IGenerateConstructorService.cs b/src/Analyzers/Core/CodeFixes/GenerateConstructor/IGenerateConstructorService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateConstructor/IGenerateConstructorService.cs rename to src/Analyzers/Core/CodeFixes/GenerateConstructor/IGenerateConstructorService.cs diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs similarity index 100% rename from src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs rename to src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs similarity index 93% rename from src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs index a130506638d6d..89d5653afbca1 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs @@ -12,6 +12,12 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.GenerateDefaultConstructors; internal abstract partial class AbstractGenerateDefaultConstructorsService @@ -54,7 +60,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke private IMethodSymbol CreateConstructorDefinition( IMethodSymbol baseConstructor) { - var syntaxFactory = _document.GetLanguageService(); + var syntaxFactory = _document.GetRequiredLanguageService(); var baseConstructorArguments = baseConstructor.Parameters.Length != 0 ? syntaxFactory.CreateArguments(baseConstructor.Parameters) : default; diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs similarity index 92% rename from src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs index f62af687ffcff..15fbd76cc4bbf 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs @@ -20,7 +20,7 @@ private static string GetDisplayText(State state, IMethodSymbol constructor) var parameterString = string.Join(", ", parameters); Contract.ThrowIfNull(state.ClassType); - return string.Format(FeaturesResources.Generate_constructor_0_1, + return string.Format(CodeFixesResources.Generate_constructor_0_1, state.ClassType.Name, parameterString); } } diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs similarity index 79% rename from src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs rename to src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs index 550c351653a00..4a26c4fb5b15d 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs @@ -12,7 +12,8 @@ internal abstract partial class AbstractGenerateDefaultConstructorsService constructors) : AbstractCodeAction(document, state, constructors, FeaturesResources.Generate_all) + IList constructors) + : AbstractCodeAction(document, state, constructors, CodeFixesResources.Generate_all) { } } diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs similarity index 99% rename from src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs index 9589a1571c1e5..9d3596e0dcacc 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.State.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.GenerateDefaultConstructors; internal abstract partial class AbstractGenerateDefaultConstructorsService { - private class State + private sealed class State { public INamedTypeSymbol? ClassType { get; private set; } diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs similarity index 96% rename from src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs rename to src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs index 0476ef6ab81b9..7b7ab477f87cc 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs @@ -17,10 +17,6 @@ namespace Microsoft.CodeAnalysis.GenerateDefaultConstructors; internal abstract partial class AbstractGenerateDefaultConstructorsService : IGenerateDefaultConstructorsService where TService : AbstractGenerateDefaultConstructorsService { - protected AbstractGenerateDefaultConstructorsService() - { - } - protected abstract bool TryInitializeState( SemanticDocument document, TextSpan textSpan, CancellationToken cancellationToken, [NotNullWhen(true)] out INamedTypeSymbol? classType); diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/IGenerateDefaultConstructorsService.cs b/src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/IGenerateDefaultConstructorsService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateDefaultConstructors/IGenerateDefaultConstructorsService.cs rename to src/Analyzers/Core/CodeFixes/GenerateDefaultConstructors/IGenerateDefaultConstructorsService.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs b/src/Analyzers/Core/CodeFixes/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs similarity index 85% rename from src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs index 48cf055fa3c7f..246c4a98ecc31 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs @@ -10,19 +10,20 @@ using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateEnumMember; internal abstract partial class AbstractGenerateEnumMemberService { - private partial class GenerateEnumMemberCodeAction(Document document, State state) : CodeAction + private sealed partial class GenerateEnumMemberCodeAction(Document document, State state) : CodeAction { private readonly Document _document = document; private readonly State _state = state; protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) { - var languageServices = _document.Project.Solution.Services.GetLanguageServices(_state.TypeToGenerateIn.Language); + var languageServices = _document.Project.Solution.Workspace.Services.GetExtendedLanguageServices(_state.TypeToGenerateIn.Language); var codeGenerator = languageServices.GetService(); var semanticFacts = languageServices.GetService(); @@ -54,7 +55,7 @@ public override string Title get { return string.Format( - FeaturesResources.Generate_enum_member_0, _state.IdentifierToken.ValueText); + CodeFixesResources.Generate_enum_member_0, _state.IdentifierToken.ValueText); } } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs b/src/Analyzers/Core/CodeFixes/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs similarity index 99% rename from src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs index b2c3082f20d4c..a40b360a6f370 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateEnumMember/AbstractGenerateEnumMemberService.State.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateEnumMember; internal abstract partial class AbstractGenerateEnumMemberService { - private partial class State + private sealed partial class State { // public TypeDeclarationSyntax ContainingTypeDeclaration { get; private set; } public INamedTypeSymbol TypeToGenerateIn { get; private set; } = null!; diff --git a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.cs b/src/Analyzers/Core/CodeFixes/GenerateEnumMember/AbstractGenerateEnumMemberService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.cs rename to src/Analyzers/Core/CodeFixes/GenerateEnumMember/AbstractGenerateEnumMemberService.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/IGenerateEnumMemberService.cs b/src/Analyzers/Core/CodeFixes/GenerateEnumMember/IGenerateEnumMemberService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateEnumMember/IGenerateEnumMemberService.cs rename to src/Analyzers/Core/CodeFixes/GenerateEnumMember/IGenerateEnumMemberService.cs diff --git a/src/Features/Core/Portable/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs similarity index 100% rename from src/Features/Core/Portable/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs rename to src/Analyzers/Core/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs diff --git a/src/Features/Core/Portable/GenerateMember/AbstractGenerateMemberService.cs b/src/Analyzers/Core/CodeFixes/GenerateMember/AbstractGenerateMemberService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/AbstractGenerateMemberService.cs rename to src/Analyzers/Core/CodeFixes/GenerateMember/AbstractGenerateMemberService.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateConversionService.State.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateConversionService.State.cs similarity index 96% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateConversionService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateConversionService.State.cs index ecea2b427e733..9943477c58250 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateConversionService.State.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateConversionService.State.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; -internal partial class AbstractGenerateConversionService +internal abstract partial class AbstractGenerateConversionService { protected new class State : AbstractGenerateParameterizedMemberService.State { diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateConversionService.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateConversionService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateConversionService.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateConversionService.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs similarity index 92% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs index adefeff36e7b1..f89ee4f535a58 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; -internal partial class AbstractGenerateDeconstructMethodService +internal abstract partial class AbstractGenerateDeconstructMethodService { internal new class State : AbstractGenerateParameterizedMemberService.State @@ -47,7 +47,8 @@ private async Task TryInitializeMethodAsync( { TypeToGenerateIn = typeToGenerateIn; IsStatic = false; - var generator = SyntaxGenerator.GetGenerator(document.Document); + var generator = document.Document.GetRequiredLanguageService(); + IdentifierToken = generator.Identifier(WellKnownMemberNames.DeconstructMethodName); MethodGenerationKind = MethodGenerationKind.Member; MethodKind = MethodKind.Ordinary; diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs similarity index 98% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs index 05ead69c62417..80ce3f8f46692 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; -internal partial class AbstractGenerateMethodService +internal abstract partial class AbstractGenerateMethodService { internal new class State : AbstractGenerateParameterizedMemberService.State { diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateMethodService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateMethodService.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs similarity index 96% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs index 7cd296978ce7b..163d6abfdb221 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.AbstractInvocationInfo.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; -internal partial class AbstractGenerateParameterizedMemberService +internal abstract partial class AbstractGenerateParameterizedMemberService { internal abstract class AbstractInvocationInfo : SignatureInfo { diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs similarity index 92% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs index 24dc35aa27167..70068fcd94e55 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; internal abstract partial class AbstractGenerateParameterizedMemberService { - private partial class GenerateParameterizedMemberCodeAction : CodeAction + private sealed partial class GenerateParameterizedMemberCodeAction : CodeAction { private readonly TService _service; private readonly Document _document; @@ -48,8 +48,8 @@ private string GetDisplayText( { case MethodGenerationKind.Member: var text = generateProperty - ? isAbstract ? FeaturesResources.Generate_abstract_property_0 : FeaturesResources.Generate_property_0 - : isAbstract ? FeaturesResources.Generate_abstract_method_0 : FeaturesResources.Generate_method_0; + ? isAbstract ? CodeFixesResources.Generate_abstract_property_0 : CodeFixesResources.Generate_property_0 + : isAbstract ? CodeFixesResources.Generate_abstract_method_0 : CodeFixesResources.Generate_method_0; var name = state.IdentifierToken.ValueText; return string.Format(text, name); diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.MethodSignatureInfo.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.MethodSignatureInfo.cs similarity index 93% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.MethodSignatureInfo.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.MethodSignatureInfo.cs index 19acf4510a645..19ce33d45b055 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.MethodSignatureInfo.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.MethodSignatureInfo.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; -internal partial class AbstractGenerateParameterizedMemberService +internal abstract partial class AbstractGenerateParameterizedMemberService { protected class MethodSignatureInfo( SemanticDocument document, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs similarity index 97% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs index dcde4780a25f6..73576ea358ae1 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs @@ -13,12 +13,19 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Utilities; using Roslyn.Utilities; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; internal abstract partial class AbstractGenerateParameterizedMemberService @@ -118,7 +125,8 @@ public async ValueTask GenerateMethodAsync( methodKind: State.MethodKind); // Ensure no conflicts between type parameter names and parameter names. - var languageServiceProvider = Document.Project.Solution.Services.GetLanguageServices(State.TypeToGenerateIn.Language); + var languageServiceProvider = Document.Project.Solution.Workspace.Services.GetExtendedLanguageServices(State.TypeToGenerateIn.Language); + var syntaxFacts = languageServiceProvider.GetService(); var equalityComparer = syntaxFacts.StringComparer; diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs similarity index 90% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs index 59fa09abb2e3b..41799eb28f0c7 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.State.cs @@ -13,10 +13,11 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; -internal partial class AbstractGenerateParameterizedMemberService +internal abstract partial class AbstractGenerateParameterizedMemberService { internal abstract class State { @@ -77,10 +78,12 @@ protected async Task TryFinishInitializingStateAsync(TService service, Sem // errors. In the former case we definitely want to offer to generate a method. In // the latter case, we want to generate a method *unless* there's an existing method // with the same signature. - var existingMethods = TypeToGenerateIn.GetMembers(IdentifierToken.ValueText) - .OfType(); + var existingMethods = TypeToGenerateIn + .GetMembers(IdentifierToken.ValueText) + .OfType(); + + var destinationProvider = document.Project.Solution.Workspace.Services.GetExtendedLanguageServices(TypeToGenerateIn.Language); - var destinationProvider = document.Project.Solution.Services.GetLanguageServices(TypeToGenerateIn.Language); var syntaxFacts = destinationProvider.GetService(); var syntaxFactory = destinationProvider.GetService(); IsContainedInUnsafeType = service.ContainingTypesOrSelfHasUnsafeKeyword(TypeToGenerateIn); diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs similarity index 94% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs index fef378293e666..f194be1ce987e 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.PooledObjects; @@ -54,7 +54,7 @@ protected async ValueTask> GetActionsAsync(Document d if (canGenerateAbstractly) result.Add(new GenerateParameterizedMemberCodeAction((TService)this, document, state, isAbstract: true, generateProperty: false)); - var semanticFacts = document.Project.Solution.Services.GetLanguageServices(state.TypeToGenerateIn.Language).GetService(); + var semanticFacts = document.Project.Solution.Workspace.Services.GetExtendedLanguageServices(state.TypeToGenerateIn.Language).GetService(); if (semanticFacts.SupportsParameterizedProperties && state.InvocationExpressionOpt != null) diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateConversionService.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/IGenerateConversionService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateConversionService.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/IGenerateConversionService.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateDeconstructMemberService.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/IGenerateDeconstructMemberService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateDeconstructMemberService.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/IGenerateDeconstructMemberService.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateParameterizedMemberService.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/IGenerateParameterizedMemberService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateParameterizedMemberService.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/IGenerateParameterizedMemberService.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/MethodGenerationKind.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/MethodGenerationKind.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/MethodGenerationKind.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/MethodGenerationKind.cs diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/TypeParameterSubstitution.cs b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/TypeParameterSubstitution.cs similarity index 97% rename from src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/TypeParameterSubstitution.cs rename to src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/TypeParameterSubstitution.cs index 2d7c248380b3c..64bf51190cffa 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/TypeParameterSubstitution.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateParameterizedMember/TypeParameterSubstitution.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; -internal partial class AbstractGenerateParameterizedMemberService +internal abstract partial class AbstractGenerateParameterizedMemberService { private static async ValueTask ReplaceTypeParametersBasedOnTypeConstraintsAsync( Project project, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs similarity index 93% rename from src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs index 4c5a8e168bf49..266549ab37266 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs @@ -15,11 +15,17 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.GenerateMember.GenerateVariable; internal abstract partial class AbstractGenerateVariableService { - private partial class GenerateVariableCodeAction : CodeAction + private sealed partial class GenerateVariableCodeAction : CodeAction { private readonly State _state; private readonly bool _generateProperty; @@ -177,10 +183,10 @@ public override string Title get { var text = _isConstant - ? FeaturesResources.Generate_constant_0 + ? CodeFixesResources.Generate_constant_0 : _generateProperty - ? _isReadonly ? FeaturesResources.Generate_read_only_property_0 : FeaturesResources.Generate_property_0 - : _isReadonly ? FeaturesResources.Generate_read_only_field_0 : FeaturesResources.Generate_field_0; + ? _isReadonly ? CodeFixesResources.Generate_read_only_property_0 : CodeFixesResources.Generate_property_0 + : _isReadonly ? CodeFixesResources.Generate_read_only_field_0 : CodeFixesResources.Generate_field_0; return string.Format( text, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs similarity index 94% rename from src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs index 27009e75e9acf..211d03906c979 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateVariable; -internal partial class AbstractGenerateVariableService +internal abstract partial class AbstractGenerateVariableService { private sealed class GenerateLocalCodeAction(TService service, Document document, State state) : CodeAction { @@ -28,7 +28,7 @@ public override string Title { get { - var text = FeaturesResources.Generate_local_0; + var text = CodeFixesResources.Generate_local_0; return string.Format( text, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs similarity index 86% rename from src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs rename to src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs index ab8cff038de7f..013ad8b00f533 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.GenerateParameterCodeAction.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateVariable; -internal partial class AbstractGenerateVariableService +internal abstract partial class AbstractGenerateVariableService { private sealed class GenerateParameterCodeAction(Document document, State state, bool includeOverridesAndImplementations, int parameterIndex) : CodeAction { @@ -25,8 +25,8 @@ public override string Title get { var text = _includeOverridesAndImplementations - ? FeaturesResources.Generate_parameter_0_and_overrides_implementations - : FeaturesResources.Generate_parameter_0; + ? CodeFixesResources.Generate_parameter_0_and_overrides_implementations + : CodeFixesResources.Generate_parameter_0; return string.Format( text, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.State.cs b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.State.cs similarity index 99% rename from src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.State.cs rename to src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.State.cs index 54921a9de274d..d6d61f9186ac8 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.State.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.State.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateVariable; internal abstract partial class AbstractGenerateVariableService { - private partial class State + private sealed partial class State { private readonly TService _service; private readonly SemanticDocument _document; diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.cs b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.cs similarity index 99% rename from src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.cs rename to src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.cs index 3aa8496a69924..a6e6702cd5762 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.cs +++ b/src/Analyzers/Core/CodeFixes/GenerateVariable/AbstractGenerateVariableService.cs @@ -80,7 +80,7 @@ public async Task> GenerateVariableAsync( // Wrap the generate variable actions into a single top level suggestion // so as to not clutter the list. return [CodeAction.Create( - string.Format(FeaturesResources.Generate_variable_0, state.IdentifierToken.ValueText), + string.Format(CodeFixesResources.Generate_variable_0, state.IdentifierToken.ValueText), actions.ToImmutable(), isInlinable: true)]; } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/IGenerateVariableService.cs b/src/Analyzers/Core/CodeFixes/GenerateVariable/IGenerateVariableService.cs similarity index 100% rename from src/Features/Core/Portable/GenerateMember/GenerateVariable/IGenerateVariableService.cs rename to src/Analyzers/Core/CodeFixes/GenerateVariable/IGenerateVariableService.cs diff --git a/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs similarity index 87% rename from src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs rename to src/Analyzers/Core/CodeFixes/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs index d62200df8bb55..89b813f459da6 100644 --- a/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.ImplementType; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.ImplementAbstractClass; @@ -39,7 +40,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; var data = await ImplementAbstractClassData.TryGetDataAsync( - document, classNode, GetClassIdentifier(classNode), context.Options.GetOptions(document.Project.Services).ImplementTypeOptions, cancellationToken).ConfigureAwait(false); + document, classNode, GetClassIdentifier(classNode), cancellationToken).ConfigureAwait(false); if (data == null) return; @@ -47,7 +48,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var id = GetCodeActionId(abstractClassType.ContainingAssembly.Name, abstractClassType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); context.RegisterCodeFix( CodeAction.Create( - FeaturesResources.Implement_abstract_class, + AnalyzersResources.Implement_abstract_class, c => data.ImplementAbstractClassAsync(throughMember: null, canDelegateAllMembers: null, c), id), context.Diagnostics); @@ -61,7 +62,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) context.RegisterCodeFix( CodeAction.Create( - string.Format(FeaturesResources.Implement_through_0, through.Name), + string.Format(AnalyzersResources.Implement_through_0, through.Name), c => data.ImplementAbstractClassAsync(through, canDelegateAllMembers, c), id), context.Diagnostics); @@ -69,5 +70,5 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) } private static string GetCodeActionId(string assemblyName, string abstractTypeFullyQualifiedName, string through = "") - => FeaturesResources.Implement_abstract_class + ";" + assemblyName + ";" + abstractTypeFullyQualifiedName + ";" + through; + => AnalyzersResources.Implement_abstract_class + ";" + assemblyName + ";" + abstractTypeFullyQualifiedName + ";" + through; } diff --git a/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs b/src/Analyzers/Core/CodeFixes/ImplementAbstractClass/ImplementAbstractClassData.cs similarity index 93% rename from src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs rename to src/Analyzers/Core/CodeFixes/ImplementAbstractClass/ImplementAbstractClassData.cs index e4ae03bb70b93..b1e7588ff6615 100644 --- a/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementAbstractClass/ImplementAbstractClassData.cs @@ -21,6 +21,12 @@ using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.ImplementAbstractClass; internal sealed class ImplementAbstractClassData( @@ -38,7 +44,7 @@ internal sealed class ImplementAbstractClassData( public readonly INamedTypeSymbol AbstractClassType = abstractClassType; public static async Task TryGetDataAsync( - Document document, SyntaxNode classNode, SyntaxToken classIdentifier, ImplementTypeOptions options, CancellationToken cancellationToken) + Document document, SyntaxNode classNode, SyntaxToken classIdentifier, CancellationToken cancellationToken) { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (semanticModel.GetDeclaredSymbol(classNode, cancellationToken) is not INamedTypeSymbol classType) @@ -62,15 +68,17 @@ internal sealed class ImplementAbstractClassData( if (unimplementedMembers.IsEmpty) return null; + var options = await document.GetImplementTypeOptionsAsync(cancellationToken).ConfigureAwait(false); + return new ImplementAbstractClassData( document, options, classNode, classIdentifier, classType, abstractClassType, unimplementedMembers); } public static async Task TryImplementAbstractClassAsync( - Document document, SyntaxNode classNode, SyntaxToken classIdentifier, ImplementTypeOptions options, CancellationToken cancellationToken) + Document document, SyntaxNode classNode, SyntaxToken classIdentifier, CancellationToken cancellationToken) { - var data = await TryGetDataAsync(document, classNode, classIdentifier, options, cancellationToken).ConfigureAwait(false); + var data = await TryGetDataAsync(document, classNode, classIdentifier, cancellationToken).ConfigureAwait(false); if (data == null) return null; @@ -93,7 +101,7 @@ public async Task ImplementAbstractClassAsync( classNodeToAddMembersTo = _classNode.ReplaceToken( _classIdentifier, _classIdentifier.WithAdditionalAnnotations(ConflictAnnotation.Create( - FeaturesResources.Base_classes_contain_inaccessible_unimplemented_members))); + AnalyzersResources.Base_classes_contain_inaccessible_unimplemented_members))); } var context = new CodeGenerationContext( @@ -170,7 +178,7 @@ private ISymbol GenerateMethod( DeclarationModifiers modifiers, Accessibility accessibility) { var syntaxFacts = _document.GetRequiredLanguageService(); - var generator = _document.GetRequiredLanguageService(); + var generator = SyntaxGenerator.GetGenerator(_document); var body = throughMember == null ? generator.CreateThrowNotImplementedStatement(compilation) : generator.GenerateDelegateThroughMemberStatement(method, throughMember); @@ -198,7 +206,7 @@ private IPropertySymbol GenerateProperty( propertyGenerationBehavior = ImplementTypePropertyGenerationBehavior.PreferThrowingProperties; } - var generator = _document.GetRequiredLanguageService(); + var generator = _document.GetRequiredLanguageService(); var preferAutoProperties = propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties; var getMethod = ShouldGenerateAccessor(property.GetMethod) @@ -230,7 +238,7 @@ private IPropertySymbol GenerateProperty( private IEventSymbol GenerateEvent( IEventSymbol @event, ISymbol? throughMember, Accessibility accessibility, DeclarationModifiers modifiers) { - var generator = _document.GetRequiredLanguageService(); + var generator = _document.GetRequiredLanguageService(); return CodeGenerationSymbolFactory.CreateEventSymbol( @event, accessibility: accessibility, modifiers: modifiers, addMethod: GetEventAddOrRemoveMethod(@event, @event.AddMethod, throughMember, generator.AddEventHandler), @@ -244,7 +252,7 @@ private IEventSymbol GenerateEvent( if (accessor == null || throughMember == null) return null; - var generator = _document.GetRequiredLanguageService(); + var generator = _document.GetRequiredLanguageService(); var throughExpression = generator.CreateDelegateThroughExpression(@event, throughMember); var statement = generator.ExpressionStatement(createAddOrRemoveHandler( generator.MemberAccessExpression(throughExpression, @event.Name), diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs similarity index 91% rename from src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs index 7b764332d0c5b..b78a2f7910461 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.ImplementType; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -37,12 +38,13 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) if (!token.Span.IntersectsWith(span)) return; + var options = await document.GetImplementTypeOptionsAsync(cancellationToken).ConfigureAwait(false); + foreach (var type in token.Parent.GetAncestorsOrThis()) { if (this.IsTypeInInterfaceBaseList(type)) { var service = document.GetRequiredLanguageService(); - var options = context.Options.GetOptions(document.Project.Services).ImplementTypeOptions; var info = await service.AnalyzeAsync( document, type, cancellationToken).ConfigureAwait(false); @@ -73,26 +75,26 @@ private static string GetTitle(ImplementInterfaceConfiguration options) if (options.ImplementDisposePattern) { return options.Explicitly - ? FeaturesResources.Implement_interface_explicitly_with_Dispose_pattern - : FeaturesResources.Implement_interface_with_Dispose_pattern; + ? CodeFixesResources.Implement_interface_explicitly_with_Dispose_pattern + : CodeFixesResources.Implement_interface_with_Dispose_pattern; } else if (options.Explicitly) { return options.OnlyRemaining - ? FeaturesResources.Implement_remaining_members_explicitly - : FeaturesResources.Implement_all_members_explicitly; + ? CodeFixesResources.Implement_remaining_members_explicitly + : CodeFixesResources.Implement_all_members_explicitly; } else if (options.Abstractly) { - return FeaturesResources.Implement_interface_abstractly; + return CodeFixesResources.Implement_interface_abstractly; } else if (options.ThroughMember != null) { - return string.Format(FeaturesResources.Implement_interface_through_0, options.ThroughMember.Name); + return string.Format(CodeFixesResources.Implement_interface_through_0, options.ThroughMember.Name); } else { - return FeaturesResources.Implement_interface; + return CodeFixesResources.Implement_interface; } } @@ -102,7 +104,6 @@ private static string GetEquivalenceKey( { var interfaceType = state.InterfaceTypes.First(); var typeName = interfaceType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - var assemblyName = interfaceType.ContainingAssembly.Name; // Legacy part of the equivalence key. Kept the same to avoid test churn. var codeActionTypeName = options.ImplementDisposePattern @@ -116,7 +117,6 @@ private static string GetEquivalenceKey( options.Abstractly.ToString() + ";" + options.OnlyRemaining.ToString() + ":" + typeName + ";" + - assemblyName + ";" + codeActionTypeName + ";" + options.ThroughMember?.Name; } diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.State.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.State.cs similarity index 100% rename from src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.State.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.State.cs diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.cs similarity index 81% rename from src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.cs index f207a6b07155d..36a3cf68a3aec 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.ImplementType; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; @@ -19,6 +20,9 @@ internal abstract partial class AbstractImplementInterfaceService() : IImplement { protected const string DisposingName = "disposing"; + protected abstract ISyntaxFormatting SyntaxFormatting { get; } + protected abstract SyntaxGeneratorInternal SyntaxGeneratorInternal { get; } + protected abstract string ToDisplayString(IMethodSymbol disposeImplMethod, SymbolDisplayFormat format); protected abstract bool CanImplementImplicitly { get; } @@ -56,23 +60,24 @@ public async Task ImplementInterfaceAsync( return State.Generate(this, document, model, interfaceType, cancellationToken); } - protected static TNode AddComment(SyntaxGenerator g, string comment, TNode node) where TNode : SyntaxNode - => AddComments(g, [comment], node); + protected TNode AddComment(string comment, TNode node) where TNode : SyntaxNode + => AddComments([comment], node); - protected static TNode AddComments(SyntaxGenerator g, string comment1, string comment2, TNode node) where TNode : SyntaxNode - => AddComments(g, [comment1, comment2], node); + protected TNode AddComments(string comment1, string comment2, TNode node) where TNode : SyntaxNode + => AddComments([comment1, comment2], node); - protected static TNode AddComments(SyntaxGenerator g, string[] comments, TNode node) where TNode : SyntaxNode - => node.WithPrependedLeadingTrivia(CreateCommentTrivia(g, comments)); + protected TNode AddComments(string[] comments, TNode node) where TNode : SyntaxNode + => node.WithPrependedLeadingTrivia(CreateCommentTrivia(comments)); - protected static SyntaxTriviaList CreateCommentTrivia(SyntaxGenerator generator, params string[] comments) + protected SyntaxTriviaList CreateCommentTrivia( + params string[] comments) { using var _ = ArrayBuilder.GetInstance(out var trivia); foreach (var comment in comments) { - trivia.Add(generator.SingleLineComment(" " + comment)); - trivia.Add(generator.ElasticCarriageReturnLineFeed); + trivia.Add(this.SyntaxGeneratorInternal.SingleLineComment(" " + comment)); + trivia.Add(this.SyntaxGeneratorInternal.ElasticCarriageReturnLineFeed); } return new SyntaxTriviaList(trivia); diff --git a/src/Features/Core/Portable/ImplementInterface/IImplementInterfaceService.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/IImplementInterfaceInfo.cs similarity index 61% rename from src/Features/Core/Portable/ImplementInterface/IImplementInterfaceService.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/IImplementInterfaceInfo.cs index 6fa7dd0e92187..707472fa1a64b 100644 --- a/src/Features/Core/Portable/ImplementInterface/IImplementInterfaceService.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/IImplementInterfaceInfo.cs @@ -3,10 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.ImplementType; namespace Microsoft.CodeAnalysis.ImplementInterface; @@ -36,25 +32,3 @@ internal interface IImplementInterfaceInfo ImmutableArray<(INamedTypeSymbol type, ImmutableArray members)> MembersWithoutExplicitOrImplicitImplementation { get; } ImmutableArray<(INamedTypeSymbol type, ImmutableArray members)> MembersWithoutExplicitImplementation { get; } } - -internal readonly record struct ImplementInterfaceConfiguration -{ - public bool ImplementDisposePattern { get; init; } - public bool Explicitly { get; init; } - public bool Abstractly { get; init; } - public bool OnlyRemaining { get; init; } - public ISymbol? ThroughMember { get; init; } -} - -internal interface IImplementInterfaceService : ILanguageService -{ - Task ImplementInterfaceAsync(Document document, ImplementTypeOptions options, SyntaxNode node, CancellationToken cancellationToken); - - Task AnalyzeAsync(Document document, SyntaxNode interfaceType, CancellationToken cancellationToken); - Task ImplementInterfaceAsync( - Document document, - IImplementInterfaceInfo info, - ImplementTypeOptions options, - ImplementInterfaceConfiguration configuration, - CancellationToken cancellationToken); -} diff --git a/src/Analyzers/Core/CodeFixes/ImplementInterface/IImplementInterfaceService.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/IImplementInterfaceService.cs new file mode 100644 index 0000000000000..e1403cb83fa29 --- /dev/null +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/IImplementInterfaceService.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.ImplementType; + +namespace Microsoft.CodeAnalysis.ImplementInterface; + +internal readonly record struct ImplementInterfaceConfiguration +{ + public bool ImplementDisposePattern { get; init; } + public bool Explicitly { get; init; } + public bool Abstractly { get; init; } + public bool OnlyRemaining { get; init; } + public ISymbol? ThroughMember { get; init; } +} + +internal interface IImplementInterfaceService : ILanguageService +{ + Task ImplementInterfaceAsync(Document document, ImplementTypeOptions options, SyntaxNode node, CancellationToken cancellationToken); + + Task AnalyzeAsync(Document document, SyntaxNode interfaceType, CancellationToken cancellationToken); + Task ImplementInterfaceAsync( + Document document, + IImplementInterfaceInfo info, + ImplementTypeOptions options, + ImplementInterfaceConfiguration configuration, + CancellationToken cancellationToken); +} diff --git a/src/Features/Core/Portable/ImplementInterface/ImplementHelpers.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementHelpers.cs similarity index 100% rename from src/Features/Core/Portable/ImplementInterface/ImplementHelpers.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementHelpers.cs diff --git a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator.cs similarity index 99% rename from src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator.cs index cba9623a8a64d..c950b2e54a02a 100644 --- a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator.cs @@ -18,6 +18,12 @@ using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.ImplementInterface; using static ImplementHelpers; diff --git a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs similarity index 93% rename from src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs index e64a3ec8df477..fa6c44be8c163 100644 --- a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs @@ -9,11 +9,17 @@ using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.ImplementInterface; internal abstract partial class AbstractImplementInterfaceService { - private partial class ImplementInterfaceGenerator + private sealed partial class ImplementInterfaceGenerator { private bool HasConflictingMember(ISymbol member, ArrayBuilder implementedVisibleMembers) { diff --git a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_DisposePattern.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_DisposePattern.cs similarity index 86% rename from src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_DisposePattern.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_DisposePattern.cs index b8158f89e8f2e..fd02292c6e66c 100644 --- a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_DisposePattern.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_DisposePattern.cs @@ -18,6 +18,12 @@ using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.ImplementInterface; using static ImplementHelpers; @@ -44,7 +50,7 @@ private async Task ImplementDisposePatternAsync( var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); var disposedValueField = await CreateDisposedValueFieldAsync( - document, State.ClassOrStructType, cancellationToken).ConfigureAwait(false); + document, this.Service.SyntaxFormatting, State.ClassOrStructType, cancellationToken).ConfigureAwait(false); var disposeMethod = TryGetIDisposableDispose(compilation)!; var (disposableMethods, finalizer) = CreateDisposableMethods(compilation, disposeMethod, disposedValueField); @@ -85,7 +91,7 @@ private async Task ImplementDisposePatternAsync( return await AddFinalizerCommentAsync(docWithAllMembers, finalizer, cancellationToken).ConfigureAwait(false); } - private static async Task AddFinalizerCommentAsync( + private async Task AddFinalizerCommentAsync( Document document, SyntaxNode finalizer, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -95,14 +101,14 @@ private static async Task AddFinalizerCommentAsync( .First(); finalizer = finalizer.NormalizeWhitespace(); - var finalizerLines = finalizer.ToFullString().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + var finalizerLines = finalizer.ToFullString().Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); var generator = document.GetRequiredLanguageService(); - var finalizerComments = CreateCommentTrivia(generator, finalizerLines); + var finalizerComments = this.Service.CreateCommentTrivia(finalizerLines); var lastMemberWithComments = lastGeneratedMember.WithPrependedLeadingTrivia( - finalizerComments.Insert(0, generator.CarriageReturnLineFeed) - .Add(generator.CarriageReturnLineFeed)); + finalizerComments.Insert(0, this.Service.SyntaxGeneratorInternal.CarriageReturnLineFeed) + .Add(this.Service.SyntaxGeneratorInternal.CarriageReturnLineFeed)); var finalRoot = root.ReplaceNode(lastGeneratedMember, lastMemberWithComments); return document.WithSyntaxRoot(finalRoot); @@ -140,6 +146,7 @@ private IMethodSymbol CreateDisposeImplementationMethod( : DeclarationModifiers.Virtual; var g = this.Document.GetRequiredLanguageService(); + var gi = this.Service.SyntaxGeneratorInternal; // if (disposing) // { @@ -148,15 +155,15 @@ private IMethodSymbol CreateDisposeImplementationMethod( var ifDisposingStatement = g.IfStatement(g.IdentifierName(DisposingName), []); ifDisposingStatement = Service.AddCommentInsideIfStatement( ifDisposingStatement, - CreateCommentTrivia(g, FeaturesResources.TODO_colon_dispose_managed_state_managed_objects)) - .WithoutTrivia().WithTrailingTrivia(g.CarriageReturnLineFeed, g.CarriageReturnLineFeed); + this.Service.CreateCommentTrivia(CodeFixesResources.TODO_colon_dispose_managed_state_managed_objects)) + .WithoutTrivia().WithTrailingTrivia(gi.CarriageReturnLineFeed, gi.CarriageReturnLineFeed); // TODO: free unmanaged ... // TODO: set large fields... // disposedValue = true - var disposedValueEqualsTrueStatement = AddComments(g, - FeaturesResources.TODO_colon_free_unmanaged_resources_unmanaged_objects_and_override_finalizer, - FeaturesResources.TODO_colon_set_large_fields_to_null, + var disposedValueEqualsTrueStatement = this.Service.AddComments( + CodeFixesResources.TODO_colon_free_unmanaged_resources_unmanaged_objects_and_override_finalizer, + CodeFixesResources.TODO_colon_set_large_fields_to_null, g.AssignmentStatement( g.IdentifierName(disposedValueField.Name), g.TrueLiteralExpression())); @@ -170,10 +177,9 @@ private IMethodSymbol CreateDisposeImplementationMethod( accessibility: accessibility, modifiers: modifiers, name: disposeMethod.Name, - parameters: ImmutableArray.Create( - CodeGenerationSymbolFactory.CreateParameterSymbol( - compilation.GetSpecialType(SpecialType.System_Boolean), - DisposingName)), + parameters: [CodeGenerationSymbolFactory.CreateParameterSymbol( + compilation.GetSpecialType(SpecialType.System_Boolean), + DisposingName)], statements: [ifStatement]); } @@ -189,8 +195,8 @@ private IMethodSymbol CreateDisposeInterfaceMethod( // // Do not change... // Dispose(true); - statements.Add(AddComment(g, - string.Format(FeaturesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, disposeMethodDisplayString), + statements.Add(this.Service.AddComment( + string.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, disposeMethodDisplayString), g.ExpressionStatement( g.InvocationExpression( g.IdentifierName(nameof(IDisposable.Dispose)), @@ -226,13 +232,14 @@ private IMethodSymbol CreateDisposeInterfaceMethod( private static async Task CreateDisposedValueFieldAsync( Document document, + ISyntaxFormatting syntaxFormatting, INamedTypeSymbol containingType, CancellationToken cancellationToken) { var rule = await document.GetApplicableNamingRuleAsync( SymbolKind.Field, Accessibility.Private, cancellationToken).ConfigureAwait(false); - var options = await document.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetSyntaxFormattingOptionsAsync(syntaxFormatting, cancellationToken).ConfigureAwait(false); var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); var boolType = compilation.GetSpecialType(SpecialType.System_Boolean); var accessibilityLevel = options.AccessibilityModifiersRequired is AccessibilityModifiersRequired.Never or AccessibilityModifiersRequired.OmitIfDefault diff --git a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Method.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Method.cs similarity index 88% rename from src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Method.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Method.cs index 7cca6268057b1..8ba8cf420dfa8 100644 --- a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Method.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Method.cs @@ -7,11 +7,17 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.ImplementInterface; internal abstract partial class AbstractImplementInterfaceService { - private partial class ImplementInterfaceGenerator + private sealed partial class ImplementInterfaceGenerator { private ISymbol GenerateMethod( Compilation compilation, diff --git a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Property.cs b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Property.cs similarity index 95% rename from src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Property.cs rename to src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Property.cs index 48e915de06709..7e6fc368666be 100644 --- a/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceGenerator_Property.cs +++ b/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Property.cs @@ -13,11 +13,17 @@ using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.ImplementInterface; internal abstract partial class AbstractImplementInterfaceService { - private partial class ImplementInterfaceGenerator + private sealed partial class ImplementInterfaceGenerator { private IEnumerable GeneratePropertyMembers( Compilation compilation, @@ -164,7 +170,7 @@ private ImmutableArray GetGetAccessorStatements( if (generateAbstractly) return default; - var generator = Document.Project.Services.GetRequiredService(); + var generator = Document.GetRequiredLanguageService(); return generator.GetGetAccessorStatements(compilation, property, ThroughMember, propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties); } diff --git a/src/Workspaces/Core/Portable/ImplementType/ImplementTypeInsertionBehavior.cs b/src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypeInsertionBehavior.cs similarity index 100% rename from src/Workspaces/Core/Portable/ImplementType/ImplementTypeInsertionBehavior.cs rename to src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypeInsertionBehavior.cs diff --git a/src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypeOptions.cs b/src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypeOptions.cs new file mode 100644 index 0000000000000..035ecd08f73a8 --- /dev/null +++ b/src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypeOptions.cs @@ -0,0 +1,82 @@ +// 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.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.ImplementType; + +[DataContract] +internal readonly record struct ImplementTypeOptions() +{ + [DataMember] + public ImplementTypeInsertionBehavior InsertionBehavior { get; init; } = ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind; + + [DataMember] + public ImplementTypePropertyGenerationBehavior PropertyGenerationBehavior { get; init; } = ImplementTypePropertyGenerationBehavior.PreferThrowingProperties; + + public static readonly ImplementTypeOptions Default = new(); +} + +internal static class ImplementTypeOptionsStorage +{ + public static readonly PerLanguageOption2 InsertionBehavior = new( + "dotnet_member_insertion_location", + defaultValue: ImplementTypeOptions.Default.InsertionBehavior, + group: MemberDisplayOptionsStorage.TypeMemberGroup, + isEditorConfigOption: true, + serializer: EditorConfigValueSerializer.CreateSerializerForEnum( + entries: + [ + ("at_the_end", ImplementTypeInsertionBehavior.AtTheEnd), + ("with_other_members_of_the_same_kind", ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind), + ], + alternativeEntries: + [ + ("AtTheEnd", ImplementTypeInsertionBehavior.AtTheEnd), + ("WithOtherMembersOfTheSameKind", ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind), + ])); + + public static readonly PerLanguageOption2 PropertyGenerationBehavior = new( + "dotnet_property_generation_behavior", + defaultValue: ImplementTypeOptions.Default.PropertyGenerationBehavior, + group: MemberDisplayOptionsStorage.TypeMemberGroup, + isEditorConfigOption: true, + serializer: EditorConfigValueSerializer.CreateSerializerForEnum( + entries: + [ + ("prefer_throwing_properties", ImplementTypePropertyGenerationBehavior.PreferThrowingProperties), + ("prefer_auto_properties", ImplementTypePropertyGenerationBehavior.PreferAutoProperties), + ], + alternativeEntries: + [ + ("PreferThrowingProperties", ImplementTypePropertyGenerationBehavior.PreferThrowingProperties), + ("PreferAutoProperties", ImplementTypePropertyGenerationBehavior.PreferAutoProperties), + ])); + + /// + /// Options that we expect the user to set in editorconfig. + /// + public static readonly ImmutableArray EditorConfigOptions = [InsertionBehavior, PropertyGenerationBehavior]; +} + +internal static class ImplementTypeOptionsProviders +{ + public static ImplementTypeOptions GetImplementTypeOptions(this IOptionsReader reader, string language) + => new() + { + InsertionBehavior = reader.GetOption(ImplementTypeOptionsStorage.InsertionBehavior, language), + PropertyGenerationBehavior = reader.GetOption(ImplementTypeOptionsStorage.PropertyGenerationBehavior, language) + }; + + public static async ValueTask GetImplementTypeOptionsAsync(this Document document, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + return configOptions.GetImplementTypeOptions(document.Project.Language); + } +} diff --git a/src/Workspaces/Core/Portable/ImplementType/ImplementTypePropertyGenerationBehavior.cs b/src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypePropertyGenerationBehavior.cs similarity index 100% rename from src/Workspaces/Core/Portable/ImplementType/ImplementTypePropertyGenerationBehavior.cs rename to src/Analyzers/Core/CodeFixes/ImplementType/ImplementTypePropertyGenerationBehavior.cs diff --git a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs index d19dfd6f28cb8..12cd6b85f7015 100644 --- a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs +++ b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes.MatchFolderAndNamespace; /// internal abstract partial class AbstractChangeNamespaceToMatchFolderCodeFixProvider { - private class CustomFixAllProvider : FixAllProvider + private sealed class CustomFixAllProvider : FixAllProvider { public static readonly CustomFixAllProvider Instance = new(); diff --git a/src/Features/Core/Portable/Shared/Naming/FallbackNamingRules.cs b/src/Analyzers/Core/CodeFixes/Naming/FallbackNamingRules.cs similarity index 100% rename from src/Features/Core/Portable/Shared/Naming/FallbackNamingRules.cs rename to src/Analyzers/Core/CodeFixes/Naming/FallbackNamingRules.cs diff --git a/src/Analyzers/Core/CodeFixes/Naming/NamingExtensions.cs b/src/Analyzers/Core/CodeFixes/Naming/NamingExtensions.cs new file mode 100644 index 0000000000000..27105cf108b7c --- /dev/null +++ b/src/Analyzers/Core/CodeFixes/Naming/NamingExtensions.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; +using Microsoft.CodeAnalysis.Shared.Naming; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Shared.Extensions; + +internal static class NamingExtensions +{ + public static async Task GetApplicableNamingRuleAsync( + this Document document, SymbolKind symbolKind, Accessibility accessibility, CancellationToken cancellationToken) + { + var rules = await document.GetNamingRulesAsync(cancellationToken).ConfigureAwait(false); + foreach (var rule in rules) + { + if (rule.SymbolSpecification.AppliesTo(symbolKind, accessibility)) + return rule; + } + + throw ExceptionUtilities.Unreachable(); + } + + /// + /// Gets the set of naming rules the user has set for this document. Will include a set of default naming rules + /// that match if the user hasn't specified any for a particular symbol type. The are added at the end so they + /// will only be used if the user hasn't specified a preference. + /// + public static async Task> GetNamingRulesAsync( + this Document document, CancellationToken cancellationToken) + { + var options = await document.GetNamingStylePreferencesAsync(cancellationToken).ConfigureAwait(false); + return options.CreateRules().NamingRules.AddRange(FallbackNamingRules.Default); + } +} diff --git a/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs index bdf383bd56b35..4deb60395c3e6 100644 --- a/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs @@ -108,7 +108,7 @@ private static async Task FixAsync( cancellationToken).ConfigureAwait(false); } - private class FixNameCodeAction : CodeAction + private sealed class FixNameCodeAction : CodeAction { #if !CODE_STYLE private readonly Solution _startingSolution; diff --git a/src/Analyzers/Core/CodeFixes/NewLines/ConsecutiveStatementPlacement/ConsecutiveStatementPlacementCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/NewLines/ConsecutiveStatementPlacement/ConsecutiveStatementPlacementCodeFixProvider.cs index b2f596fd3bafb..b79c4bc2147e8 100644 --- a/src/Analyzers/Core/CodeFixes/NewLines/ConsecutiveStatementPlacement/ConsecutiveStatementPlacementCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/NewLines/ConsecutiveStatementPlacement/ConsecutiveStatementPlacementCodeFixProvider.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -43,7 +44,7 @@ private static Task UpdateDocumentAsync(Document document, Diagnostic public static async Task FixAllAsync(Document document, ImmutableArray diagnostics, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var options = await document.GetCodeFixOptionsAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetLineFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var generator = document.GetRequiredLanguageService(); var endOfLineTrivia = generator.EndOfLine(options.NewLine); diff --git a/src/Analyzers/Core/CodeFixes/NewLines/MultipleBlankLines/AbstractMultipleBlankLinesCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/NewLines/MultipleBlankLines/AbstractMultipleBlankLinesCodeFixProvider.cs index 17068655065fb..ac80d29bdeb18 100644 --- a/src/Analyzers/Core/CodeFixes/NewLines/MultipleBlankLines/AbstractMultipleBlankLinesCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/NewLines/MultipleBlankLines/AbstractMultipleBlankLinesCodeFixProvider.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.NewLines.MultipleBlankLines; [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.RemoveBlankLines), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal class MultipleBlankLinesCodeFixProvider() : CodeFixProvider +internal sealed class MultipleBlankLinesCodeFixProvider() : CodeFixProvider { public override ImmutableArray FixableDiagnosticIds => [IDEDiagnosticIds.MultipleBlankLinesDiagnosticId]; diff --git a/src/Analyzers/Core/CodeFixes/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsCodeFixProvider.cs index e922d0b210d18..a731d282a912c 100644 --- a/src/Analyzers/Core/CodeFixes/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsCodeFixProvider.cs @@ -38,14 +38,11 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) protected abstract string GetTitle(); - private async Task RemoveUnnecessaryImportsAsync( + private static async Task RemoveUnnecessaryImportsAsync( Document document, CancellationToken cancellationToken) { var service = document.GetRequiredLanguageService(); - - var options = await document.GetCodeFixOptionsAsync(cancellationToken).ConfigureAwait(false); - var formattingOptions = options.GetFormattingOptions(GetSyntaxFormatting()); - return await service.RemoveUnnecessaryImportsAsync(document, formattingOptions, cancellationToken).ConfigureAwait(false); + return await service.RemoveUnnecessaryImportsAsync(document, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs index 1b23c3f0ee10b..9e78db585b68e 100644 --- a/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs @@ -63,7 +63,7 @@ internal abstract class AbstractRemoveUnusedValuesCodeFixProvider FixableDiagnosticIds => [IDEDiagnosticIds.ExpressionValueIsUnusedDiagnosticId, IDEDiagnosticIds.ValueAssignedIsUnusedDiagnosticId]; - protected abstract ISyntaxFormatting GetSyntaxFormatting(); + protected abstract ISyntaxFormatting SyntaxFormatting { get; } /// /// Method to update the identifier token for the local/parameter declaration or reference @@ -284,8 +284,7 @@ private static async Task PreprocessDocumentAsync(Document document, I protected sealed override async Task FixAllAsync(Document document, ImmutableArray diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { - var options = await document.GetCodeFixOptionsAsync(cancellationToken).ConfigureAwait(false); - var formattingOptions = options.GetFormattingOptions(GetSyntaxFormatting()); + var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(SyntaxFormatting, cancellationToken).ConfigureAwait(false); var preprocessedDocument = await PreprocessDocumentAsync(document, diagnostics, cancellationToken).ConfigureAwait(false); var newRoot = await GetNewRootAsync(preprocessedDocument, formattingOptions, diagnostics, cancellationToken).ConfigureAwait(false); editor.ReplaceNode(editor.OriginalRoot, newRoot); @@ -846,15 +845,10 @@ private async Task AdjustLocalDeclarationsAsync( // Finally, we apply replace the memberDeclaration in the originalEditor as a single edit. var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var rootWithTrackedNodes = root.TrackNodes(originalDeclStatementsToMoveOrRemove); + var spansToFormat = originalDeclStatementsToMoveOrRemove.Select(s => s.Span); // Run formatter prior to invoking IMoveDeclarationNearReferenceService. -#if CODE_STYLE - var provider = GetSyntaxFormatting(); - rootWithTrackedNodes = FormatterHelper.Format(rootWithTrackedNodes, originalDeclStatementsToMoveOrRemove.Select(s => s.Span), provider, options, rules: default, cancellationToken); -#else - var provider = document.Project.Solution.Services; - rootWithTrackedNodes = Formatter.Format(rootWithTrackedNodes, originalDeclStatementsToMoveOrRemove.Select(s => s.Span), provider, options, rules: default, cancellationToken); -#endif + rootWithTrackedNodes = SyntaxFormatting.GetFormattingResult(rootWithTrackedNodes, spansToFormat, options, rules: default, cancellationToken).GetFormattedRoot(cancellationToken); document = document.WithSyntaxRoot(rootWithTrackedNodes); await OnDocumentUpdatedAsync().ConfigureAwait(false); diff --git a/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/AbstractUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.cs similarity index 60% rename from src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.cs rename to src/Analyzers/Core/CodeFixes/UseCoalesceExpression/AbstractUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.cs index 4587299b879b3..6bcdd1ce88458 100644 --- a/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/AbstractUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.cs @@ -2,27 +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.Immutable; -using System.Composition; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.UseCoalesceExpression; -[ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.UseCoalesceExpressionForIfNullStatementCheck), Shared] -[ExtensionOrder(Before = PredefinedCodeFixProviderNames.AddBraces)] -[method: ImportingConstructor] -[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal class UseCoalesceExpressionForIfNullStatementCheckCodeFixProvider() : SyntaxEditorBasedCodeFixProvider +internal abstract class AbstractUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider() : SyntaxEditorBasedCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => [IDEDiagnosticIds.UseCoalesceExpressionForIfNullCheckDiagnosticId]; @@ -33,10 +26,16 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) return Task.CompletedTask; } - protected override Task FixAllAsync( + protected virtual ITypeSymbol? TryGetExplicitCast( + SemanticModel semanticModel, SyntaxNode expressionToCoalesce, + SyntaxNode leftAssignmentPart, SyntaxNode rightAssignmentPart, + CancellationToken cancellationToken) => null; + + protected override async Task FixAllAsync( Document document, ImmutableArray diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetRequiredLanguageService(); var generator = editor.Generator; @@ -50,11 +49,34 @@ protected override Task FixAllAsync( editor.ReplaceNode( expressionToCoalesce, generator.CoalesceExpression( - expressionToCoalesce.WithoutTrivia(), + TryAddExplicitCast(expressionToCoalesce, whenTrueStatement).WithoutTrivia(), GetWhenNullExpression(whenTrueStatement).WithoutTrailingTrivia()).WithTriviaFrom(expressionToCoalesce)); } - return Task.CompletedTask; + return; + + SyntaxNode TryAddExplicitCast(SyntaxNode expressionToCoalesce, SyntaxNode whenTrueStatement) + { + // This can be either SimpleAssignmentStatement or ThrowStatement + // We only care about casting in the former case since the two + // types being coalesce-d might not be the same and might result in broken + // code without the cast. + // In the latter case something like + // _ = myParameter ?? throw new ArgumentNullException(nameof(myParameter)); + // will be always valid. + if (!syntaxFacts.IsSimpleAssignmentStatement(whenTrueStatement)) + return expressionToCoalesce; + + syntaxFacts.GetPartsOfAssignmentStatement(whenTrueStatement, out var left, out var right); + + var castTo = TryGetExplicitCast(semanticModel, expressionToCoalesce, left, right, cancellationToken); + if (castTo is null) + { + return expressionToCoalesce; + } + + return generator.CastExpression(castTo, expressionToCoalesce); + } SyntaxNode GetWhenNullExpression(SyntaxNode whenTrueStatement) { diff --git a/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForNullableTernaryConditionalCheckCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForNullableTernaryConditionalCheckCodeFixProvider.cs index be0c9156f20df..208cdecb01d30 100644 --- a/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForNullableTernaryConditionalCheckCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForNullableTernaryConditionalCheckCodeFixProvider.cs @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.UseCoalesceExpression; [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.UseCoalesceExpressionForNullableTernaryConditionalCheck), Shared] [method: ImportingConstructor] [method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] -internal class UseCoalesceExpressionForNullableTernaryConditionalCheckCodeFixProvider() : SyntaxEditorBasedCodeFixProvider +internal sealed class UseCoalesceExpressionForNullableTernaryConditionalCheckCodeFixProvider() : SyntaxEditorBasedCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => [IDEDiagnosticIds.UseCoalesceExpressionForNullableTernaryConditionalCheckDiagnosticId]; diff --git a/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForTernaryConditionalCheckCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForTernaryConditionalCheckCodeFixProvider.cs index 048139c0e6652..adba206a1f33d 100644 --- a/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForTernaryConditionalCheckCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForTernaryConditionalCheckCodeFixProvider.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.UseCoalesceExpression; [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.UseCoalesceExpressionForTernaryConditionalCheck), Shared] [method: ImportingConstructor] [method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] -internal class UseCoalesceExpressionForTernaryConditionalCheckCodeFixProvider() : SyntaxEditorBasedCodeFixProvider +internal sealed class UseCoalesceExpressionForTernaryConditionalCheckCodeFixProvider() : SyntaxEditorBasedCodeFixProvider { public override ImmutableArray FixableDiagnosticIds => [IDEDiagnosticIds.UseCoalesceExpressionForTernaryConditionalCheckDiagnosticId]; diff --git a/src/Analyzers/Core/CodeFixes/UseCollectionInitializer/AbstractUseCollectionInitializerCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseCollectionInitializer/AbstractUseCollectionInitializerCodeFixProvider.cs index 3bd8365d3a7b3..d1c1ed93b6077 100644 --- a/src/Analyzers/Core/CodeFixes/UseCollectionInitializer/AbstractUseCollectionInitializerCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/UseCollectionInitializer/AbstractUseCollectionInitializerCodeFixProvider.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageService; @@ -54,7 +53,9 @@ public sealed override ImmutableArray FixableDiagnosticIds protected abstract TAnalyzer GetAnalyzer(); protected abstract Task<(SyntaxNode oldNode, SyntaxNode newNode)> GetReplacementNodesAsync( - Document document, TObjectCreationExpressionSyntax objectCreation, bool useCollectionExpression, ImmutableArray> matches, CancellationToken cancellationToken); + Document document, TObjectCreationExpressionSyntax objectCreation, bool useCollectionExpression, + ImmutableArray> preMatches, + ImmutableArray> postMatches, CancellationToken cancellationToken); protected sealed override async Task FixAsync( Document document, @@ -75,17 +76,20 @@ protected sealed override async Task FixAsync( using var analyzer = GetAnalyzer(); var useCollectionExpression = properties.ContainsKey(UseCollectionInitializerHelpers.UseCollectionExpressionName) is true; - var matches = analyzer.Analyze( + var (preMatches, postMatches) = analyzer.Analyze( semanticModel, syntaxFacts, objectCreation, useCollectionExpression, cancellationToken); - if (matches.IsDefault) + if (preMatches.IsDefault || postMatches.IsDefault) return; var (oldNode, newNode) = await GetReplacementNodesAsync( - document, objectCreation, useCollectionExpression, matches, cancellationToken).ConfigureAwait(false); + document, objectCreation, useCollectionExpression, preMatches, postMatches, cancellationToken).ConfigureAwait(false); editor.ReplaceNode(oldNode, newNode); - foreach (var match in matches) - editor.RemoveNode(match.Statement, SyntaxRemoveOptions.KeepUnbalancedDirectives); + + // We only need to remove the post-matches. The pre-matches are the arguments in teh object creation, which + // itself got replaced above. + foreach (var match in postMatches) + editor.RemoveNode(match.Node, SyntaxRemoveOptions.KeepUnbalancedDirectives); } } diff --git a/src/Analyzers/Core/CodeFixes/UseConditionalExpression/AbstractUseConditionalExpressionCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseConditionalExpression/AbstractUseConditionalExpressionCodeFixProvider.cs index 580548d1cd46d..fcba559fe08f2 100644 --- a/src/Analyzers/Core/CodeFixes/UseConditionalExpression/AbstractUseConditionalExpressionCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/UseConditionalExpression/AbstractUseConditionalExpressionCodeFixProvider.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.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -16,12 +15,6 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; -#if CODE_STYLE -using Formatter = Microsoft.CodeAnalysis.Formatting.FormatterHelper; -#else -using Formatter = Microsoft.CodeAnalysis.Formatting.Formatter; -#endif - namespace Microsoft.CodeAnalysis.UseConditionalExpression; using static UseConditionalExpressionCodeFixHelpers; @@ -40,7 +33,7 @@ internal abstract class AbstractUseConditionalExpressionCodeFixProvider< protected abstract ISyntaxFacts SyntaxFacts { get; } protected abstract AbstractFormattingRule GetMultiLineFormattingRule(); - protected abstract ISyntaxFormatting GetSyntaxFormatting(); + protected abstract ISyntaxFormatting SyntaxFormatting { get; } protected abstract TExpressionSyntax ConvertToExpression(IThrowOperation throwOperation); protected abstract TStatementSyntax WrapWithBlockIfAppropriate(TIfStatementSyntax ifStatement, TStatementSyntax statement); @@ -55,13 +48,7 @@ protected override async Task FixAllAsync( { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); -#if CODE_STYLE - var provider = GetSyntaxFormatting(); -#else - var provider = document.Project.Solution.Services; -#endif - var options = await document.GetCodeFixOptionsAsync(cancellationToken).ConfigureAwait(false); - var formattingOptions = options.GetFormattingOptions(GetSyntaxFormatting()); + var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(SyntaxFormatting, cancellationToken).ConfigureAwait(false); // Defer to our callback to actually make the edits for each diagnostic. In turn, it // will return 'true' if it made a multi-line conditional expression. In that case, @@ -81,9 +68,9 @@ await FixOneAsync( // conditional expression as that's the only node that has the appropriate // annotation on it. var rules = ImmutableArray.Create(GetMultiLineFormattingRule()); + var spansToFormat = FormattingExtensions.GetAnnotatedSpans(changedRoot, SpecializedFormattingAnnotation); - var formattedRoot = Formatter.Format(changedRoot, SpecializedFormattingAnnotation, provider, formattingOptions, rules, cancellationToken); - + var formattedRoot = SyntaxFormatting.GetFormattingResult(changedRoot, spansToFormat, formattingOptions, rules, cancellationToken).GetFormattedRoot(cancellationToken); changedRoot = formattedRoot; editor.ReplaceNode(root, changedRoot); diff --git a/src/Analyzers/Core/CodeFixes/UseExplicitTupleName/UseExplicitTupleNameCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseExplicitTupleName/UseExplicitTupleNameCodeFixProvider.cs index 50b9ce94f5389..3e93da6cf6d98 100644 --- a/src/Analyzers/Core/CodeFixes/UseExplicitTupleName/UseExplicitTupleNameCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/UseExplicitTupleName/UseExplicitTupleNameCodeFixProvider.cs @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.UseExplicitTupleName; [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.UseExplicitTupleName), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal partial class UseExplicitTupleNameCodeFixProvider() : SyntaxEditorBasedCodeFixProvider +internal sealed partial class UseExplicitTupleNameCodeFixProvider() : SyntaxEditorBasedCodeFixProvider { public override ImmutableArray FixableDiagnosticIds { get; } = [IDEDiagnosticIds.UseExplicitTupleNameDiagnosticId]; diff --git a/src/Analyzers/Core/CodeFixes/UseObjectInitializer/AbstractUseObjectInitializerCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseObjectInitializer/AbstractUseObjectInitializerCodeFixProvider.cs index e24f92920c2fb..2c81b61a74744 100644 --- a/src/Analyzers/Core/CodeFixes/UseObjectInitializer/AbstractUseObjectInitializerCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/UseObjectInitializer/AbstractUseObjectInitializerCodeFixProvider.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; diff --git a/src/Analyzers/Core/CodeFixes/UseSystemHashCode/UseSystemHashCodeCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseSystemHashCode/UseSystemHashCodeCodeFixProvider.cs index 5197aa83293c2..ff27c1ab4a616 100644 --- a/src/Analyzers/Core/CodeFixes/UseSystemHashCode/UseSystemHashCodeCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/UseSystemHashCode/UseSystemHashCodeCodeFixProvider.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.UseSystemHashCode; [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.UseSystemHashCode), Shared] [method: ImportingConstructor] [method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] -internal class UseSystemHashCodeCodeFixProvider() : SyntaxEditorBasedCodeFixProvider +internal sealed class UseSystemHashCodeCodeFixProvider() : SyntaxEditorBasedCodeFixProvider { public override ImmutableArray FixableDiagnosticIds { get; } = [IDEDiagnosticIds.UseSystemHashCode]; diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf index 33815baba51e3..df0ada9dff80f 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf @@ -62,6 +62,11 @@ Převést typ na {0} + + Do not change this code. Put cleanup code in '{0}' method + Neměňte tento kód. Kód pro vyčištění vložte do metody {0}. + + Fix all occurrences in Opravit všechny výskyty v @@ -72,6 +77,156 @@ Opravit porušení názvu: {0} + + Generate abstract method '{0}' + Generovat abstraktní metodu {0} + + + + Generate abstract property '{0}' + Generovat abstraktní vlastnost {0} + + + + Generate all + Generovat všechno + + + + Generate constant '{0}' + Generovat konstantu {0} + + + + Generate constructor '{0}({1})' + Generovat konstruktor {0}({1}) + + + + Generate constructor in '{0}' + Generovat konstruktor v: {0} + + + + Generate constructor in '{0}' (with fields) + Vygenerovat konstruktor v {0} (s poli) + + + + Generate constructor in '{0}' (with properties) + Vygenerovat konstruktor v {0} (s vlastnostmi) + + + + Generate enum member '{0}' + Generovat člena výčtu {0} + + + + Generate explicit conversion operator in '{0}' + Generovat explicitní operátor převodu v {0} + + + + Generate field '{0}' + Generovat pole {0} + + + + Generate field assigning constructor '{0}({1})' + Generovat konstruktor přiřazující pole {0}({1}) + + + + Generate implicit conversion operator in '{0}' + Generovat implicitní operátor převodu v {0} + + + + Generate local '{0}' + Generovat místní: {0} + + + + Generate method '{0}' + Generovat metodu {0} + + + + Generate narrowing conversion in '{0}' + Generovat zužující převod v {0} + + + + Generate parameter '{0}' + Generovat parametr {0} + + + + Generate parameter '{0}' (and overrides/implementations) + Generovat parametr {0} (a přepsání/implementace) + + + + Generate property '{0}' + Generovat vlastnost {0} + + + + Generate read-only field '{0}' + Generovat pole {0} jen pro čtení + + + + Generate read-only property '{0}' + Generovat vlastnost {0} jen pro čtení + + + + Generate variable '{0}' + Generovat proměnnou {0} + + + + Generate widening conversion in '{0}' + Generovat rozšiřující konverzi v {0} + + + + Implement all members explicitly + Implementovat všechny členy explicitně + + + + Implement interface + Implementujte rozhraní. + + + + Implement interface abstractly + Implementovat rozhraní abstraktně + + + + Implement interface explicitly with Dispose pattern + Implementovat rozhraní explicitně se vzorem Dispose + + + + Implement interface through '{0}' + Implementovat rozhraní přes {0} + + + + Implement interface with Dispose pattern + Implementovat rozhraní se vzorem Dispose + + + + Implement remaining members explicitly + Implementovat zbývající členy explicitně + + Make class 'abstract' Nastavit třídu jako abstract @@ -122,6 +277,26 @@ Potlačit nebo konfigurovat problémy + + TODO: dispose managed state (managed objects) + TODO: Uvolněte spravovaný stav (spravované objekty). + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: Uvolněte nespravované prostředky (nespravované objekty) a přepište finalizační metodu. + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: Finalizační metodu přepište, jen pokud metoda {0} obsahuje kód pro uvolnění nespravovaných prostředků. + + + + TODO: set large fields to null + TODO: Nastavte velká pole na hodnotu null. + + Take '{0}' Vzít {0} diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf index 17fd20f02ead1..f4ef29827f0f8 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf @@ -62,6 +62,11 @@ Typ in "{0}" konvertieren + + Do not change this code. Put cleanup code in '{0}' method + Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "{0}" ein. + + Fix all occurrences in Alle Vorkommen korrigieren in @@ -72,6 +77,156 @@ Namensverletzung beheben: {0} + + Generate abstract method '{0}' + Abstrakte Methode „{0}“ generieren + + + + Generate abstract property '{0}' + Abstrakte Eigenschaft „{0}X generieren + + + + Generate all + Alle generieren + + + + Generate constant '{0}' + Konstante „{0}“ generieren + + + + Generate constructor '{0}({1})' + Konstruktor "{0}({1})" generieren + + + + Generate constructor in '{0}' + Konstruktor in "{0}" generieren + + + + Generate constructor in '{0}' (with fields) + Konstruktor in "{0}" (mit Feldern) generieren + + + + Generate constructor in '{0}' (with properties) + Konstruktor in "{0}" (mit Eigenschaften) generieren + + + + Generate enum member '{0}' + Aufzählungselement „{0}“ generieren + + + + Generate explicit conversion operator in '{0}' + Expliziten Konversionsoperator in '{0}' generieren + + + + Generate field '{0}' + Feld „{0}“ generieren + + + + Generate field assigning constructor '{0}({1})' + Feldzuweisungskonstruktor "{0}({1})" generieren + + + + Generate implicit conversion operator in '{0}' + Impliziten Konversionsoperator in '{0}' generieren + + + + Generate local '{0}' + Lokales "{0}" generieren + + + + Generate method '{0}' + Methode „{0}“ generieren + + + + Generate narrowing conversion in '{0}' + Einschränkende Konvertierung in "{0}" generieren + + + + Generate parameter '{0}' + Parameter "{0}" generieren + + + + Generate parameter '{0}' (and overrides/implementations) + Parameter "{0}" (und Außerkraftsetzungen/Implementierungen) generieren + + + + Generate property '{0}' + Eigenschaft „{0}“ generieren + + + + Generate read-only field '{0}' + Schreibgeschütztes Feld „{0}“ generieren + + + + Generate read-only property '{0}' + Schreibgeschützte Eigenschaft „{0}“ generieren + + + + Generate variable '{0}' + Variable "{0}" generieren + + + + Generate widening conversion in '{0}' + Erweiternde Konvertierung in "{0}" generieren + + + + Implement all members explicitly + Alle Member explizit implementieren + + + + Implement interface + Schnittstelle implementieren + + + + Implement interface abstractly + Schnittstelle abstrakt implementieren + + + + Implement interface explicitly with Dispose pattern + Schnittstelle explizit mit Dispose-Muster implementieren + + + + Implement interface through '{0}' + Schnittstelle über "{0}" implementieren + + + + Implement interface with Dispose pattern + Schnittstelle mit Dispose-Muster implementieren + + + + Implement remaining members explicitly + Verbleibende Member explizit implementieren + + Make class 'abstract' Klasse als "abstract" festlegen @@ -122,6 +277,26 @@ Issues unterdrücken oder konfigurieren + + TODO: dispose managed state (managed objects) + TODO: Verwalteten Zustand (verwaltete Objekte) bereinigen + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalizer überschreiben + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: Finalizer nur überschreiben, wenn "{0}" Code für die Freigabe nicht verwalteter Ressourcen enthält + + + + TODO: set large fields to null + TODO: Große Felder auf NULL setzen + + Take '{0}' "{0}" übernehmen diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf index 29a17948a007f..ad015fdf015bd 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf @@ -62,6 +62,11 @@ Convertir tipo en "{0}" + + Do not change this code. Put cleanup code in '{0}' method + No cambie este código. Coloque el código de limpieza en el método "{0}". + + Fix all occurrences in Corregir todas las repeticiones de @@ -72,6 +77,156 @@ Corregir infracción de nombre: {0} + + Generate abstract method '{0}' + Generar método abstracto "{0}" + + + + Generate abstract property '{0}' + Generar propiedad abstracta "{0}" + + + + Generate all + Generar todo + + + + Generate constant '{0}' + Generar constante "{0}" + + + + Generate constructor '{0}({1})' + Generar el constructor '{0}({1})' + + + + Generate constructor in '{0}' + Generar constructor en '{0}' + + + + Generate constructor in '{0}' (with fields) + Generar un constructor en "{0}" (con campos) + + + + Generate constructor in '{0}' (with properties) + Generar un constructor en "{0}" (con propiedades) + + + + Generate enum member '{0}' + Generar miembro de enumeración "{0}" + + + + Generate explicit conversion operator in '{0}' + Generar operador de conversión explícito en '{0}' + + + + Generate field '{0}' + Generar campo "{0}" + + + + Generate field assigning constructor '{0}({1})' + Generar campo asignando constructor '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Generar operador de conversión implícito en '{0}' + + + + Generate local '{0}' + Generar la variable local '{0}' + + + + Generate method '{0}' + Generar método "{0}" + + + + Generate narrowing conversion in '{0}' + Generar conversión de restricción en "{0}" + + + + Generate parameter '{0}' + Generar el parámetro "{0}" + + + + Generate parameter '{0}' (and overrides/implementations) + Generar el parámetro "{0}" (y reemplazos/implementaciones) + + + + Generate property '{0}' + Generar propiedad "{0}" + + + + Generate read-only field '{0}' + Generar un campo de sólo lectura "{0}" + + + + Generate read-only property '{0}' + Generar propiedad de solo lectura "{0}" + + + + Generate variable '{0}' + Generar variable '{0}' + + + + Generate widening conversion in '{0}' + Generar conversión de ampliación en "{0}" + + + + Implement all members explicitly + Implementar todos los miembros de forma explícita + + + + Implement interface + Implementar interfaz + + + + Implement interface abstractly + Implementar interfaz de forma abstracta + + + + Implement interface explicitly with Dispose pattern + Implementar la interfaz de forma explícita con el patrón de Dispose + + + + Implement interface through '{0}' + Implementar interfaz a través de '{0}' + + + + Implement interface with Dispose pattern + Implementar la interfaz con el patrón de Dispose + + + + Implement remaining members explicitly + Implementar los miembros restantes de forma explícita + + Make class 'abstract' Convertir la clase en "abstract" @@ -122,6 +277,26 @@ Suprimir o configurar incidencias + + TODO: dispose managed state (managed objects) + TODO: eliminar el estado administrado (objetos administrados) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: liberar los recursos no administrados (objetos no administrados) y reemplazar el finalizador + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: reemplazar el finalizador solo si "{0}" tiene código para liberar los recursos no administrados + + + + TODO: set large fields to null + TODO: establecer los campos grandes como NULL + + Take '{0}' Tomar "{0}" diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf index ab3786fa36de1..bdb523901dffa 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf @@ -62,6 +62,11 @@ Convertir le type en '{0}' + + Do not change this code. Put cleanup code in '{0}' method + Ne changez pas ce code. Placez le code de nettoyage dans la méthode '{0}' + + Fix all occurrences in Corriger toutes les occurrences dans @@ -72,6 +77,156 @@ Corrigez la violation de nom : {0} + + Generate abstract method '{0}' + Générer la méthode abstraite '{0}' + + + + Generate abstract property '{0}' + Générer la propriété abstraite '{0}' + + + + Generate all + Générer tout + + + + Generate constant '{0}' + Générer une constante '{0}' + + + + Generate constructor '{0}({1})' + Générer le constructeur '{0}({1})' + + + + Generate constructor in '{0}' + Générer un constructeur dans '{0}' + + + + Generate constructor in '{0}' (with fields) + Générer le constructeur dans '{0}' (avec les champs) + + + + Generate constructor in '{0}' (with properties) + Générer le constructeur dans '{0}' (avec les propriétés) + + + + Generate enum member '{0}' + Générer le membre enum '{0}' + + + + Generate explicit conversion operator in '{0}' + Générer l’opérateur de conversion explicite dans « {0} » + + + + Generate field '{0}' + Générer le champ '{0}' + + + + Generate field assigning constructor '{0}({1})' + Générer un constructeur d'assignation de champ '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Générer l’opérateur de conversion implicite dans « {0} » + + + + Generate local '{0}' + Générer le '{0}' local + + + + Generate method '{0}' + Générer la méthode '{0}' + + + + Generate narrowing conversion in '{0}' + Générer une conversion restrictive dans '{0}' + + + + Generate parameter '{0}' + Générer le paramètre '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Générer le paramètre '{0}' (et les substitutions/implémentations) + + + + Generate property '{0}' + Générer la propriété '{0}' + + + + Generate read-only field '{0}' + Générer le champ en lecture seule '{0}' + + + + Generate read-only property '{0}' + Générer la propriété en lecture seule '{0}' + + + + Generate variable '{0}' + Générer la variable '{0}' + + + + Generate widening conversion in '{0}' + Générer une conversation étendue dans '{0}' + + + + Implement all members explicitly + Implémenter tous les membres explicitement + + + + Implement interface + Implémenter l'interface + + + + Implement interface abstractly + Implémenter l'interface abstraitement + + + + Implement interface explicitly with Dispose pattern + Implémenter l'interface explicitement avec le modèle Dispose + + + + Implement interface through '{0}' + Implémenter l'interface via '{0}' + + + + Implement interface with Dispose pattern + Implémenter l'interface avec le modèle Dispose + + + + Implement remaining members explicitly + Implémenter les membres restants explicitement + + Make class 'abstract' Rendre la classe 'abstract' @@ -122,6 +277,26 @@ Supprimer ou configurer des problèmes + + TODO: dispose managed state (managed objects) + TODO: supprimer l'état managé (objets managés) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: libérer les ressources non managées (objets non managés) et substituer le finaliseur + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: substituer le finaliseur uniquement si '{0}' a du code pour libérer les ressources non managées + + + + TODO: set large fields to null + TODO: affecter aux grands champs une valeur null + + Take '{0}' Prendre '{0}' diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf index fee5fb3af984d..5b2bc25a44da9 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf @@ -62,6 +62,11 @@ Converti il tipo in '{0}' + + Do not change this code. Put cleanup code in '{0}' method + Non modificare questo codice. Inserire il codice di pulizia nel metodo '{0}' + + Fix all occurrences in Correggi tutte le occorrenze in @@ -72,6 +77,156 @@ Correggi violazione del nome: {0} + + Generate abstract method '{0}' + Genera il metodo astratto '{0}' + + + + Generate abstract property '{0}' + Genera la proprietà astratta '{0}' + + + + Generate all + Genera tutto + + + + Generate constant '{0}' + Genera la costante '{0}' + + + + Generate constructor '{0}({1})' + Genera il costruttore '{0}({1})' + + + + Generate constructor in '{0}' + Genera il costruttore in '{0}' + + + + Generate constructor in '{0}' (with fields) + Genera il costruttore in '{0}' (con campi) + + + + Generate constructor in '{0}' (with properties) + Genera il costruttore in '{0}' (con proprietà) + + + + Generate enum member '{0}' + Genera il membro di enumerazione '{0}' + + + + Generate explicit conversion operator in '{0}' + Genera l'operatore di conversione esplicito in '{0}' + + + + Generate field '{0}' + Genera il campo '{0}' + + + + Generate field assigning constructor '{0}({1})' + Genera il costruttore per l'assegnazione dei campi '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + Genera l'operatore di conversione implicito in '{0}' + + + + Generate local '{0}' + Genera l'elemento '{0}' locale + + + + Generate method '{0}' + Genera il metodo '{0}' + + + + Generate narrowing conversion in '{0}' + Genera la conversione che supporta un minor numero di dati in '{0}' + + + + Generate parameter '{0}' + Generare il parametro '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Generare il parametro '{0}' (e override/implementazioni) + + + + Generate property '{0}' + Genera la proprietà '{0}' + + + + Generate read-only field '{0}' + Genera il campo di sola lettura '{0}' + + + + Generate read-only property '{0}' + Genera la proprietà di sola lettura '{0}' + + + + Generate variable '{0}' + Genera la variabile '{0}' + + + + Generate widening conversion in '{0}' + Genera la conversione che supporta un maggior numero di dati in '{0}' + + + + Implement all members explicitly + Implementare tutti i membri in modo esplicito + + + + Implement interface + Implementa l'interfaccia + + + + Implement interface abstractly + Implementa l'interfaccia in modo astratto + + + + Implement interface explicitly with Dispose pattern + Implementa l'interfaccia in modo esplicito con il criterio Dispose + + + + Implement interface through '{0}' + Implementa l'interfaccia tramite '{0}' + + + + Implement interface with Dispose pattern + Implementa l'interfaccia con il criterio Dispose + + + + Implement remaining members explicitly + Implementare i membri rimanenti in modo esplicito + + Make class 'abstract' Rendi la classe 'abstract' @@ -122,6 +277,26 @@ Elimina o configura i problemi + + TODO: dispose managed state (managed objects) + TODO: eliminare lo stato gestito (oggetti gestiti) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: liberare risorse non gestite (oggetti non gestiti) ed eseguire l'override del finalizzatore + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: eseguire l'override del finalizzatore solo se '{0}' contiene codice per liberare risorse non gestite + + + + TODO: set large fields to null + TODO: impostare campi di grandi dimensioni su Null + + Take '{0}' Accetta '{0}' diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf index 41b2e4fc1180e..768bc0053cb87 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf @@ -62,6 +62,11 @@ 型を '{0}' に変換 + + Do not change this code. Put cleanup code in '{0}' method + このコードを変更しないでください。クリーンアップ コードを '{0}' メソッドに記述します + + Fix all occurrences in 次の場所のすべての出現箇所を修正します @@ -72,6 +77,156 @@ 名前の違反を修正します: {0} + + Generate abstract method '{0}' + 抽象メソッド '{0}' を生成する + + + + Generate abstract property '{0}' + 抽象プロパティ '{0}' を生成する + + + + Generate all + すべてを生成します + + + + Generate constant '{0}' + 定数 '{0}' を生成する + + + + Generate constructor '{0}({1})' + コンストラクター '{0}({1})' を生成します + + + + Generate constructor in '{0}' + '{0}' にコンストラクターを生成します + + + + Generate constructor in '{0}' (with fields) + '{0}' にコンストラクターを生成します (フィールドを含む) + + + + Generate constructor in '{0}' (with properties) + '{0}' にコンストラクターを生成します (プロパティを含む) + + + + Generate enum member '{0}' + 列挙型メンバー '{0}' を生成する + + + + Generate explicit conversion operator in '{0}' + 明示的な変換演算子を '{0}' に生成します + + + + Generate field '{0}' + フィールド '{0}' を生成する + + + + Generate field assigning constructor '{0}({1})' + フィールドを割り当てるコンストラクター '{0}({1})' を生成します + + + + Generate implicit conversion operator in '{0}' + 暗黙的な変換演算子を '{0}' に生成します + + + + Generate local '{0}' + ローカルの '{0}' を生成します + + + + Generate method '{0}' + メソッド '{0}' を生成する + + + + Generate narrowing conversion in '{0}' + '{0}' で縮小変換を生成する + + + + Generate parameter '{0}' + パラメーター '{0}' の生成 + + + + Generate parameter '{0}' (and overrides/implementations) + パラメーター '{0}' の生成 (およびオーバーライド/実装) + + + + Generate property '{0}' + プロパティ '{0}' を生成する + + + + Generate read-only field '{0}' + 読み取り専用フィールド '{0}' を生成する + + + + Generate read-only property '{0}' + 読み取り専用プロパティ '{0}' を生成する + + + + Generate variable '{0}' + 変数 '{0}' を生成する + + + + Generate widening conversion in '{0}' + '{0}' で拡大変換を生成する + + + + Implement all members explicitly + すべてのメンバーを明示的に実装する + + + + Implement interface + インターフェイスを実装します + + + + Implement interface abstractly + インタ フェースを抽象的に実装します + + + + Implement interface explicitly with Dispose pattern + 破棄パターンを使って明示的にインターフェイスを実装します + + + + Implement interface through '{0}' + '{0}' を通じてインターフェイスを実装します + + + + Implement interface with Dispose pattern + 破棄パターンを使ってインターフェイスを実装します + + + + Implement remaining members explicitly + 残りのメンバーを明示的に実装する + + Make class 'abstract' クラスを 'abstract' にしてください @@ -122,6 +277,26 @@ 問題の抑制または構成 + + TODO: dispose managed state (managed objects) + TODO: マネージド状態を破棄します (マネージド オブジェクト) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: アンマネージド リソース (アンマネージド オブジェクト) を解放し、ファイナライザーをオーバーライドします + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: '{0}' にアンマネージド リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします + + + + TODO: set large fields to null + TODO: 大きなフィールドを null に設定します + + Take '{0}' '{0}' を取る diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf index 99dce2d2bb5ac..b8e3236d8292b 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf @@ -62,6 +62,11 @@ 형식을 '{0}'(으)로 변환 + + Do not change this code. Put cleanup code in '{0}' method + 이 코드를 변경하지 마세요. '{0}' 메서드에 정리 코드를 입력합니다. + + Fix all occurrences in 다음 위치에서 모든 발생 수정 @@ -72,6 +77,156 @@ 이름 위반 수정: {0} + + Generate abstract method '{0}' + '{0}' 요약 메서드 생성 + + + + Generate abstract property '{0}' + '{0}' 요약 속성 생성 + + + + Generate all + 모두 생성 + + + + Generate constant '{0}' + '{0}' 상수 생성 + + + + Generate constructor '{0}({1})' + 생성자 '{0}({1})' 생성 + + + + Generate constructor in '{0}' + '{0}'에서 생성자 생성 + + + + Generate constructor in '{0}' (with fields) + '{0}'에 생성자 생성(필드 포함) + + + + Generate constructor in '{0}' (with properties) + '{0}'에 생성자 생성(속성 포함) + + + + Generate enum member '{0}' + '{0}' 열거형 멤버 생성 + + + + Generate explicit conversion operator in '{0}' + '{0}'에서 명시적 변환 연산자 생성 + + + + Generate field '{0}' + '{0}' 필드 생성 + + + + Generate field assigning constructor '{0}({1})' + 생성자 '{0}({1})'을(를) 할당하는 필드 생성 + + + + Generate implicit conversion operator in '{0}' + '{0}'에서 암시적 변환 연산자 생성 + + + + Generate local '{0}' + '{0}' 로컬을 생성합니다. + + + + Generate method '{0}' + ‘{0}’ 메서드 생성 + + + + Generate narrowing conversion in '{0}' + '{0}'에서 축소 변환 생성 + + + + Generate parameter '{0}' + '{0}' 매개 변수 생성 + + + + Generate parameter '{0}' (and overrides/implementations) + '{0}' 매개 변수(및 재정의/구현) 생성 + + + + Generate property '{0}' + '{0}' 속성 생성 + + + + Generate read-only field '{0}' + '{0}' 읽기 전용 필드 생성 + + + + Generate read-only property '{0}' + '{0}' 읽기 전용 속성 생성 + + + + Generate variable '{0}' + '{0}' 변수 생성 + + + + Generate widening conversion in '{0}' + '{0}'에서 확대 변환 생성 + + + + Implement all members explicitly + 모든 멤버를 명시적으로 구현 + + + + Implement interface + 인터페이스 구현 + + + + Implement interface abstractly + 추상적으로 인터페이스 구현 + + + + Implement interface explicitly with Dispose pattern + 인터페이스를 Dispose 패턴으로 명시적으로 구현 + + + + Implement interface through '{0}' + '{0}'을(를) 통해 인터페이스 구현 + + + + Implement interface with Dispose pattern + 인터페이스를 Dispose 패턴으로 구현 + + + + Implement remaining members explicitly + 나머지 멤버를 명시적으로 구현 + + Make class 'abstract' 'abstract' 클래스 만들기 @@ -122,6 +277,26 @@ 문제 표시 안 함 또는 구성 + + TODO: dispose managed state (managed objects) + TODO: 관리형 상태(관리형 개체)를 삭제합니다. + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: 비관리형 리소스(비관리형 개체)를 해제하고 종료자를 재정의합니다. + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: 비관리형 리소스를 해제하는 코드가 '{0}'에 포함된 경우에만 종료자를 재정의합니다. + + + + TODO: set large fields to null + TODO: 큰 필드를 null로 설정합니다. + + Take '{0}' '{0}' 사용 diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf index c0e6807ae65d4..d2d1cbde96c89 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf @@ -62,6 +62,11 @@ Konwertuj typ na „{0}” + + Do not change this code. Put cleanup code in '{0}' method + Nie zmieniaj tego kodu. Umieść kod czyszczący w metodzie „{0}”. + + Fix all occurrences in Popraw wszystkie wystąpienia w @@ -72,6 +77,156 @@ Rozwiąż problem z naruszeniem nazwy: {0} + + Generate abstract method '{0}' + Generuj metodę abstrakcyjną „{0}” + + + + Generate abstract property '{0}' + Generuj właściwość abstrakcyjną „{0}” + + + + Generate all + Generuj wszystko + + + + Generate constant '{0}' + Generuj stałą „{0}” + + + + Generate constructor '{0}({1})' + Generuj konstruktor „{0}({1})” + + + + Generate constructor in '{0}' + Generuj konstruktor w elemencie „{0}” + + + + Generate constructor in '{0}' (with fields) + Generuj konstruktor w elemencie „{0}” (z polami) + + + + Generate constructor in '{0}' (with properties) + Generuj konstruktor w elemencie „{0}” (z właściwościami) + + + + Generate enum member '{0}' + Generuj składową wyliczenia „{0}” + + + + Generate explicit conversion operator in '{0}' + Generuj operator jawnej konwersji w elemencie „{0}” + + + + Generate field '{0}' + Generuj pole „{0}” + + + + Generate field assigning constructor '{0}({1})' + Generuj konstruktor przypisujący pola „{0}({1})” + + + + Generate implicit conversion operator in '{0}' + Generuj operator niejawnej konwersji w elemencie „{0}” + + + + Generate local '{0}' + Generuj lokalny element „{0}” + + + + Generate method '{0}' + Generuj metodę „{0}” + + + + Generate narrowing conversion in '{0}' + Generuj konwersję zawężającą w elemencie „{0}” + + + + Generate parameter '{0}' + Generuj parametr „{0}” + + + + Generate parameter '{0}' (and overrides/implementations) + Generowanie parametru „{0}” (i przesłonięć/implementacji) + + + + Generate property '{0}' + Generuj właściwość „{0}” + + + + Generate read-only field '{0}' + Generuj pole tylko do odczytu „{0}” + + + + Generate read-only property '{0}' + Generuj właściwość tylko do odczytu „{0}” + + + + Generate variable '{0}' + Generuj zmienną „{0}” + + + + Generate widening conversion in '{0}' + Generuj konwersję rozszerzającą w elemencie „{0}” + + + + Implement all members explicitly + Jawnie zaimplementuj wszystkie składowe + + + + Implement interface + Zaimplementuj interfejs + + + + Implement interface abstractly + Implementuj interfejs abstrakcyjnie + + + + Implement interface explicitly with Dispose pattern + Jawnie implementuj interfejs za pomocą wzorca likwidacji + + + + Implement interface through '{0}' + Implementuj interfejs za pomocą elementu „{0}” + + + + Implement interface with Dispose pattern + Implementuj interfejs za pomocą wzorca likwidacji + + + + Implement remaining members explicitly + Jawnie zaimplementuj pozostałe składowe + + Make class 'abstract' Ustaw specyfikator „abstract” dla klasy @@ -122,6 +277,26 @@ Problemy z pomijaniem lub konfigurowaniem + + TODO: dispose managed state (managed objects) + TODO: Wyczyścić stan zarządzany (obiekty zarządzane) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: Zwolnić niezarządzane zasoby (niezarządzane obiekty) i przesłonić finalizator + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: Przesłonić finalizator tylko w sytuacji, gdy powyższa metoda „{0}” zawiera kod służący do zwalniania niezarządzanych zasobów + + + + TODO: set large fields to null + TODO: Ustawić wartość null dla dużych pól + + Take '{0}' Przyjmij „{0}” diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf index d0a61bbafcdb1..9731fad0f8a89 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf @@ -62,6 +62,11 @@ Converter o tipo em '{0}' + + Do not change this code. Put cleanup code in '{0}' method + Não altere este código. Coloque o código de limpeza no método '{0}' + + Fix all occurrences in Corrigir todas as ocorrências em @@ -72,6 +77,156 @@ Corrigir violação de nome: {0} + + Generate abstract method '{0}' + Gerar o método abstrato '{0}' + + + + Generate abstract property '{0}' + Gerar a propriedade abstrata '{0}' + + + + Generate all + Gerar todos + + + + Generate constant '{0}' + Gerar constante '{0}' + + + + Generate constructor '{0}({1})' + Gerar construtor "{0}({1})" + + + + Generate constructor in '{0}' + Gerar construtor em '{0}' + + + + Generate constructor in '{0}' (with fields) + Gerar o construtor em '{0}' (com campos) + + + + Generate constructor in '{0}' (with properties) + Gerar o construtor em '{0}' (com propriedades) + + + + Generate enum member '{0}' + Gerar o membro de enumeração '{0}' + + + + Generate explicit conversion operator in '{0}' + Gerar um operador de conversão explícita em '{0}' + + + + Generate field '{0}' + Gerar campo '{0}' + + + + Generate field assigning constructor '{0}({1})' + Gerar construtor de atribuição de campo "{0}({1})" + + + + Generate implicit conversion operator in '{0}' + Gerar um operador de conversão implícita em '{0}' + + + + Generate local '{0}' + Gerar local '{0}' + + + + Generate method '{0}' + Gerar método '{0}' + + + + Generate narrowing conversion in '{0}' + Gerar conversão de restrição no '{0}' + + + + Generate parameter '{0}' + Gerar o parâmetro '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + Gerar o parâmetro '{0}' (e as substituições/implementações) + + + + Generate property '{0}' + Gerar propriedade '{0}' + + + + Generate read-only field '{0}' + Gerar o campo somente leitura '{0}' + + + + Generate read-only property '{0}' + Gerar a propriedade somente leitura '{0}' + + + + Generate variable '{0}' + Gerar variável '{0}' + + + + Generate widening conversion in '{0}' + Gerar conversão de expansão no '{0}' + + + + Implement all members explicitly + Implementar todos os membros explicitamente + + + + Implement interface + Implementar a interface + + + + Implement interface abstractly + Implementar interface de forma abstrata + + + + Implement interface explicitly with Dispose pattern + Implementar interface explicitamente com Padrão de descarte + + + + Implement interface through '{0}' + Implementar interface por meio de "{0}" + + + + Implement interface with Dispose pattern + Implementar interface com Padrão de descarte + + + + Implement remaining members explicitly + Implementar os membros restantes explicitamente + + Make class 'abstract' Tornar a classe 'abstract' @@ -122,6 +277,26 @@ Suprimir ou configurar problemas + + TODO: dispose managed state (managed objects) + TODO: descartar o estado gerenciado (objetos gerenciados) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: liberar recursos não gerenciados (objetos não gerenciados) e substituir o finalizador + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: substituir o finalizador somente se '{0}' tiver o código para liberar recursos não gerenciados + + + + TODO: set large fields to null + TODO: definir campos grandes como nulos + + Take '{0}' Obter '{0}' diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf index dbcb72b49cb7e..c8f12b1f613a6 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf @@ -62,6 +62,11 @@ Преобразовать тип в "{0}" + + Do not change this code. Put cleanup code in '{0}' method + Не изменяйте этот код. Разместите код очистки в методе "{0}". + + Fix all occurrences in Исправить все случаи в @@ -72,6 +77,156 @@ Устраните нарушение имени: {0} + + Generate abstract method '{0}' + Создать абстрактный метод "{0}" + + + + Generate abstract property '{0}' + Создать абстрактное свойство "{0}" + + + + Generate all + Создать все + + + + Generate constant '{0}' + Создать константу "{0}" + + + + Generate constructor '{0}({1})' + Создать конструктор "{0}({1})" + + + + Generate constructor in '{0}' + Создайте конструктор в "{0}" + + + + Generate constructor in '{0}' (with fields) + Создать конструктор в "{0}" (с полями) + + + + Generate constructor in '{0}' (with properties) + Создать конструктор в "{0}" (со свойствами) + + + + Generate enum member '{0}' + Создать элемент перечисления "{0}" + + + + Generate explicit conversion operator in '{0}' + Создать явный оператор преобразования в "{0}" + + + + Generate field '{0}' + Создать поле "{0}" + + + + Generate field assigning constructor '{0}({1})' + Создать назначающий поля конструктор "{0}({1})" + + + + Generate implicit conversion operator in '{0}' + Создать неявный оператор преобразования в "{0}" + + + + Generate local '{0}' + Создайте локальную переменную "{0}" + + + + Generate method '{0}' + Создать метод "{0}" + + + + Generate narrowing conversion in '{0}' + Создайте сужающее преобразование в "{0}" + + + + Generate parameter '{0}' + Создать параметр "{0}" + + + + Generate parameter '{0}' (and overrides/implementations) + Создать параметр "{0}" (а также переопределения или реализации) + + + + Generate property '{0}' + Создать свойство "{0}" + + + + Generate read-only field '{0}' + Создать поле только для чтения "{0}" + + + + Generate read-only property '{0}' + Создать свойство только для чтения "{0}" + + + + Generate variable '{0}' + Создать переменную "{0}" + + + + Generate widening conversion in '{0}' + Создайте расширяющееся преобразование в "{0}" + + + + Implement all members explicitly + Реализовать все элементы явно + + + + Implement interface + Реализовать интерфейс + + + + Implement interface abstractly + Реализовать интерфейс абстрактно + + + + Implement interface explicitly with Dispose pattern + Явно внедрите интерфейс с шаблоном освобождения + + + + Implement interface through '{0}' + Реализовать интерфейс через "{0}" + + + + Implement interface with Dispose pattern + Внедрите интерфейс с шаблоном освобождения + + + + Implement remaining members explicitly + Реализовать оставшиеся элементы явно + + Make class 'abstract' Сделать класс абстрактным @@ -122,6 +277,26 @@ Подавление проблем или настройка уровня их серьезности + + TODO: dispose managed state (managed objects) + TODO: освободить управляемое состояние (управляемые объекты) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: освободить неуправляемые ресурсы (неуправляемые объекты) и переопределить метод завершения + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: переопределить метод завершения, только если "{0}" содержит код для освобождения неуправляемых ресурсов + + + + TODO: set large fields to null + TODO: установить значение NULL для больших полей + + Take '{0}' Принимать "{0}" diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf index ed417833d3f9f..a84e8f7f908f6 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf @@ -62,6 +62,11 @@ Türü '{0}' olarak dönüştür + + Do not change this code. Put cleanup code in '{0}' method + Bu kodu değiştirmeyin. Temizleme kodunu '{0}' metodunun içine yerleştirin. + + Fix all occurrences in Tüm oluşumları şurada düzelt: @@ -72,6 +77,156 @@ Ad ihlalini düzelt: {0} + + Generate abstract method '{0}' + '{0}' soyut metodunu üret + + + + Generate abstract property '{0}' + '{0}' soyut özelliğini üret + + + + Generate all + Tümünü üret + + + + Generate constant '{0}' + '{0}' sabitini üret + + + + Generate constructor '{0}({1})' + {0}({1})' oluşturucusunu üret + + + + Generate constructor in '{0}' + '{0}' içinde oluşturucu üretin + + + + Generate constructor in '{0}' (with fields) + '{0}' içinde oluşturucu üret (alanlarla birlikte) + + + + Generate constructor in '{0}' (with properties) + '{0}' içinde oluşturucu üret (özelliklerle birlikte) + + + + Generate enum member '{0}' + '{0}' sabit listesi üyesini üret + + + + Generate explicit conversion operator in '{0}' + '{0}' içinde açık dönüşüm işleci oluştur + + + + Generate field '{0}' + '{0}' alanını üret + + + + Generate field assigning constructor '{0}({1})' + {0}({1})' alan atama oluşturucusunu üret + + + + Generate implicit conversion operator in '{0}' + '{0}' içinde örtük dönüşüm işleci oluştur + + + + Generate local '{0}' + Yerel '{0}' üretin + + + + Generate method '{0}' + '{0}' metodunu üret + + + + Generate narrowing conversion in '{0}' + '{0}' öğesinde daraltma dönüştürmesi oluştur + + + + Generate parameter '{0}' + '{0}' parametresini üret + + + + Generate parameter '{0}' (and overrides/implementations) + '{0}' parametresini (ve geçersiz kılmaları/uygulamaları) üret + + + + Generate property '{0}' + '{0}' özelliğini üret + + + + Generate read-only field '{0}' + '{0}' salt okunur alanını üret + + + + Generate read-only property '{0}' + '{0}' salt okunur özelliğini üret + + + + Generate variable '{0}' + '{0}' değişkenini oluştur + + + + Generate widening conversion in '{0}' + '{0}' öğesinde genişletme dönüşümü oluştur + + + + Implement all members explicitly + Tüm üyeleri açıkça uygula + + + + Implement interface + Arabirimi uygula + + + + Implement interface abstractly + Arabirimi soyut olarak uygula + + + + Implement interface explicitly with Dispose pattern + Ara birimi açık olarak Dispose düzeniyle uygula + + + + Implement interface through '{0}' + Arabirimi '{0}' aracılığıyla uygula + + + + Implement interface with Dispose pattern + Ara birimi Dispose düzeniyle uygula + + + + Implement remaining members explicitly + Kalan üyeleri açıkça uygula + + Make class 'abstract' Sınıfı 'abstract' yap @@ -122,6 +277,26 @@ Sorunları gizle veya yapılandır + + TODO: dispose managed state (managed objects) + TODO: yönetilen durumu (yönetilen nesneleri) atın + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: yönetilmeyen kaynakları (yönetilmeyen nesneleri) serbest bırakın ve sonlandırıcıyı geçersiz kılın + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: sonlandırıcıyı yalnızca '{0}' içinde yönetilmeyen kaynakları serbest bırakacak kod varsa geçersiz kılın + + + + TODO: set large fields to null + TODO: büyük alanları null olarak ayarlayın + + Take '{0}' '{0}' al diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf index 7899eeed84cc2..4a55a88276c5a 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf @@ -62,6 +62,11 @@ 将类型转换为“{0}” + + Do not change this code. Put cleanup code in '{0}' method + 不要更改此代码。请将清理代码放入“{0}”方法中 + + Fix all occurrences in 修复以下对象中的所有实例: @@ -72,6 +77,156 @@ 解决名称冲突: {0} + + Generate abstract method '{0}' + 生成抽象方法“{0}” + + + + Generate abstract property '{0}' + 生成抽象属性“{0}” + + + + Generate all + 生成所有 + + + + Generate constant '{0}' + 生成常数“{0}” + + + + Generate constructor '{0}({1})' + 生成构造函数 “{0}({1})” + + + + Generate constructor in '{0}' + 在“{0}”中生成构造函数 + + + + Generate constructor in '{0}' (with fields) + 在“{0}”中生成构造函数(包含字段) + + + + Generate constructor in '{0}' (with properties) + 在“{0}”中生成构造函数(包含属性) + + + + Generate enum member '{0}' + 生成枚举成员“{0}” + + + + Generate explicit conversion operator in '{0}' + 在“{0}”中生成显示转换运算符 + + + + Generate field '{0}' + 生成字段“{0}” + + + + Generate field assigning constructor '{0}({1})' + 生成字段分配构造函数“{0}({1})” + + + + Generate implicit conversion operator in '{0}' + 在“{0}”中生成隐式转换运算符 + + + + Generate local '{0}' + 生成本地“{0}” + + + + Generate method '{0}' + 生成方法“{0}” + + + + Generate narrowing conversion in '{0}' + 在“{0}”中生成收缩转换 + + + + Generate parameter '{0}' + 生成参数 "{0}" + + + + Generate parameter '{0}' (and overrides/implementations) + 生成参数 {0}(和重写/实现) + + + + Generate property '{0}' + 生成属性“{0}” + + + + Generate read-only field '{0}' + 生成只读字段“{0}” + + + + Generate read-only property '{0}' + 生成只读属性“{0}” + + + + Generate variable '{0}' + 生成变量 {0} + + + + Generate widening conversion in '{0}' + 在“{0}”中生成扩大转换 + + + + Implement all members explicitly + 显式实现所有成员 + + + + Implement interface + 实现接口 + + + + Implement interface abstractly + 以抽象方式实现接口 + + + + Implement interface explicitly with Dispose pattern + 通过释放模式显式实现接口 + + + + Implement interface through '{0}' + 通过“{0}”实现接口 + + + + Implement interface with Dispose pattern + 通过释放模式实现接口 + + + + Implement remaining members explicitly + 显式实现剩余成员 + + Make class 'abstract' 将类设置为 "abstract" @@ -122,6 +277,26 @@ 抑制或配置方面的问题 + + TODO: dispose managed state (managed objects) + TODO: 释放托管状态(托管对象) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: 释放未托管的资源(未托管的对象)并重写终结器 + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: 仅当“{0}”拥有用于释放未托管资源的代码时才替代终结器 + + + + TODO: set large fields to null + TODO: 将大型字段设置为 null + + Take '{0}' 采用“{0}” diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf index dc96d5081194a..550e8db9681f7 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf @@ -62,6 +62,11 @@ 將類型轉換為 '{0}' + + Do not change this code. Put cleanup code in '{0}' method + 請勿變更此程式碼。請將清除程式碼放入 '{0}' 方法 + + Fix all occurrences in 修正所有出現之處於 @@ -72,6 +77,156 @@ 修正名稱違規: {0} + + Generate abstract method '{0}' + 產生抽象方法 '{0}' + + + + Generate abstract property '{0}' + 產生抽象屬性 '{0}' + + + + Generate all + 產生全部 + + + + Generate constant '{0}' + 產生常數 '{0}' + + + + Generate constructor '{0}({1})' + 產生建構函式 '{0}({1})' + + + + Generate constructor in '{0}' + 在 '{0}' 中產生建構函式 + + + + Generate constructor in '{0}' (with fields) + 在 '{0}' 中產生建構函式 (使用欄位) + + + + Generate constructor in '{0}' (with properties) + 在 '{0}' 中產生建構函式 (使用屬性) + + + + Generate enum member '{0}' + 產生列舉成員 '{0}' + + + + Generate explicit conversion operator in '{0}' + 在 '{0}' 中產生明確轉換運算子 + + + + Generate field '{0}' + 產生欄位 '{0}' + + + + Generate field assigning constructor '{0}({1})' + 產生欄位指派建構函式 '{0}({1})' + + + + Generate implicit conversion operator in '{0}' + 在 '{0}' 中產生隱含轉換運算子 + + + + Generate local '{0}' + 產生區域 '{0}' + + + + Generate method '{0}' + 產生方法 '{0}' + + + + Generate narrowing conversion in '{0}' + 在 '{0}' 中產生縮小轉換 + + + + Generate parameter '{0}' + 產生參數 '{0}' + + + + Generate parameter '{0}' (and overrides/implementations) + 產生參數 '{0}' (以及覆寫/實作) + + + + Generate property '{0}' + 產生屬性 '{0}' + + + + Generate read-only field '{0}' + 產生唯讀欄位 '{0}' + + + + Generate read-only property '{0}' + 產生唯讀屬性 '{0}' + + + + Generate variable '{0}' + 產生變數 '{0}' + + + + Generate widening conversion in '{0}' + 在 '{0}' 中產生放大轉換 + + + + Implement all members explicitly + 明確實作所有成員 + + + + Implement interface + 實作介面 + + + + Implement interface abstractly + 以抽象方式實作介面 + + + + Implement interface explicitly with Dispose pattern + 使用 Dispose 模式明確地實作介面 + + + + Implement interface through '{0}' + 透過 '{0}' 實作介面 + + + + Implement interface with Dispose pattern + 使用 Dispose 模式實作介面 + + + + Implement remaining members explicitly + 明確實作剩餘的成員 + + Make class 'abstract' 將類別設為 'abstract' @@ -122,6 +277,26 @@ 抑制或設定問題 + + TODO: dispose managed state (managed objects) + TODO: 處置受控狀態 (受控物件) + + + + TODO: free unmanaged resources (unmanaged objects) and override finalizer + TODO: 釋出非受控資源 (非受控物件) 並覆寫完成項 + + + + TODO: override finalizer only if '{0}' has code to free unmanaged resources + TODO: 僅有當 '{0}' 具有會釋出非受控資源的程式碼時,才覆寫完成項 + + + + TODO: set large fields to null + TODO: 將大型欄位設為 Null + + Take '{0}' 接受 '{0}' diff --git a/src/Analyzers/VisualBasic/Analyzers/RemoveUnusedMembers/VisualBasicRemoveUnusedMembersDiagnosticAnalyzer.vb b/src/Analyzers/VisualBasic/Analyzers/RemoveUnusedMembers/VisualBasicRemoveUnusedMembersDiagnosticAnalyzer.vb index e5a7cff41e3c1..21a7da1fd0061 100644 --- a/src/Analyzers/VisualBasic/Analyzers/RemoveUnusedMembers/VisualBasicRemoveUnusedMembersDiagnosticAnalyzer.vb +++ b/src/Analyzers/VisualBasic/Analyzers/RemoveUnusedMembers/VisualBasicRemoveUnusedMembersDiagnosticAnalyzer.vb @@ -59,5 +59,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnusedMembers Protected Overrides Function GetMembers(typeDeclaration As TypeBlockSyntax) As SyntaxList(Of StatementSyntax) Return typeDeclaration.Members End Function + + Protected Overrides Function GetParentIfSoleDeclarator(node As SyntaxNode) As SyntaxNode + Dim modifiedIdentifier = TryCast(node, ModifiedIdentifierSyntax) + Dim declarator = TryCast(modifiedIdentifier?.Parent, VariableDeclaratorSyntax) + Dim field = TryCast(declarator?.Parent, FieldDeclarationSyntax) + + If declarator?.Names.Count = 1 AndAlso field?.Declarators.Count = 1 Then + Return field + End If + + Return node + End Function End Class End Namespace diff --git a/src/Analyzers/VisualBasic/Analyzers/UseAutoProperty/VisualBasicUseAutoPropertyAnalyzer.vb b/src/Analyzers/VisualBasic/Analyzers/UseAutoProperty/VisualBasicUseAutoPropertyAnalyzer.vb index 39a420c3c7ff0..044d82e42b2f8 100644 --- a/src/Analyzers/VisualBasic/Analyzers/UseAutoProperty/VisualBasicUseAutoPropertyAnalyzer.vb +++ b/src/Analyzers/VisualBasic/Analyzers/UseAutoProperty/VisualBasicUseAutoPropertyAnalyzer.vb @@ -2,6 +2,8 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Collections.Concurrent +Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.LanguageService @@ -32,11 +34,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseAutoProperty Return DirectCast(compilation, VisualBasicCompilation).LanguageVersion >= LanguageVersion.VisualBasic10 End Function - Protected Overrides Function CanExplicitInterfaceImplementationsBeFixed() As Boolean - Return True + Protected Overrides Function SupportsFieldExpression(compilation As Compilation) As Boolean + ' 'field' keyword not supported in VB. + Return False + End Function + + Protected Overrides ReadOnly Property CanExplicitInterfaceImplementationsBeFixed As Boolean = True + Protected Overrides ReadOnly Property SupportsFieldAttributesOnProperties As Boolean = False + + Protected Overrides Function ContainsFieldExpression(propertyDeclaration As PropertyBlockSyntax, cancellationToken As CancellationToken) As Boolean + Return False End Function - Protected Overrides Sub RegisterIneligibleFieldsAction(fieldNames As HashSet(Of String), ineligibleFields As ConcurrentSet(Of IFieldSymbol), semanticModel As SemanticModel, codeBlock As SyntaxNode, cancellationToken As CancellationToken) + Protected Overrides Sub RecordIneligibleFieldLocations( + fieldNames As HashSet(Of String), + ineligibleFieldUsageIfOutsideProperty As ConcurrentDictionary(Of IFieldSymbol, ConcurrentSet(Of SyntaxNode)), + semanticModel As SemanticModel, + codeBlock As SyntaxNode, + cancellationToken As CancellationToken) ' There are no syntactic constructs that make a field ineligible to be replaced with ' a property. In C# you can't use a property in a ref/out position. But that restriction ' doesn't apply to VB. @@ -100,7 +115,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseAutoProperty Return Nothing End Function - Protected Overrides Function GetSetterExpression(setMethod As IMethodSymbol, semanticModel As SemanticModel, cancellationToken As CancellationToken) As ExpressionSyntax + Protected Overrides Function GetSetterExpression(semanticModel As SemanticModel, setMethod As IMethodSymbol, cancellationToken As CancellationToken) As ExpressionSyntax ' Setter has to be of the form: ' ' Set(value) @@ -132,5 +147,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseAutoProperty Protected Overrides Function GetFieldNode(fieldDeclaration As FieldDeclarationSyntax, identifier As ModifiedIdentifierSyntax) As SyntaxNode Return GetNodeToRemove(identifier) End Function + + Protected Overrides Sub AddAccessedFields(semanticModel As SemanticModel, accessor As IMethodSymbol, fieldNames As HashSet(Of String), result As HashSet(Of IFieldSymbol), cancellationToken As CancellationToken) + Throw ExceptionUtilities.Unreachable() + End Sub End Class End Namespace diff --git a/src/Analyzers/VisualBasic/Analyzers/UseCollectionInitializer/VisualBasicCollectionInitializerAnalyzer.vb b/src/Analyzers/VisualBasic/Analyzers/UseCollectionInitializer/VisualBasicCollectionInitializerAnalyzer.vb index e6667bf0464bd..f93006673927f 100644 --- a/src/Analyzers/VisualBasic/Analyzers/UseCollectionInitializer/VisualBasicCollectionInitializerAnalyzer.vb +++ b/src/Analyzers/VisualBasic/Analyzers/UseCollectionInitializer/VisualBasicCollectionInitializerAnalyzer.vb @@ -4,6 +4,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.UseCollectionExpression Imports Microsoft.CodeAnalysis.UseCollectionInitializer Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -37,7 +38,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseCollectionInitializer Return TypeOf _objectCreationExpression.Initializer Is ObjectMemberInitializerSyntax End Function - Protected Overrides Function ValidateMatchesForCollectionExpression(matches As ArrayBuilder(Of Match(Of StatementSyntax)), cancellationToken As CancellationToken) As Boolean + Protected Overrides Function AnalyzeMatchesAndCollectionConstructorForCollectionExpression( + preMatches As ArrayBuilder(Of CollectionMatch(Of SyntaxNode)), + postMatches As ArrayBuilder(Of CollectionMatch(Of SyntaxNode)), + cancellationToken As CancellationToken) As Boolean ' Only called for collection expressions, which VB does not support Throw ExceptionUtilities.Unreachable() End Function diff --git a/src/Features/VisualBasic/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateConstructor/GenerateConstructorCodeFixProvider.vb similarity index 97% rename from src/Features/VisualBasic/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateConstructor/GenerateConstructorCodeFixProvider.vb index 850b3ec580a61..3992689a627f3 100644 --- a/src/Features/VisualBasic/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/GenerateConstructor/GenerateConstructorCodeFixProvider.vb @@ -15,10 +15,9 @@ Imports Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor - - Friend Class GenerateConstructorCodeFixProvider + Friend NotInheritable Class GenerateConstructorCodeFixProvider Inherits AbstractGenerateMemberCodeFixProvider diff --git a/src/Features/VisualBasic/Portable/GenerateConstructor/VisualBasicGenerateConstructorService.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateConstructor/VisualBasicGenerateConstructorService.vb similarity index 100% rename from src/Features/VisualBasic/Portable/GenerateConstructor/VisualBasicGenerateConstructorService.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateConstructor/VisualBasicGenerateConstructorService.vb diff --git a/src/Features/VisualBasic/Portable/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsCodeFixProvider.vb similarity index 95% rename from src/Features/VisualBasic/Portable/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsCodeFixProvider.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsCodeFixProvider.vb index ae87499be8307..d979c9b1613a3 100644 --- a/src/Features/VisualBasic/Portable/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsCodeFixProvider.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsCodeFixProvider.vb @@ -11,7 +11,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateDefaultConstructors - Friend Class VisualBasicGenerateDefaultConstructorsCodeFixProvider + Friend NotInheritable Class VisualBasicGenerateDefaultConstructorsCodeFixProvider Inherits AbstractGenerateDefaultConstructorCodeFixProvider Private Const BC30387 As String = NameOf(BC30387) ' Class 'C' must declare a 'Sub New' because its base class 'B' does not have an accessible 'Sub New' that can be called with no arguments. diff --git a/src/Features/VisualBasic/Portable/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb similarity index 96% rename from src/Features/VisualBasic/Portable/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb index 24f2988e0397c..20f4a9c03de6f 100644 --- a/src/Features/VisualBasic/Portable/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/GenerateDefaultConstructors/VisualBasicGenerateDefaultConstructorsService.vb @@ -12,7 +12,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateDefaultConstructors - Partial Friend Class VisualBasicGenerateDefaultConstructorsService + Partial Friend NotInheritable Class VisualBasicGenerateDefaultConstructorsService Inherits AbstractGenerateDefaultConstructorsService(Of VisualBasicGenerateDefaultConstructorsService) diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.vb similarity index 97% rename from src/Features/VisualBasic/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.vb index 408486abd861d..276998efdd7b1 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.vb @@ -16,7 +16,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEnumMember - Friend Class GenerateEnumMemberCodeFixProvider + Friend NotInheritable Class GenerateEnumMemberCodeFixProvider Inherits AbstractGenerateMemberCodeFixProvider Friend Const BC30456 As String = "BC30456" ' error BC30456: 'Red' is not a member of 'Color'. diff --git a/src/Features/VisualBasic/Portable/GenerateMember/GenerateEnumMember/VisualBasicGenerateEnumMemberService.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateEnumMember/VisualBasicGenerateEnumMemberService.vb similarity index 97% rename from src/Features/VisualBasic/Portable/GenerateMember/GenerateEnumMember/VisualBasicGenerateEnumMemberService.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateEnumMember/VisualBasicGenerateEnumMemberService.vb index 524e172962db2..4fcbabb52aef4 100644 --- a/src/Features/VisualBasic/Portable/GenerateMember/GenerateEnumMember/VisualBasicGenerateEnumMemberService.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/GenerateEnumMember/VisualBasicGenerateEnumMemberService.vb @@ -11,7 +11,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateEnumMember - Partial Friend Class VisualBasicGenerateEnumMemberService + Partial Friend NotInheritable Class VisualBasicGenerateEnumMemberService Inherits AbstractGenerateEnumMemberService(Of VisualBasicGenerateEnumMemberService, SimpleNameSyntax, ExpressionSyntax) diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateConversionCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/GenerateConversionCodeFixProvider.vb similarity index 97% rename from src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateConversionCodeFixProvider.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/GenerateConversionCodeFixProvider.vb index 66f6f65869b15..eba274d4bf834 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateConversionCodeFixProvider.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/GenerateConversionCodeFixProvider.vb @@ -16,7 +16,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateMethod - Friend Class GenerateConversionCodeFixProvider + Friend NotInheritable Class GenerateConversionCodeFixProvider Inherits AbstractGenerateMemberCodeFixProvider Friend Const BC30311 As String = "BC30311" ' error BC30311: Cannot convert type 'x' to type 'y' diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateParameterizedMemberCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/GenerateParameterizedMemberCodeFixProvider.vb similarity index 98% rename from src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateParameterizedMemberCodeFixProvider.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/GenerateParameterizedMemberCodeFixProvider.vb index a4306b7efc38b..ab2feaf6fe4e9 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateParameterizedMemberCodeFixProvider.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/GenerateParameterizedMemberCodeFixProvider.vb @@ -16,7 +16,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateMethod - Friend Class GenerateParameterizedMemberCodeFixProvider + Friend NotInheritable Class GenerateParameterizedMemberCodeFixProvider Inherits AbstractGenerateMemberCodeFixProvider Friend Const BC30057 As String = "BC30057" ' error BC30057: Too many arguments to 'Public Sub Baz()' diff --git a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicCommonGenerationServiceMethods.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/VisualBasicCommonGenerationServiceMethods.vb similarity index 100% rename from src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicCommonGenerationServiceMethods.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/VisualBasicCommonGenerationServiceMethods.vb diff --git a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb similarity index 97% rename from src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb index c11b85604a33b..4a8becca9d097 100644 --- a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb @@ -13,7 +13,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateMethod - Partial Friend Class VisualBasicGenerateConversionService + Partial Friend NotInheritable Class VisualBasicGenerateConversionService Inherits AbstractGenerateConversionService(Of VisualBasicGenerateConversionService, SimpleNameSyntax, ExpressionSyntax, InvocationExpressionSyntax) @@ -164,11 +164,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateMethod End Function Protected Overrides Function GetExplicitConversionDisplayText(state As AbstractGenerateParameterizedMemberService(Of VisualBasicGenerateConversionService, SimpleNameSyntax, ExpressionSyntax, InvocationExpressionSyntax).State) As String - Return String.Format(VBFeaturesResources.Generate_narrowing_conversion_in_0, state.TypeToGenerateIn.Name) + Return String.Format(CodeFixesResources.Generate_narrowing_conversion_in_0, state.TypeToGenerateIn.Name) End Function Protected Overrides Function GetImplicitConversionDisplayText(state As AbstractGenerateParameterizedMemberService(Of VisualBasicGenerateConversionService, SimpleNameSyntax, ExpressionSyntax, InvocationExpressionSyntax).State) As String - Return String.Format(VBFeaturesResources.Generate_widening_conversion_in_0, state.TypeToGenerateIn.Name) + Return String.Format(CodeFixesResources.Generate_widening_conversion_in_0, state.TypeToGenerateIn.Name) End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateMethodService.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/VisualBasicGenerateMethodService.vb similarity index 98% rename from src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateMethodService.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/VisualBasicGenerateMethodService.vb index 27de6db3d16ad..11ad944d7ebd9 100644 --- a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateMethodService.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/VisualBasicGenerateMethodService.vb @@ -13,7 +13,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateMethod - Partial Friend Class VisualBasicGenerateMethodService + Partial Friend NotInheritable Class VisualBasicGenerateMethodService Inherits AbstractGenerateMethodService(Of VisualBasicGenerateMethodService, SimpleNameSyntax, ExpressionSyntax, InvocationExpressionSyntax) @@ -116,7 +116,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateMethod invocationExpressionOpt = DirectCast(simpleNameOrMemberAccessExpression.Parent, InvocationExpressionSyntax) Return invocationExpressionOpt.ArgumentList Is Nothing OrElse Not invocationExpressionOpt.ArgumentList.CloseParenToken.IsMissing - ElseIf TryCast(TryCast(TryCast(simpleNameOrMemberAccessExpression, ConditionalAccessExpressionSyntax)?.WhenNotNull, InvocationExpressionSyntax)?.Expression, MemberAccessExpressionSyntax)?.Name Is simpleName + ElseIf TryCast(TryCast(TryCast(simpleNameOrMemberAccessExpression, ConditionalAccessExpressionSyntax)?.WhenNotNull, InvocationExpressionSyntax)?.Expression, MemberAccessExpressionSyntax)?.Name Is simpleName Then invocationExpressionOpt = DirectCast(DirectCast(simpleNameOrMemberAccessExpression, ConditionalAccessExpressionSyntax).WhenNotNull, InvocationExpressionSyntax) Return invocationExpressionOpt.ArgumentList Is Nothing OrElse Not invocationExpressionOpt.ArgumentList.CloseParenToken.IsMissing diff --git a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateParameterizedMemberService.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/VisualBasicGenerateParameterizedMemberService.vb similarity index 99% rename from src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateParameterizedMemberService.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/VisualBasicGenerateParameterizedMemberService.vb index 7823eb6fdc4e0..677d27c679149 100644 --- a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateParameterizedMemberService.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/GenerateParameterizedMember/VisualBasicGenerateParameterizedMemberService.vb @@ -54,7 +54,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateMethod Return Me.Document.SemanticModel.Compilation.GetSpecialType(SpecialType.System_String) End Select - Dim typeInference = Document.Project.Services.GetService(Of ITypeInferenceService)() + Dim typeInference = Document.Document.GetRequiredLanguageService(Of ITypeInferenceService)() Dim inferredType = typeInference.InferType( Document.SemanticModel, Me.InvocationExpression, objectAsDefault:=True, name:=Me.State.IdentifierToken.ValueText, cancellationToken:=cancellationToken) diff --git a/src/Features/VisualBasic/Portable/GenerateVariable/VisualBasicGenerateVariableCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/GenerateVariable/VisualBasicGenerateVariableCodeFixProvider.vb similarity index 97% rename from src/Features/VisualBasic/Portable/GenerateVariable/VisualBasicGenerateVariableCodeFixProvider.vb rename to src/Analyzers/VisualBasic/CodeFixes/GenerateVariable/VisualBasicGenerateVariableCodeFixProvider.vb index b5b81092baacc..d2e40b57a8b73 100644 --- a/src/Features/VisualBasic/Portable/GenerateVariable/VisualBasicGenerateVariableCodeFixProvider.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/GenerateVariable/VisualBasicGenerateVariableCodeFixProvider.vb @@ -16,7 +16,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateVariable - Friend Class VisualBasicGenerateVariableCodeFixProvider + Friend NotInheritable Class VisualBasicGenerateVariableCodeFixProvider Inherits AbstractGenerateMemberCodeFixProvider Friend Const BC30456 As String = "BC30456" ' error BC30456: 'Goo' is not a member of 'P'. diff --git a/src/Features/VisualBasic/Portable/ImplementAbstractClass/VisualBasicImplementAbstractClassCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/ImplementAbstractClass/VisualBasicImplementAbstractClassCodeFixProvider.vb similarity index 100% rename from src/Features/VisualBasic/Portable/ImplementAbstractClass/VisualBasicImplementAbstractClassCodeFixProvider.vb rename to src/Analyzers/VisualBasic/CodeFixes/ImplementAbstractClass/VisualBasicImplementAbstractClassCodeFixProvider.vb diff --git a/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb similarity index 100% rename from src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb rename to src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb diff --git a/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceService.vb b/src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceService.vb similarity index 88% rename from src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceService.vb rename to src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceService.vb index ebbf799aca6a0..161a9857bd4db 100644 --- a/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceService.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceService.vb @@ -7,8 +7,11 @@ Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editing +Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.ImplementInterface +Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration +Imports Microsoft.CodeAnalysis.VisualBasic.Formatting Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ImplementInterface @@ -21,6 +24,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ImplementInterface Public Sub New() End Sub + Protected Overrides ReadOnly Property SyntaxFormatting As ISyntaxFormatting = VisualBasicSyntaxFormatting.Instance + + Protected Overrides ReadOnly Property SyntaxGeneratorInternal As SyntaxGeneratorInternal = VisualBasicSyntaxGeneratorInternal.Instance + Protected Overrides Function ToDisplayString(disposeImplMethod As IMethodSymbol, format As SymbolDisplayFormat) As String Return SymbolDisplay.ToDisplayString(disposeImplMethod, format) End Function @@ -104,8 +111,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ImplementInterface ' ' Do not change this code... ' Dispose(False) - Dim disposeStatement = AddComment(g, - String.Format(FeaturesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, disposeMethodDisplayString), + Dim disposeStatement = AddComment( + String.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, disposeMethodDisplayString), g.ExpressionStatement(g.InvocationExpression( g.IdentifierName(NameOf(IDisposable.Dispose)), g.Argument(DisposingName, RefKind.None, g.FalseLiteralExpression())))) @@ -121,8 +128,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ImplementInterface modifiers:=DeclarationModifiers.Override, statements:={disposeStatement, finalizeStatement}) - Return AddComment(g, - String.Format(FeaturesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, disposeMethodDisplayString), + Return AddComment( + String.Format(CodeFixesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, disposeMethodDisplayString), methodDecl) End Function End Class diff --git a/src/Analyzers/VisualBasic/CodeFixes/RemoveUnusedParametersAndValues/VisualBasicRemoveUnusedValuesCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/RemoveUnusedParametersAndValues/VisualBasicRemoveUnusedValuesCodeFixProvider.vb index 7f22c5dd7e244..7a5e5970879cf 100644 --- a/src/Analyzers/VisualBasic/CodeFixes/RemoveUnusedParametersAndValues/VisualBasicRemoveUnusedValuesCodeFixProvider.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/RemoveUnusedParametersAndValues/VisualBasicRemoveUnusedValuesCodeFixProvider.vb @@ -25,9 +25,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnusedParametersAndValues Public Sub New() End Sub - Protected Overrides Function GetSyntaxFormatting() As ISyntaxFormatting - Return VisualBasicSyntaxFormatting.Instance - End Function + Protected Overrides ReadOnly Property SyntaxFormatting As ISyntaxFormatting = VisualBasicSyntaxFormatting.Instance Protected Overrides Function WrapWithBlockIfNecessary(statements As IEnumerable(Of StatementSyntax)) As StatementSyntax ' Unreachable code path as VB statements don't need to be wrapped in special BlockSyntax. diff --git a/src/Analyzers/VisualBasic/CodeFixes/UseCoalesceExpression/VisualBasicUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/UseCoalesceExpression/VisualBasicUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.vb new file mode 100644 index 0000000000000..d226917e0bcd5 --- /dev/null +++ b/src/Analyzers/VisualBasic/CodeFixes/UseCoalesceExpression/VisualBasicUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider.vb @@ -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. + +Imports System.Composition +Imports Microsoft.CodeAnalysis.CodeFixes +Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.UseCoalesceExpression + +Namespace Microsoft.CodeAnalysis.VisualBasic.UseCoalesceExpression + + + Friend Class VisualBasicUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider + Inherits AbstractUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider + + + + Public Sub New() + End Sub + End Class +End Namespace diff --git a/src/Analyzers/VisualBasic/CodeFixes/UseCollectionInitializer/VisualBasicUseCollectionInitializerCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/UseCollectionInitializer/VisualBasicUseCollectionInitializerCodeFixProvider.vb index 4d0b85942cbfe..c646b08b34da3 100644 --- a/src/Analyzers/VisualBasic/CodeFixes/UseCollectionInitializer/VisualBasicUseCollectionInitializerCodeFixProvider.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/UseCollectionInitializer/VisualBasicUseCollectionInitializerCodeFixProvider.vb @@ -6,10 +6,10 @@ Imports System.Collections.Immutable Imports System.Composition Imports System.Diagnostics.CodeAnalysis Imports System.Threading -Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.UseCollectionExpression Imports Microsoft.CodeAnalysis.UseCollectionInitializer Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.UseObjectInitializer @@ -42,21 +42,23 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseCollectionInitializer document As Document, objectCreation As ObjectCreationExpressionSyntax, useCollectionExpression As Boolean, - matches As ImmutableArray(Of Match(Of StatementSyntax)), + preMatches As ImmutableArray(Of CollectionMatch(Of SyntaxNode)), + postMatches As ImmutableArray(Of CollectionMatch(Of SyntaxNode)), cancellationToken As CancellationToken) As Task(Of (SyntaxNode, SyntaxNode)) + Contract.ThrowIfFalse(preMatches.IsEmpty) Contract.ThrowIfTrue(useCollectionExpression, "VB does not support collection expressions") Dim statement = objectCreation.FirstAncestorOrSelf(Of StatementSyntax) Dim newStatement = statement.ReplaceNode( objectCreation, - GetNewObjectCreation(objectCreation, matches)) + GetNewObjectCreation(objectCreation, postMatches)) Dim totalTrivia = ArrayBuilder(Of SyntaxTrivia).GetInstance() totalTrivia.AddRange(statement.GetLeadingTrivia()) totalTrivia.Add(SyntaxFactory.ElasticMarker) - For Each match In matches - For Each trivia In match.Statement.GetLeadingTrivia() + For Each match In postMatches + For Each trivia In match.Node.GetLeadingTrivia() If trivia.Kind = SyntaxKind.CommentTrivia Then totalTrivia.Add(trivia) totalTrivia.Add(SyntaxFactory.ElasticMarker) @@ -70,7 +72,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseCollectionInitializer Private Shared Function GetNewObjectCreation( objectCreation As ObjectCreationExpressionSyntax, - matches As ImmutableArray(Of Match(Of StatementSyntax))) As ObjectCreationExpressionSyntax + matches As ImmutableArray(Of CollectionMatch(Of SyntaxNode))) As ObjectCreationExpressionSyntax Return UseInitializerHelpers.GetNewObjectCreation( objectCreation, @@ -80,13 +82,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseCollectionInitializer Private Shared Function CreateCollectionInitializer( objectCreation As ObjectCreationExpressionSyntax, - matches As ImmutableArray(Of Match(Of StatementSyntax))) As CollectionInitializerSyntax + matches As ImmutableArray(Of CollectionMatch(Of SyntaxNode))) As CollectionInitializerSyntax Dim nodesAndTokens = ArrayBuilder(Of SyntaxNodeOrToken).GetInstance() AddExistingItems(objectCreation, nodesAndTokens) For i = 0 To matches.Length - 1 - Dim expressionStatement = DirectCast(matches(i).Statement, ExpressionStatementSyntax) + Dim expressionStatement = DirectCast(matches(i).Node, ExpressionStatementSyntax) Dim newExpression As ExpressionSyntax Dim invocationExpression = DirectCast(expressionStatement.Expression, InvocationExpressionSyntax) diff --git a/src/Analyzers/VisualBasic/CodeFixes/UseConditionalExpression/VisualBasicUseConditionalExpressionForAssignmentCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/UseConditionalExpression/VisualBasicUseConditionalExpressionForAssignmentCodeFixProvider.vb index 1a6b8ee8fb0aa..05be72bc80158 100644 --- a/src/Analyzers/VisualBasic/CodeFixes/UseConditionalExpression/VisualBasicUseConditionalExpressionForAssignmentCodeFixProvider.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/UseConditionalExpression/VisualBasicUseConditionalExpressionForAssignmentCodeFixProvider.vb @@ -56,8 +56,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseConditionalExpression Return statement End Function - Protected Overrides Function GetSyntaxFormatting() As ISyntaxFormatting - Return VisualBasicSyntaxFormatting.Instance - End Function + Protected Overrides ReadOnly Property SyntaxFormatting As ISyntaxFormatting = VisualBasicSyntaxFormatting.Instance End Class End Namespace diff --git a/src/Analyzers/VisualBasic/CodeFixes/UseConditionalExpression/VisualBasicUseConditionalExpressionForReturnCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/UseConditionalExpression/VisualBasicUseConditionalExpressionForReturnCodeFixProvider.vb index d52a4a8f6aafd..71031eef222f0 100644 --- a/src/Analyzers/VisualBasic/CodeFixes/UseConditionalExpression/VisualBasicUseConditionalExpressionForReturnCodeFixProvider.vb +++ b/src/Analyzers/VisualBasic/CodeFixes/UseConditionalExpression/VisualBasicUseConditionalExpressionForReturnCodeFixProvider.vb @@ -40,8 +40,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseConditionalExpression Return statement End Function - Protected Overrides Function GetSyntaxFormatting() As ISyntaxFormatting - Return VisualBasicSyntaxFormatting.Instance - End Function + Protected Overrides ReadOnly Property SyntaxFormatting As ISyntaxFormatting = VisualBasicSyntaxFormatting.Instance End Class End Namespace diff --git a/src/Analyzers/VisualBasic/CodeFixes/VisualBasicCodeFixes.projitems b/src/Analyzers/VisualBasic/CodeFixes/VisualBasicCodeFixes.projitems index 77ef8bc4ae0cd..a25a0e527ed83 100644 --- a/src/Analyzers/VisualBasic/CodeFixes/VisualBasicCodeFixes.projitems +++ b/src/Analyzers/VisualBasic/CodeFixes/VisualBasicCodeFixes.projitems @@ -27,7 +27,23 @@ + + + + + + + + + + + + + + + + @@ -50,6 +66,7 @@ + diff --git a/src/Features/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb b/src/Analyzers/VisualBasic/Tests/GenerateConstructor/GenerateConstructorTests.vb similarity index 99% rename from src/Features/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb rename to src/Analyzers/VisualBasic/Tests/GenerateConstructor/GenerateConstructorTests.vb index a621c3601e426..4d8e0645acec8 100644 --- a/src/Features/VisualBasicTest/GenerateConstructor/GenerateConstructorTests.vb +++ b/src/Analyzers/VisualBasic/Tests/GenerateConstructor/GenerateConstructorTests.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateConstructor - Public Class GenerateConstructorTests + Public NotInheritable Class GenerateConstructorTests Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest_NoEditor Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) @@ -1386,55 +1386,6 @@ Public Class D End Class") End Function - - Public Async Function TestAttributesWithAllValidArguments() As Task - Await TestInRegularAndScriptAsync( -"Enum A - A1 -End Enum - -Public Class MyAttribute - Inherits System.Attribute -End Class -[||] -Public Class D End Class", -"Enum A - A1 -End Enum - -Public Class MyAttribute - Inherits System.Attribute - - Private shorts As Short() - Private a1 As A - Private v1 As Boolean - Private v2 As Integer - Private v3 As Char - Private v4 As Short - Private v5 As Integer - Private v6 As Long - Private v7 As Double - Private v8 As Single - Private v9 As String - - Public Sub New(shorts() As Short, a1 As A, v1 As Boolean, v2 As Integer, v3 As Char, v4 As Short, v5 As Integer, v6 As Long, v7 As Double, v8 As Single, v9 As String) - Me.shorts = shorts - Me.a1 = a1 - Me.v1 = v1 - Me.v2 = v2 - Me.v3 = v3 - Me.v4 = v4 - Me.v5 = v5 - Me.v6 = v6 - Me.v7 = v7 - Me.v8 = v8 - Me.v9 = v9 - End Sub -End Class - -Public Class D End Class") - End Function - Public Async Function TestAttributesWithLambda() As Task Await TestMissingInRegularAndScriptAsync( @@ -1909,94 +1860,6 @@ Public Class B End Class") End Function - - Public Async Function TestDelegateConstructorCrossLanguage() As Task - Await TestInRegularAndScriptAsync( - - - -public class BaseType -{ - public BaseType(string x) { } -} - - - CSharpProject - -Option Strict On - -Public Class B - Public Sub M() - Dim x = [|New BaseType(42)|] - End Sub -End Class - - -.ToString(), -" -public class BaseType -{ - private int v; - - public BaseType(string x) { } - - public BaseType(int v) - { - this.v = v; - } -}") - End Function - - - Public Async Function TestDelegateConstructorCrossLanguageWithMissingType() As Task - Await TestAsync( - - - -public class ExtraType { } - - - - CSharpProjectWithExtraType - -public class C -{ - public C(ExtraType t) { } - public C(string s, int i) { } -} - - - - CSharpProjectGeneratingInto - -Option Strict On - -Public Class B - Public Sub M() - Dim x = [|New C(42, 42)|] - End Sub -End Class - - -.ToString(), -" -public class C -{ - private int v1; - private int v2; - - public C(ExtraType t) { } - public C(string s, int i) { } - - public C(int v1, int v2) - { - this.v1 = v1; - this.v2 = v2; - } -} - ", TestOptions.Regular) - End Function - Public Async Function CreateFieldDefaultNamingStyle() As Task Await TestInRegularAndScriptAsync( @@ -2114,39 +1977,6 @@ End Class ") End Function - - Public Async Function TestGenerateNameFromTypeArgument() As Task - Await TestInRegularAndScriptAsync( -"Imports System.Collections.Generic - -Class Frog -End Class - -Class C - Private Function M() As C - Return New C([||]New List(Of Frog)()) - End Function -End Class -", -"Imports System.Collections.Generic - -Class Frog -End Class - -Class C - Private frogs As List(Of Frog) - - Public Sub New(frogs As List(Of Frog)) - Me.frogs = frogs - End Sub - - Private Function M() As C - Return New C(New List(Of Frog)()) - End Function -End Class -") - End Function - Public Async Function TestDoNotGenerateNameFromTypeArgumentIfNotEnumerable() As Task Await TestInRegularAndScriptAsync( @@ -2284,5 +2114,179 @@ End Class ") End Function +#If Not CODE_STYLE Then + + + Public Async Function TestAttributesWithAllValidArguments() As Task + Await TestInRegularAndScriptAsync( +"Enum A + A1 +End Enum + +Public Class MyAttribute + Inherits System.Attribute +End Class +[||] +Public Class D End Class", +"Enum A + A1 +End Enum + +Public Class MyAttribute + Inherits System.Attribute + + Private shorts As Short() + Private a1 As A + Private v1 As Boolean + Private v2 As Integer + Private v3 As Char + Private v4 As Short + Private v5 As Integer + Private v6 As Long + Private v7 As Double + Private v8 As Single + Private v9 As String + + Public Sub New(shorts() As Short, a1 As A, v1 As Boolean, v2 As Integer, v3 As Char, v4 As Short, v5 As Integer, v6 As Long, v7 As Double, v8 As Single, v9 As String) + Me.shorts = shorts + Me.a1 = a1 + Me.v1 = v1 + Me.v2 = v2 + Me.v3 = v3 + Me.v4 = v4 + Me.v5 = v5 + Me.v6 = v6 + Me.v7 = v7 + Me.v8 = v8 + Me.v9 = v9 + End Sub +End Class + +Public Class D End Class") + End Function + + + Public Async Function TestDelegateConstructorCrossLanguage() As Task + Await TestInRegularAndScriptAsync( + + + +public class BaseType +{ + public BaseType(string x) { } +} + + + CSharpProject + +Option Strict On + +Public Class B + Public Sub M() + Dim x = [|New BaseType(42)|] + End Sub +End Class + + +.ToString(), +" +public class BaseType +{ + private int v; + + public BaseType(string x) { } + + public BaseType(int v) + { + this.v = v; + } +}") + End Function + + + Public Async Function TestDelegateConstructorCrossLanguageWithMissingType() As Task + Await TestAsync( + + + +public class ExtraType { } + + + + CSharpProjectWithExtraType + +public class C +{ + public C(ExtraType t) { } + public C(string s, int i) { } +} + + + + CSharpProjectGeneratingInto + +Option Strict On + +Public Class B + Public Sub M() + Dim x = [|New C(42, 42)|] + End Sub +End Class + + +.ToString(), +" +public class C +{ + private int v1; + private int v2; + + public C(ExtraType t) { } + public C(string s, int i) { } + + public C(int v1, int v2) + { + this.v1 = v1; + this.v2 = v2; + } +} + ", TestOptions.Regular) + End Function + + + Public Async Function TestGenerateNameFromTypeArgument() As Task + Await TestInRegularAndScriptAsync( +"Imports System.Collections.Generic + +Class Frog +End Class + +Class C + Private Function M() As C + Return New C([||]New List(Of Frog)()) + End Function +End Class +", +"Imports System.Collections.Generic + +Class Frog +End Class + +Class C + Private frogs As List(Of Frog) + + Public Sub New(frogs As List(Of Frog)) + Me.frogs = frogs + End Sub + + Private Function M() As C + Return New C(New List(Of Frog)()) + End Function +End Class +") + End Function + +#End If + End Class End Namespace diff --git a/src/Features/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb b/src/Analyzers/VisualBasic/Tests/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb similarity index 98% rename from src/Features/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb rename to src/Analyzers/VisualBasic/Tests/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb index e1cfe17d143e7..4f1ddfc866499 100644 --- a/src/Features/VisualBasicTest/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb +++ b/src/Analyzers/VisualBasic/Tests/GenerateDefaultConstructors/GenerateDefaultConstructorsTests.vb @@ -6,16 +6,20 @@ #If NET472 Then Imports VerifyCodeFix = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeFixVerifier(Of - Microsoft.CodeAnalysis.Testing.EmptyDiagnosticAnalyzer, - Microsoft.CodeAnalysis.VisualBasic.GenerateDefaultConstructors.VisualBasicGenerateDefaultConstructorsCodeFixProvider) + Microsoft.CodeAnalysis.Testing.EmptyDiagnosticAnalyzer, + Microsoft.CodeAnalysis.VisualBasic.GenerateDefaultConstructors.VisualBasicGenerateDefaultConstructorsCodeFixProvider) +#If Not CODE_STYLE Then Imports VerifyRefactoring = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeRefactoringVerifier(Of - Microsoft.CodeAnalysis.GenerateDefaultConstructors.GenerateDefaultConstructorsCodeRefactoringProvider) + Microsoft.CodeAnalysis.GenerateDefaultConstructors.GenerateDefaultConstructorsCodeRefactoringProvider) +#End If Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateDefaultConstructors Public Class GenerateDefaultConstructorsTests +#If Not CODE_STYLE Then + Private Shared Async Function TestRefactoringAsync(source As String, fixedSource As String, Optional index As Integer = 0) As Task Await TestRefactoringOnlyAsync(source, fixedSource, index) Await TestCodeFixMissingAsync(source) @@ -30,6 +34,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateDefaultCon }.RunAsync() End Function +#End If + Private Shared Async Function TestCodeFixAsync(source As String, fixedSource As String, Optional index As Integer = 0) As Task Await New VerifyCodeFix.Test With { @@ -38,9 +44,13 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateDefaultCon .CodeActionIndex = index }.RunAsync() +#If Not CODE_STYLE Then Await TestRefactoringMissingAsync(source) +#End If End Function +#If Not CODE_STYLE Then + Private Shared Async Function TestRefactoringMissingAsync(source As String) As Task Await New VerifyRefactoring.Test With { @@ -49,6 +59,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateDefaultCon }.RunAsync() End Function +#End If + Private Shared Async Function TestCodeFixMissingAsync(source As String) As Task source = source.Replace("[||]", "") Await New VerifyCodeFix.Test With @@ -58,173 +70,313 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.GenerateDefaultCon }.RunAsync() End Function - - Public Async Function TestException0() As Task - Await TestRefactoringAsync( -"Imports System -Imports System.Collections.Generic -Imports System.Linq -Class Program - Inherits [||]Exception - Sub Main(args As String()) + + Public Async Function TestGenerateInDerivedType_InvalidClassStatement() As Task + Await TestCodeFixAsync( +" +Public Class Base + Public Sub New(a As Integer, Optional b As String = Nothing) + End Sub +End Class + +Public [||]Class {|BC30203:|}{|BC30387:|}{|BC30037:;|}{|BC30037:;|}Derived + Inherits Base + End Class", -"Imports System -Imports System.Collections.Generic -Imports System.Linq -Class Program - Inherits Exception +" +Public Class Base + Public Sub New(a As Integer, Optional b As String = Nothing) - Public Sub New() End Sub +End Class - Sub Main(args As String()) +Public Class {|BC30203:|}{|BC30037:;|}{|BC30037:;|}Derived + Inherits Base + + Public Sub New(a As Integer, Optional b As String = Nothing) + MyBase.New(a, b) End Sub End Class") End Function - - Public Async Function TestException1() As Task - Await TestRefactoringAsync( -"Imports System -Imports System.Collections.Generic -Imports System.Linq -Class Program - Inherits [||]Exception - Sub Main(args As String()) + + + Public Async Function TestGenerateInDerivedType1() As Task + Await TestCodeFixAsync( +" +Public Class Base + Public Sub New(a As String) + End Sub +End Class + +Public Class [||]{|BC30387:Derived|} + Inherits Base + End Class", -"Imports System -Imports System.Collections.Generic -Imports System.Linq -Class Program - Inherits Exception +" +Public Class Base + Public Sub New(a As String) - Public Sub New(message As String) - MyBase.New(message) End Sub +End Class - Sub Main(args As String()) +Public Class Derived + Inherits Base + + Public Sub New(a As String) + MyBase.New(a) End Sub -End Class", -index:=1) +End Class") End Function - - Public Async Function TestException2() As Task - Await TestRefactoringAsync( -"Imports System -Imports System.Collections.Generic -Imports System.Linq -Class Program - Inherits [||]Exception - Sub Main(args As String()) + + + Public Async Function TestGenerateInDerivedType2() As Task + Await TestCodeFixAsync( +" +Public Class Base + Public Sub New(a As Integer, Optional b As String = Nothing) + End Sub +End Class + +Public Class [||]{|BC30387:Derived|} + Inherits Base + End Class", -"Imports System -Imports System.Collections.Generic -Imports System.Linq -Class Program - Inherits Exception +" +Public Class Base + Public Sub New(a As Integer, Optional b As String = Nothing) - Public Sub New(message As String, innerException As Exception) - MyBase.New(message, innerException) End Sub +End Class - Sub Main(args As String()) +Public Class Derived + Inherits Base + + Public Sub New(a As Integer, Optional b As String = Nothing) + MyBase.New(a, b) End Sub -End Class", -index:=2) +End Class") End Function - Public Async Function TestException3() As Task - Await TestRefactoringAsync( -"Imports System -Imports System.Collections.Generic -Imports System.Linq -Class Program - Inherits [||]Exception - Sub Main(args As String()) + + Public Async Function TestGenerateConstructorFromFriendConstructor() As Task + Await TestCodeFixAsync( +Class {|BC30387:C|} + Inherits B[||] +End Class + +MustInherit Class B + Friend Sub New(x As Integer) End Sub -End Class", -"Imports System -Imports System.Collections.Generic -Imports System.Linq -Imports System.Runtime.Serialization -Class Program - Inherits Exception +End Class.Value.Replace(vbLf, vbCrLf), +Class C + Inherits B - Protected Sub New(info As SerializationInfo, context As StreamingContext) - MyBase.New(info, context) + Public Sub New(x As Integer) + MyBase.New(x) End Sub +End Class - Sub Main(args As String()) +MustInherit Class B + Friend Sub New(x As Integer) End Sub -End Class", -index:=3) +End Class.Value.Replace(vbLf, vbCrLf)) End Function - Public Async Function TestException4() As Task - Await TestRefactoringAsync( -"Imports System -Imports System.Collections.Generic -Imports System.Linq -Class Program - Inherits [||]Exception - Sub Main(args As String()) + + Public Async Function TestGenerateConstructorFromFriendConstructor2() As Task + Await TestCodeFixAsync( +MustInherit Class {|BC30387:C|} + Inherits B[||] +End Class + +MustInherit Class B + Friend Sub New(x As Integer) End Sub -End Class", -"Imports System -Imports System.Collections.Generic -Imports System.Linq -Imports System.Runtime.Serialization -Class Program - Inherits Exception +End Class.Value.Replace(vbLf, vbCrLf), +MustInherit Class C + Inherits B - Public Sub New() + Friend Sub New(x As Integer) + MyBase.New(x) End Sub +End Class - Public Sub New(message As String) - MyBase.New(message) +MustInherit Class B + Friend Sub New(x As Integer) End Sub +End Class.Value.Replace(vbLf, vbCrLf)) + End Function - Public Sub New(message As String, innerException As Exception) - MyBase.New(message, innerException) + + + Public Async Function TestGenerateConstructorFromProtectedConstructor() As Task + Await TestCodeFixAsync( +Class {|BC30387:C|} + Inherits B[||] +End Class + +MustInherit Class B + Protected Sub New(x As Integer) End Sub +End Class.Value.Replace(vbLf, vbCrLf), +Class C + Inherits B - Protected Sub New(info As SerializationInfo, context As StreamingContext) - MyBase.New(info, context) + Public Sub New(x As Integer) + MyBase.New(x) End Sub +End Class - Sub Main(args As String()) +MustInherit Class B + Protected Sub New(x As Integer) End Sub -End Class", -index:=4) +End Class.Value.Replace(vbLf, vbCrLf)) End Function - - Public Async Function TestNotOfferedOnResolvedBaseClassName() As Task - Await TestRefactoringAsync( -"Class Base -End Class -Class Derived - Inherits B[||]ase -End Class", -"Class Base + + Public Async Function TestGenerateConstructorFromProtectedConstructor2() As Task + Await TestCodeFixAsync( +MustInherit Class {|BC30387:C|} + Inherits B[||] End Class -Class Derived - Inherits Base - Public Sub New() +MustInherit Class B + Protected Sub New(x As Integer) End Sub -End Class") - End Function +End Class.Value.Replace(vbLf, vbCrLf), +MustInherit Class C + Inherits B - - Public Async Function TestNotOfferedOnUnresolvedBaseClassName() As Task + Protected Sub New(x As Integer) + MyBase.New(x) + End Sub +End Class + +MustInherit Class B + Protected Sub New(x As Integer) + End Sub +End Class.Value.Replace(vbLf, vbCrLf)) + End Function + + + + Public Async Function TestGenerateConstructorFromProtectedFriendConstructor() As Task + Await TestCodeFixAsync( +Class {|BC30387:C|} + Inherits B[||] +End Class + +MustInherit Class B + Protected Friend Sub New(x As Integer) + End Sub +End Class.Value.Replace(vbLf, vbCrLf), +Class C + Inherits B + + Public Sub New(x As Integer) + MyBase.New(x) + End Sub +End Class + +MustInherit Class B + Protected Friend Sub New(x As Integer) + End Sub +End Class.Value.Replace(vbLf, vbCrLf)) + End Function + + + + Public Async Function TestGenerateConstructorFromProtectedFriendConstructor2() As Task + Await TestCodeFixAsync( +MustInherit Class {|BC30387:C|} + Inherits B[||] +End Class + +MustInherit Class B + Protected Friend Sub New(x As Integer) + End Sub +End Class.Value.Replace(vbLf, vbCrLf), +MustInherit Class C + Inherits B + + Protected Friend Sub New(x As Integer) + MyBase.New(x) + End Sub +End Class + +MustInherit Class B + Protected Friend Sub New(x As Integer) + End Sub +End Class.Value.Replace(vbLf, vbCrLf)) + End Function + + + + Public Async Function TestGenerateConstructorFromPublicConstructor() As Task + Await TestCodeFixAsync( +Class {|BC30387:C|} + Inherits B[||] +End Class + +MustInherit Class B + Public Sub New(x As Integer) + End Sub +End Class.Value.Replace(vbLf, vbCrLf), +Class C + Inherits B + + Public Sub New(x As Integer) + MyBase.New(x) + End Sub +End Class + +MustInherit Class B + Public Sub New(x As Integer) + End Sub +End Class.Value.Replace(vbLf, vbCrLf)) + End Function + + + + + Public Async Function TestGenerateConstructorInAbstractClassFromPublicConstructor() As Task + Await TestCodeFixAsync( +MustInherit Class {|BC30387:C|} + Inherits B[||] +End Class + +MustInherit Class B + Public Sub New(x As Integer) + End Sub +End Class.Value.Replace(vbLf, vbCrLf), +MustInherit Class C + Inherits B + + Protected Sub New(x As Integer) + MyBase.New(x) + End Sub +End Class + +MustInherit Class B + Public Sub New(x As Integer) + End Sub +End Class.Value.Replace(vbLf, vbCrLf)) + End Function + +#If Not CODE_STYLE Then + + + + + Public Async Function TestNotOfferedOnUnresolvedBaseClassName() As Task Await TestRefactoringMissingAsync( "Class Derived Inherits [||]{|BC30002:Base|} @@ -458,441 +610,308 @@ Class B End Class.Value.Replace(vbLf, vbCrLf)) End Function - - Public Async Function TestFixAll() As Task + + Public Async Function TestException0() As Task Await TestRefactoringAsync( - -Class C - Inherits [||]B - - Public Sub New(y As Boolean) - End Sub -End Class - -Class B - Friend Sub New(x As Integer) - End Sub - - Protected Sub New(x As String) - End Sub - - Public Sub New(x As Boolean) - End Sub - - Public Sub New(x As Long) +"Imports System +Imports System.Collections.Generic +Imports System.Linq +Class Program + Inherits [||]Exception + Sub Main(args As String()) End Sub -End Class -.Value.Replace(vbLf, vbCrLf), - -Class C - Inherits B +End Class", +"Imports System +Imports System.Collections.Generic +Imports System.Linq +Class Program + Inherits Exception - Friend Sub New(x As Integer) - MyBase.New(x) + Public Sub New() End Sub - Protected Sub New(x As String) - MyBase.New(x) + Sub Main(args As String()) End Sub +End Class") + End Function - Public Sub New(x As Long) - MyBase.New(x) + + Public Async Function TestException1() As Task + Await TestRefactoringAsync( +"Imports System +Imports System.Collections.Generic +Imports System.Linq +Class Program + Inherits [||]Exception + Sub Main(args As String()) End Sub +End Class", +"Imports System +Imports System.Collections.Generic +Imports System.Linq +Class Program + Inherits Exception - Public Sub New(y As Boolean) + Public Sub New(message As String) + MyBase.New(message) End Sub -End Class -Class B - Friend Sub New(x As Integer) + Sub Main(args As String()) End Sub +End Class", +index:=1) + End Function - Protected Sub New(x As String) + + Public Async Function TestException2() As Task + Await TestRefactoringAsync( +"Imports System +Imports System.Collections.Generic +Imports System.Linq +Class Program + Inherits [||]Exception + Sub Main(args As String()) End Sub +End Class", +"Imports System +Imports System.Collections.Generic +Imports System.Linq +Class Program + Inherits Exception - Public Sub New(x As Boolean) + Public Sub New(message As String, innerException As Exception) + MyBase.New(message, innerException) End Sub - Public Sub New(x As Long) + Sub Main(args As String()) End Sub -End Class -.Value.Replace(vbLf, vbCrLf), +End Class", index:=2) - Throw New Exception() ' (Skip:="https://github.com/dotnet/roslyn/issues/15005") End Function - - Public Async Function TestFixAll_WithTuples() As Task + + Public Async Function TestException3() As Task Await TestRefactoringAsync( - -Class C - Inherits [||]B - - Public Sub New(y As (Boolean, Boolean)) - End Sub -End Class - -Class B - Friend Sub New(x As (Integer, Integer)) +"Imports System +Imports System.Collections.Generic +Imports System.Linq +Class Program + Inherits [||]Exception + Sub Main(args As String()) End Sub +End Class", +"Imports System +Imports System.Collections.Generic +Imports System.Linq +Imports System.Runtime.Serialization +Class Program + Inherits Exception - Protected Sub New(x As (String, String)) + Protected Sub New(info As SerializationInfo, context As StreamingContext) + MyBase.New(info, context) End Sub - Public Sub New(x As (Boolean, Boolean)) + Sub Main(args As String()) End Sub +End Class", +index:=3) + End Function - Public Sub New(x As (Long, Long)) - End Sub -End Class -.Value.Replace(vbLf, vbCrLf), - -Class C - Inherits B - - Friend Sub New(x As (Integer, Integer)) - MyBase.New(x) - End Sub - - Protected Sub New(x As (String, String)) - MyBase.New(x) - End Sub - - Public Sub New(x As (Long, Long)) - MyBase.New(x) + + Public Async Function TestException4() As Task + Await TestRefactoringAsync( +"Imports System +Imports System.Collections.Generic +Imports System.Linq +Class Program + Inherits [||]Exception + Sub Main(args As String()) End Sub +End Class", +"Imports System +Imports System.Collections.Generic +Imports System.Linq +Imports System.Runtime.Serialization +Class Program + Inherits Exception - Public Sub New(y As (Boolean, Boolean)) + Public Sub New() End Sub -End Class -Class B - Friend Sub New(x As (Integer, Integer)) + Public Sub New(message As String) + MyBase.New(message) End Sub - Protected Sub New(x As (String, String)) + Public Sub New(message As String, innerException As Exception) + MyBase.New(message, innerException) End Sub - Public Sub New(x As (Boolean, Boolean)) + Protected Sub New(info As SerializationInfo, context As StreamingContext) + MyBase.New(info, context) End Sub - Public Sub New(x As (Long, Long)) + Sub Main(args As String()) End Sub -End Class -.Value.Replace(vbLf, vbCrLf), -index:=2) +End Class", +index:=4) End Function - - Public Async Function TestGenerateInDerivedType_InvalidClassStatement() As Task - Await TestCodeFixAsync( -" -Public Class Base - Public Sub New(a As Integer, Optional b As String = Nothing) - - End Sub + + + Public Async Function TestNotOfferedOnResolvedBaseClassName() As Task + Await TestRefactoringAsync( +"Class Base End Class - -Public [||]Class {|BC30203:|}{|BC30387:|}{|BC30037:;|}{|BC30037:;|}Derived - Inherits Base - +Class Derived + Inherits B[||]ase End Class", -" -Public Class Base - Public Sub New(a As Integer, Optional b As String = Nothing) - - End Sub +"Class Base End Class - -Public Class {|BC30203:|}{|BC30037:;|}{|BC30037:;|}Derived +Class Derived Inherits Base - Public Sub New(a As Integer, Optional b As String = Nothing) - MyBase.New(a, b) + Public Sub New() End Sub End Class") End Function - - - Public Async Function TestGenerateInDerivedType1() As Task - Await TestCodeFixAsync( -" -Public Class Base - Public Sub New(a As String) - - End Sub -End Class - -Public Class [||]{|BC30387:Derived|} - Inherits Base - -End Class", -" -Public Class Base - Public Sub New(a As String) + + Public Async Function TestFixAll() As Task + Await TestRefactoringAsync( + +Class C + Inherits [||]B + Public Sub New(y As Boolean) End Sub End Class -Public Class Derived - Inherits Base - - Public Sub New(a As String) - MyBase.New(a) +Class B + Friend Sub New(x As Integer) End Sub -End Class") - End Function - - - - Public Async Function TestGenerateInDerivedType2() As Task - Await TestCodeFixAsync( -" -Public Class Base - Public Sub New(a As Integer, Optional b As String = Nothing) + Protected Sub New(x As String) End Sub -End Class - -Public Class [||]{|BC30387:Derived|} - Inherits Base - -End Class", -" -Public Class Base - Public Sub New(a As Integer, Optional b As String = Nothing) + Public Sub New(x As Boolean) End Sub -End Class - -Public Class Derived - Inherits Base - Public Sub New(a As Integer, Optional b As String = Nothing) - MyBase.New(a, b) + Public Sub New(x As Long) End Sub -End Class") - End Function - - - - Public Async Function TestNotOnEnum() As Task - Await TestRefactoringMissingAsync( -" -Public Enum [||]E - A -End Enum") - End Function - - - - Public Async Function TestGenerateConstructorFromFriendConstructor() As Task - Await TestCodeFixAsync( -Class {|BC30387:C|} - Inherits B[||] End Class - -MustInherit Class B - Friend Sub New(x As Integer) - End Sub -End Class.Value.Replace(vbLf, vbCrLf), -Class C +.Value.Replace(vbLf, vbCrLf), + +Class C Inherits B - Public Sub New(x As Integer) + Friend Sub New(x As Integer) MyBase.New(x) End Sub -End Class -MustInherit Class B - Friend Sub New(x As Integer) + Protected Sub New(x As String) + MyBase.New(x) End Sub -End Class.Value.Replace(vbLf, vbCrLf)) - End Function - - - - Public Async Function TestGenerateConstructorFromFriendConstructor2() As Task - Await TestCodeFixAsync( -MustInherit Class {|BC30387:C|} - Inherits B[||] -End Class -MustInherit Class B - Friend Sub New(x As Integer) + Public Sub New(x As Long) + MyBase.New(x) End Sub -End Class.Value.Replace(vbLf, vbCrLf), -MustInherit Class C - Inherits B - Friend Sub New(x As Integer) - MyBase.New(x) + Public Sub New(y As Boolean) End Sub End Class -MustInherit Class B +Class B Friend Sub New(x As Integer) End Sub -End Class.Value.Replace(vbLf, vbCrLf)) - End Function - - - - Public Async Function TestGenerateConstructorFromProtectedConstructor() As Task - Await TestCodeFixAsync( -Class {|BC30387:C|} - Inherits B[||] -End Class -MustInherit Class B - Protected Sub New(x As Integer) + Protected Sub New(x As String) End Sub -End Class.Value.Replace(vbLf, vbCrLf), -Class C - Inherits B - Public Sub New(x As Integer) - MyBase.New(x) + Public Sub New(x As Boolean) End Sub -End Class -MustInherit Class B - Protected Sub New(x As Integer) + Public Sub New(x As Long) End Sub -End Class.Value.Replace(vbLf, vbCrLf)) - End Function - - - - Public Async Function TestGenerateConstructorFromProtectedConstructor2() As Task - Await TestCodeFixAsync( -MustInherit Class {|BC30387:C|} - Inherits B[||] End Class +.Value.Replace(vbLf, vbCrLf), +index:=2) + Throw New Exception() ' (Skip:="https://github.com/dotnet/roslyn/issues/15005") + End Function -MustInherit Class B - Protected Sub New(x As Integer) - End Sub -End Class.Value.Replace(vbLf, vbCrLf), -MustInherit Class C - Inherits B + + Public Async Function TestFixAll_WithTuples() As Task + Await TestRefactoringAsync( + +Class C + Inherits [||]B - Protected Sub New(x As Integer) - MyBase.New(x) + Public Sub New(y As (Boolean, Boolean)) End Sub End Class -MustInherit Class B - Protected Sub New(x As Integer) +Class B + Friend Sub New(x As (Integer, Integer)) End Sub -End Class.Value.Replace(vbLf, vbCrLf)) - End Function - - - Public Async Function TestGenerateConstructorFromProtectedFriendConstructor() As Task - Await TestCodeFixAsync( -Class {|BC30387:C|} - Inherits B[||] -End Class - -MustInherit Class B - Protected Friend Sub New(x As Integer) + Protected Sub New(x As (String, String)) End Sub -End Class.Value.Replace(vbLf, vbCrLf), -Class C - Inherits B - Public Sub New(x As Integer) - MyBase.New(x) + Public Sub New(x As (Boolean, Boolean)) End Sub -End Class -MustInherit Class B - Protected Friend Sub New(x As Integer) + Public Sub New(x As (Long, Long)) End Sub -End Class.Value.Replace(vbLf, vbCrLf)) - End Function - - - - Public Async Function TestGenerateConstructorFromProtectedFriendConstructor2() As Task - Await TestCodeFixAsync( -MustInherit Class {|BC30387:C|} - Inherits B[||] End Class - -MustInherit Class B - Protected Friend Sub New(x As Integer) - End Sub -End Class.Value.Replace(vbLf, vbCrLf), -MustInherit Class C +.Value.Replace(vbLf, vbCrLf), + +Class C Inherits B - Protected Friend Sub New(x As Integer) + Friend Sub New(x As (Integer, Integer)) MyBase.New(x) End Sub -End Class -MustInherit Class B - Protected Friend Sub New(x As Integer) + Protected Sub New(x As (String, String)) + MyBase.New(x) End Sub -End Class.Value.Replace(vbLf, vbCrLf)) - End Function - - - Public Async Function TestGenerateConstructorFromPublicConstructor() As Task - Await TestCodeFixAsync( -Class {|BC30387:C|} - Inherits B[||] -End Class - -MustInherit Class B - Public Sub New(x As Integer) + Public Sub New(x As (Long, Long)) + MyBase.New(x) End Sub -End Class.Value.Replace(vbLf, vbCrLf), -Class C - Inherits B - Public Sub New(x As Integer) - MyBase.New(x) + Public Sub New(y As (Boolean, Boolean)) End Sub End Class -MustInherit Class B - Public Sub New(x As Integer) +Class B + Friend Sub New(x As (Integer, Integer)) End Sub -End Class.Value.Replace(vbLf, vbCrLf)) - End Function - - - - Public Async Function TestGenerateConstructorInAbstractClassFromPublicConstructor() As Task - Await TestCodeFixAsync( -MustInherit Class {|BC30387:C|} - Inherits B[||] -End Class + Protected Sub New(x As (String, String)) + End Sub -MustInherit Class B - Public Sub New(x As Integer) + Public Sub New(x As (Boolean, Boolean)) End Sub -End Class.Value.Replace(vbLf, vbCrLf), -MustInherit Class C - Inherits B - Protected Sub New(x As Integer) - MyBase.New(x) + Public Sub New(x As (Long, Long)) End Sub End Class +.Value.Replace(vbLf, vbCrLf), +index:=2) + End Function -MustInherit Class B - Public Sub New(x As Integer) - End Sub -End Class.Value.Replace(vbLf, vbCrLf)) + + + Public Async Function TestNotOnEnum() As Task + Await TestRefactoringMissingAsync( +" +Public Enum [||]E + A +End Enum") End Function + +#End If + End Class End Namespace #End If diff --git a/src/Features/VisualBasicTest/GenerateEnumMember/GenerateEnumMemberTests.vb b/src/Analyzers/VisualBasic/Tests/GenerateEnumMember/GenerateEnumMemberTests.vb similarity index 99% rename from src/Features/VisualBasicTest/GenerateEnumMember/GenerateEnumMemberTests.vb rename to src/Analyzers/VisualBasic/Tests/GenerateEnumMember/GenerateEnumMemberTests.vb index 2507f10f089d1..af76a833710ba 100644 --- a/src/Features/VisualBasicTest/GenerateEnumMember/GenerateEnumMemberTests.vb +++ b/src/Analyzers/VisualBasic/Tests/GenerateEnumMember/GenerateEnumMemberTests.vb @@ -8,7 +8,7 @@ Imports Microsoft.CodeAnalysis.Diagnostics Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.GenerateEnumMember - Public Class GenerateEnumMemberTests + Public NotInheritable Class GenerateEnumMemberTests Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest_NoEditor Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) diff --git a/src/Features/VisualBasicTest/GenerateMethod/GenerateConversionTests.vb b/src/Analyzers/VisualBasic/Tests/GenerateMethod/GenerateConversionTests.vb similarity index 99% rename from src/Features/VisualBasicTest/GenerateMethod/GenerateConversionTests.vb rename to src/Analyzers/VisualBasic/Tests/GenerateMethod/GenerateConversionTests.vb index 995ae22d0eb83..96318debc1e5f 100644 --- a/src/Features/VisualBasicTest/GenerateMethod/GenerateConversionTests.vb +++ b/src/Analyzers/VisualBasic/Tests/GenerateMethod/GenerateConversionTests.vb @@ -9,7 +9,7 @@ Imports Microsoft.CodeAnalysis.Diagnostics Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.GenerateMethod Partial Public Class GenerateMethodTests - Public Class GenerateConversionTests + Public NotInheritable Class GenerateConversionTests Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest_NoEditor Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) diff --git a/src/Features/VisualBasicTest/ImplementAbstractClass/ImplementAbstractClassTests.vb b/src/Analyzers/VisualBasic/Tests/ImplementAbstractClass/ImplementAbstractClassTests.vb similarity index 99% rename from src/Features/VisualBasicTest/ImplementAbstractClass/ImplementAbstractClassTests.vb rename to src/Analyzers/VisualBasic/Tests/ImplementAbstractClass/ImplementAbstractClassTests.vb index ba5a5d140a57b..2e44de7baf4b7 100644 --- a/src/Features/VisualBasicTest/ImplementAbstractClass/ImplementAbstractClassTests.vb +++ b/src/Analyzers/VisualBasic/Tests/ImplementAbstractClass/ImplementAbstractClassTests.vb @@ -632,7 +632,7 @@ Class C Throw New System.NotImplementedException() End Set End Property -End Class", parameters:=New TestParameters(globalOptions:=[Option](ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties))) +End Class", parameters:=New TestParameters(options:=[Option](ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties))) End Function End Class End Namespace diff --git a/src/Features/VisualBasicTest/ImplementAbstractClass/ImplementAbstractClassTests_FixAllTests.vb b/src/Analyzers/VisualBasic/Tests/ImplementAbstractClass/ImplementAbstractClassTests_FixAllTests.vb similarity index 100% rename from src/Features/VisualBasicTest/ImplementAbstractClass/ImplementAbstractClassTests_FixAllTests.vb rename to src/Analyzers/VisualBasic/Tests/ImplementAbstractClass/ImplementAbstractClassTests_FixAllTests.vb diff --git a/src/Features/VisualBasicTest/ImplementInterface/ImplementInterfaceTests.vb b/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests.vb similarity index 98% rename from src/Features/VisualBasicTest/ImplementInterface/ImplementInterfaceTests.vb rename to src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests.vb index 5ebe68a2a6a6c..8658148219004 100644 --- a/src/Features/VisualBasicTest/ImplementInterface/ImplementInterfaceTests.vb +++ b/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests.vb @@ -4183,24 +4183,24 @@ Class _ Protected Overridable Sub Dispose(disposing As Boolean) If Not disposedValue Then If disposing Then - ' { FeaturesResources.TODO_colon_dispose_managed_state_managed_objects } + ' { CodeFixesResources.TODO_colon_dispose_managed_state_managed_objects } End If - ' { FeaturesResources.TODO_colon_free_unmanaged_resources_unmanaged_objects_and_override_finalizer} - ' { FeaturesResources.TODO_colon_set_large_fields_to_null } + ' { CodeFixesResources.TODO_colon_free_unmanaged_resources_unmanaged_objects_and_override_finalizer} + ' { CodeFixesResources.TODO_colon_set_large_fields_to_null } disposedValue = True End If End Sub - ' ' { String.Format(FeaturesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, "Dispose(disposing As Boolean)") } + ' ' { String.Format(CodeFixesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, "Dispose(disposing As Boolean)") } ' Protected Overrides Sub Finalize() - ' ' { String.Format(FeaturesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)") } + ' ' { String.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)") } ' Dispose(disposing:=False) ' MyBase.Finalize() ' End Sub Public Sub Dispose() Implements IDisposable.Dispose - ' { String.Format(FeaturesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)") } + ' { String.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)") } Dispose(disposing:=True) GC.SuppressFinalize(Me) End Sub @@ -4254,24 +4254,24 @@ Partial Class C Protected Overridable Sub Dispose(disposing As Boolean) If Not disposedValue Then If disposing Then - ' { FeaturesResources.TODO_colon_dispose_managed_state_managed_objects } + ' { CodeFixesResources.TODO_colon_dispose_managed_state_managed_objects } End If - ' { FeaturesResources.TODO_colon_free_unmanaged_resources_unmanaged_objects_and_override_finalizer } - ' { FeaturesResources.TODO_colon_set_large_fields_to_null } + ' { CodeFixesResources.TODO_colon_free_unmanaged_resources_unmanaged_objects_and_override_finalizer } + ' { CodeFixesResources.TODO_colon_set_large_fields_to_null } disposedValue = True End If End Sub - ' ' { String.Format(FeaturesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, "Dispose(disposing As Boolean)") } + ' ' { String.Format(CodeFixesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, "Dispose(disposing As Boolean)") } ' Protected Overrides Sub Finalize() - ' ' { String.Format(FeaturesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)")} + ' ' { String.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)")} ' Dispose(disposing:=False) ' MyBase.Finalize() ' End Sub Public Sub Dispose() Implements IDisposable.Dispose - ' { String.Format(FeaturesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)") } + ' { String.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)") } Dispose(disposing:=True) GC.SuppressFinalize(Me) End Sub @@ -4294,24 +4294,24 @@ End Interface", {disposeMethodAccessibility} {disposeMethodModifiers}Sub Dispose(disposing As Boolean) If Not {disposeField} Then If disposing Then - ' {FeaturesResources.TODO_colon_dispose_managed_state_managed_objects} + ' {CodeFixesResources.TODO_colon_dispose_managed_state_managed_objects} End If - ' {FeaturesResources.TODO_colon_free_unmanaged_resources_unmanaged_objects_and_override_finalizer} - ' {FeaturesResources.TODO_colon_set_large_fields_to_null} + ' {CodeFixesResources.TODO_colon_free_unmanaged_resources_unmanaged_objects_and_override_finalizer} + ' {CodeFixesResources.TODO_colon_set_large_fields_to_null} {disposeField} = True End If End Sub - ' ' {String.Format(FeaturesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, "Dispose(disposing As Boolean)")} + ' ' {String.Format(CodeFixesResources.TODO_colon_override_finalizer_only_if_0_has_code_to_free_unmanaged_resources, "Dispose(disposing As Boolean)")} ' Protected Overrides Sub Finalize() - ' ' {String.Format(FeaturesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)")} + ' ' {String.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)")} ' Dispose(disposing:=False) ' MyBase.Finalize() ' End Sub Public Sub Dispose() Implements System.IDisposable.Dispose - ' {String.Format(FeaturesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)")} + ' {String.Format(CodeFixesResources.Do_not_change_this_code_Put_cleanup_code_in_0_method, "Dispose(disposing As Boolean)")} Dispose(disposing:=True) {gcPrefix}GC.SuppressFinalize(Me) End Sub" @@ -4532,7 +4532,7 @@ class Class Throw New System.NotImplementedException() End Set End Property -end class", parameters:=New TestParameters(globalOptions:=[Option](ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties))) +end class", parameters:=New TestParameters(options:=[Option](ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties))) End Function End Class End Namespace diff --git a/src/Features/VisualBasicTest/ImplementInterface/ImplementInterfaceTests_FixAllTests.vb b/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.vb similarity index 98% rename from src/Features/VisualBasicTest/ImplementInterface/ImplementInterfaceTests_FixAllTests.vb rename to src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.vb index 2074f1be2e429..46138758ecf48 100644 --- a/src/Features/VisualBasicTest/ImplementInterface/ImplementInterfaceTests_FixAllTests.vb +++ b/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.vb @@ -491,9 +491,17 @@ Class B3 Implements I1 Implements I2 + Public Sub F1() Implements I1.F1 + Throw New NotImplementedException() + End Sub + Private Class C3 Implements I1 Implements I2 + + Public Sub F1() Implements I1.F1 + Throw New NotImplementedException() + End Sub End Class End Class]]> diff --git a/src/Analyzers/VisualBasic/Tests/UseCoalesceExpression/UseCoalesceExpressionForIfNullStatementCheckTests.vb b/src/Analyzers/VisualBasic/Tests/UseCoalesceExpression/UseCoalesceExpressionForIfNullStatementCheckTests.vb index fe1ce8a086531..61cc9e0559e24 100644 --- a/src/Analyzers/VisualBasic/Tests/UseCoalesceExpression/UseCoalesceExpressionForIfNullStatementCheckTests.vb +++ b/src/Analyzers/VisualBasic/Tests/UseCoalesceExpression/UseCoalesceExpressionForIfNullStatementCheckTests.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.UseCoalesceExpression Imports VerifyVB = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeFixVerifier(Of Microsoft.CodeAnalysis.VisualBasic.UseCoalesceExpression.VisualBasicUseCoalesceExpressionForIfNullStatementCheckDiagnosticAnalyzer, - Microsoft.CodeAnalysis.UseCoalesceExpression.UseCoalesceExpressionForIfNullStatementCheckCodeFixProvider) + Microsoft.CodeAnalysis.VisualBasic.UseCoalesceExpression.VisualBasicUseCoalesceExpressionForIfNullStatementCheckCodeFixProvider) Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.UseCoalesceExpression @@ -254,5 +254,87 @@ end class .FixedCode = text }.RunAsync() End Function + + + Public Async Function TestLocalDeclaration_NoCastBaseAssignment() As Task + Await New VerifyVB.Test With { + .TestCode = " +interface I +end interface + +class C + implements I + + sub Main(o as object) + dim item as I = TryCast(o, C) + [|if|] item is nothing then + item = TryCast(o, D) + end if + end sub +end class + +class D + implements I +end class + ", + .FixedCode = " +interface I +end interface + +class C + implements I + + sub Main(o as object) + dim item as I = If(TryCast(o, C), TryCast(o, D)) + end sub +end class + +class D + implements I +end class + " + }.RunAsync() + End Function + + + Public Async Function TestLocalDeclaration_NoCastBaseAssignment1() As Task + Await New VerifyVB.Test With { + .TestCode = " +interface I +end interface + +class C + implements I + + sub Main(c as C, d as D) + dim item as I = c + [|if|] item is nothing then + item = d + end if + end sub +end class + +class D + implements I +end class + ", + .FixedCode = " +interface I +end interface + +class C + implements I + + sub Main(c as C, d as D) + dim item as I = If(c, d) + end sub +end class + +class D + implements I +end class + " + }.RunAsync() + End Function End Class End Namespace diff --git a/src/Analyzers/VisualBasic/Tests/UseObjectInitializer/UseObjectInitializerTests.vb b/src/Analyzers/VisualBasic/Tests/UseObjectInitializer/UseObjectInitializerTests.vb index 9621cfb8cb6de..0f6022a2a48b0 100644 --- a/src/Analyzers/VisualBasic/Tests/UseObjectInitializer/UseObjectInitializerTests.vb +++ b/src/Analyzers/VisualBasic/Tests/UseObjectInitializer/UseObjectInitializerTests.vb @@ -9,13 +9,6 @@ Imports VerifyVB = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBas Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.UseObjectInitializer Public Class UseObjectInitializerTests - Private Shared Async Function TestInRegularAndScriptAsync(testCode As String, fixedCode As String) As Task - Await New VerifyVB.Test With { - .TestCode = testCode, - .FixedCode = fixedCode - }.RunAsync() - End Function - Private Shared Async Function TestMissingInRegularAndScriptAsync(testCode As String) As Task Await New VerifyVB.Test With { .TestCode = testCode, @@ -25,16 +18,15 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.UseObj Public Async Function TestOnVariableDeclarator() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Dim i As Integer Sub M() - Dim c = [|New|] C() - [|c|].i = 1 + Dim c = {|#1:{|#0:New|} C()|} + {|#2:c|}.i = 1 End Sub -End Class", -" +End Class" + Dim fixedCode = " Class C Dim i As Integer Sub M() @@ -42,21 +34,30 @@ Class C .i = 1 } End Sub -End Class") +End Class" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(5,17): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2)) + + Await test.RunAsync() End Function Public Async Function TestOnVariableDeclarator2() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Dim i As Integer Sub M() - Dim c As [|New|] C() - [|c|].i = 1 + Dim c As {|#1:{|#0:New|} C()|} + {|#2:c|}.i = 1 End Sub -End Class", -" +End Class" + Dim fixedCode = " Class C Dim i As Integer Sub M() @@ -64,22 +65,31 @@ Class C .i = 1 } End Sub -End Class") +End Class" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(5,18): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2)) + + Await test.RunAsync() End Function Public Async Function TestOnAssignmentExpression() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Dim i As Integer Sub M() Dim c as C = Nothing - c = [|New|] C() - [|c|].i = 1 + c = {|#1:{|#0:New|} C()|} + {|#2:c|}.i = 1 End Sub -End Class", -" +End Class" + Dim fixedCode = " Class C Dim i As Integer Sub M() @@ -88,22 +98,31 @@ Class C .i = 1 } End Sub -End Class") +End Class" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(6,13): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2)) + + Await test.RunAsync() End Function Public Async Function TestStopOnDuplicateMember() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Dim i As Integer Sub M() - Dim c = [|New|] C() - [|c|].i = 1 + Dim c = {|#1:{|#0:New|} C()|} + {|#2:c|}.i = 1 c.i = 2 End Sub -End Class", -" +End Class" + Dim fixedCode = " Class C Dim i As Integer Sub M() @@ -112,25 +131,34 @@ Class C } c.i = 2 End Sub -End Class") +End Class" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(5,17): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2)) + + Await test.RunAsync() End Function Public Async Function TestComplexInitializer() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Dim i As Integer Dim j As Integer Sub M() Dim array As C() - array(0) = [|New|] C() - [|array(0)|].i = 1 - [|array(0)|].j = 2 + array(0) = {|#1:{|#0:New|} C()|} + {|#2:array(0)|}.i = 1 + {|#3:array(0)|}.j = 2 End Sub -End Class", -" +End Class" + Dim fixedCode = " Class C Dim i As Integer Dim j As Integer @@ -142,23 +170,32 @@ Class C .j = 2 } End Sub -End Class") +End Class" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(8,20): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3)) + + Await test.RunAsync() End Function Public Async Function TestNotOnCompoundAssignment() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Dim i As Integer Dim j As Integer Sub M() - Dim c = [|New|] C() - [|c|].i = 1 + Dim c = {|#1:{|#0:New|} C()|} + {|#2:c|}.i = 1 c.j += 1 End Sub -End Class", -" +End Class" + Dim fixedCode = " Class C Dim i As Integer Dim j As Integer @@ -168,63 +205,91 @@ Class C } c.j += 1 End Sub -End Class") +End Class" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(6,17): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2)) + + Await test.RunAsync() End Function Public Async Function TestWithExistingInitializer() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Dim i As Integer Dim j As Integer Sub M() - Dim c = [|New|] C() With { + Dim c = {|#1:{|#0:New|} C() With { .i = 1 - } - [|c|].j = 1 + }|} + {|#2:c|}.j = 1 End Sub -End Class", -" +End Class" + Dim fixedCode = " Class C Dim i As Integer Dim j As Integer Sub M() - Dim c = [|New|] C With { + Dim c = New C With { .i = 1, .j = 1 } End Sub -End Class") +End Class" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(6,17): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2)) + + Await test.RunAsync() End Function Public Async Function TestWithExistingInitializerNotIfAlreadyInitialized() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Dim i As Integer Dim j As Integer Sub M() - Dim c = [|New|] C() With { + Dim c = {|#1:{|#0:New|} C() With { .i = 1 - } - [|c|].j = 1 + }|} + {|#2:c|}.j = 1 c.i = 2 End Sub -End Class", -" +End Class" + Dim fixedCode = " Class C Dim i As Integer Dim j As Integer Sub M() - Dim c = [|New|] C With { + Dim c = New C With { .i = 1, .j = 1 } c.i = 2 End Sub -End Class") +End Class" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(6,17): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2)) + + Await test.RunAsync() End Function @@ -245,21 +310,20 @@ End Class") Public Async Function TestIfImplicitMemberAccessWouldNotChange() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " imports system.diagnostics Class C Sub M() - Dim x As ProcessStartInfo = [|New|] ProcessStartInfo() - [|x|].Arguments = {|BC30491:Sub() + Dim x As ProcessStartInfo = {|#1:{|#0:New|} ProcessStartInfo()|} + {|#2:x|}.Arguments = {|BC30491:Sub() With New String(Nothing) Dim a = .Length.ToString() End With End Sub()|} End Sub -End Class", -" +End Class" + Dim fixedCode = " imports system.diagnostics Class C @@ -272,29 +336,38 @@ Class C End Sub()|} } End Sub -End Class") +End Class" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(6,37): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2)) + + Await test.RunAsync() End Function Public Async Function TestFixAllInDocument() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Dim i As Integer Dim j As Integer Sub M() Dim array As C() - array(0) = [|New|] C() - [|array(0)|].i = 1 - [|array(0)|].j = 2 + array(0) = {|#1:{|#0:New|} C()|} + {|#2:array(0)|}.i = 1 + {|#3:array(0)|}.j = 2 - array(1) = [|New|] C() - [|array(1)|].i = 3 - [|array(1)|].j = 4 + array(1) = {|#5:{|#4:New|} C()|} + {|#6:array(1)|}.i = 3 + {|#7:array(1)|}.j = 4 End Sub -End Class", -" +End Class" + Dim fixedCode = " Class C Dim i As Integer Dim j As Integer @@ -311,23 +384,36 @@ Class C .j = 4 } End Sub -End Class") +End Class" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(8,20): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3)) + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(12,20): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(4).WithLocation(5).WithLocation(6).WithLocation(7)) + + Await test.RunAsync() End Function Public Async Function TestTrivia1() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Dim i As Integer Dim j As Integer Sub M() - Dim c = [|New|] C() - [|c|].i = 1 ' Goo - [|c|].j = 2 ' Bar + Dim c = {|#1:{|#0:New|} C()|} + {|#2:c|}.i = 1 ' Goo + {|#3:c|}.j = 2 ' Bar End Sub -End Class", -" +End Class" + Dim fixedCode = " Class C Dim i As Integer Dim j As Integer @@ -337,20 +423,29 @@ Class C .j = 2 ' Bar } End Sub -End Class") +End Class" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(6,17): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3)) + + Await test.RunAsync() End Function Public Async Function TestTrivia2() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Sub M(Reader as String) - Dim XmlAppConfigReader As [|New|] XmlTextReader(Reader) + Dim XmlAppConfigReader As {|#1:{|#0:New|} XmlTextReader(Reader)|} ' Required by Fxcop rule CA3054 - DoNotAllowDTDXmlTextReader - [|XmlAppConfigReader|].x = 0 - [|XmlAppConfigReader|].y = 1 + {|#2:XmlAppConfigReader|}.x = 0 + {|#3:XmlAppConfigReader|}.y = 1 End Sub End Class @@ -361,8 +456,8 @@ class XmlTextReader public x as integer public y as integer end class -", " + Dim fixedCode = " Class C Sub M(Reader as String) ' Required by Fxcop rule CA3054 - DoNotAllowDTDXmlTextReader @@ -380,22 +475,31 @@ class XmlTextReader public x as integer public y as integer end class -") +" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(4,35): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3)) + + Await test.RunAsync() End Function Public Async Function TestTrivia3() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Sub M(Reader as String) - Dim XmlAppConfigReader As [|New|] XmlTextReader(Reader) + Dim XmlAppConfigReader As {|#1:{|#0:New|} XmlTextReader(Reader)|} ' Required by Fxcop rule CA3054 - DoNotAllowDTDXmlTextReader - [|XmlAppConfigReader|].x = 0 + {|#2:XmlAppConfigReader|}.x = 0 ' Bar - [|XmlAppConfigReader|].y = 1 + {|#3:XmlAppConfigReader|}.y = 1 End Sub End Class @@ -406,8 +510,8 @@ class XmlTextReader public x as integer public y as integer end class -", " + Dim fixedCode = " Class C Sub M(Reader as String) ' Required by Fxcop rule CA3054 - DoNotAllowDTDXmlTextReader @@ -426,25 +530,34 @@ class XmlTextReader public x as integer public y as integer end class -") +" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(4,35): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2).WithLocation(3)) + + Await test.RunAsync() End Function Public Async Function TestSharedMember() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " Class C Dim x As Integer Shared y As Integer Sub M() - Dim z = [|New|] C() - [|z|].x = 1 + Dim z = {|#1:{|#0:New|} C()|} + {|#2:z|}.x = 1 z.y = 2 End Sub End Class -", " + Dim fixedCode = " Class C Dim x As Integer Shared y As Integer @@ -456,7 +569,17 @@ Class C z.y = 2 End Sub End Class -") +" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(7,17): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2)) + + Await test.RunAsync() End Function @@ -512,12 +635,11 @@ End Class Public Async Function TestWithExplicitImplementedInterfaceMembers3() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " class C Sub Bar() - Dim c As IExample = [|New|] Goo - [|c|].LastName = String.Empty + Dim c As IExample = {|#1:{|#0:New|} Goo|} + {|#2:c|}.LastName = String.Empty c.Name = String.Empty End Sub End Class @@ -533,8 +655,8 @@ Class Goo Private Property Name As String Implements IExample.Name Public Property LastName As String Implements IExample.LastName End Class -", " + Dim fixedCode = " class C Sub Bar() Dim c As IExample = New Goo With { @@ -555,17 +677,26 @@ Class Goo Private Property Name As String Implements IExample.Name Public Property LastName As String Implements IExample.LastName End Class -") +" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(4,29): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2)) + + Await test.RunAsync() End Function Public Async Function TestWithExplicitImplementedInterfaceMembers4() As Task - Await TestInRegularAndScriptAsync( -" + Dim testCode = " class C Sub Bar() - Dim c As IExample = [|New|] Goo - [|c|].LastName = String.Empty + Dim c As IExample = {|#1:{|#0:New|} Goo|} + {|#2:c|}.LastName = String.Empty c.Name = String.Empty End Sub End Class @@ -581,8 +712,8 @@ Class Goo Private Property Name As String Implements IExample.Name Public Property MyLastName As String Implements IExample.LastName End Class -", " + Dim fixedCode = " class C Sub Bar() Dim c As IExample = New Goo With { @@ -603,7 +734,17 @@ Class Goo Private Property Name As String Implements IExample.Name Public Property MyLastName As String Implements IExample.LastName End Class -") +" + Dim test = New VerifyVB.Test With { + .TestCode = testCode, + .FixedCode = fixedCode + } + + test.ExpectedDiagnostics.Add( + _ ' /0/Test0.vb(4,29): info IDE0017: Object initialization can be simplified + VerifyVB.Diagnostic().WithSeverity(DiagnosticSeverity.Info).WithLocation(0).WithLocation(1).WithLocation(2)) + + Await test.RunAsync() End Function End Class End Namespace diff --git a/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems b/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems index 9073e0997b3c4..9f5434bfc464c 100644 --- a/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems +++ b/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems @@ -23,6 +23,14 @@ + + + + + + + + diff --git a/src/CodeStyle/CSharp/Tests/Microsoft.CodeAnalysis.CSharp.CodeStyle.UnitTests.csproj b/src/CodeStyle/CSharp/Tests/Microsoft.CodeAnalysis.CSharp.CodeStyle.UnitTests.csproj index 5181891d7aeb9..bc1113d4f05c9 100644 --- a/src/CodeStyle/CSharp/Tests/Microsoft.CodeAnalysis.CSharp.CodeStyle.UnitTests.csproj +++ b/src/CodeStyle/CSharp/Tests/Microsoft.CodeAnalysis.CSharp.CodeStyle.UnitTests.csproj @@ -15,6 +15,7 @@ + diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index 0b68a2d055d75..48f34cef5364a 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -14,7 +14,9 @@ + + diff --git a/src/CodeStyle/Core/Tests/Directory.Build.props b/src/CodeStyle/Core/Tests/Directory.Build.props index b6ffeb0a027c0..089dcb1906af4 100644 --- a/src/CodeStyle/Core/Tests/Directory.Build.props +++ b/src/CodeStyle/Core/Tests/Directory.Build.props @@ -1,6 +1,6 @@ - true + true \ No newline at end of file diff --git a/src/CodeStyle/Core/Tests/UnitTestUtilities/Microsoft.CodeAnalysis.CodeStyle.UnitTestUtilities.csproj b/src/CodeStyle/Core/Tests/UnitTestUtilities/Microsoft.CodeAnalysis.CodeStyle.UnitTestUtilities.csproj index 69807d0f912fa..3a5c8ce8f9c94 100644 --- a/src/CodeStyle/Core/Tests/UnitTestUtilities/Microsoft.CodeAnalysis.CodeStyle.UnitTestUtilities.csproj +++ b/src/CodeStyle/Core/Tests/UnitTestUtilities/Microsoft.CodeAnalysis.CodeStyle.UnitTestUtilities.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/CodeStyle/Tools/Program.cs b/src/CodeStyle/Tools/Program.cs index 6a289be8b28f7..adbc52aa691ee 100644 --- a/src/CodeStyle/Tools/Program.cs +++ b/src/CodeStyle/Tools/Program.cs @@ -264,9 +264,10 @@ and an implied numerical option (such as '4') --> - + + diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index df47e679fd665..aea6580634b3a 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -388,6 +388,11 @@ private static AccessorKind GetIndexerAccessorKind(BoundIndexerAccess indexerAcc return AccessorKind.Get; } + return GetAccessorKind(valueKind); + } + + private static AccessorKind GetAccessorKind(BindValueKind valueKind) + { var coreValueKind = valueKind & ValueKindSignificantBitsMask; return coreValueKind switch { @@ -523,6 +528,28 @@ private BoundExpression CheckValue(BoundExpression expr, BindValueKind valueKind Debug.Assert(valueKind is (BindValueKind.Assignable or BindValueKind.RefOrOut or BindValueKind.RefAssignable) || diagnostics.DiagnosticBag is null || diagnostics.HasAnyResolvedErrors()); return expr; + case BoundKind.PropertyAccess: + if (!InAttributeArgument) + { + // If the property has a synthesized backing field, record the accessor kind of the property + // access for determining whether the property access can use the backing field directly. + var propertyAccess = (BoundPropertyAccess)expr; + if (HasSynthesizedBackingField(propertyAccess.PropertySymbol, out _)) + { + expr = propertyAccess.Update( + propertyAccess.ReceiverOpt, + propertyAccess.InitialBindingReceiverIsSubjectToCloning, + propertyAccess.PropertySymbol, + autoPropertyAccessorKind: GetAccessorKind(valueKind), + propertyAccess.ResultKind, + propertyAccess.Type); + } + } +#if DEBUG + expr.WasPropertyBackingFieldAccessChecked = true; +#endif + break; + case BoundKind.IndexerAccess: expr = BindIndexerDefaultArgumentsAndParamsCollection((BoundIndexerAccess)expr, valueKind, diagnostics); break; @@ -898,6 +925,12 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin break; case BoundKind.ConditionalOperator: + if (RequiresRefAssignableVariable(valueKind)) + { + Error(diagnostics, ErrorCode.ERR_RefLocalOrParamExpected, node); + return false; + } + var conditional = (BoundConditionalOperator)expr; // byref conditional defers to its operands @@ -918,6 +951,13 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin } case BoundKind.AssignmentOperator: + // Cannot ref-assign to a ref assignment. + if (RequiresRefAssignableVariable(valueKind)) + { + Error(diagnostics, ErrorCode.ERR_RefLocalOrParamExpected, node); + return false; + } + var assignment = (BoundAssignmentOperator)expr; return CheckSimpleAssignmentValueKind(node, assignment, valueKind, diagnostics); @@ -926,7 +966,7 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin break; default: - Debug.Assert(expr is not BoundValuePlaceholderBase, $"Placeholder kind {expr.Kind} should be explicitly handled"); + RoslynDebug.Assert(expr is not BoundValuePlaceholderBase, $"Placeholder kind {expr.Kind} should be explicitly handled"); break; } @@ -1358,6 +1398,21 @@ private bool CheckFieldValueKind(SyntaxNode node, BoundFieldAccess fieldAccess, } } + if (RequiresReferenceToLocation(valueKind)) + { + switch (fieldSymbol.RefKind) + { + case RefKind.None: + break; + case RefKind.Ref: + case RefKind.RefReadOnly: + // ref readonly access to a ref (readonly) field is fine regardless of the receiver + return true; + default: + throw ExceptionUtilities.UnexpectedValue(fieldSymbol.RefKind); + } + } + // r/w fields that are static or belong to reference types are writeable and returnable if (fieldSymbol.IsStatic || fieldSymbol.ContainingType.IsReferenceType) { @@ -1694,7 +1749,7 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV if (setMethod is null) { var containing = this.ContainingMemberOrLambda; - if (!AccessingAutoPropertyFromConstructor(receiver, propertySymbol, containing) + if (!AccessingAutoPropertyFromConstructor(receiver, propertySymbol, containing, AccessorKind.Set) && !isAllowedDespiteReadonly(receiver)) { Error(diagnostics, ErrorCode.ERR_AssgReadonlyProp, node, propertySymbol); @@ -4479,7 +4534,7 @@ internal uint GetValEscape(BoundExpression expr, uint scopeOfTheContainingExpres // in error situations some unexpected nodes could make here // returning "scopeOfTheContainingExpression" seems safer than throwing. // we will still assert to make sure that all nodes are accounted for. - Debug.Assert(false, $"{expr.Kind} expression of {expr.Type} type"); + RoslynDebug.Assert(false, $"{expr.Kind} expression of {expr.Type} type"); return scopeOfTheContainingExpression; } } @@ -4624,6 +4679,13 @@ uint getIndexerEscape( uint receiverEscapeScope = CallingMethodScope; foreach (var escapeValue in escapeValues) { + // This is a call to an indexer so the ref escape scope can only impact the escape value if it + // can be assigned to `this`. Return Only can't do this. + if (escapeValue.IsRefEscape && escapeValue.EscapeLevel != EscapeLevel.CallingMethod) + { + continue; + } + uint escapeScope = escapeValue.IsRefEscape ? GetRefEscape(escapeValue.Argument, scopeOfTheContainingExpression) : GetValEscape(escapeValue.Argument, scopeOfTheContainingExpression); @@ -5267,7 +5329,7 @@ internal bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint escapeF // in error situations some unexpected nodes could make here // returning "false" seems safer than throwing. // we will still assert to make sure that all nodes are accounted for. - Debug.Assert(false, $"{expr.Kind} expression of {expr.Type} type"); + RoslynDebug.Assert(false, $"{expr.Kind} expression of {expr.Type} type"); diagnostics.Add(ErrorCode.ERR_InternalError, node.Location); return false; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs index 5ce1a7173d21d..601bcdd9c92b2 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs @@ -137,7 +137,7 @@ internal static void GetAttributes( internal BoundAttribute BindAttribute(AttributeSyntax node, NamedTypeSymbol attributeType, Symbol? attributedMember, BindingDiagnosticBag diagnostics) { - return this.GetRequiredBinder(node).BindAttributeCore(node, attributeType, attributedMember, diagnostics); + return BindAttributeCore(this.GetRequiredBinder(node), node, attributeType, attributedMember, diagnostics); } private Binder SkipSemanticModelBinder() @@ -152,9 +152,10 @@ private Binder SkipSemanticModelBinder() return result; } - private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol attributeType, Symbol? attributedMember, BindingDiagnosticBag diagnostics) + private static BoundAttribute BindAttributeCore(Binder binder, AttributeSyntax node, NamedTypeSymbol attributeType, Symbol? attributedMember, BindingDiagnosticBag diagnostics) { - Debug.Assert(this.SkipSemanticModelBinder() == this.GetRequiredBinder(node).SkipSemanticModelBinder()); + Debug.Assert(binder.SkipSemanticModelBinder() == binder.GetRequiredBinder(node).SkipSemanticModelBinder()); + binder = binder.WithAdditionalFlags(BinderFlags.AttributeArgument); // If attribute name bound to an error type with a single named type // candidate symbol, we want to bind the attribute constructor @@ -178,8 +179,7 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a // Bind constructor and named attribute arguments using the attribute binder var argumentListOpt = node.ArgumentList; - Binder attributeArgumentBinder = this.WithAdditionalFlags(BinderFlags.AttributeArgument); - AnalyzedAttributeArguments analyzedArguments = attributeArgumentBinder.BindAttributeArguments(argumentListOpt, attributeTypeForBinding, diagnostics); + AnalyzedAttributeArguments analyzedArguments = binder.BindAttributeArguments(argumentListOpt, attributeTypeForBinding, diagnostics); ImmutableArray argsToParamsOpt; bool expanded = false; @@ -189,13 +189,13 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a if (attributeTypeForBinding.IsErrorType()) { boundConstructorArguments = analyzedArguments.ConstructorArguments.Arguments.SelectAsArray( - static (arg, attributeArgumentBinder) => attributeArgumentBinder.BindToTypeForErrorRecovery(arg), - attributeArgumentBinder); + static (arg, binder) => binder.BindToTypeForErrorRecovery(arg), + binder); argsToParamsOpt = default; } else { - bool found = attributeArgumentBinder.TryPerformConstructorOverloadResolution( + bool found = binder.TryPerformConstructorOverloadResolution( attributeTypeForBinding, analyzedArguments.ConstructorArguments, attributeTypeForBinding.Name, @@ -211,7 +211,7 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a if (memberResolutionResult.IsNotNull) { - this.CheckAndCoerceArguments(node, memberResolutionResult, analyzedArguments.ConstructorArguments, diagnostics, receiver: null, invokedAsExtensionMethod: false, out argsToParamsOpt); + binder.CheckAndCoerceArguments(node, memberResolutionResult, analyzedArguments.ConstructorArguments, diagnostics, receiver: null, invokedAsExtensionMethod: false, out argsToParamsOpt); } else { @@ -223,17 +223,17 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a if (!found) { - CompoundUseSiteInfo useSiteInfo = attributeArgumentBinder.GetNewCompoundUseSiteInfo(diagnostics); + CompoundUseSiteInfo useSiteInfo = binder.GetNewCompoundUseSiteInfo(diagnostics); resultKind = resultKind.WorseResultKind( - memberResolutionResult.IsValid && !attributeArgumentBinder.IsConstructorAccessible(memberResolutionResult.Member, ref useSiteInfo) ? + memberResolutionResult.IsValid && !binder.IsConstructorAccessible(memberResolutionResult.Member, ref useSiteInfo) ? LookupResultKind.Inaccessible : LookupResultKind.OverloadResolutionFailure); - boundConstructorArguments = attributeArgumentBinder.BuildArgumentsForErrorRecovery(analyzedArguments.ConstructorArguments, candidateConstructors); + boundConstructorArguments = binder.BuildArgumentsForErrorRecovery(analyzedArguments.ConstructorArguments, candidateConstructors); diagnostics.Add(node, useSiteInfo); } else { - attributeArgumentBinder.BindDefaultArguments( + binder.BindDefaultArguments( node, attributeConstructor.Parameters, analyzedArguments.ConstructorArguments.Arguments, @@ -242,7 +242,7 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a ref argsToParamsOpt, out defaultArguments, expanded, - enableCallerInfo: !IsEarlyAttributeBinder, + enableCallerInfo: !binder.IsEarlyAttributeBinder, diagnostics, attributedMember: attributedMember); boundConstructorArguments = analyzedArguments.ConstructorArguments.Arguments.ToImmutable(); @@ -578,7 +578,7 @@ private BoundAssignmentOperator BindNamedAttributeArgument(AttributeArgumentSynt var propertySymbol = namedArgumentNameSymbol as PropertySymbol; if (propertySymbol is object) { - lvalue = new BoundPropertyAccess(nameSyntax, receiverOpt: null, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, propertySymbol, resultKind, namedArgumentType); + lvalue = new BoundPropertyAccess(nameSyntax, receiverOpt: null, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, propertySymbol, autoPropertyAccessorKind: AccessorKind.Unknown, resultKind, namedArgumentType); } else { diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 8128a83e56663..5b48c643a0ad4 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -870,7 +870,13 @@ private BoundCollectionExpression ConvertCollectionExpression( Debug.Assert((collectionCreation is BoundNewT && !isExpanded && constructor is null) || (collectionCreation is BoundObjectCreationExpression creation && creation.Expanded == isExpanded && creation.Constructor == constructor)); - var collectionInitializerAddMethodBinder = this.WithAdditionalFlags(BinderFlags.CollectionInitializerAddMethod); + if (!elements.IsDefaultOrEmpty && HasCollectionInitializerTypeInProgress(syntax, targetType)) + { + diagnostics.Add(ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls, syntax, targetType); + return BindCollectionExpressionForErrorRecovery(node, targetType, inConversion: true, diagnostics); + } + + var collectionInitializerAddMethodBinder = new CollectionInitializerAddMethodBinder(syntax, targetType, this); foreach (var element in elements) { BoundNode convertedElement = element is BoundCollectionExpressionSpreadElement spreadElement ? @@ -881,7 +887,7 @@ private BoundCollectionExpression ConvertCollectionExpression( implicitReceiver, diagnostics) : BindCollectionInitializerElementAddMethod( - (ExpressionSyntax)element.Syntax, + element.Syntax, ImmutableArray.Create((BoundExpression)element), hasEnumerableInitializerType: true, collectionInitializerAddMethodBinder, @@ -973,6 +979,24 @@ BoundNode bindSpreadElement(BoundCollectionExpressionSpreadElement element, Type } } + private bool HasCollectionInitializerTypeInProgress(SyntaxNode syntax, TypeSymbol targetType) + { + Binder? current = this; + while (current?.Flags.Includes(BinderFlags.CollectionInitializerAddMethod) == true) + { + if (current is CollectionInitializerAddMethodBinder binder && + binder.Syntax == syntax && + binder.CollectionType.OriginalDefinition.Equals(targetType.OriginalDefinition, TypeCompareKind.AllIgnoreOptions)) + { + return true; + } + + current = current.Next; + } + + return false; + } + internal MethodSymbol? GetAndValidateCollectionBuilderMethod( SyntaxNode syntax, NamedTypeSymbol namedType, diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index c19f2399a4cc0..3defebbef0d8d 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -598,6 +598,8 @@ BoundExpression bindExpressionInternal(ExpressionSyntax node, BindingDiagnosticB return BindThis((ThisExpressionSyntax)node, diagnostics); case SyntaxKind.BaseExpression: return BindBase((BaseExpressionSyntax)node, diagnostics); + case SyntaxKind.FieldExpression: + return BindFieldExpression((FieldExpressionSyntax)node, diagnostics); case SyntaxKind.InvocationExpression: return BindInvocationExpression((InvocationExpressionSyntax)node, diagnostics); case SyntaxKind.ArrayInitializerExpression: @@ -1433,6 +1435,56 @@ private BoundExpression BindSizeOf(SizeOfExpressionSyntax node, BindingDiagnosti this.GetSpecialType(SpecialType.System_Int32, diagnostics, node), hasErrors); } + private BoundExpression BindFieldExpression(FieldExpressionSyntax node, BindingDiagnosticBag diagnostics) + { + Debug.Assert(ContainingType is { }); + SynthesizedBackingFieldSymbolBase? field = null; + + if (hasOtherFieldSymbolInScope()) + { + diagnostics.Add(ErrorCode.WRN_FieldIsAmbiguous, node, Compilation.LanguageVersion.ToDisplayString()); + } + + switch (ContainingMember()) + { + case SynthesizedBackingFieldSymbolBase backingField: + field = backingField; + break; + case MethodSymbol { AssociatedSymbol: SourcePropertySymbol property }: + field = property.BackingField; + break; + default: + { + Debug.Assert((this.Flags & BinderFlags.InContextualAttributeBinder) != 0); + var contextualAttributeBinder = TryGetContextualAttributeBinder(this); + if (contextualAttributeBinder is { AttributeTarget: MethodSymbol { AssociatedSymbol: SourcePropertySymbol property } }) + { + field = property.BackingField; + } + break; + } + } + + if (field is null) + { + throw ExceptionUtilities.UnexpectedValue(ContainingMember()); + } + + var implicitReceiver = field.IsStatic ? null : ThisReference(node, field.ContainingType, wasCompilerGenerated: true); + return new BoundFieldAccess(node, implicitReceiver, field, constantValueOpt: null); + + bool hasOtherFieldSymbolInScope() + { + var lookupResult = LookupResult.GetInstance(); + var useSiteInfo = CompoundUseSiteInfo.Discarded; + this.LookupIdentifier(lookupResult, name: "field", arity: 0, invoked: false, ref useSiteInfo); + bool result = lookupResult.Kind != LookupResultKind.Empty; + Debug.Assert(!result || lookupResult.Symbols.Count > 0); + lookupResult.Free(); + return result; + } + } + /// true if managed type-related errors were found, otherwise false. internal static bool CheckManagedAddr(CSharpCompilation compilation, TypeSymbol type, Location location, BindingDiagnosticBag diagnostics, bool errorForManaged = false) { @@ -1549,11 +1601,6 @@ private BoundExpression BindIdentifier( var members = ArrayBuilder.GetInstance(); Symbol symbol = GetSymbolOrMethodOrPropertyGroup(lookupResult, node, name, node.Arity, members, diagnostics, out isError, qualifierOpt: null); // reports diagnostics in result. - if (symbol is not SynthesizedAccessorValueParameterSymbol { Name: "value" }) - { - ReportFieldOrValueContextualKeywordConflictIfAny(node, node.Identifier, diagnostics); - } - if ((object)symbol == null) { Debug.Assert(members.Count > 0); @@ -1736,28 +1783,12 @@ void reportPrimaryConstructorParameterShadowing(SimpleNameSyntax node, Symbol sy } } -#nullable enable - /// - /// Report a diagnostic for a 'field' or 'value' identifier that the meaning will - /// change when the identifier is considered a contextual keyword. - /// - internal void ReportFieldOrValueContextualKeywordConflictIfAny(SyntaxNode syntax, SyntaxToken identifier, BindingDiagnosticBag diagnostics) + private void LookupIdentifier(LookupResult lookupResult, SimpleNameSyntax node, bool invoked, ref CompoundUseSiteInfo useSiteInfo) { - string name = identifier.Text; - switch (name) - { - case "field" when ContainingMember() is MethodSymbol { MethodKind: MethodKind.PropertyGet or MethodKind.PropertySet, AssociatedSymbol: PropertySymbol { IsIndexer: false } }: - case "value" when ContainingMember() is MethodSymbol { MethodKind: MethodKind.PropertySet or MethodKind.EventAdd or MethodKind.EventRemove }: - { - var requiredVersion = MessageID.IDS_FeatureFieldAndValueKeywords.RequiredVersion(); - diagnostics.Add(ErrorCode.INF_IdentifierConflictWithContextualKeyword, syntax, name, requiredVersion.ToDisplayString()); - } - break; - } + LookupIdentifier(lookupResult, name: node.Identifier.ValueText, arity: node.Arity, invoked, useSiteInfo: ref useSiteInfo); } -#nullable disable - private void LookupIdentifier(LookupResult lookupResult, SimpleNameSyntax node, bool invoked, ref CompoundUseSiteInfo useSiteInfo) + private void LookupIdentifier(LookupResult lookupResult, string name, int arity, bool invoked, ref CompoundUseSiteInfo useSiteInfo) { LookupOptions options = LookupOptions.AllMethodsOnArityZero; if (invoked) @@ -1771,7 +1802,7 @@ private void LookupIdentifier(LookupResult lookupResult, SimpleNameSyntax node, options |= LookupOptions.MustNotBeMethodTypeParameter; } - this.LookupSymbolsWithFallback(lookupResult, node.Identifier.ValueText, arity: node.Arity, useSiteInfo: ref useSiteInfo, options: options); + this.LookupSymbolsWithFallback(lookupResult, name, arity, useSiteInfo: ref useSiteInfo, options: options); } /// @@ -5216,11 +5247,20 @@ static BoundNode bindSpreadElement(SpreadElementSyntax syntax, BindingDiagnostic Debug.Assert(conversion.IsValid); diagnostics.Add(syntax.Expression, useSiteInfo); var convertedExpression = @this.ConvertForEachCollection(expressionPlaceholder, conversion, collectionType, diagnostics); + BoundExpression? lengthOrCount; - if (!@this.TryBindLengthOrCount(syntax.Expression, expressionPlaceholder, out lengthOrCount, diagnostics)) + + if (enumeratorInfo is { InlineArraySpanType: not WellKnownType.Unknown }) + { + _ = expression.Type.HasInlineArrayAttribute(out int length); + Debug.Assert(length > 0); + lengthOrCount = new BoundLiteral(expression.Syntax, ConstantValue.Create(length), @this.GetSpecialType(SpecialType.System_Int32, diagnostics, expression.Syntax)) { WasCompilerGenerated = true }; + } + else if (!@this.TryBindLengthOrCount(syntax.Expression, expressionPlaceholder, out lengthOrCount, diagnostics)) { lengthOrCount = null; } + return new BoundCollectionExpressionSpreadElement( syntax, expression, @@ -8586,7 +8626,7 @@ private BoundExpression BindPropertyAccess( WarnOnAccessOfOffDefault(node, receiver, diagnostics); } - return new BoundPropertyAccess(node, receiver, initialBindingReceiverIsSubjectToCloning: ReceiverIsSubjectToCloning(receiver, propertySymbol), propertySymbol, lookupResult, propertySymbol.Type, hasErrors: (hasErrors || hasError)); + return new BoundPropertyAccess(node, receiver, initialBindingReceiverIsSubjectToCloning: ReceiverIsSubjectToCloning(receiver, propertySymbol), propertySymbol, autoPropertyAccessorKind: AccessorKind.Unknown, lookupResult, propertySymbol.Type, hasErrors: (hasErrors || hasError)); } #nullable disable @@ -10361,13 +10401,13 @@ private MethodGroupResolution ResolveDefaultMethodGroup( #nullable enable internal NamedTypeSymbol? GetMethodGroupDelegateType(BoundMethodGroup node) { - var method = GetUniqueSignatureFromMethodGroup(node); + var method = GetUniqueSignatureFromMethodGroup(node, out bool useParams); if (method is null) { return null; } - return GetMethodGroupOrLambdaDelegateType(node.Syntax, method); + return GetMethodGroupOrLambdaDelegateType(node.Syntax, method, hasParams: useParams); } /// @@ -10375,9 +10415,13 @@ private MethodGroupResolution ResolveDefaultMethodGroup( /// have the same signature, ignoring parameter names and custom modifiers. The particular /// method returned is not important since the caller is interested in the signature only. /// - private MethodSymbol? GetUniqueSignatureFromMethodGroup_CSharp10(BoundMethodGroup node) + /// + /// Whether the last parameter of the signature should have the modifier. + /// + private MethodSymbol? GetUniqueSignatureFromMethodGroup_CSharp10(BoundMethodGroup node, out bool useParams) { MethodSymbol? method = null; + var methods = ArrayBuilder.GetInstance(capacity: node.Methods.Length); foreach (var m in node.Methods) { switch (node.ReceiverOpt) @@ -10392,37 +10436,92 @@ private MethodGroupResolution ResolveDefaultMethodGroup( if (m.IsStatic) continue; break; } + methods.Add(m); + } + + if (!OverloadResolution.FilterMethodsForUniqueSignature(methods, out useParams)) + { + methods.Free(); + return null; + } + + var seenAnyApplicableCandidates = methods.Count != 0; + + foreach (var m in methods) + { if (!isCandidateUnique(ref method, m)) { + methods.Free(); + useParams = false; return null; } } + if (node.SearchExtensionMethods) { var receiver = node.ReceiverOpt!; foreach (var scope in new ExtensionMethodScopes(this)) { + methods.Clear(); var methodGroup = MethodGroup.GetInstance(); PopulateExtensionMethodsFromSingleBinder(scope, methodGroup, node.Syntax, receiver, node.Name, node.TypeArgumentsOpt, BindingDiagnosticBag.Discarded); foreach (var m in methodGroup.Methods) { - if (m.ReduceExtensionMethod(receiver.Type, Compilation) is { } reduced && - !isCandidateUnique(ref method, reduced)) + if (m.ReduceExtensionMethod(receiver.Type, Compilation) is { } reduced) { - methodGroup.Free(); - return null; + methods.Add(reduced); } } methodGroup.Free(); + + if (methods.Count == 0) + { + continue; + } + + if (!OverloadResolution.FilterMethodsForUniqueSignature(methods, out bool useParamsForScope)) + { + methods.Free(); + useParams = false; + return null; + } + + Debug.Assert(methods.Count != 0); + + // If we had some candidates that differ in `params` from the current scope, we don't have a unique signature. + if (seenAnyApplicableCandidates && useParamsForScope != useParams) + { + methods.Free(); + useParams = false; + return null; + } + + useParams = useParamsForScope; + seenAnyApplicableCandidates = true; + + foreach (var reduced in methods) + { + if (!isCandidateUnique(ref method, reduced)) + { + methods.Free(); + useParams = false; + return null; + } + } } } + + methods.Free(); + if (method is null) { + useParams = false; return null; } int n = node.TypeArgumentsOpt.IsDefaultOrEmpty ? 0 : node.TypeArgumentsOpt.Length; if (method.Arity != n) { + useParams = false; return null; } else if (n > 0) @@ -10452,17 +10551,22 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) /// in the nearest scope, have the same signature ignoring parameter names and custom modifiers. /// The particular method returned is not important since the caller is interested in the signature only. /// - private MethodSymbol? GetUniqueSignatureFromMethodGroup(BoundMethodGroup node) + /// + /// Whether the last parameter of the signature should have the modifier. + /// + private MethodSymbol? GetUniqueSignatureFromMethodGroup(BoundMethodGroup node, out bool useParams) { if (Compilation.LanguageVersion < LanguageVersion.CSharp13) { - return GetUniqueSignatureFromMethodGroup_CSharp10(node); + return GetUniqueSignatureFromMethodGroup_CSharp10(node, out useParams); } + useParams = false; MethodSymbol? foundMethod = null; var typeArguments = node.TypeArgumentsOpt; if (node.ResultKind == LookupResultKind.Viable) { + var methods = ArrayBuilder.GetInstance(capacity: node.Methods.Length); foreach (var memberMethod in node.Methods) { switch (node.ReceiverOpt) @@ -10492,12 +10596,27 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) continue; } + methods.Add(substituted); + } + + if (!OverloadResolution.FilterMethodsForUniqueSignature(methods, out useParams)) + { + methods.Free(); + return null; + } + + foreach (var substituted in methods) + { if (!isCandidateUnique(ref foundMethod, substituted)) { + methods.Free(); + useParams = false; return null; } } + methods.Free(); + if (foundMethod is not null) { return foundMethod; @@ -10512,6 +10631,7 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) { methodGroup.Clear(); PopulateExtensionMethodsFromSingleBinder(scope, methodGroup, node.Syntax, receiver, node.Name, typeArguments, BindingDiagnosticBag.Discarded); + var methods = ArrayBuilder.GetInstance(capacity: methodGroup.Methods.Count); foreach (var extensionMethod in methodGroup.Methods) { var substituted = typeArguments.IsDefaultOrEmpty ? extensionMethod : extensionMethod.Construct(typeArguments); @@ -10533,14 +10653,29 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) continue; } - var wasUnique = isCandidateUnique(ref foundMethod, reduced); - if (!wasUnique) + methods.Add(reduced); + } + + if (!OverloadResolution.FilterMethodsForUniqueSignature(methods, out useParams)) + { + methods.Free(); + methodGroup.Free(); + return null; + } + + foreach (var reduced in methods) + { + if (!isCandidateUnique(ref foundMethod, reduced)) { + methods.Free(); methodGroup.Free(); + useParams = false; return null; } } + methods.Free(); + if (foundMethod is not null) { methodGroup.Free(); @@ -10550,6 +10685,7 @@ static bool isCandidateUnique(ref MethodSymbol? method, MethodSymbol candidate) methodGroup.Free(); } + useParams = false; return null; static bool isCandidateUnique(ref MethodSymbol? foundMethod, MethodSymbol candidate) @@ -10569,7 +10705,7 @@ static bool isCandidateUnique(ref MethodSymbol? foundMethod, MethodSymbol candid bool satisfiesConstraintChecks(MethodSymbol method) { - if (method.Arity == 0) + if (!ConstraintsHelper.RequiresChecking(method)) { return true; } @@ -10595,6 +10731,7 @@ bool satisfiesConstraintChecks(MethodSymbol method) internal NamedTypeSymbol? GetMethodGroupOrLambdaDelegateType( SyntaxNode syntax, MethodSymbol methodSymbol, + bool hasParams, ImmutableArray? parameterScopesOverride = null, ImmutableArray? parameterHasUnscopedRefAttributesOverride = null, RefKind? returnRefKindOverride = null, @@ -10613,8 +10750,6 @@ bool satisfiesConstraintChecks(MethodSymbol method) parameters.SelectAsArray(p => p.ExplicitDefaultConstantValue) : default; - var hasParams = OverloadResolution.IsValidParams(this, methodSymbol, disallowExpandedNonArrayParams: false, out _); - Debug.Assert(ContainingMemberOrLambda is { }); Debug.Assert(parameterRefKinds.IsDefault || parameterRefKinds.Length == parameterTypes.Length); Debug.Assert(parameterDefaultValues.IsDefault || parameterDefaultValues.Length == parameterTypes.Length); diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs index 8f75c4fcfce84..860fbe3e56536 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs @@ -363,7 +363,7 @@ private bool BindLengthAndIndexerForListPattern(SyntaxNode node, TypeSymbol inpu hasErrors |= !TryGetSpecialTypeMember(Compilation, SpecialMember.System_Array__Length, node, diagnostics, out PropertySymbol lengthProperty); if (lengthProperty is not null) { - lengthAccess = new BoundPropertyAccess(node, receiverPlaceholder, initialBindingReceiverIsSubjectToCloning: ThreeState.False, lengthProperty, LookupResultKind.Viable, lengthProperty.Type) { WasCompilerGenerated = true }; + lengthAccess = new BoundPropertyAccess(node, receiverPlaceholder, initialBindingReceiverIsSubjectToCloning: ThreeState.False, lengthProperty, autoPropertyAccessorKind: AccessorKind.Unknown, LookupResultKind.Viable, lengthProperty.Type) { WasCompilerGenerated = true }; } else { @@ -1734,100 +1734,145 @@ private BoundPattern BindBinaryPattern( bool hasErrors, BindingDiagnosticBag diagnostics) { - bool isDisjunction = node.Kind() == SyntaxKind.OrPattern; - if (isDisjunction) + // Users (such as ourselves) can have many, many nested binary patterns. To avoid crashing, do left recursion manually. + + var binaryPatternStack = ArrayBuilder<(BinaryPatternSyntax pat, bool permitDesignations)>.GetInstance(); + BinaryPatternSyntax? currentNode = node; + + do { - MessageID.IDS_FeatureOrPattern.CheckFeatureAvailability(diagnostics, node.OperatorToken); + permitDesignations = permitDesignations && currentNode.IsKind(SyntaxKind.AndPattern); + binaryPatternStack.Push((currentNode, permitDesignations)); + currentNode = currentNode.Left as BinaryPatternSyntax; + } while (currentNode != null); - permitDesignations = false; // prevent designators under 'or' - var left = BindPattern(node.Left, inputType, permitDesignations, hasErrors, diagnostics); - var right = BindPattern(node.Right, inputType, permitDesignations, hasErrors, diagnostics); + Debug.Assert(binaryPatternStack.Count > 0); - // Compute the common type. This algorithm is quadratic, but disjunctive patterns are unlikely to be huge - var narrowedTypeCandidates = ArrayBuilder.GetInstance(2); - collectCandidates(left, narrowedTypeCandidates); - collectCandidates(right, narrowedTypeCandidates); - var narrowedType = leastSpecificType(node, narrowedTypeCandidates, diagnostics) ?? inputType; - narrowedTypeCandidates.Free(); + var binaryPatternAndPermitDesignations = binaryPatternStack.Pop(); + BoundPattern result = BindPattern(binaryPatternAndPermitDesignations.pat.Left, inputType, binaryPatternAndPermitDesignations.permitDesignations, hasErrors, diagnostics); + var narrowedTypeCandidates = ArrayBuilder.GetInstance(2); + collectCandidates(result, narrowedTypeCandidates); - return new BoundBinaryPattern(node, disjunction: isDisjunction, left, right, inputType: inputType, narrowedType: narrowedType, hasErrors); + do + { + result = bindBinaryPattern( + result, + this, + binaryPatternAndPermitDesignations.pat, + binaryPatternAndPermitDesignations.permitDesignations, + inputType, + narrowedTypeCandidates, + hasErrors, + diagnostics); + } while (binaryPatternStack.TryPop(out binaryPatternAndPermitDesignations)); - static void collectCandidates(BoundPattern pat, ArrayBuilder candidates) - { - if (pat is BoundBinaryPattern { Disjunction: true } p) - { - collectCandidates(p.Left, candidates); - collectCandidates(p.Right, candidates); - } - else - { - candidates.Add(pat.NarrowedType); - } - } + binaryPatternStack.Free(); + narrowedTypeCandidates.Free(); + return result; - TypeSymbol? leastSpecificType(SyntaxNode node, ArrayBuilder candidates, BindingDiagnosticBag diagnostics) + static BoundPattern bindBinaryPattern( + BoundPattern preboundLeft, + Binder binder, + BinaryPatternSyntax node, + bool permitDesignations, + TypeSymbol inputType, + ArrayBuilder narrowedTypeCandidates, + bool hasErrors, + BindingDiagnosticBag diagnostics) + { + bool isDisjunction = node.Kind() == SyntaxKind.OrPattern; + if (isDisjunction) { - Debug.Assert(candidates.Count >= 2); - CompoundUseSiteInfo useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); - TypeSymbol? bestSoFar = candidates[0]; - // first pass: select a candidate for which no other has been shown to be an improvement. - for (int i = 1, n = candidates.Count; i < n; i++) + Debug.Assert(!permitDesignations); + MessageID.IDS_FeatureOrPattern.CheckFeatureAvailability(diagnostics, node.OperatorToken); + + var right = binder.BindPattern(node.Right, inputType, permitDesignations, hasErrors, diagnostics); + + // Compute the common type. This algorithm is quadratic, but disjunctive patterns are unlikely to be huge + collectCandidates(right, narrowedTypeCandidates); + var narrowedType = leastSpecificType(node, narrowedTypeCandidates, diagnostics) ?? inputType; + + return new BoundBinaryPattern(node, disjunction: isDisjunction, preboundLeft, right, inputType: inputType, narrowedType: narrowedType, hasErrors); + + TypeSymbol? leastSpecificType(SyntaxNode node, ArrayBuilder candidates, BindingDiagnosticBag diagnostics) { - TypeSymbol candidate = candidates[i]; - bestSoFar = lessSpecificCandidate(bestSoFar, candidate, ref useSiteInfo) ?? bestSoFar; + Debug.Assert(candidates.Count >= 2); + CompoundUseSiteInfo useSiteInfo = binder.GetNewCompoundUseSiteInfo(diagnostics); + TypeSymbol? bestSoFar = candidates[0]; + // first pass: select a candidate for which no other has been shown to be an improvement. + for (int i = 1, n = candidates.Count; i < n; i++) + { + TypeSymbol candidate = candidates[i]; + bestSoFar = lessSpecificCandidate(bestSoFar, candidate, ref useSiteInfo) ?? bestSoFar; + } + // second pass: check that it is no more specific than any candidate. + for (int i = 0, n = candidates.Count; i < n; i++) + { + TypeSymbol candidate = candidates[i]; + TypeSymbol? spoiler = lessSpecificCandidate(candidate, bestSoFar, ref useSiteInfo); + if (spoiler is null) + { + bestSoFar = null; + break; + } + + // Our specificity criteria are transitive + Debug.Assert(spoiler.Equals(bestSoFar, TypeCompareKind.ConsiderEverything)); + } + + diagnostics.Add(node, useSiteInfo); + return bestSoFar; } - // second pass: check that it is no more specific than any candidate. - for (int i = 0, n = candidates.Count; i < n; i++) + + // Given a candidate least specific type so far, attempt to refine it with a possibly less specific candidate. + TypeSymbol? lessSpecificCandidate(TypeSymbol bestSoFar, TypeSymbol possiblyLessSpecificCandidate, ref CompoundUseSiteInfo useSiteInfo) { - TypeSymbol candidate = candidates[i]; - TypeSymbol? spoiler = lessSpecificCandidate(candidate, bestSoFar, ref useSiteInfo); - if (spoiler is null) + if (bestSoFar.Equals(possiblyLessSpecificCandidate, TypeCompareKind.AllIgnoreOptions)) { - bestSoFar = null; - break; + // When the types are equivalent, merge them. + return bestSoFar.MergeEquivalentTypes(possiblyLessSpecificCandidate, VarianceKind.Out); + } + else if (binder.Conversions.HasImplicitReferenceConversion(bestSoFar, possiblyLessSpecificCandidate, ref useSiteInfo)) + { + // When there is an implicit reference conversion from T to U, U is less specific + return possiblyLessSpecificCandidate; + } + else if (binder.Conversions.HasBoxingConversion(bestSoFar, possiblyLessSpecificCandidate, ref useSiteInfo)) + { + // when there is a boxing conversion from T to U, U is less specific. + return possiblyLessSpecificCandidate; + } + else + { + // We have no improved candidate to offer. + return null; } - - // Our specificity criteria are transitive - Debug.Assert(spoiler.Equals(bestSoFar, TypeCompareKind.ConsiderEverything)); } + } + else + { + MessageID.IDS_FeatureAndPattern.CheckFeatureAvailability(diagnostics, node.OperatorToken); - diagnostics.Add(node, useSiteInfo); - return bestSoFar; + var right = binder.BindPattern(node.Right, preboundLeft.NarrowedType, permitDesignations, hasErrors, diagnostics); + narrowedTypeCandidates.Clear(); + narrowedTypeCandidates.Add(right.NarrowedType); + return new BoundBinaryPattern(node, disjunction: isDisjunction, preboundLeft, right, inputType: inputType, narrowedType: right.NarrowedType, hasErrors); } + } - // Given a candidate least specific type so far, attempt to refine it with a possibly less specific candidate. - TypeSymbol? lessSpecificCandidate(TypeSymbol bestSoFar, TypeSymbol possiblyLessSpecificCandidate, ref CompoundUseSiteInfo useSiteInfo) + static void collectCandidates(BoundPattern pat, ArrayBuilder candidates) + { + if (pat is BoundBinaryPattern { Disjunction: true } p) { - if (bestSoFar.Equals(possiblyLessSpecificCandidate, TypeCompareKind.AllIgnoreOptions)) - { - // When the types are equivalent, merge them. - return bestSoFar.MergeEquivalentTypes(possiblyLessSpecificCandidate, VarianceKind.Out); - } - else if (Conversions.HasImplicitReferenceConversion(bestSoFar, possiblyLessSpecificCandidate, ref useSiteInfo)) - { - // When there is an implicit reference conversion from T to U, U is less specific - return possiblyLessSpecificCandidate; - } - else if (Conversions.HasBoxingConversion(bestSoFar, possiblyLessSpecificCandidate, ref useSiteInfo)) - { - // when there is a boxing conversion from T to U, U is less specific. - return possiblyLessSpecificCandidate; - } - else - { - // We have no improved candidate to offer. - return null; - } + collectCandidates(p.Left, candidates); + collectCandidates(p.Right, candidates); + } + else + { + candidates.Add(pat.NarrowedType); } } - else - { - MessageID.IDS_FeatureAndPattern.CheckFeatureAvailability(diagnostics, node.OperatorToken); - 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_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index b0f799d6ae6c3..e6f37d414bc57 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -1749,26 +1750,43 @@ private DiagnosticInfo GetBadEventUsageDiagnosticInfo(EventSymbol eventSymbol) new CSDiagnosticInfo(ErrorCode.ERR_BadEventUsageNoField, leastOverridden); } +#nullable enable internal static bool AccessingAutoPropertyFromConstructor(BoundPropertyAccess propertyAccess, Symbol fromMember) { - return AccessingAutoPropertyFromConstructor(propertyAccess.ReceiverOpt, propertyAccess.PropertySymbol, fromMember); + return AccessingAutoPropertyFromConstructor(propertyAccess.ReceiverOpt, propertyAccess.PropertySymbol, fromMember, propertyAccess.AutoPropertyAccessorKind); } - private static bool AccessingAutoPropertyFromConstructor(BoundExpression receiver, PropertySymbol propertySymbol, Symbol fromMember) + private static bool AccessingAutoPropertyFromConstructor(BoundExpression? receiver, PropertySymbol propertySymbol, Symbol fromMember, AccessorKind accessorKind) + { + if (!HasSynthesizedBackingField(propertySymbol, out var sourceProperty)) + { + return false; + } + + var propertyIsStatic = propertySymbol.IsStatic; + + return sourceProperty is { } && + sourceProperty.CanUseBackingFieldDirectlyInConstructor(useAsLvalue: accessorKind != AccessorKind.Get) && + TypeSymbol.Equals(sourceProperty.ContainingType, fromMember.ContainingType, TypeCompareKind.AllIgnoreOptions) && + IsConstructorOrField(fromMember, isStatic: propertyIsStatic) && + (propertyIsStatic || receiver?.Kind == BoundKind.ThisReference); + } + + private static bool HasSynthesizedBackingField(PropertySymbol propertySymbol, [NotNullWhen(true)] out SourcePropertySymbolBase? sourcePropertyDefinition) { if (!propertySymbol.IsDefinition && propertySymbol.ContainingType.Equals(propertySymbol.ContainingType.OriginalDefinition, TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)) { propertySymbol = propertySymbol.OriginalDefinition; } - var sourceProperty = propertySymbol as SourcePropertySymbolBase; - var propertyIsStatic = propertySymbol.IsStatic; + if (propertySymbol is SourcePropertySymbolBase { BackingField: { } } sourceProperty) + { + sourcePropertyDefinition = sourceProperty; + return true; + } - return (object)sourceProperty != null && - sourceProperty.IsAutoPropertyWithGetAccessor && - TypeSymbol.Equals(sourceProperty.ContainingType, fromMember.ContainingType, TypeCompareKind.AllIgnoreOptions) && - IsConstructorOrField(fromMember, isStatic: propertyIsStatic) && - (propertyIsStatic || receiver.Kind == BoundKind.ThisReference); + sourcePropertyDefinition = null; + return false; } private static bool IsConstructorOrField(Symbol member, bool isStatic) @@ -1778,6 +1796,7 @@ private static bool IsConstructorOrField(Symbol member, bool isStatic) MethodKind.Constructor) || (member as FieldSymbol)?.IsStatic == isStatic; } +#nullable disable private TypeSymbol GetAccessThroughType(BoundExpression receiver) { @@ -2494,15 +2513,64 @@ private void GenerateImplicitConversionErrorsForTupleLiteralArguments( } } +#nullable enable private BoundStatement BindIfStatement(IfStatementSyntax node, BindingDiagnosticBag diagnostics) { - var condition = BindBooleanExpression(node.Condition, diagnostics); - var consequence = BindPossibleEmbeddedStatement(node.Statement, diagnostics); - BoundStatement alternative = (node.Else == null) ? null : BindPossibleEmbeddedStatement(node.Else.Statement, diagnostics); + return bindIfStatement(this, node, diagnostics); - BoundStatement result = new BoundIfStatement(node, condition, consequence, alternative); - return result; + static BoundStatement bindIfStatement(Binder binder, IfStatementSyntax node, BindingDiagnosticBag diagnostics) + { + var stack = ArrayBuilder<(Binder, IfStatementSyntax IfStatementSyntax, BoundExpression Condition, BoundStatement Consequence)>.GetInstance(); + + BoundStatement? alternative; + while (true) + { + var condition = binder.BindBooleanExpression(node.Condition, diagnostics); + var consequence = binder.BindPossibleEmbeddedStatement(node.Statement, diagnostics); + stack.Push((binder, node, condition, consequence)); + + if (node.Else == null) + { + alternative = null; + break; + } + + var elseStatementSyntax = node.Else.Statement; + if (elseStatementSyntax is IfStatementSyntax ifStatementSyntax) + { + var b = binder.GetBinder(ifStatementSyntax); + Debug.Assert(b != null); + binder = b; + node = ifStatementSyntax; + } + else + { + alternative = binder.BindPossibleEmbeddedStatement(elseStatementSyntax, diagnostics); + break; + } + } + + BoundStatement result; + do + { + BoundExpression condition; + BoundStatement consequence; + (binder, node, condition, consequence) = stack.Pop(); + result = new BoundIfStatement(node, condition, consequence, alternative); + if (stack.Any()) + { + result = binder.WrapWithVariablesIfAny(node, result); + } + alternative = result; + } + while (stack.Any()); + + stack.Free(); + + return result; + } } +#nullable disable internal BoundExpression BindBooleanExpression(ExpressionSyntax node, BindingDiagnosticBag diagnostics) { @@ -3581,7 +3649,7 @@ private BoundNode BindSimpleProgramCompilationUnit(CompilationUnitSyntax compila private BoundNode BindPrimaryConstructorBody(TypeDeclarationSyntax typeDecl, BindingDiagnosticBag diagnostics) { Debug.Assert(typeDecl.ParameterList is object); - Debug.Assert(typeDecl.Kind() is SyntaxKind.RecordDeclaration or SyntaxKind.ClassDeclaration); + Debug.Assert(typeDecl.Kind() is SyntaxKind.RecordDeclaration or SyntaxKind.ClassDeclaration or SyntaxKind.RecordStructDeclaration or SyntaxKind.StructDeclaration); BoundExpressionStatement initializer; ImmutableArray constructorLocals; diff --git a/src/Compilers/CSharp/Portable/Binder/CollectionInitializerAddMethodBinder.cs b/src/Compilers/CSharp/Portable/Binder/CollectionInitializerAddMethodBinder.cs new file mode 100644 index 0000000000000..56b98aaefd9fb --- /dev/null +++ b/src/Compilers/CSharp/Portable/Binder/CollectionInitializerAddMethodBinder.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Symbols; + +namespace Microsoft.CodeAnalysis.CSharp; + +/// +/// Keeps track of the type for which we are trying to bind a collection initializer. +/// +internal sealed class CollectionInitializerAddMethodBinder : Binder +{ + public SyntaxNode Syntax { get; } + public TypeSymbol CollectionType { get; } + + internal CollectionInitializerAddMethodBinder(SyntaxNode syntax, TypeSymbol collectionType, Binder next) + : base(next, next.Flags | BinderFlags.CollectionInitializerAddMethod) + { + Syntax = syntax; + CollectionType = collectionType; + } +} diff --git a/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs b/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs index 9fb7f496e7fad..8597cc16bdf25 100644 --- a/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs +++ b/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs @@ -645,33 +645,59 @@ private Tests MakeTestsAndBindingsForBinaryPattern( out BoundDagTemp output, ArrayBuilder bindings) { - var builder = ArrayBuilder.GetInstance(2); - if (bin.Disjunction) + // Users (such as ourselves) can have many, many nested binary patterns. To avoid crashing, do left recursion manually. + + var binaryPatternStack = ArrayBuilder.GetInstance(); + var currentNode = bin; + + do + { + binaryPatternStack.Push(currentNode); + currentNode = currentNode.Left as BoundBinaryPattern; + } while (currentNode != null); + + currentNode = binaryPatternStack.Pop(); + Tests result = MakeTestsAndBindings(input, currentNode.Left, out output, bindings); + + do + { + result = makeTestsAndBindingsForBinaryPattern(this, result, output, input, currentNode, out output, bindings); + } while (binaryPatternStack.TryPop(out currentNode)); + + binaryPatternStack.Free(); + + return result; + + static Tests makeTestsAndBindingsForBinaryPattern(DecisionDagBuilder @this, Tests leftTests, BoundDagTemp leftOutput, BoundDagTemp input, BoundBinaryPattern bin, out BoundDagTemp output, ArrayBuilder bindings) { - builder.Add(MakeTestsAndBindings(input, bin.Left, bindings)); - builder.Add(MakeTestsAndBindings(input, bin.Right, bindings)); - var result = Tests.OrSequence.Create(builder); - if (bin.InputType.Equals(bin.NarrowedType)) + var builder = ArrayBuilder.GetInstance(2); + if (bin.Disjunction) { - output = input; - return result; + builder.Add(leftTests); + builder.Add(@this.MakeTestsAndBindings(input, bin.Right, bindings)); + var result = Tests.OrSequence.Create(builder); + if (bin.InputType.Equals(bin.NarrowedType)) + { + output = input; + return result; + } + else + { + builder = ArrayBuilder.GetInstance(2); + builder.Add(result); + output = @this.MakeConvertToType(input: input, syntax: bin.Syntax, type: bin.NarrowedType, isExplicitTest: false, tests: builder); + return Tests.AndSequence.Create(builder); + } } else { - builder = ArrayBuilder.GetInstance(2); - builder.Add(result); - output = MakeConvertToType(input: input, syntax: bin.Syntax, type: bin.NarrowedType, isExplicitTest: false, tests: builder); + builder.Add(leftTests); + builder.Add(@this.MakeTestsAndBindings(leftOutput, bin.Right, out var rightOutput, bindings)); + output = rightOutput; + Debug.Assert(bin.HasErrors || output.Type.Equals(bin.NarrowedType, TypeCompareKind.AllIgnoreOptions)); return Tests.AndSequence.Create(builder); } } - else - { - builder.Add(MakeTestsAndBindings(input, bin.Left, out var leftOutput, bindings)); - builder.Add(MakeTestsAndBindings(leftOutput, bin.Right, out var rightOutput, bindings)); - output = rightOutput; - Debug.Assert(bin.HasErrors || output.Type.Equals(bin.NarrowedType, TypeCompareKind.AllIgnoreOptions)); - return Tests.AndSequence.Create(builder); - } } private Tests MakeTestsAndBindingsForRelationalPattern( diff --git a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs index daa0cc7adad07..32d3a145843b8 100644 --- a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs @@ -339,6 +339,28 @@ public override void VisitBinaryExpression(BinaryExpressionSyntax node) operands.Free(); } + public override void VisitBinaryPattern(BinaryPatternSyntax node) + { + // Like binary expressions, binary patterns are left-associative, and can be deeply nested (even in our own code). + // Handle this with manual recursion. + PatternSyntax currentPattern = node; + + var rightPatternStack = ArrayBuilder.GetInstance(); + + while (currentPattern is BinaryPatternSyntax binaryPattern) + { + rightPatternStack.Push(binaryPattern.Right); + currentPattern = binaryPattern.Left; + } + + do + { + Visit(currentPattern); + } while (rightPatternStack.TryPop(out currentPattern)); + + rightPatternStack.Free(); + } + public override void VisitInvocationExpression(InvocationExpressionSyntax node) { if (receiverIsInvocation(node, out InvocationExpressionSyntax nested)) diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachEnumeratorInfo.cs b/src/Compilers/CSharp/Portable/Binder/ForEachEnumeratorInfo.cs index c27c93cfabed9..d9bae8fd45861 100644 --- a/src/Compilers/CSharp/Portable/Binder/ForEachEnumeratorInfo.cs +++ b/src/Compilers/CSharp/Portable/Binder/ForEachEnumeratorInfo.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { @@ -63,11 +64,11 @@ private ForEachEnumeratorInfo( BoundExpression? currentConversion, BinderFlags location) { - Debug.Assert((object)collectionType != null, $"Field '{nameof(collectionType)}' cannot be null"); - Debug.Assert(elementType.HasType, $"Field '{nameof(elementType)}' cannot be null"); - Debug.Assert((object)getEnumeratorInfo != null, $"Field '{nameof(getEnumeratorInfo)}' cannot be null"); - Debug.Assert((object)currentPropertyGetter != null, $"Field '{nameof(currentPropertyGetter)}' cannot be null"); - Debug.Assert((object)moveNextInfo != null, $"Field '{nameof(moveNextInfo)}' cannot be null"); + RoslynDebug.Assert((object)collectionType != null, $"Field '{nameof(collectionType)}' cannot be null"); + RoslynDebug.Assert(elementType.HasType, $"Field '{nameof(elementType)}' cannot be null"); + RoslynDebug.Assert((object)getEnumeratorInfo != null, $"Field '{nameof(getEnumeratorInfo)}' cannot be null"); + RoslynDebug.Assert((object)currentPropertyGetter != null, $"Field '{nameof(currentPropertyGetter)}' cannot be null"); + RoslynDebug.Assert((object)moveNextInfo != null, $"Field '{nameof(moveNextInfo)}' cannot be null"); Debug.Assert(patternDisposeInfo == null || needsDisposal); Debug.Assert(inlineArraySpanType is WellKnownType.Unknown or WellKnownType.System_Span_T or WellKnownType.System_ReadOnlySpan_T); Debug.Assert(inlineArraySpanType == WellKnownType.Unknown || diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs index 888094f169b44..42057ac1ae5e1 100644 --- a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs @@ -527,7 +527,7 @@ private BoundForEachStatement BindForEachPartsWorker(BindingDiagnosticBag diagno if (builder.InlineArraySpanType == WellKnownType.Unknown && getEnumeratorType.IsRestrictedType() && (IsDirectlyInIterator || IsInAsyncMethod())) { - diagnostics.Add(ErrorCode.ERR_BadSpecialByRefIterator, foreachKeyword.GetLocation(), getEnumeratorType); + CheckFeatureAvailability(foreachKeyword, MessageID.IDS_FeatureRefUnsafeInIteratorAsync, diagnostics); } diagnostics.Add(_syntax.ForEachKeyword, useSiteInfo); diff --git a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs index 1e6ee6bfc4953..5c837a30cb87d 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs @@ -796,11 +796,47 @@ public override void VisitSwitchExpression(SwitchExpressionSyntax node) } } + public override void VisitBinaryPattern(BinaryPatternSyntax node) + { + // Users (such as ourselves) can have many, many nested binary patterns. To avoid crashing, do left recursion manually. + while (true) + { + Visit(node.Right); + if (node.Left is not BinaryPatternSyntax binOp) + { + Visit(node.Left); + break; + } + + node = binOp; + } + } + public override void VisitIfStatement(IfStatementSyntax node) { - Visit(node.Condition, _enclosing); - VisitPossibleEmbeddedStatement(node.Statement, _enclosing); - Visit(node.Else, _enclosing); + Binder enclosing = _enclosing; + while (true) + { + Visit(node.Condition, enclosing); + VisitPossibleEmbeddedStatement(node.Statement, enclosing); + + if (node.Else == null) + { + break; + } + + var elseStatementSyntax = node.Else.Statement; + if (elseStatementSyntax is IfStatementSyntax ifStatementSyntax) + { + node = ifStatementSyntax; + enclosing = GetBinderForPossibleEmbeddedStatement(node, enclosing); + } + else + { + VisitPossibleEmbeddedStatement(elseStatementSyntax, enclosing); + break; + } + } } public override void VisitElseClause(ElseClauseSyntax node) @@ -1019,23 +1055,29 @@ private Binder GetBinderForPossibleEmbeddedStatement(StatementSyntax statement, } } - private void VisitPossibleEmbeddedStatement(StatementSyntax statement, Binder enclosing) + private Binder GetBinderForPossibleEmbeddedStatement(StatementSyntax statement, Binder enclosing) { - if (statement != null) + CSharpSyntaxNode embeddedScopeDesignator; + // Some statements by default do not introduce its own scope for locals. + // For example: Expression Statement, Return Statement, etc. However, + // when a statement like that is an embedded statement (like IfStatementSyntax.Statement), + // then it should introduce a scope for locals declared within it. Here we are detecting + // such statements and creating a binder that should own the scope. + enclosing = GetBinderForPossibleEmbeddedStatement(statement, enclosing, out embeddedScopeDesignator); + + if (embeddedScopeDesignator != null) { - CSharpSyntaxNode embeddedScopeDesignator; - // Some statements by default do not introduce its own scope for locals. - // For example: Expression Statement, Return Statement, etc. However, - // when a statement like that is an embedded statement (like IfStatementSyntax.Statement), - // then it should introduce a scope for locals declared within it. Here we are detecting - // such statements and creating a binder that should own the scope. - enclosing = GetBinderForPossibleEmbeddedStatement(statement, enclosing, out embeddedScopeDesignator); + AddToMap(embeddedScopeDesignator, enclosing); + } - if (embeddedScopeDesignator != null) - { - AddToMap(embeddedScopeDesignator, enclosing); - } + return enclosing; + } + private void VisitPossibleEmbeddedStatement(StatementSyntax statement, Binder enclosing) + { + if (statement != null) + { + enclosing = GetBinderForPossibleEmbeddedStatement(statement, enclosing); Visit(statement, enclosing); } } diff --git a/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs b/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs index 3b49411795218..5a9120ced46af 100644 --- a/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs +++ b/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs @@ -285,7 +285,7 @@ private void TrackVisit(BoundNode? node) if (_visited is { } && _visited.Count <= MaxTrackVisited) { bool added = _visited.Add(expr); - Debug.Assert(added, $"Expression {expr} `{expr.Syntax}` visited more than once."); + RoslynDebug.Assert(added, $"Expression {expr} `{expr.Syntax}` visited more than once."); } } } @@ -298,7 +298,7 @@ private void AssertVisited(BoundExpression expr) } else if (_visited is { } && _visited.Count <= MaxTrackVisited) { - Debug.Assert(_visited.Contains(expr), $"Expected {expr} `{expr.Syntax}` to be visited."); + RoslynDebug.Assert(_visited.Contains(expr), $"Expected {expr} `{expr.Syntax}` to be visited."); } } #endif diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs index babc0428a6c1d..3ca7c1cdbae37 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs @@ -69,6 +69,7 @@ public static NullableFlowState GetNullableState(ArrayBuilder typ HashSet candidateTypes = new HashSet(comparer); foreach (BoundExpression expr in exprs) { + Debug.Assert(!NullableWalker.IsTargetTypedExpression(expr)); TypeSymbol? type = expr.GetTypeOrFunctionType(); if (type is { }) @@ -132,9 +133,9 @@ public static NullableFlowState GetNullableState(ArrayBuilder typ try { var conversionsWithoutNullability = conversions.WithNullability(false); - TypeSymbol? type1 = expr1.Type; - if (type1 is { }) + Debug.Assert(!NullableWalker.IsTargetTypedExpression(expr1)); + if (expr1.Type is { } type1) { if (type1.IsErrorType()) { @@ -148,9 +149,8 @@ public static NullableFlowState GetNullableState(ArrayBuilder typ } } - TypeSymbol? type2 = expr2.Type; - - if (type2 is { }) + Debug.Assert(!NullableWalker.IsTargetTypedExpression(expr2)); + if (expr2.Type is { } type2) { if (type2.IsErrorType()) { diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs index 1a292dae61494..731dcf784e037 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs @@ -254,7 +254,7 @@ private static void AssertTrivialConversion(ConversionKind kind) break; } - Debug.Assert(isTrivial, "this conversion needs additional data: " + kind); + RoslynDebug.Assert(isTrivial, $"this conversion needs additional data: {kind}"); } internal static Conversion GetTrivialConversion(ConversionKind kind) diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs index 133a01ffd8dee..05b8dba5dc1cc 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs @@ -580,34 +580,6 @@ public Conversion ClassifyStandardConversion(BoundExpression sourceExpression, T return Conversion.NoConversion; } - private static bool IsStandardImplicitConversionFromExpression(ConversionKind kind) - { - if (IsStandardImplicitConversionFromType(kind)) - { - return true; - } - - // See comment in ClassifyStandardImplicitConversion(BoundExpression, ...) - // where the set of standard implicit conversions is extended from the spec - // to include conversions from expression. - switch (kind) - { - case ConversionKind.NullLiteral: - case ConversionKind.AnonymousFunction: - case ConversionKind.MethodGroup: - case ConversionKind.ImplicitEnumeration: - case ConversionKind.ImplicitDynamic: - case ConversionKind.ImplicitNullToPointer: - case ConversionKind.ImplicitTupleLiteral: - case ConversionKind.StackAllocToPointerType: - case ConversionKind.StackAllocToSpanType: - case ConversionKind.InlineArray: - return true; - default: - return false; - } - } - // See https://github.com/dotnet/csharpstandard/blob/standard-v7/standard/conversions.md#1042-standard-implicit-conversions: // "The standard conversions are those pre-defined conversions that can occur as part of a user-defined conversion." private static bool IsStandardImplicitConversionFromType(ConversionKind kind) @@ -672,7 +644,7 @@ private Conversion ClassifyStandardImplicitConversion(BoundExpression sourceExpr !conversion.IsInterpolatedStringHandler && !isImplicitCollectionExpressionConversion(conversion)) { - Debug.Assert(IsStandardImplicitConversionFromExpression(conversion.Kind)); + Debug.Assert(isStandardImplicitConversionFromExpression(conversion.Kind)); return conversion; } @@ -692,6 +664,32 @@ static bool isImplicitCollectionExpressionConversion(Conversion conversion) _ => false, }; } + + static bool isStandardImplicitConversionFromExpression(ConversionKind kind) + { + if (IsStandardImplicitConversionFromType(kind)) + { + return true; + } + + switch (kind) + { + case ConversionKind.NullLiteral: + case ConversionKind.AnonymousFunction: + case ConversionKind.MethodGroup: + case ConversionKind.ImplicitEnumeration: + case ConversionKind.ImplicitDynamic: + case ConversionKind.ImplicitNullToPointer: + case ConversionKind.ImplicitTupleLiteral: + case ConversionKind.StackAllocToPointerType: + case ConversionKind.StackAllocToSpanType: + case ConversionKind.InlineArray: + case ConversionKind.InterpolatedString: + return true; + default: + return false; + } + } } private Conversion ClassifyStandardImplicitConversion(TypeSymbol source, TypeSymbol destination, ref CompoundUseSiteInfo useSiteInfo) diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs index 61e32db081e38..a2180aebd7540 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs @@ -128,6 +128,7 @@ public enum Options : ushort DynamicResolution = 1 << 6, DynamicConvertsToAnything = 1 << 7, DisallowExpandedNonArrayParams = 1 << 8, + InferringUniqueMethodGroupSignature = 1 << 9, } // Perform overload resolution on the given method group, with the given arguments and @@ -219,6 +220,102 @@ internal void MethodOrPropertyOverloadResolution( } } +#nullable enable + /// false if there are ambiguous candidates in the set + internal bool FilterMethodsForUniqueSignature(ArrayBuilder methods, out bool useParams) + { + useParams = false; + + if (methods.Count == 0) + { + return true; + } + + var result = OverloadResolutionResult.GetInstance(); + var results = result.ResultsBuilder; + var useSiteInfo = CompoundUseSiteInfo.Discarded; + + // Type arguments are verified in the caller. + var typeArguments = ArrayBuilder.GetInstance(0); + + // We do not have any arguments when determining unique signature. + var arguments = AnalyzedArguments.GetInstance(); + + // Avoid passing reduced methods to overload resolution. + var unreducedMethods = methods; + if (methods.Any(static m => m.ReducedFrom is not null)) + { + unreducedMethods = ArrayBuilder.GetInstance(methods.Count); + foreach (var method in methods) + { + unreducedMethods.Add(method.ReducedFrom ?? method); + } + } + + PerformMemberOverloadResolutionStart( + results, + unreducedMethods, + typeArguments, + arguments, + completeResults: false, + ref useSiteInfo, + Options.InferringUniqueMethodGroupSignature | Options.IgnoreNormalFormIfHasValidParamsParameter, + checkOverriddenOrHidden: true); + + arguments.Free(); + typeArguments.Free(); + + // If we have a candidate applicable in expanded form and a candidate applicable in normal form, + // that's an ambiguity (the candidates cannot have a unique signature). + var hasExpandedForm = results.Any(static r => r.Resolution == MemberResolutionKind.ApplicableInExpandedForm); + if (hasExpandedForm && results.Any(static r => r.Resolution == MemberResolutionKind.ApplicableInNormalForm)) + { + if (unreducedMethods != methods) + { + unreducedMethods.Free(); + } + + result.Free(); + return false; + } + + // Get applicable members (the original ones from `methods` not `unreducedMethods`). + if (unreducedMethods == methods) + { + var applicableMethods = result.GetAllApplicableMembers(); + if (applicableMethods.Length != methods.Count) + { + methods.Clear(); + methods.AddRange(applicableMethods); + } + } + else + { + var applicableMethods = ArrayBuilder.GetInstance(methods.Count); + foreach (var res in results) + { + if (res.Result.IsApplicable) + { + var index = unreducedMethods.IndexOf(res.Member); + applicableMethods.Add(methods[index]); + } + } + if (applicableMethods.Count != methods.Count) + { + methods.Clear(); + methods.AddRange(applicableMethods); + } + applicableMethods.Free(); + unreducedMethods.Free(); + } + + result.Free(); + + useParams = hasExpandedForm; + return true; + } +#nullable disable + private static bool OverloadResolutionResultIsValid(ArrayBuilder> results, bool hasDynamicArgument) where TMember : Symbol { @@ -250,28 +347,17 @@ private static bool OverloadResolutionResultIsValid(ArrayBuilder( + private void PerformMemberOverloadResolutionStart( ArrayBuilder> results, ArrayBuilder members, ArrayBuilder typeArguments, - BoundExpression receiver, AnalyzedArguments arguments, bool completeResults, - RefKind returnRefKind, - TypeSymbol returnType, - in CallingConventionInfo callingConventionInfo, ref CompoundUseSiteInfo useSiteInfo, Options options, bool checkOverriddenOrHidden) where TMember : Symbol { - // SPEC: The binding-time processing of a method invocation of the form M(A), where M is a - // SPEC: method group (possibly including a type-argument-list), and A is an optional - // SPEC: argument-list, consists of the following steps: - // NOTE: We use a quadratic algorithm to determine which members override/hide // each other (i.e. we compare them pairwise). We could move to a linear // algorithm that builds the closure set of overridden/hidden members and then @@ -313,7 +399,8 @@ private void PerformMemberOverloadResolution( // SPEC: The set of candidate methods is reduced to contain only methods from the most derived types. if (checkOverriddenOrHidden) { - if ((options & Options.DynamicResolution) != 0) + if ((options & Options.DynamicResolution) != 0 || + (options & Options.InferringUniqueMethodGroupSignature) != 0) { // 'AddMemberToCandidateSet' takes care of hiding by name and by override, // but we still need to take care of hiding by signature in order to @@ -322,6 +409,8 @@ private void PerformMemberOverloadResolution( // That is due to the fact that 'dynamic' converts to anything else, and // a method applicable at compile time, might actually be inapplicable at runtime, // therefore shouldn't shadow members with different signature from base, etc. + // Similarly when inferring method signature we don't know the argument types + // so we don't want to remove less derived members with different signature. RemoveHiddenMembers(results); } else @@ -329,6 +418,31 @@ private void PerformMemberOverloadResolution( RemoveLessDerivedMembers(results, ref useSiteInfo); } } + } + + // Perform method/indexer overload resolution, storing the results into "results". If + // completeResults is false, then invalid results don't have to be stored. The results will + // still contain all possible successful resolution. + private void PerformMemberOverloadResolution( + ArrayBuilder> results, + ArrayBuilder members, + ArrayBuilder typeArguments, + BoundExpression receiver, + AnalyzedArguments arguments, + bool completeResults, + RefKind returnRefKind, + TypeSymbol returnType, + in CallingConventionInfo callingConventionInfo, + ref CompoundUseSiteInfo useSiteInfo, + Options options, + bool checkOverriddenOrHidden) + where TMember : Symbol + { + // SPEC: The binding-time processing of a method invocation of the form M(A), where M is a + // SPEC: method group (possibly including a type-argument-list), and A is an optional + // SPEC: argument-list, consists of the following steps: + + PerformMemberOverloadResolutionStart(results, members, typeArguments, arguments, completeResults, ref useSiteInfo, options, checkOverriddenOrHidden); if (Compilation.LanguageVersion.AllowImprovedOverloadCandidates()) { @@ -1024,7 +1138,7 @@ private void AddMemberToCandidateSet( var leastOverriddenMember = (TMember)member.GetLeastOverriddenMember(_binder.ContainingType); // Filter out members with unsupported metadata. - if (member.HasUnsupportedMetadata) + if ((options & Options.InferringUniqueMethodGroupSignature) == 0 && member.HasUnsupportedMetadata) { Debug.Assert(!MemberAnalysisResult.UnsupportedMetadata().HasUseSiteDiagnosticToReportFor(member)); if (completeResults) @@ -1073,7 +1187,7 @@ private void AddMemberToCandidateSet( typeArguments, arguments, definitionElementType, - allowRefOmittedArguments: (options & Options.AllowRefOmittedArguments) != 0, + options, completeResults: completeResults, dynamicConvertsToAnything: (options & Options.DynamicConvertsToAnything) != 0, isMethodGroupConversion: (options & Options.IsMethodGroupConversion) != 0, @@ -1715,10 +1829,15 @@ private int GetTheBestCandidateIndex(ArrayBuilder(ArrayBuilder results) + private void RemoveLowerPriorityMembers(ArrayBuilder results) where TMemberResolution : IMemberResolutionResultWithPriority where TMember : Symbol { + if (!Compilation.IsFeatureEnabled(MessageID.IDS_OverloadResolutionPriority)) + { + return; + } + // - Then, the reduced set of candidate members is grouped by declaring type. Within each group: // - Candidate function members are ordered by *overload_resolution_priority*. // - All members that have a lower *overload_resolution_priority* than the highest found within its declaring type group are removed. @@ -2414,13 +2533,10 @@ private BetterResult BetterFunctionMember( if (!Conversions.HasIdentityConversion(t1, t2)) { - if (IsBetterParamsCollectionType(t1, t2, ref useSiteInfo)) + var betterResult = BetterParamsCollectionType(t1, t2, ref useSiteInfo); + if (betterResult != BetterResult.Neither) { - return BetterResult.Left; - } - if (IsBetterParamsCollectionType(t2, t1, ref useSiteInfo)) - { - return BetterResult.Right; + return betterResult; } } } @@ -2848,15 +2964,7 @@ private BetterResult BetterConversionFromExpression(BoundExpression node, TypeSy if (conv1.Kind == ConversionKind.CollectionExpression && conv2.Kind == ConversionKind.CollectionExpression) { - if (IsBetterCollectionExpressionConversion(t1, conv1, t2, conv2, ref useSiteInfo)) - { - return BetterResult.Left; - } - if (IsBetterCollectionExpressionConversion(t2, conv2, t1, conv1, ref useSiteInfo)) - { - return BetterResult.Right; - } - return BetterResult.Neither; + return BetterCollectionExpressionConversion((BoundUnconvertedCollectionExpression)node, t1, conv1, t2, conv2, ref useSiteInfo); } switch ((conv1.Kind, conv2.Kind)) @@ -2874,19 +2982,149 @@ private BetterResult BetterConversionFromExpression(BoundExpression node, TypeSy return BetterConversionTarget(node, t1, conv1, t2, conv2, ref useSiteInfo, out okToDowngradeToNeither); } + private BetterResult BetterCollectionExpressionConversion( + BoundUnconvertedCollectionExpression collectionExpression, + TypeSymbol t1, Conversion conv1, + TypeSymbol t2, Conversion conv2, + ref CompoundUseSiteInfo useSiteInfo) + { + var kind1 = conv1.GetCollectionExpressionTypeKind(out TypeSymbol elementType1, out _, out _); + var kind2 = conv2.GetCollectionExpressionTypeKind(out TypeSymbol elementType2, out _, out _); + + if (Compilation.LanguageVersion < LanguageVersion.CSharp13) + { + if (IsBetterCollectionExpressionConversion_CSharp12(t1, kind1, elementType1, t2, kind2, elementType2, ref useSiteInfo)) + { + return BetterResult.Left; + } + if (IsBetterCollectionExpressionConversion_CSharp12(t2, kind2, elementType2, t1, kind1, elementType1, ref useSiteInfo)) + { + return BetterResult.Right; + } + + return BetterResult.Neither; + } + else + { + return BetterCollectionExpressionConversion( + collectionExpression.Elements, + t1, kind1, elementType1, conv1.UnderlyingConversions, + t2, kind2, elementType2, conv2.UnderlyingConversions, + ref useSiteInfo); + } + } + // Implements the rules for // - E is a collection expression and one of the following holds: ... - private bool IsBetterCollectionExpressionConversion(TypeSymbol t1, Conversion conv1, TypeSymbol t2, Conversion conv2, ref CompoundUseSiteInfo useSiteInfo) + private BetterResult BetterCollectionExpressionConversion( + ImmutableArray collectionExpressionElements, + TypeSymbol t1, CollectionExpressionTypeKind kind1, TypeSymbol elementType1, ImmutableArray underlyingElementConversions1, + TypeSymbol t2, CollectionExpressionTypeKind kind2, TypeSymbol elementType2, ImmutableArray underlyingElementConversions2, + ref CompoundUseSiteInfo useSiteInfo) { - TypeSymbol elementType1; - var kind1 = conv1.GetCollectionExpressionTypeKind(out elementType1, out _, out _); - TypeSymbol elementType2; - var kind2 = conv2.GetCollectionExpressionTypeKind(out elementType2, out _, out _); + // Given: + // - `E` is a collection expression with element expressions `[EL₁, EL₂, ..., ELₙ]` + // - `T₁` and `T₂` are collection types + // - `E₁` is the element type of `T₁` + // - `E₂` is the element type of `T₂` + // - `CE₁ᵢ` are the series of conversions from `ELᵢ` to `E₁` + // - `CE₂ᵢ` are the series of conversions from `ELᵢ` to `E₂` + + var t1IsSpanType = kind1 is CollectionExpressionTypeKind.ReadOnlySpan or CollectionExpressionTypeKind.Span; + var t2IsSpanType = kind2 is CollectionExpressionTypeKind.ReadOnlySpan or CollectionExpressionTypeKind.Span; - return IsBetterCollectionExpressionConversion(t1, kind1, elementType1, t2, kind2, elementType2, ref useSiteInfo); + // `C₁` is a ***better collection conversion from expression*** than `C₂` if: + // - Both T₁ and T₂ are not *span types*, and `T₁` is implicitly convertible to `T₂`, and `T₂` is not implicitly convertible to `T₁`, or + if (!t1IsSpanType && !t2IsSpanType) + { + var t1IsConvertibleToT2 = Conversions.ClassifyImplicitConversionFromType(t1, t2, ref useSiteInfo).IsImplicit; + var t2IsConvertibleToT1 = Conversions.ClassifyImplicitConversionFromType(t2, t1, ref useSiteInfo).IsImplicit; + + switch (t1IsConvertibleToT2, t2IsConvertibleToT1) + { + case (true, false): + return BetterResult.Left; + case (false, true): + return BetterResult.Right; + } + } + + // - `E₁` does not have an identity conversion to `E₂`, and the element conversions to `E₁` are better than the element conversions to `E₂`, or + // - `E₁` has an identity conversion to `E₂`, and one of the following holds: + + // `E₁` is compared to `E₂` as follows: + // If there is an identity conversion from `E₁` to `E₂`, then the element conversions are as good as each other. Otherwise, the element conversions + // to `E₁` are better than the element conversions to `E₂` if: + // - For every `ELᵢ`, `CE₁ᵢ` is at least as good as `CE₂ᵢ`, and + // - There is at least one i where `CE₁ᵢ` is better than `CE₂ᵢ` + // Otherwise, neither set of element conversions is better than the other, and they are also not as good as each other. + // Conversion comparisons are made using better conversion from expression if `ELᵢ` is not a spread element. If `ELᵢ` is a spread element, we use better conversion from the element type of the spread collection to `E₁` or `E₂`, respectively. + + if (!Conversions.HasIdentityConversion(elementType1, elementType2)) + { + var betterResult = BetterResult.Neither; + Debug.Assert(underlyingElementConversions1.Length == underlyingElementConversions2.Length && underlyingElementConversions1.Length == collectionExpressionElements.Length); + + for (int i = 0; i < underlyingElementConversions1.Length; i++) + { + // Conversion comparisons are made using better conversion from expression if `ELᵢ` is not a spread element. If `ELᵢ` is a spread element, + // we use better conversion from the element type of the spread collection to `E₁` or `E₂`, respectively. + var element = collectionExpressionElements[i]; + var conversionToE1 = underlyingElementConversions1[i]; + var conversionToE2 = underlyingElementConversions2[i]; + + BetterResult elementBetterResult; + if (element is BoundCollectionExpressionSpreadElement spread) + { + elementBetterResult = BetterConversionTarget(spread, elementType1, conversionToE1, elementType2, conversionToE2, ref useSiteInfo, okToDowngradeToNeither: out _); + } + else + { + elementBetterResult = BetterConversionFromExpression((BoundExpression)element, elementType1, conversionToE1, elementType2, conversionToE2, ref useSiteInfo, okToDowngradeToNeither: out _); + } + + if (elementBetterResult == BetterResult.Neither) + { + continue; + } + + if (betterResult != BetterResult.Neither) + { + if (betterResult != elementBetterResult) + { + return BetterResult.Neither; + } + } + else + { + betterResult = elementBetterResult; + } + } + + return betterResult; + } + + // - `T₁` is `System.ReadOnlySpan`, and `T₂` is `System.Span`, or + // - `T₁` is `System.ReadOnlySpan` or `System.Span`, and `T₂` is an *array_or_array_interface* with *element type* `E₂` + + if (t1IsSpanType || t2IsSpanType) + { + switch ((kind1, kind2)) + { + case (CollectionExpressionTypeKind.ReadOnlySpan, CollectionExpressionTypeKind.Span): + case (CollectionExpressionTypeKind.ReadOnlySpan or CollectionExpressionTypeKind.Span, _) when IsSZArrayOrArrayInterface(t2, out _): + return BetterResult.Left; + + case (CollectionExpressionTypeKind.Span, CollectionExpressionTypeKind.ReadOnlySpan): + case (_, CollectionExpressionTypeKind.ReadOnlySpan or CollectionExpressionTypeKind.Span) when IsSZArrayOrArrayInterface(t1, out _): + return BetterResult.Right; + } + } + + return BetterResult.Neither; } - private bool IsBetterCollectionExpressionConversion( + private bool IsBetterCollectionExpressionConversion_CSharp12( TypeSymbol t1, CollectionExpressionTypeKind kind1, TypeSymbol elementType1, TypeSymbol t2, CollectionExpressionTypeKind kind2, TypeSymbol elementType2, ref CompoundUseSiteInfo useSiteInfo) @@ -2922,12 +3160,26 @@ bool hasImplicitConversion(TypeSymbol source, TypeSymbol destination, ref Compou Conversions.ClassifyImplicitConversionFromType(source, destination, ref useSiteInfo).IsImplicit; } - private bool IsBetterParamsCollectionType(TypeSymbol t1, TypeSymbol t2, ref CompoundUseSiteInfo useSiteInfo) + private BetterResult BetterParamsCollectionType(TypeSymbol t1, TypeSymbol t2, ref CompoundUseSiteInfo useSiteInfo) { CollectionExpressionTypeKind kind1 = ConversionsBase.GetCollectionExpressionTypeKind(Compilation, t1, out TypeWithAnnotations elementType1); CollectionExpressionTypeKind kind2 = ConversionsBase.GetCollectionExpressionTypeKind(Compilation, t2, out TypeWithAnnotations elementType2); - return IsBetterCollectionExpressionConversion(t1, kind1, elementType1.Type, t2, kind2, elementType2.Type, ref useSiteInfo); + if (kind1 is CollectionExpressionTypeKind.CollectionBuilder or CollectionExpressionTypeKind.ImplementsIEnumerable) + { + _binder.TryGetCollectionIterationType(CSharpSyntaxTree.Dummy.GetRoot(), t1, out elementType1); + } + + if (kind2 is CollectionExpressionTypeKind.CollectionBuilder or CollectionExpressionTypeKind.ImplementsIEnumerable) + { + _binder.TryGetCollectionIterationType(CSharpSyntaxTree.Dummy.GetRoot(), t2, out elementType2); + } + + return BetterCollectionExpressionConversion( + collectionExpressionElements: [], + t1, kind1, elementType1.Type, underlyingElementConversions1: [], + t2, kind2, elementType2.Type, underlyingElementConversions2: [], + ref useSiteInfo); } private static bool IsSZArrayOrArrayInterface(TypeSymbol type, out TypeSymbol elementType) @@ -3114,7 +3366,7 @@ public override BoundNode Visit(BoundNode node) return null; } - protected override BoundExpression VisitExpressionWithoutStackGuard(BoundExpression node) + protected override BoundNode VisitExpressionOrPatternWithoutStackGuard(BoundNode node) { throw ExceptionUtilities.Unreachable(); } @@ -3134,17 +3386,6 @@ public override BoundNode VisitReturnStatement(BoundReturnStatement node) private const int BetterConversionTargetRecursionLimit = 100; -#if DEBUG - private BetterResult BetterConversionTarget( - TypeSymbol type1, - TypeSymbol type2, - ref CompoundUseSiteInfo useSiteInfo) - { - bool okToDowngradeToNeither; - return BetterConversionTargetCore(null, type1, default(Conversion), type2, default(Conversion), ref useSiteInfo, out okToDowngradeToNeither, BetterConversionTargetRecursionLimit); - } -#endif - private BetterResult BetterConversionTargetCore( TypeSymbol type1, TypeSymbol type2, @@ -3161,7 +3402,7 @@ private BetterResult BetterConversionTargetCore( } private BetterResult BetterConversionTarget( - BoundExpression node, + BoundNode node, TypeSymbol type1, Conversion conv1, TypeSymbol type2, @@ -3173,7 +3414,7 @@ private BetterResult BetterConversionTarget( } private BetterResult BetterConversionTargetCore( - BoundExpression node, + BoundNode node, TypeSymbol type1, Conversion conv1, TypeSymbol type2, @@ -3423,7 +3664,7 @@ private bool CanDowngradeConversionFromLambdaToNeither(BetterResult currentResul Debug.Assert( r1.IsErrorType() || r2.IsErrorType() || - currentResult == BetterConversionTarget(r1, r2, ref useSiteInfo)); + currentResult == BetterConversionTargetCore(null, type1, default(Conversion), type2, default(Conversion), ref useSiteInfo, out _, BetterConversionTargetRecursionLimit)); } #endif } @@ -3767,7 +4008,9 @@ private MemberResolutionResult IsMemberApplicableInNormalForm( { // AnalyzeArguments matches arguments to parameter names and positions. // For that purpose we use the most derived member. - var argumentAnalysis = AnalyzeArguments(member, arguments, isMethodGroupConversion: (options & Options.IsMethodGroupConversion) != 0, expanded: false); + var argumentAnalysis = (options & Options.InferringUniqueMethodGroupSignature) != 0 + ? ArgumentAnalysisResult.NormalForm(argsToParamsOpt: default) + : AnalyzeArguments(member, arguments, isMethodGroupConversion: (options & Options.IsMethodGroupConversion) != 0, expanded: false); if (!argumentAnalysis.IsValid) { switch (argumentAnalysis.Kind) @@ -3787,7 +4030,7 @@ private MemberResolutionResult IsMemberApplicableInNormalForm( // Check after argument analysis, but before more complicated type inference and argument type validation. // NOTE: The diagnostic may not be reported (e.g. if the member is later removed as less-derived). - if (member.HasUseSiteError) + if ((options & Options.InferringUniqueMethodGroupSignature) == 0 && member.HasUseSiteError) { return new MemberResolutionResult(member, leastOverriddenMember, MemberAnalysisResult.UseSiteError(), hasTypeArgumentInferredFromFunctionType: false); } @@ -3810,7 +4053,7 @@ private MemberResolutionResult IsMemberApplicableInNormalForm( // The applicability is checked based on effective parameters passed in. var applicableResult = IsApplicable( member, leastOverriddenMemberConstructedFrom, - typeArguments, arguments, constructedFromEffectiveParameters, + typeArguments, arguments, options, constructedFromEffectiveParameters, definitionParamsElementTypeOpt: default, isExpanded: false, argumentAnalysis.ArgsToParamsOpt, @@ -3837,7 +4080,7 @@ private MemberResolutionResult IsMemberApplicableInExpandedForm typeArguments, AnalyzedArguments arguments, TypeWithAnnotations definitionParamsElementType, - bool allowRefOmittedArguments, + Options options, bool completeResults, bool dynamicConvertsToAnything, bool isMethodGroupConversion, @@ -3846,7 +4089,9 @@ private MemberResolutionResult IsMemberApplicableInExpandedForm(member, leastOverriddenMember, MemberAnalysisResult.ArgumentParameterMismatch(argumentAnalysis), hasTypeArgumentInferredFromFunctionType: false); @@ -3854,7 +4099,7 @@ private MemberResolutionResult IsMemberApplicableInExpandedForm(member, leastOverriddenMember, MemberAnalysisResult.UseSiteError(), hasTypeArgumentInferredFromFunctionType: false); } @@ -3867,17 +4112,17 @@ private MemberResolutionResult IsMemberApplicableInExpandedForm IsApplicable( TMember leastOverriddenMember, // method or property ArrayBuilder typeArgumentsBuilder, AnalyzedArguments arguments, + Options options, EffectiveParameters constructedFromEffectiveParameters, TypeWithAnnotations definitionParamsElementTypeOpt, bool isExpanded, @@ -3915,7 +4161,8 @@ private MemberResolutionResult IsApplicable( MethodSymbol method; EffectiveParameters constructedEffectiveParameters; bool hasTypeArgumentsInferredFromFunctionType = false; - if (member.Kind == SymbolKind.Method && (method = (MethodSymbol)(Symbol)member).Arity > 0) + if ((options & Options.InferringUniqueMethodGroupSignature) == 0 && + member.Kind == SymbolKind.Method && (method = (MethodSymbol)(Symbol)member).Arity > 0) { MethodSymbol leastOverriddenMethod = (MethodSymbol)(Symbol)leastOverriddenMember; ImmutableArray typeArguments; diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundDagEvaluation.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundDagEvaluation.cs index 21c4a6100604c..801255696ceb4 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundDagEvaluation.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundDagEvaluation.cs @@ -83,8 +83,8 @@ public int Id } internal set { - Debug.Assert(value > 0, "Id must be positive but was set to " + value); - Debug.Assert(_id == -1, $"Id was set to {_id} and set again to {value}"); + RoslynDebug.Assert(value > 0, "Id must be positive but was set to " + value); + RoslynDebug.Assert(_id == -1, $"Id was set to {_id} and set again to {value}"); _id = value; } } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNode.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundNode.cs index 8f92867f0dd10..a121970dfa9d9 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNode.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNode.cs @@ -55,6 +55,11 @@ private enum BoundNodeAttributes : short ParamsArrayOrCollection = 1 << 9, + /// + /// Set after checking if the property access should use the backing field directly. + /// + WasPropertyBackingFieldAccessChecked = 1 << 10, + AttributesPreservedInClone = HasErrors | CompilerGenerated | IsSuppressed | WasConverted | ParamsArrayOrCollection, } @@ -325,6 +330,22 @@ protected set } } } + + public bool WasPropertyBackingFieldAccessChecked + { + get + { + return (_attributes & BoundNodeAttributes.WasPropertyBackingFieldAccessChecked) != 0; + } + set + { + Debug.Assert((_attributes & BoundNodeAttributes.WasPropertyBackingFieldAccessChecked) == 0, "should not be set twice or reset"); + if (value) + { + _attributes |= BoundNodeAttributes.WasPropertyBackingFieldAccessChecked; + } + } + } #endif public bool IsParamsArrayOrCollection @@ -335,7 +356,7 @@ public bool IsParamsArrayOrCollection } protected set { - Debug.Assert((_attributes & BoundNodeAttributes.ParamsArrayOrCollection) == 0, $"{nameof(BoundNodeAttributes.ParamsArrayOrCollection)} flag should not be set twice or reset"); + RoslynDebug.Assert((_attributes & BoundNodeAttributes.ParamsArrayOrCollection) == 0, $"{nameof(BoundNodeAttributes.ParamsArrayOrCollection)} flag should not be set twice or reset"); Debug.Assert(value || !IsParamsArrayOrCollection); Debug.Assert(!value || this is BoundArrayCreation { Bounds: [BoundLiteral { WasCompilerGenerated: true }], InitializerOpt: BoundArrayInitialization { WasCompilerGenerated: true }, WasCompilerGenerated: true } or diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index 289afc739f4f2..28e5f8a9cc8c0 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -661,6 +661,15 @@ + + + + + + + + diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeRewriter.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeRewriter.cs index 6f489cb0cf2ae..e55fc8af21250 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeRewriter.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeRewriter.cs @@ -78,23 +78,22 @@ protected BoundTreeRewriterWithStackGuard(int recursionDepth) [return: NotNullIfNotNull(nameof(node))] public override BoundNode? Visit(BoundNode? node) { - var expression = node as BoundExpression; - if (expression != null) + if (node is BoundExpression or BoundPattern) { - return VisitExpressionWithStackGuard(ref _recursionDepth, expression); + return VisitExpressionOrPatternWithStackGuard(ref _recursionDepth, node); } return base.Visit(node); } - protected BoundExpression VisitExpressionWithStackGuard(BoundExpression node) + protected BoundNode VisitExpressionOrPatternWithStackGuard(BoundNode node) { - return VisitExpressionWithStackGuard(ref _recursionDepth, node); + return VisitExpressionOrPatternWithStackGuard(ref _recursionDepth, node); } - protected sealed override BoundExpression VisitExpressionWithoutStackGuard(BoundExpression node) + protected sealed override BoundNode VisitExpressionOrPatternWithoutStackGuard(BoundNode node) { - return (BoundExpression)base.Visit(node); + return base.Visit(node); } } @@ -152,5 +151,93 @@ protected BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperat return left; } + + public sealed override BoundNode? VisitIfStatement(BoundIfStatement node) + { + if (node.AlternativeOpt is not BoundIfStatement ifStatement) + { + return base.VisitIfStatement(node); + } + + var stack = ArrayBuilder.GetInstance(); + stack.Push(node); + + BoundStatement? alternative; + while (true) + { + stack.Push(ifStatement); + + alternative = ifStatement.AlternativeOpt; + if (alternative is not BoundIfStatement nextIfStatement) + { + break; + } + + ifStatement = nextIfStatement; + } + + alternative = (BoundStatement?)this.Visit(alternative); + + do + { + ifStatement = stack.Pop(); + + BoundExpression condition = (BoundExpression)this.Visit(ifStatement.Condition); + BoundStatement consequence = (BoundStatement)this.Visit(ifStatement.Consequence); + + alternative = ifStatement.Update(condition, consequence, alternative); + } + while (stack.Count > 0); + + Debug.Assert((object)ifStatement == node); + stack.Free(); + + return alternative; + } + + public sealed override BoundNode? VisitBinaryPattern(BoundBinaryPattern node) + { + BoundPattern child = node.Left; + + if (child.Kind != BoundKind.BinaryPattern) + { + return base.VisitBinaryPattern(node); + } + + var stack = ArrayBuilder.GetInstance(); + stack.Push(node); + + BoundBinaryPattern binary = (BoundBinaryPattern)child; + + while (true) + { + stack.Push(binary); + child = binary.Left; + + if (child.Kind != BoundKind.BinaryPattern) + { + break; + } + + binary = (BoundBinaryPattern)child; + } + + var left = (BoundPattern?)this.Visit(child); + Debug.Assert(left is { }); + + do + { + binary = stack.Pop(); + var right = (BoundPattern?)this.Visit(binary.Right); + Debug.Assert(right is { }); + left = binary.Update(binary.Disjunction, left, right, VisitType(binary.InputType), VisitType(binary.NarrowedType)); + } + while (stack.Count > 0); + + Debug.Assert((object)binary == node); + stack.Free(); + + return left; + } } } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeVisitors.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeVisitors.cs index 5e93ce79faa9b..397ded7692115 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeVisitors.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeVisitors.cs @@ -184,9 +184,9 @@ public static Location GetTooLongOrComplexExpressionErrorLocation(BoundNode node { SyntaxNode syntax = node.Syntax; - if (!(syntax is ExpressionSyntax)) + if (syntax is not (ExpressionSyntax or PatternSyntax)) { - syntax = syntax.DescendantNodes(n => !(n is ExpressionSyntax)).OfType().FirstOrDefault() ?? syntax; + syntax = syntax.DescendantNodes(n => n is not (ExpressionSyntax or PatternSyntax)).FirstOrDefault(n => n is ExpressionSyntax or PatternSyntax) ?? syntax; } return syntax.GetFirstToken().GetLocation(); @@ -194,12 +194,13 @@ public static Location GetTooLongOrComplexExpressionErrorLocation(BoundNode node } /// - /// Consumers must provide implementation for . + /// Consumers must provide implementation for . /// [DebuggerStepThrough] - protected BoundExpression VisitExpressionWithStackGuard(ref int recursionDepth, BoundExpression node) + protected BoundNode VisitExpressionOrPatternWithStackGuard(ref int recursionDepth, BoundNode node) { - BoundExpression result; + Debug.Assert(node is BoundExpression or BoundPattern); + BoundNode result; recursionDepth++; #if DEBUG int saveRecursionDepth = recursionDepth; @@ -209,11 +210,11 @@ protected BoundExpression VisitExpressionWithStackGuard(ref int recursionDepth, { EnsureSufficientExecutionStack(recursionDepth); - result = VisitExpressionWithoutStackGuard(node); + result = VisitExpressionOrPatternWithoutStackGuard(node); } else { - result = VisitExpressionWithStackGuard(node); + result = VisitExpressionOrPatternWithStackGuard(node); } #if DEBUG @@ -235,11 +236,11 @@ protected virtual bool ConvertInsufficientExecutionStackExceptionToCancelledBySt #nullable enable [DebuggerStepThrough] - private BoundExpression? VisitExpressionWithStackGuard(BoundExpression node) + private BoundNode? VisitExpressionOrPatternWithStackGuard(BoundNode node) { try { - return VisitExpressionWithoutStackGuard(node); + return VisitExpressionOrPatternWithoutStackGuard(node); } catch (InsufficientExecutionStackException ex) { @@ -250,6 +251,6 @@ protected virtual bool ConvertInsufficientExecutionStackExceptionToCancelledBySt /// /// We should be intentional about behavior of derived classes regarding guarding against stack overflow. /// - protected abstract BoundExpression? VisitExpressionWithoutStackGuard(BoundExpression node); + protected abstract BoundNode? VisitExpressionOrPatternWithoutStackGuard(BoundNode node); } } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeWalker.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeWalker.cs index 8f0df23b1e56c..fbc7ae185a974 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundTreeWalker.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundTreeWalker.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Diagnostics; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.CSharp @@ -69,23 +70,23 @@ protected BoundTreeWalkerWithStackGuard(int recursionDepth) public override BoundNode? Visit(BoundNode? node) { - var expression = node as BoundExpression; - if (expression != null) + if (node is BoundExpression or BoundPattern) { - return VisitExpressionWithStackGuard(ref _recursionDepth, expression); + return VisitExpressionOrPatternWithStackGuard(ref _recursionDepth, node); } return base.Visit(node); } - protected BoundExpression VisitExpressionWithStackGuard(BoundExpression node) + protected BoundNode VisitExpressionOrPatternWithStackGuard(BoundNode node) { - return VisitExpressionWithStackGuard(ref _recursionDepth, node); + return VisitExpressionOrPatternWithStackGuard(ref _recursionDepth, node); } - protected sealed override BoundExpression VisitExpressionWithoutStackGuard(BoundExpression node) + protected sealed override BoundNode VisitExpressionOrPatternWithoutStackGuard(BoundNode node) { - return (BoundExpression)base.Visit(node); + Debug.Assert(node is BoundExpression or BoundPattern); + return base.Visit(node); } } @@ -103,7 +104,7 @@ protected BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator public sealed override BoundNode? VisitBinaryOperator(BoundBinaryOperator node) { - if (node.Left.Kind != BoundKind.BinaryOperator) + if (node.Left is not BoundBinaryOperator binary) { return base.VisitBinaryOperator(node); } @@ -112,12 +113,10 @@ protected BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator rightOperands.Push(node.Right); - var binary = (BoundBinaryOperator)node.Left; - BeforeVisitingSkippedBoundBinaryOperatorChildren(binary); rightOperands.Push(binary.Right); - BoundExpression current = binary.Left; + BoundExpression? current = binary.Left; while (current.Kind == BoundKind.BinaryOperator) { @@ -129,10 +128,11 @@ protected BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator this.Visit(current); - while (rightOperands.Count > 0) + current = rightOperands.Pop(); + do { - this.Visit(rightOperands.Pop()); - } + this.Visit(current); + } while (rightOperands.TryPop(out current)); rightOperands.Free(); return null; @@ -142,6 +142,40 @@ protected virtual void BeforeVisitingSkippedBoundBinaryOperatorChildren(BoundBin { } + public sealed override BoundNode? VisitBinaryPattern(BoundBinaryPattern node) + { + if (node.Left is not BoundBinaryPattern binary) + { + return base.VisitBinaryPattern(node); + } + + var rightOperands = ArrayBuilder.GetInstance(); + + rightOperands.Push(node.Right); + rightOperands.Push(binary.Right); + + BoundPattern? current = binary.Left; + + while (current.Kind == BoundKind.BinaryPattern) + { + binary = (BoundBinaryPattern)current; + rightOperands.Push(binary.Right); + current = binary.Left; + } + + Visit(current); + + current = rightOperands.Pop(); + + do + { + Visit(current); + } while (rightOperands.TryPop(out current)); + + rightOperands.Free(); + return null; + } + public sealed override BoundNode? VisitCall(BoundCall node) { if (node.ReceiverOpt is BoundCall receiver1) @@ -195,5 +229,29 @@ protected virtual void VisitArguments(BoundCall node) { this.VisitList(node.Arguments); } + + public sealed override BoundNode? VisitIfStatement(BoundIfStatement node) + { + while (true) + { + Visit(node.Condition); + Visit(node.Consequence); + var alternative = node.AlternativeOpt; + if (alternative is null) + { + break; + } + if (alternative is BoundIfStatement elseIfStatement) + { + node = elseIfStatement; + } + else + { + Visit(alternative); + break; + } + } + return null; + } } } diff --git a/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs b/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs index a3f7e05139976..e7d6bcdc47e6a 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Formatting.cs @@ -18,7 +18,7 @@ public virtual object Display { get { - Debug.Assert(this.Type is { }, $"Unexpected null type in {this.GetType().Name}"); + RoslynDebug.Assert(this.Type is { }, $"Unexpected null type in {this.GetType().Name}"); return this.Type; } } diff --git a/src/Compilers/CSharp/Portable/BoundTree/NullabilityRewriter.cs b/src/Compilers/CSharp/Portable/BoundTree/NullabilityRewriter.cs index db5389f0b60c1..99544b65651fc 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/NullabilityRewriter.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/NullabilityRewriter.cs @@ -12,9 +12,9 @@ namespace Microsoft.CodeAnalysis.CSharp { internal sealed partial class NullabilityRewriter : BoundTreeRewriter { - protected override BoundExpression? VisitExpressionWithoutStackGuard(BoundExpression node) + protected override BoundNode? VisitExpressionOrPatternWithoutStackGuard(BoundNode node) { - return (BoundExpression)Visit(node); + return Visit(node); } public override BoundNode? VisitBinaryOperator(BoundBinaryOperator node) @@ -27,6 +27,49 @@ internal sealed partial class NullabilityRewriter : BoundTreeRewriter return VisitBinaryOperatorBase(node); } + public override BoundNode? VisitIfStatement(BoundIfStatement node) + { + var stack = ArrayBuilder<(BoundIfStatement, BoundExpression, BoundStatement)>.GetInstance(); + + BoundStatement? rewrittenAlternative; + while (true) + { + var rewrittenCondition = (BoundExpression)Visit(node.Condition); + var rewrittenConsequence = (BoundStatement)Visit(node.Consequence); + Debug.Assert(rewrittenConsequence is { }); + stack.Push((node, rewrittenCondition, rewrittenConsequence)); + + var alternative = node.AlternativeOpt; + if (alternative is null) + { + rewrittenAlternative = null; + break; + } + + if (alternative is BoundIfStatement elseIfStatement) + { + node = elseIfStatement; + } + else + { + rewrittenAlternative = (BoundStatement)Visit(alternative); + break; + } + } + + BoundStatement result; + do + { + var (ifStatement, rewrittenCondition, rewrittenConsequence) = stack.Pop(); + result = ifStatement.Update(rewrittenCondition, rewrittenConsequence, rewrittenAlternative); + rewrittenAlternative = result; + } + while (stack.Any()); + + stack.Free(); + return result; + } + private BoundNode VisitBinaryOperatorBase(BoundBinaryOperatorBase binaryOperator) { // Use an explicit stack to avoid blowing the managed stack when visiting deeply-recursive diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index 1447dff19215c..a3a7d38e23a5b 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -360,7 +360,7 @@ public static void GetReturnTypes(ArrayBuilder<(BoundReturnStatement, TypeWithAn return null; } - protected override BoundExpression VisitExpressionWithoutStackGuard(BoundExpression node) + protected override BoundNode VisitExpressionOrPatternWithoutStackGuard(BoundNode node) { throw ExceptionUtilities.Unreachable(); } @@ -764,6 +764,7 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo return Binder.GetMethodGroupOrLambdaDelegateType( _unboundLambda.Syntax, lambdaSymbol, + hasParams: OverloadResolution.IsValidParams(Binder, lambdaSymbol, disallowExpandedNonArrayParams: false, out _), parameterScopesBuilder.ToImmutableAndFree(), lambdaSymbol.Parameters.SelectAsArray(p => p.HasUnscopedRefAttribute), returnRefKind, diff --git a/src/Compilers/CSharp/Portable/CSharpParseOptions.cs b/src/Compilers/CSharp/Portable/CSharpParseOptions.cs index 675f7cd9db8ed..8ae7033ac2fd0 100644 --- a/src/Compilers/CSharp/Portable/CSharpParseOptions.cs +++ b/src/Compilers/CSharp/Portable/CSharpParseOptions.cs @@ -22,7 +22,7 @@ public sealed class CSharpParseOptions : ParseOptions, IEquatable _features; - private ImmutableArray> _interceptorsPreviewNamespaces; + private ImmutableArray> _interceptorsNamespaces; /// /// Gets the effective language version, which the compiler uses to select the @@ -177,21 +177,21 @@ public override IReadOnlyDictionary Features } } - internal ImmutableArray> InterceptorsPreviewNamespaces + internal ImmutableArray> InterceptorsNamespaces { get { - if (!_interceptorsPreviewNamespaces.IsDefault) + if (!_interceptorsNamespaces.IsDefault) { - return _interceptorsPreviewNamespaces; + return _interceptorsNamespaces; } // e.g. [["System", "Threading"], ["System", "Collections"]] - ImmutableArray> previewNamespaces = Features.TryGetValue("InterceptorsPreviewNamespaces", out var namespaces) && namespaces.Length > 0 + ImmutableArray> previewNamespaces = Features.TryGetValue("InterceptorsNamespaces", out var namespaces) && namespaces.Length > 0 ? makeNamespaces(namespaces) : ImmutableArray>.Empty; - ImmutableInterlocked.InterlockedInitialize(ref _interceptorsPreviewNamespaces, previewNamespaces); + ImmutableInterlocked.InterlockedInitialize(ref _interceptorsNamespaces, previewNamespaces); return previewNamespaces; static ImmutableArray> makeNamespaces(string namespaces) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 25598d433796e..bb91e6bdbce81 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -1808,8 +1808,8 @@ If such a class is used as a base class and if the deriving class defines a dest The DllImport attribute must be specified on a method marked 'static' and 'extern' - - Cannot update '{0}'; attribute '{1}' is missing. + + Cannot emit update; {0} '{1}' is missing. The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. @@ -3845,9 +3845,6 @@ Give the compiler some way to differentiate the methods. For example, you can gi The 'async' modifier can only be used in methods that have a body. - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. @@ -4891,7 +4888,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Expected identifier or numeric literal - Only auto-implemented properties can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. Instance properties in interfaces cannot have initializers. @@ -5879,7 +5876,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Local function '{0}' must declare a body because it is not marked 'static extern'. - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} {0} is not a valid C# conversion expression @@ -6868,8 +6865,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Compiling requires binding the lambda expression many times. Consider declaring the lambda expression with explicit parameter types, or if the containing method call is generic, consider using explicit type arguments. - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + The 'field' keyword binds to a synthesized backing field for the property. Identifier is a contextual keyword, with a specific meaning, in a later language version. @@ -7609,7 +7609,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ A switch expression arm does not begin with a 'case' keyword. - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. An interceptor cannot be declared in the global namespace. @@ -7860,6 +7860,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}' is applicable only with expanded form of non-array params collection which is not supported during dynamic dispatch. + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Creation of params collection '{0}' results in an infinite chain of invocation of constructor '{1}'. @@ -7902,8 +7905,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ ref and unsafe in async and iterator methods - - field and value keywords + + field keyword A 'ref' local cannot be preserved across 'await' or 'yield' boundary. @@ -7974,6 +7977,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Both partial property declarations must be required or neither may be required + + A partial property cannot have an initializer on both the definition and implementation. + allows ref struct constraint @@ -7989,6 +7995,13 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + first-class Span types diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs index c35bfcbf6f63b..0635d237c63a1 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs @@ -431,7 +431,7 @@ private bool TryEmitOptimizedReadonlySpanCreation(NamedTypeSymbol spanType, Boun // the null terminator off as part of creating the span instance. Debug.Assert(inPlaceTarget is null || TargetIsNotOnHeap(inPlaceTarget), "in-place construction target should not be on heap"); - Debug.Assert(_diagnostics.DiagnosticBag is not null, $"Expected non-null {nameof(_diagnostics)}.{nameof(_diagnostics.DiagnosticBag)}"); + RoslynDebug.Assert(_diagnostics.DiagnosticBag is not null, $"Expected non-null {nameof(_diagnostics)}.{nameof(_diagnostics.DiagnosticBag)}"); if (start is null != length is null) { diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 1a4fae886824a..b9f065e75ff1d 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -154,6 +154,10 @@ private void EmitExpressionCore(BoundExpression expression, bool used) EmitArrayElementLoad((BoundArrayAccess)expression, used); break; + case BoundKind.RefArrayAccess: + EmitArrayElementRefLoad((BoundRefArrayAccess)expression, used); + break; + case BoundKind.ArrayLength: EmitArrayLength((BoundArrayLength)expression, used); break; @@ -729,7 +733,8 @@ private void EmitArgument(BoundExpression argument, RefKind refKind) if (unexpectedTemp != null) { // interestingly enough "ref dynamic" sometimes is passed via a clone - Debug.Assert(argument.Type.IsDynamic(), "passing args byref should not clone them into temps"); + // receiver of a ref field can be cloned too + Debug.Assert(argument.Type.IsDynamic() || argument is BoundFieldAccess { FieldSymbol.RefKind: not RefKind.None }, "passing args byref should not clone them into temps"); AddExpressionTemp(unexpectedTemp); } @@ -1099,6 +1104,17 @@ private void EmitArrayElementLoad(BoundArrayAccess arrayAccess, bool used) EmitPopIfUnused(used); } + private void EmitArrayElementRefLoad(BoundRefArrayAccess refArrayAccess, bool used) + { + if (used) + { + throw ExceptionUtilities.Unreachable(); + } + + EmitArrayElementAddress(refArrayAccess.ArrayAccess, AddressKind.Writeable); + _builder.EmitOpCode(ILOpCode.Pop); + } + private void EmitFieldLoad(BoundFieldAccess fieldAccess, bool used) { var field = fieldAccess.FieldSymbol; diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs index 0cfeba75f526f..e27bdc7ccd18e 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs @@ -92,7 +92,7 @@ private void EmitStackAlloc(TypeSymbol type, BoundArrayInitialization? inits, Bo // span.get_Item[0] _builder.EmitIntConstant(0); - _builder.EmitOpCode(ILOpCode.Call, 0); + _builder.EmitOpCode(ILOpCode.Call, -1); EmitSymbolToken(spanGetItem, syntaxNode, optArgList: null); _builder.EmitIntConstant(data.Length); diff --git a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs index a704cc630aa4e..c628a423e0faa 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs @@ -532,7 +532,7 @@ private BoundExpression VisitExpressionCoreWithStackGuard(BoundExpression node, } } - protected override BoundExpression VisitExpressionWithoutStackGuard(BoundExpression node) + protected override BoundNode VisitExpressionOrPatternWithoutStackGuard(BoundNode node) { throw ExceptionUtilities.Unreachable(); } @@ -2186,6 +2186,16 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) if (isLast) { + if (node.IsRef && + !node.WasCompilerGenerated && + left.LocalSymbol.RefKind == RefKind.Ref && + right is BoundArrayAccess arrayAccess && + // Value types do not need runtime element type checks. + !arrayAccess.Type.IsValueType) + { + return new BoundRefArrayAccess(arrayAccess.Syntax, arrayAccess); + } + // assigned local is not used later => just emit the Right return right; } diff --git a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs index 9c1ff91e6ab4a..108c348aa4427 100644 --- a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs +++ b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs @@ -267,7 +267,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar } else { - // When a features value like "InterceptorsPreviewNamespaces=NS1;NS2" is provided, + // When a features value like "InterceptorsNamespaces=NS1;NS2" is provided, // the build system will quote it so that splitting doesn't occur in the wrong layer. // We need to unquote here so that subsequent layers can properly identify the feature name and value. features.Add(value.Unquote()); diff --git a/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs b/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs index 7c7ab46535c77..2be61b2562537 100644 --- a/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs +++ b/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs @@ -375,7 +375,7 @@ protected override void ResolveEmbeddedFilesFromExternalSourceDirectives( private protected override GeneratorDriver CreateGeneratorDriver(string baseDirectory, ParseOptions parseOptions, ImmutableArray generators, AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider, ImmutableArray additionalTexts) { - return CSharpGeneratorDriver.Create(generators, additionalTexts, (CSharpParseOptions)parseOptions, analyzerConfigOptionsProvider, driverOptions: new GeneratorDriverOptions() { BaseDirectory = baseDirectory }); + return CSharpGeneratorDriver.Create(generators, additionalTexts, (CSharpParseOptions)parseOptions, analyzerConfigOptionsProvider, driverOptions: new GeneratorDriverOptions(disabledOutputs: IncrementalGeneratorOutputKind.Host) { BaseDirectory = baseDirectory }); } private protected override void DiagnoseBadAccesses(TextWriter consoleOutput, ErrorLogger? errorLogger, Compilation compilation, ImmutableArray diagnostics) diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 04b74a1dbd441..6d8755832f9c4 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -142,13 +142,6 @@ internal Conversions Conversions /// private ImmutableHashSet? _usageOfUsingsRecordedInTrees = ImmutableHashSet.Empty; - /// - /// Optional data collected during testing only. - /// Used for instance for nullable analysis () - /// and inferred delegate types (). - /// - internal object? TestOnlyCompilationData; - internal ImmutableHashSet? UsageOfUsingsRecordedInTrees => Volatile.Read(ref _usageOfUsingsRecordedInTrees); /// @@ -3533,6 +3526,9 @@ internal override bool CompileMethods( return true; } + private protected override EmitBaseline MapToCompilation(CommonPEModuleBuilder moduleBeingBuilt) + => EmitHelpers.MapToCompilation(this, (PEDeltaAssemblyBuilder)moduleBeingBuilt); + private class DuplicateFilePathsVisitor : CSharpSymbolVisitor { // note: the default HashSet uses an ordinal comparison diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs index b79df55c6af72..c3405df8f8be7 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs @@ -1679,7 +1679,7 @@ private ImmutableArray LookupSymbolsInternal( } if (name == null) - FilterNotReferenceable(results); + results.RemoveWhere(static (symbol, _, _) => !symbol.CanBeReferencedByName, arg: default(VoidResult)); return results.ToImmutableAndFree(); } @@ -1795,24 +1795,6 @@ private Symbol RemapSymbolIfNecessary(Symbol symbol) /// internal abstract Symbol RemapSymbolIfNecessaryCore(Symbol symbol); - private static void FilterNotReferenceable(ArrayBuilder sealedResults) - { - var writeIndex = 0; - for (var i = 0; i < sealedResults.Count; i++) - { - var symbol = sealedResults[i]; - if (symbol.CanBeReferencedByName) - { - if (writeIndex != i) - sealedResults[writeIndex] = symbol; - - writeIndex++; - } - } - - sealedResults.Count = writeIndex; - } - /// /// Determines if the symbol is accessible from the specified location. /// diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.NodeMapBuilder.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.NodeMapBuilder.cs index 8a489265541c9..6b2b869a74ef7 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.NodeMapBuilder.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.NodeMapBuilder.cs @@ -5,14 +5,12 @@ #nullable disable using System.Collections.Generic; -using System.Collections.Immutable; +using System.Diagnostics; using Microsoft.CodeAnalysis.Collections; +using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; -using System.Diagnostics; -using System.Linq; -using Microsoft.CodeAnalysis.CSharp.Symbols; namespace Microsoft.CodeAnalysis.CSharp { @@ -52,7 +50,7 @@ public static void AddToMap(BoundNode root, Dictionary.GetInstance(); @@ -223,6 +220,33 @@ public override BoundNode Visit(BoundNode node) stack.Free(); } + else if (current is BoundBinaryPattern binaryPattern) + { + var stack = ArrayBuilder.GetInstance(); + + stack.Push(binaryPattern.Right); + BoundPattern currentPattern = binaryPattern.Left; + binaryPattern = currentPattern as BoundBinaryPattern; + + while (binaryPattern != null) + { + if (ShouldAddNode(binaryPattern)) + { + _map.Add(binaryPattern.Syntax, binaryPattern); + } + + stack.Push(binaryPattern.Right); + currentPattern = binaryPattern.Left; + binaryPattern = currentPattern as BoundBinaryPattern; + } + + do + { + Visit(currentPattern); + } while (stack.TryPop(out currentPattern)); + + stack.Free(); + } else { base.Visit(current); @@ -287,6 +311,37 @@ public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) throw ExceptionUtilities.Unreachable(); } + public override BoundNode VisitIfStatement(BoundIfStatement node) + { + while (true) + { + this.Visit(node.Condition); + this.Visit(node.Consequence); + + var alternative = node.AlternativeOpt; + if (alternative is null) + { + break; + } + + if (alternative is BoundIfStatement elseIfStatement) + { + node = elseIfStatement; + if (ShouldAddNode(node)) + { + _map.Add(node.Syntax, node); + } + } + else + { + this.Visit(alternative); + break; + } + } + + return null; + } + protected override bool ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException() { return false; diff --git a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs index dcae3e0001579..edd5c97d36375 100644 --- a/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/DocumentationCommentCompiler.cs @@ -1238,7 +1238,7 @@ private void BeginTemporaryString() private string GetAndEndTemporaryString() { TemporaryStringBuilder t = _temporaryStringBuilders.Pop(); - Debug.Assert(_indentDepth == t.InitialIndentDepth, $"Temporary strings should be indent-neutral (was {t.InitialIndentDepth}, is {_indentDepth})"); + RoslynDebug.Assert(_indentDepth == t.InitialIndentDepth, $"Temporary strings should be indent-neutral (was {t.InitialIndentDepth}, is {_indentDepth})"); _indentDepth = t.InitialIndentDepth; return t.Pooled.ToStringAndFree(); } diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 7940f2df63ec4..03176e8d1a351 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -168,6 +168,13 @@ public static void CompileMethodBodies( var embeddedTypes = moduleBeingBuiltOpt.GetEmbeddedTypes(diagnostics); methodCompiler.CompileSynthesizedMethods(embeddedTypes, diagnostics); + // Create and compile HotReloadException type if emitting deltas even if it is not used. + // We might need to use it for deleted members, which we determine when indexing metadata. + if (moduleBeingBuiltOpt.TryGetOrCreateSynthesizedHotReloadExceptionType() is { } hotReloadException) + { + methodCompiler.CompileSynthesizedMethods([(NamedTypeSymbol)hotReloadException], diagnostics); + } + if (emitMethodBodies) { // By this time we have processed all types reachable from module's global namespace @@ -813,10 +820,20 @@ private void CompileSynthesizedExplicitImplementations(SourceMemberContainerType // we are not generating any observable diagnostics here so it is ok to short-circuit on global errors. if (!_globalHasErrors) { + var interfaces = sourceTypeSymbol.GetInterfacesToEmit(); + var discardedDiagnostics = BindingDiagnosticBag.GetInstance(_diagnostics); foreach (var synthesizedExplicitImpl in sourceTypeSymbol.GetSynthesizedExplicitImplementations(_cancellationToken).ForwardingMethods) { Debug.Assert(synthesizedExplicitImpl.SynthesizesLoweredBoundBody); + + // Avoid emitting duplicate forwarding methods (e.g., when the class implements the same interface twice with different nullability). + if (!interfaces.Contains(synthesizedExplicitImpl.ExplicitInterfaceImplementations[0].ContainingType, + Symbols.SymbolEqualityComparer.ConsiderEverything)) + { + continue; + } + synthesizedExplicitImpl.GenerateMethodBody(compilationState, discardedDiagnostics); Debug.Assert(!discardedDiagnostics.HasAnyErrors()); discardedDiagnostics.DiagnosticBag.Clear(); @@ -1735,12 +1752,7 @@ private static void GetStateMachineSlotDebugInfo( initializersBody ??= GetSynthesizedEmptyBody(method); - if (method is SynthesizedPrimaryConstructor primaryCtor && method.ContainingType.IsStructType()) - { - body = BoundBlock.SynthesizedNoLocals(primaryCtor.GetSyntax()); - nullableInitialState = getInitializerState(body); - } - else if (method is SourceMemberMethodSymbol sourceMethod) + if (method is SourceMemberMethodSymbol sourceMethod) { CSharpSyntaxNode syntaxNode = sourceMethod.SyntaxNode; @@ -1828,6 +1840,7 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax && #if DEBUG Debug.Assert(IsEmptyRewritePossible(methodBody)); + Debug.Assert(WasPropertyBackingFieldAccessChecked.FindUncheckedAccess(methodBody) is null); #endif RefSafetyAnalysis.Analyze(compilation, method, methodBody, diagnostics); @@ -1879,8 +1892,7 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax && } else { - var property = sourceMethod.AssociatedSymbol as SourcePropertySymbolBase; - if (property is not null && property.IsAutoPropertyWithGetAccessor) + if (sourceMethod is SourcePropertyAccessorSymbol { IsAutoPropertyAccessor: true }) { return MethodBodySynthesizer.ConstructAutoPropertyAccessorBody(sourceMethod); } @@ -2015,6 +2027,8 @@ static void buildIdentifierMapOfBindIdentifierTargets( } } + // Logic in this lambda is based on Binder.IdentifierUsedAsValueFinder.CheckIdentifiersInNode.childrenNeedChecking. + // It can be more permissive (i.e. allow us to dive into more nodes), but should not be more restrictive static void addIdentifiers(CSharpSyntaxNode? node, ConcurrentDictionary identifierMap) { if (node is null) @@ -2102,6 +2116,7 @@ static void assertBindIdentifierTargets(InMethodBinder? inMethodBinder, Concurre { inMethodBinder.IdentifierMap = null; + // In presence of errors, we're not guaranteed to have bound all identifiers, so we don't care about correctness of our prediction if (!diagnostics.HasAnyResolvedErrors()) { foreach (var (id, flags) in identifierMap) @@ -2138,6 +2153,14 @@ static void assertBindIdentifierTargets(InMethodBinder? inMethodBinder, Concurre { continue; } + + // If an attribute is misplaced (invalid target), it is expected that identifiers within were not bound. + // In that case, we emit a warning and skip binding the attribute. + if (id.Ancestors(ascendOutOfTrivia: false).OfType().Any() && + diagnostics.DiagnosticBag!.AsEnumerable().Any(d => d.Code == (int)ErrorCode.WRN_AttributeLocationOnBadDeclaration)) + { + continue; + } } Debug.Assert(false); @@ -2164,7 +2187,7 @@ private static bool IsEmptyRewritePossible(BoundNode node) } } - private sealed class EmptyRewriter : BoundTreeRewriterWithStackGuard + private sealed class EmptyRewriter : BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator { } @@ -2211,6 +2234,94 @@ public static bool FoundInUnboundLambda(BoundNode methodBody, IdentifierNameSynt return base.Visit(node); } } + + private sealed class WasPropertyBackingFieldAccessChecked : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator + { + public static BoundPropertyAccess? FindUncheckedAccess(BoundNode node) + { + var walker = new WasPropertyBackingFieldAccessChecked(); + walker.Visit(node); + return walker._found; + } + + private BoundPropertyAccess? _found; + private bool _suppressChecking; + + private WasPropertyBackingFieldAccessChecked() + { + } + + public override BoundNode? Visit(BoundNode? node) + { + if (_found is { }) + { + return null; + } + + return base.Visit(node); + } + + public override BoundNode? VisitPropertyAccess(BoundPropertyAccess node) + { + if (!_suppressChecking && + !node.WasPropertyBackingFieldAccessChecked) + { + _found = node; + } + + return base.VisitPropertyAccess(node); + } + + public override BoundNode? VisitRangeVariable(BoundRangeVariable node) + { + using (new ChangeSuppression(this, suppressChecking: true)) + { + return base.VisitRangeVariable(node); + } + } + + public override BoundNode? VisitAssignmentOperator(BoundAssignmentOperator node) + { + using (new ChangeSuppression(this, suppressChecking: false)) + { + return base.VisitAssignmentOperator(node); + } + } + + public override BoundNode? VisitNameOfOperator(BoundNameOfOperator node) + { + using (new ChangeSuppression(this, suppressChecking: true)) + { + return base.VisitNameOfOperator(node); + } + } + + public override BoundNode? VisitBadExpression(BoundBadExpression node) + { + using (new ChangeSuppression(this, suppressChecking: true)) + { + return base.VisitBadExpression(node); + } + } + + private struct ChangeSuppression : IDisposable + { + private readonly WasPropertyBackingFieldAccessChecked _walker; + private readonly bool _previousValue; + + internal ChangeSuppression(WasPropertyBackingFieldAccessChecked walker, bool suppressChecking) + { + _walker = walker; + _previousValue = walker._suppressChecking; + walker._suppressChecking = suppressChecking; + } + + public void Dispose() + { + _walker._suppressChecking = _previousValue; + } + } + } #endif #nullable disable diff --git a/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs index 36c30da75eba5..7d32f05c174f9 100644 --- a/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs @@ -68,12 +68,21 @@ public override void VisitNamedType(NamedTypeSymbol symbol) { if (_moduleBeingBuilt != null) { + var interfaces = sourceTypeSymbol.GetInterfacesToEmit(); + // In some circumstances (e.g. implicit implementation of an interface method by a non-virtual method in a // base type from another assembly) it is necessary for the compiler to generate explicit implementations for // some interface methods. They don't go in the symbol table, but if we are emitting metadata, then we should // generate MethodDef entries for them. foreach (var synthesizedExplicitImpl in sourceTypeSymbol.GetSynthesizedExplicitImplementations(_cancellationToken).ForwardingMethods) { + // Avoid emitting duplicate forwarding methods (e.g., when the class implements the same interface twice with different nullability). + if (!interfaces.Contains(synthesizedExplicitImpl.ExplicitInterfaceImplementations[0].ContainingType, + Symbols.SymbolEqualityComparer.ConsiderEverything)) + { + continue; + } + _moduleBeingBuilt.AddSynthesizedDefinition(symbol, synthesizedExplicitImpl.GetCciAdapter()); } } diff --git a/src/Compilers/CSharp/Portable/Declarations/MergedNamespaceDeclaration.cs b/src/Compilers/CSharp/Portable/Declarations/MergedNamespaceDeclaration.cs index 1bb47fab0f034..394ef7cbe16cf 100644 --- a/src/Compilers/CSharp/Portable/Declarations/MergedNamespaceDeclaration.cs +++ b/src/Compilers/CSharp/Portable/Declarations/MergedNamespaceDeclaration.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; @@ -139,43 +140,102 @@ private ImmutableArray MakeChildren() var children = ArrayBuilder.GetInstance(); - if (namespaces != null) + addNamespacesToChildren(namespaces, allNamespacesHaveSameName, children); + addTypesToChildren(types, allTypesHaveSameIdentity, children); + + return children.ToImmutableAndFree(); + + static void addNamespacesToChildren(ArrayBuilder namespaces, bool allNamespacesHaveSameName, ArrayBuilder children) { - if (allNamespacesHaveSameName) - { - children.Add(MergedNamespaceDeclaration.Create(namespaces.ToImmutableAndFree())); - } - else + if (namespaces != null) { - var namespaceGroups = namespaces.ToDictionary(n => n.Name, StringOrdinalComparer.Instance); - namespaces.Free(); - - foreach (var namespaceGroup in namespaceGroups.Values) + if (allNamespacesHaveSameName) + { + children.Add(MergedNamespaceDeclaration.Create(namespaces.ToImmutableAndFree())); + } + else { - children.Add(MergedNamespaceDeclaration.Create(namespaceGroup)); + // PERF: Don't use ArrayBuilder.ToDictionary directly as it requires an extra dictionary allocation. Other options such + // as MultiDictionary and Dictionary> + // are even less appealing as they don't perform well when their value sets grow to contain a large number of items, + // as typically happens when processing the namespaces. + var namespaceGroups = new Dictionary>(StringOrdinalComparer.Instance); + + foreach (var n in namespaces) + { + var builder = namespaceGroups.GetOrAdd(n.Name, static () => ArrayBuilder.GetInstance()); + + builder.Add(n); + } + + namespaces.Free(); + + foreach (var (_, namespaceGroup) in namespaceGroups) + { + children.Add(MergedNamespaceDeclaration.Create(namespaceGroup.ToImmutableAndFree())); + } } } } - if (types != null) + static void addTypesToChildren(ArrayBuilder types, bool allTypesHaveSameIdentity, ArrayBuilder children) { - if (allTypesHaveSameIdentity) - { - children.Add(new MergedTypeDeclaration(types.ToImmutableAndFree())); - } - else + if (types != null) { - var typeGroups = types.ToDictionary(t => t.Identity); - types.Free(); - - foreach (var typeGroup in typeGroups.Values) + if (allTypesHaveSameIdentity) + { + children.Add(new MergedTypeDeclaration(types.ToImmutableAndFree())); + } + else { - children.Add(new MergedTypeDeclaration(typeGroup)); + // PERF: Use object as the value in this dictionary to efficiently represent single item collections. + // If only a single object has been seen with a given identity, the value will be a SingleTypeDeclaration, + // otherwise, the value will be an ArrayBuilder. This code differs from + // addNamespacesToChildren intentionally as the vast majority of identities are represented by only a + // single item in the types collection. + var typeGroups = PooledDictionary.GetInstance(); + + foreach (var t in types) + { + var id = t.Identity; + + if (typeGroups.TryGetValue(id, out var existingValue)) + { + if (existingValue is not ArrayBuilder builder) + { + builder = ArrayBuilder.GetInstance(); + builder.Add((SingleTypeDeclaration)existingValue); + typeGroups[id] = builder; + } + + builder.Add(t); + } + else + { + typeGroups.Add(id, t); + } + } + + foreach (var (_, typeGroup) in typeGroups) + { + if (typeGroup is SingleTypeDeclaration t) + { + children.Add(new MergedTypeDeclaration([t])); + } + else + { + var builder = (ArrayBuilder)typeGroup; + children.Add(new MergedTypeDeclaration(builder.ToImmutableAndFree())); + } + } + + types.Free(); + + // ArrayBuilder values were freed above. + typeGroups.Free(); } } } - - return children.ToImmutableAndFree(); } public new ImmutableArray Children diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpDefinitionMap.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpDefinitionMap.cs index 8733d6d331ede..0c4d0bc839d16 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpDefinitionMap.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpDefinitionMap.cs @@ -27,11 +27,11 @@ internal sealed class CSharpDefinitionMap( MetadataDecoder metadataDecoder, CSharpSymbolMatcher previousSourceToMetadata, CSharpSymbolMatcher sourceToMetadata, - CSharpSymbolMatcher? previousSourceToCurrentSource, + CSharpSymbolMatcher? sourceToPreviousSource, EmitBaseline baseline) : DefinitionMap(edits, baseline) { private readonly MetadataDecoder _metadataDecoder = metadataDecoder; - private readonly CSharpSymbolMatcher _sourceToPrevious = previousSourceToCurrentSource ?? sourceToMetadata; + private readonly CSharpSymbolMatcher _sourceToPrevious = sourceToPreviousSource ?? sourceToMetadata; public override SymbolMatcher SourceToMetadataSymbolMatcher { get; } = sourceToMetadata; public override SymbolMatcher SourceToPreviousSymbolMatcher => _sourceToPrevious; diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs index 610bb81ebd641..020e601857447 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs @@ -7,12 +7,11 @@ using System.Collections.Immutable; using System.Diagnostics; using System.IO; -using System.Linq; using System.Reflection.Metadata; using System.Threading; using Microsoft.CodeAnalysis.CodeGen; -using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -39,18 +38,66 @@ internal static EmitDifferenceResult EmitDifference( var serializationProperties = compilation.ConstructModuleSerializationProperties(emitOptions, runtimeMDVersion, baseline.ModuleVersionId); var manifestResources = SpecializedCollections.EmptyEnumerable(); + if (!GetPredefinedHotReloadExceptionTypeConstructor(compilation, diagnostics, out var predefinedHotReloadExceptionConstructor)) + { + return new EmitDifferenceResult( + success: false, + diagnostics: diagnostics.ToReadOnlyAndFree(), + baseline: null, + updatedMethods: [], + changedTypes: []); + } + + CSharpSymbolChanges changes; + CSharpDefinitionMap definitionMap; PEDeltaAssemblyBuilder moduleBeingBuilt; try { + var sourceAssembly = compilation.SourceAssembly; + var initialBaseline = baseline.InitialBaseline; + + var previousSourceAssembly = ((CSharpCompilation)baseline.Compilation).SourceAssembly; + + // Hydrate symbols from initial metadata. Once we do so it is important to reuse these symbols across all generations, + // in order for the symbol matcher to be able to use reference equality once it maps symbols to initial metadata. + var metadataSymbols = PEDeltaAssemblyBuilder.GetOrCreateMetadataSymbols(initialBaseline, sourceAssembly.DeclaringCompilation); + var metadataDecoder = (MetadataDecoder)metadataSymbols.MetadataDecoder; + var metadataAssembly = (PEAssemblySymbol)metadataDecoder.ModuleSymbol.ContainingAssembly; + + var sourceToMetadata = new CSharpSymbolMatcher( + metadataSymbols.SynthesizedTypes, + sourceAssembly, + metadataAssembly); + + var previousSourceToMetadata = new CSharpSymbolMatcher( + metadataSymbols.SynthesizedTypes, + previousSourceAssembly, + metadataAssembly); + + CSharpSymbolMatcher? currentSourceToPreviousSource = null; + if (baseline.Ordinal > 0) + { + Debug.Assert(baseline.PEModuleBuilder != null); + + currentSourceToPreviousSource = new CSharpSymbolMatcher( + sourceAssembly: sourceAssembly, + otherAssembly: previousSourceAssembly, + baseline.SynthesizedTypes, + otherSynthesizedMembers: baseline.SynthesizedMembers, + otherDeletedMembers: baseline.DeletedMembers); + } + + definitionMap = new CSharpDefinitionMap(edits, metadataDecoder, previousSourceToMetadata, sourceToMetadata, currentSourceToPreviousSource, baseline); + changes = new CSharpSymbolChanges(definitionMap, edits, isAddedSymbol); + moduleBeingBuilt = new PEDeltaAssemblyBuilder( compilation.SourceAssembly, + changes, emitOptions: emitOptions, outputKind: compilation.Options.OutputKind, serializationProperties: serializationProperties, manifestResources: manifestResources, - previousGeneration: baseline, - edits: edits, - isAddedSymbol: isAddedSymbol); + predefinedHotReloadExceptionConstructor); } catch (NotSupportedException e) { @@ -60,8 +107,8 @@ internal static EmitDifferenceResult EmitDifference( success: false, diagnostics: diagnostics.ToReadOnlyAndFree(), baseline: null, - updatedMethods: ImmutableArray.Empty, - changedTypes: ImmutableArray.Empty); + updatedMethods: [], + changedTypes: []); } if (testData != null) @@ -69,10 +116,6 @@ internal static EmitDifferenceResult EmitDifference( moduleBeingBuilt.SetTestData(testData); } - var definitionMap = moduleBeingBuilt.PreviousDefinitions; - var changes = moduleBeingBuilt.EncSymbolChanges; - Debug.Assert(changes != null); - EmitBaseline? newBaseline = null; var updatedMethods = ArrayBuilder.GetInstance(); var changedTypes = ArrayBuilder.GetInstance(); @@ -84,14 +127,8 @@ internal static EmitDifferenceResult EmitDifference( filterOpt: s => changes.RequiresCompilation(s), cancellationToken: cancellationToken)) { - // Map the definitions from the previous compilation to the current compilation. - // This must be done after compiling above since synthesized definitions - // (generated when compiling method bodies) may be required. - var mappedBaseline = MapToCompilation(compilation, moduleBeingBuilt); - newBaseline = compilation.SerializeToDeltaStreams( moduleBeingBuilt, - mappedBaseline, definitionMap, changes, metadataStream, @@ -113,6 +150,33 @@ internal static EmitDifferenceResult EmitDifference( changedTypes: changedTypes.ToImmutableAndFree()); } + /// + /// Returns true if the correct constructor is found or if the type is not defined at all, in which case it can be synthesized. + /// + private static bool GetPredefinedHotReloadExceptionTypeConstructor(CSharpCompilation compilation, DiagnosticBag diagnostics, out MethodSymbol? constructor) + { + constructor = compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_HotReloadException__ctorStringInt32) as MethodSymbol; + if (constructor is { }) + { + return true; + } + + var type = compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_HotReloadException); + if (type.Kind == SymbolKind.ErrorType) + { + // type is missing and will be synthesized + return true; + } + + diagnostics.Add( + ErrorCode.ERR_ModuleEmitFailure, + NoLocation.Singleton, + compilation.AssemblyName, + string.Format(CodeAnalysisResources.Type0DoesNotHaveExpectedConstructor, type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat))); + + return false; + } + /// /// Return a version of the baseline with all definitions mapped to this compilation. /// Definitions from the initial generation, from metadata, are not mapped since @@ -120,7 +184,7 @@ internal static EmitDifferenceResult EmitDifference( /// types, methods, ... in the TypesAdded, MethodsAdded, ... collections are replaced /// by the corresponding symbols from the current compilation. /// - private static EmitBaseline MapToCompilation( + internal static EmitBaseline MapToCompilation( CSharpCompilation compilation, PEDeltaAssemblyBuilder moduleBeingBuilt) { @@ -144,10 +208,10 @@ private static EmitBaseline MapToCompilation( var currentDeletedMembers = moduleBeingBuilt.EncSymbolChanges.DeletedMembers; // Mapping from previous compilation to the current. - var sourceAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly; + var previousSourceAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly; var matcher = new CSharpSymbolMatcher( - sourceAssembly, + previousSourceAssembly, compilation.SourceAssembly, synthesizedTypes, currentSynthesizedMembers, @@ -160,7 +224,7 @@ private static EmitBaseline MapToCompilation( // TODO: can we reuse some data from the previous matcher? var matcherWithAllSynthesizedMembers = new CSharpSymbolMatcher( - sourceAssembly, + previousSourceAssembly, compilation.SourceAssembly, synthesizedTypes, mappedSynthesizedMembers, diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs index 006b8bb003513..636dd4a119a61 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs @@ -6,72 +6,54 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Linq; using System.Reflection.Metadata; +using System.Threading; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Emit { internal sealed class PEDeltaAssemblyBuilder : PEAssemblyBuilderBase, IPEDeltaAssemblyBuilder { - private readonly CSharpDefinitionMap _previousDefinitions; private readonly SymbolChanges _changes; private readonly CSharpSymbolMatcher.DeepTranslator _deepTranslator; + private readonly MethodSymbol? _predefinedHotReloadExceptionConstructor; + + /// + /// HotReloadException type. May be created even if not used. We might find out + /// we need it late in the emit phase only after all types and members have been compiled. + /// indicates if the type is actually used in the delta. + /// + private SynthesizedHotReloadExceptionSymbol? _lazyHotReloadExceptionType; + + /// + /// True if usage of HotReloadException type symbol has been observed and shouldn't be changed anymore. + /// + private volatile bool _freezeHotReloadExceptionTypeUsage; + + /// + /// True if HotReloadException type is actually used in the delta. + /// + private volatile bool _isHotReloadExceptionTypeUsed; public PEDeltaAssemblyBuilder( SourceAssemblySymbol sourceAssembly, + CSharpSymbolChanges changes, EmitOptions emitOptions, OutputKind outputKind, Cci.ModulePropertiesForSerialization serializationProperties, IEnumerable manifestResources, - EmitBaseline previousGeneration, - IEnumerable edits, - Func isAddedSymbol) - : base(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, additionalTypes: ImmutableArray.Empty) + MethodSymbol? predefinedHotReloadExceptionConstructor) + : base(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, additionalTypes: []) { - var initialBaseline = previousGeneration.InitialBaseline; - - var previousSourceAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly; - - // Hydrate symbols from initial metadata. Once we do so it is important to reuse these symbols across all generations, - // in order for the symbol matcher to be able to use reference equality once it maps symbols to initial metadata. - var metadataSymbols = GetOrCreateMetadataSymbols(initialBaseline, sourceAssembly.DeclaringCompilation); - var metadataDecoder = (MetadataDecoder)metadataSymbols.MetadataDecoder; - var metadataAssembly = (PEAssemblySymbol)metadataDecoder.ModuleSymbol.ContainingAssembly; - - var sourceToMetadata = new CSharpSymbolMatcher( - metadataSymbols.SynthesizedTypes, - sourceAssembly, - metadataAssembly); - - var previousSourceToMetadata = new CSharpSymbolMatcher( - metadataSymbols.SynthesizedTypes, - previousSourceAssembly, - metadataAssembly); - - CSharpSymbolMatcher? previousSourceToCurrentSource = null; - if (previousGeneration.Ordinal > 0) - { - Debug.Assert(previousGeneration.PEModuleBuilder != null); - - previousSourceToCurrentSource = new CSharpSymbolMatcher( - sourceAssembly: sourceAssembly, - otherAssembly: previousSourceAssembly, - previousGeneration.SynthesizedTypes, - otherSynthesizedMembers: previousGeneration.SynthesizedMembers, - otherDeletedMembers: previousGeneration.DeletedMembers); - } - - _previousDefinitions = new CSharpDefinitionMap(edits, metadataDecoder, previousSourceToMetadata, sourceToMetadata, previousSourceToCurrentSource, previousGeneration); - _changes = new CSharpSymbolChanges(_previousDefinitions, edits, isAddedSymbol); + _changes = changes; // Workaround for https://github.com/dotnet/roslyn/issues/3192. // When compiling state machine we stash types of awaiters and state-machine hoisted variables, @@ -86,22 +68,24 @@ public PEDeltaAssemblyBuilder( // In order to get the fully lowered form we run the type symbols of stashed variables through a deep translator // that translates the symbol recursively. _deepTranslator = new CSharpSymbolMatcher.DeepTranslator(sourceAssembly.GetSpecialType(SpecialType.System_Object)); + + _predefinedHotReloadExceptionConstructor = predefinedHotReloadExceptionConstructor; } public override SymbolChanges? EncSymbolChanges => _changes; - public override EmitBaseline PreviousGeneration => _previousDefinitions.Baseline; + public override EmitBaseline PreviousGeneration => _changes.DefinitionMap.Baseline; internal override Cci.ITypeReference EncTranslateLocalVariableType(TypeSymbol type, DiagnosticBag diagnostics) { // Note: The translator is not aware of synthesized types. If type is a synthesized type it won't get mapped. // In such case use the type itself. This can only happen for variables storing lambda display classes. var visited = (TypeSymbol)_deepTranslator.Visit(type); - Debug.Assert((object)visited != null); + Debug.Assert(visited is not null); //Debug.Assert(visited != null || type is LambdaFrame || ((NamedTypeSymbol)type).ConstructedFrom is LambdaFrame); return Translate(visited ?? type, null, diagnostics); } - private static EmitBaseline.MetadataSymbols GetOrCreateMetadataSymbols(EmitBaseline initialBaseline, CSharpCompilation compilation) + internal static EmitBaseline.MetadataSymbols GetOrCreateMetadataSymbols(EmitBaseline initialBaseline, CSharpCompilation compilation) { if (initialBaseline.LazyMetadataSymbols != null) { @@ -234,9 +218,7 @@ private static bool TryGetAnonymousTypeKey( } internal CSharpDefinitionMap PreviousDefinitions - { - get { return _previousDefinitions; } - } + => (CSharpDefinitionMap)_changes.DefinitionMap; public SynthesizedTypeMaps GetSynthesizedTypes() { @@ -261,7 +243,7 @@ public SynthesizedTypeMaps GetSynthesizedTypes() internal override VariableSlotAllocator? TryCreateVariableSlotAllocator(MethodSymbol method, MethodSymbol topLevelMethod, DiagnosticBag diagnostics) { - return _previousDefinitions.TryCreateVariableSlotAllocator(Compilation, method, topLevelMethod, diagnostics); + return _changes.DefinitionMap.TryCreateVariableSlotAllocator(Compilation, method, topLevelMethod, diagnostics); } internal override MethodInstrumentation GetMethodBodyInstrumentations(MethodSymbol method) @@ -269,7 +251,7 @@ internal override MethodInstrumentation GetMethodBodyInstrumentations(MethodSymb // EmitDifference does not allow setting instrumentation kinds on EmitOptions: Debug.Assert(EmitOptions.InstrumentationKinds.IsEmpty); - return _previousDefinitions.GetMethodBodyInstrumentations(method); + return _changes.DefinitionMap.GetMethodBodyInstrumentations(method); } internal override ImmutableArray GetPreviousAnonymousTypes() @@ -291,7 +273,7 @@ internal override int GetNextAnonymousDelegateIndex() internal override bool TryGetPreviousAnonymousTypeValue(AnonymousTypeManager.AnonymousTypeOrDelegateTemplateSymbol template, out AnonymousTypeValue typeValue) { Debug.Assert(Compilation == template.DeclaringCompilation); - return _previousDefinitions.TryGetAnonymousTypeValue(template, out typeValue); + return PreviousDefinitions.TryGetAnonymousTypeValue(template, out typeValue); } public void OnCreatedIndices(DiagnosticBag diagnostics) @@ -305,5 +287,52 @@ public void OnCreatedIndices(DiagnosticBag diagnostics) } } } + + public override INamedTypeSymbolInternal? TryGetOrCreateSynthesizedHotReloadExceptionType() + => _predefinedHotReloadExceptionConstructor is null + ? GetOrCreateSynthesizedHotReloadExceptionType() + : null; + + public override IMethodSymbolInternal GetOrCreateHotReloadExceptionConstructorDefinition() + { + if (_predefinedHotReloadExceptionConstructor is not null) + { + return _predefinedHotReloadExceptionConstructor; + } + + if (_freezeHotReloadExceptionTypeUsage) + { + // the type shouldn't be used after usage has been frozen. + throw ExceptionUtilities.Unreachable(); + } + + _isHotReloadExceptionTypeUsed = true; + return GetOrCreateSynthesizedHotReloadExceptionType().Constructor; + } + + public override INamedTypeSymbolInternal? GetUsedSynthesizedHotReloadExceptionType() + { + _freezeHotReloadExceptionTypeUsage = true; + return _isHotReloadExceptionTypeUsed ? _lazyHotReloadExceptionType : null; + } + + private SynthesizedHotReloadExceptionSymbol GetOrCreateSynthesizedHotReloadExceptionType() + { + var symbol = _lazyHotReloadExceptionType; + if (symbol is not null) + { + return symbol; + } + + var exceptionType = Compilation.GetWellKnownType(WellKnownType.System_Exception); + var stringType = Compilation.GetSpecialType(SpecialType.System_String); + var intType = Compilation.GetSpecialType(SpecialType.System_Int32); + + var containingNamespace = GetOrSynthesizeNamespace(SynthesizedHotReloadExceptionSymbol.NamespaceName); + symbol = new SynthesizedHotReloadExceptionSymbol(containingNamespace, exceptionType, stringType, intType); + + Interlocked.CompareExchange(ref _lazyHotReloadExceptionType, symbol, comparand: null); + return _lazyHotReloadExceptionType; + } } } diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs index 9398dac28e1e9..349edede8b243 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs @@ -658,12 +658,24 @@ internal virtual bool IsMetadataFinal /// signature). /// WARN WARN WARN: We won't have a final value for this until declaration /// diagnostics have been computed for all s, so pass - /// ignoringInterfaceImplementationChanges: true if you need a value sooner + /// option: if you need a value sooner /// and aren't concerned about tweaks made to satisfy interface implementation /// requirements. /// NOTE: Not ignoring changes can only result in a value that is more true. + /// + /// Use IsMetadataVirtualOption.ForceCompleteIfNeeded in DEBUG/assertion code + /// to get the final value. /// - internal abstract bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false); + internal abstract bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None); + + internal enum IsMetadataVirtualOption + { + None = 0, + IgnoreInterfaceImplementationChanges, +#if DEBUG + ForceCompleteIfNeeded +#endif + } internal virtual bool ReturnValueIsMarshalledExplicitly { diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs index 1579988e11ddf..19a7bb6dc27da 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/NamedTypeSymbolAdapter.cs @@ -382,9 +382,18 @@ Cci.ITypeReference Cci.ITypeDefinition.GetBaseClass(EmitContext context) if (AdaptedNamedTypeSymbol is SourceMemberContainerTypeSymbol container) { + var interfaces = container.GetInterfacesToEmit(); + foreach ((MethodSymbol body, MethodSymbol implemented) in container.GetSynthesizedExplicitImplementations(cancellationToken: default).MethodImpls) { Debug.Assert(body.ContainingType == (object)container); + + // Avoid emitting duplicate methodimpl entries (e.g., when the class implements the same interface twice with different nullability). + if (!interfaces.Contains(implemented.ContainingType, SymbolEqualityComparer.ConsiderEverything)) + { + continue; + } + yield return new Microsoft.Cci.MethodImplementation(body.GetCciAdapter(), moduleBeingBuilt.TranslateOverriddenMethodReference(implemented, (CSharpSyntaxNode)context.SyntaxNode, context.Diagnostics)); } } diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs index 0d7aa385dafc0..b3a8ca9e082d4 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs @@ -63,7 +63,7 @@ internal abstract class PEAssemblyBuilderBase : PEModuleBuilder, Cci.IAssemblyRe /// In cases 1 and 2b, we expect (metadataName == sourceAssembly.MetadataName). /// private readonly string _metadataName; - +#nullable enable public PEAssemblyBuilderBase( SourceAssemblySymbol sourceAssembly, EmitOptions emitOptions, @@ -81,7 +81,7 @@ public PEAssemblyBuilderBase( AssemblyOrModuleSymbolToModuleRefMap.Add(sourceAssembly, this); } - +#nullable disable public sealed override ISourceAssemblySymbolInternal SourceAssemblyOpt => _sourceAssembly; @@ -586,7 +586,7 @@ private void AddDiagnosticsForExistingAttribute(AttributeDescription description #nullable disable - private NamespaceSymbol GetOrSynthesizeNamespace(string namespaceFullName) + protected NamespaceSymbol GetOrSynthesizeNamespace(string namespaceFullName) { var result = SourceModule.GlobalNamespace; @@ -628,19 +628,24 @@ private void EnsureAttributeUsageAttributeMembersAvailable(BindingDiagnosticBag } } #nullable enable - internal sealed class PEAssemblyBuilder : PEAssemblyBuilderBase + internal sealed class PEAssemblyBuilder( + SourceAssemblySymbol sourceAssembly, + EmitOptions emitOptions, + OutputKind outputKind, + Cci.ModulePropertiesForSerialization serializationProperties, + IEnumerable manifestResources) + : PEAssemblyBuilderBase(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, additionalTypes: []) { - public PEAssemblyBuilder( - SourceAssemblySymbol sourceAssembly, - EmitOptions emitOptions, - OutputKind outputKind, - Cci.ModulePropertiesForSerialization serializationProperties, - IEnumerable manifestResources) - : base(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, ImmutableArray.Empty) - { - } - public override EmitBaseline? PreviousGeneration => null; public override SymbolChanges? EncSymbolChanges => null; + + public override INamedTypeSymbolInternal? TryGetOrCreateSynthesizedHotReloadExceptionType() + => null; + + public override IMethodSymbolInternal GetOrCreateHotReloadExceptionConstructorDefinition() + => throw ExceptionUtilities.Unreachable(); + + public override INamedTypeSymbolInternal? GetUsedSynthesizedHotReloadExceptionType() + => null; } } diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PENetModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PENetModuleBuilder.cs index 85b4e6fd9eea5..44acf7e6ee24a 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PENetModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PENetModuleBuilder.cs @@ -35,9 +35,19 @@ protected override void AddEmbeddedResourcesFromAddedModules(ArrayBuilder null; public override SymbolChanges? EncSymbolChanges => null; + public override INamedTypeSymbolInternal? TryGetOrCreateSynthesizedHotReloadExceptionType() + => null; + + public override IMethodSymbolInternal GetOrCreateHotReloadExceptionConstructorDefinition() + => throw ExceptionUtilities.Unreachable(); + + public override INamedTypeSymbolInternal? GetUsedSynthesizedHotReloadExceptionType() + => null; + public override IEnumerable GetFiles(EmitContext context) => SpecializedCollections.EmptyEnumerable(); public override ISourceAssemblySymbolInternal? SourceAssemblyOpt => null; } diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 350d7a829cf11..7c07bb82d271e 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1185,7 +1185,7 @@ internal enum ErrorCode // ERR_NameIllegallyOverrides3 = 7040, // Not used anymore due to 'Single Meaning' relaxation changes ERR_ResourceFileNameNotUnique = 7041, ERR_DllImportOnGenericMethod = 7042, - ERR_EncUpdateFailedMissingAttribute = 7043, + ERR_EncUpdateFailedMissingSymbol = 7043, ERR_ParameterNotValidForType = 7045, ERR_AttributeParameterRequired1 = 7046, @@ -1529,7 +1529,7 @@ internal enum ErrorCode ERR_AutoPropsInRoStruct = 8341, ERR_FieldlikeEventsInRoStruct = 8342, // ERR_RefStructInterfaceImpl = 8343, - ERR_BadSpecialByRefIterator = 8344, + // ERR_BadSpecialByRefIterator = 8344, ERR_FieldAutoPropCantBeByRefLike = 8345, ERR_StackAllocConversionNotPossible = 8346, @@ -2292,7 +2292,7 @@ internal enum ErrorCode // available 9219, // available 9220, // available 9221, - // available 9222, + ERR_CollectionInitializerInfiniteChainOfAddCalls = 9222, ERR_ParamsCollectionInfiniteChainOfConstructorCalls = 9223, ERR_ParamsMemberCannotBeLessVisibleThanDeclaringMember = 9224, ERR_ParamsCollectionConstructorDoesntInitializeRequiredMember = 9225, @@ -2336,13 +2336,16 @@ internal enum ErrorCode WRN_PartialPropertySignatureDifference = 9256, ERR_PartialPropertyRequiredDifference = 9257, - INF_IdentifierConflictWithContextualKeyword = 9258, + WRN_FieldIsAmbiguous = 9258, ERR_InlineArrayAttributeOnRecord = 9259, ERR_FeatureNotAvailableInVersion13 = 9260, ERR_CannotApplyOverloadResolutionPriorityToOverride = 9261, ERR_CannotApplyOverloadResolutionPriorityToMember = 9262, + ERR_PartialPropertyDuplicateInitializer = 9263, + + WRN_UninitializedNonNullableBackingField = 9264, // Note: you will need to do the following after adding errors: // 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 619d08c98c3e8..4c8a7e03fa39c 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Globalization; using System.Reflection; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { @@ -82,6 +83,8 @@ static ErrorFacts() nullableWarnings.Add(GetId(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnInterceptor)); nullableWarnings.Add(GetId(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnInterceptor)); + nullableWarnings.Add(GetId(ErrorCode.WRN_UninitializedNonNullableBackingField)); + NullableWarnings = nullableWarnings.ToImmutable(); } @@ -132,7 +135,7 @@ internal static DiagnosticSeverity GetSeverity(ErrorCode code) public static string GetMessage(MessageID code, CultureInfo culture) { string message = ResourceManager.GetString(code.ToString(), culture); - Debug.Assert(!string.IsNullOrEmpty(message), code.ToString()); + RoslynDebug.Assert(!string.IsNullOrEmpty(message), $"{code}"); return message; } @@ -140,7 +143,7 @@ public static string GetMessage(MessageID code, CultureInfo culture) public static string GetMessage(ErrorCode code, CultureInfo culture) { string message = ResourceManager.GetString(code.ToString(), culture); - Debug.Assert(!string.IsNullOrEmpty(message), code.ToString()); + RoslynDebug.Assert(!string.IsNullOrEmpty(message), $"{code}"); return message; } @@ -555,7 +558,8 @@ internal static int GetWarningLevel(ErrorCode code) case ErrorCode.WRN_CollectionExpressionRefStructSpreadMayAllocate: case ErrorCode.WRN_ConvertingLock: case ErrorCode.WRN_PartialPropertySignatureDifference: - + case ErrorCode.WRN_FieldIsAmbiguous: + case ErrorCode.WRN_UninitializedNonNullableBackingField: return 1; default: return 0; @@ -1590,7 +1594,7 @@ or ErrorCode.WRN_InvalidVersionFormat or ErrorCode.ERR_NoCorrespondingArgument or ErrorCode.ERR_ResourceFileNameNotUnique or ErrorCode.ERR_DllImportOnGenericMethod - or ErrorCode.ERR_EncUpdateFailedMissingAttribute + or ErrorCode.ERR_EncUpdateFailedMissingSymbol or ErrorCode.ERR_ParameterNotValidForType or ErrorCode.ERR_AttributeParameterRequired1 or ErrorCode.ERR_AttributeParameterRequired2 @@ -1837,7 +1841,6 @@ or ErrorCode.ERR_InExtensionMustBeValueType or ErrorCode.ERR_FieldsInRoStruct or ErrorCode.ERR_AutoPropsInRoStruct or ErrorCode.ERR_FieldlikeEventsInRoStruct - or ErrorCode.ERR_BadSpecialByRefIterator or ErrorCode.ERR_FieldAutoPropCantBeByRefLike or ErrorCode.ERR_StackAllocConversionNotPossible or ErrorCode.ERR_EscapeCall @@ -2415,6 +2418,7 @@ or ErrorCode.ERR_CollectionExpressionMissingConstructor or ErrorCode.ERR_CollectionExpressionMissingAdd or ErrorCode.WRN_ConvertingLock or ErrorCode.ERR_DynamicDispatchToParamsCollection + or ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls or ErrorCode.ERR_ParamsCollectionInfiniteChainOfConstructorCalls or ErrorCode.ERR_ParamsMemberCannotBeLessVisibleThanDeclaringMember or ErrorCode.ERR_ParamsCollectionConstructorDoesntInitializeRequiredMember @@ -2449,11 +2453,13 @@ or ErrorCode.ERR_PartialPropertyInitMismatch or ErrorCode.ERR_PartialPropertyTypeDifference or ErrorCode.WRN_PartialPropertySignatureDifference or ErrorCode.ERR_PartialPropertyRequiredDifference - or ErrorCode.INF_IdentifierConflictWithContextualKeyword + or ErrorCode.WRN_FieldIsAmbiguous or ErrorCode.ERR_InlineArrayAttributeOnRecord or ErrorCode.ERR_FeatureNotAvailableInVersion13 or ErrorCode.ERR_CannotApplyOverloadResolutionPriorityToOverride or ErrorCode.ERR_CannotApplyOverloadResolutionPriorityToMember + or ErrorCode.ERR_PartialPropertyDuplicateInitializer + or ErrorCode.WRN_UninitializedNonNullableBackingField => false, }; #pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 36ca89853aebf..ddf0e8d382d5b 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -288,7 +288,7 @@ internal enum MessageID IDS_FeatureRefStructInterfaces = MessageBase + 12844, IDS_FeaturePartialProperties = MessageBase + 12845, - IDS_FeatureFieldAndValueKeywords = MessageBase + 12846, + IDS_FeatureFieldKeyword = MessageBase + 12846, IDS_FeatureAllowsRefStructConstraint = MessageBase + 12847, IDS_OverloadResolutionPriority = MessageBase + 12848, @@ -474,8 +474,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) // PREFER reporting diagnostics in binding when diagnostics do not affect the shape of the syntax tree // C# preview features. - case MessageID.IDS_FeatureRefStructInterfaces: - case MessageID.IDS_FeatureFieldAndValueKeywords: + case MessageID.IDS_FeatureFieldKeyword: case MessageID.IDS_FeatureFirstClassSpan: return LanguageVersion.Preview; @@ -485,6 +484,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureLockObject: case MessageID.IDS_FeatureParamsCollections: case MessageID.IDS_FeatureRefUnsafeInIteratorAsync: + case MessageID.IDS_FeatureRefStructInterfaces: case MessageID.IDS_FeatureAllowsRefStructConstraint: case MessageID.IDS_FeaturePartialProperties: case MessageID.IDS_OverloadResolutionPriority: diff --git a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs index 9f8c85d0755c8..cdd1ca8b7f5f2 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs @@ -247,7 +247,7 @@ public override void ReportDuplicateMetadataReferenceWeak(DiagnosticBag diagnost public override int ERR_TooManyUserStrings => (int)ErrorCode.ERR_TooManyUserStrings; public override int ERR_PeWritingFailure => (int)ErrorCode.ERR_PeWritingFailure; public override int ERR_ModuleEmitFailure => (int)ErrorCode.ERR_ModuleEmitFailure; - public override int ERR_EncUpdateFailedMissingAttribute => (int)ErrorCode.ERR_EncUpdateFailedMissingAttribute; + public override int ERR_EncUpdateFailedMissingSymbol => (int)ErrorCode.ERR_EncUpdateFailedMissingSymbol; public override int ERR_InvalidDebugInfo => (int)ErrorCode.ERR_InvalidDebugInfo; public override int ERR_FunctionPointerTypesInAttributeNotSupported => (int)ErrorCode.ERR_FunctionPointerTypesInAttributeNotSupported; diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs index 9d4bef8a46fe0..cdb93dcbf2bf5 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs @@ -361,19 +361,18 @@ protected BoundNode VisitAlways(BoundNode node) [DebuggerStepThrough] private BoundNode VisitWithStackGuard(BoundNode node) { - var expression = node as BoundExpression; - if (expression != null) + if (node is BoundExpression or BoundPattern) { - return VisitExpressionWithStackGuard(ref _recursionDepth, expression); + return VisitExpressionOrPatternWithStackGuard(ref _recursionDepth, node); } return base.Visit(node); } [DebuggerStepThrough] - protected override BoundExpression VisitExpressionWithoutStackGuard(BoundExpression node) + protected override BoundNode VisitExpressionOrPatternWithoutStackGuard(BoundNode node) { - return (BoundExpression)base.Visit(node); + return base.Visit(node); } protected override bool ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException() @@ -895,7 +894,7 @@ protected void RestorePending(SavedPending oldPending) /// public override BoundNode DefaultVisit(BoundNode node) { - Debug.Assert(false, $"Should Visit{node.Kind} be overridden in {this.GetType().Name}?"); + RoslynDebug.Assert(false, $"Should Visit{node.Kind} be overridden in {this.GetType().Name}?"); Diagnostics.Add(ErrorCode.ERR_InternalError, node.Syntax.Location); return null; } @@ -996,17 +995,27 @@ static bool patternMatchesNull(BoundPattern pattern) case BoundNegatedPattern negated: return !patternMatchesNull(negated.Negated); case BoundBinaryPattern binary: - if (binary.Disjunction) + var binaryPatterns = getBinaryPatterns(binary); + Debug.Assert(binaryPatterns.Peek().Left is not BoundBinaryPattern); + bool currentPatternMatchesNull = patternMatchesNull(binaryPatterns.Peek().Left); + + while (binaryPatterns.TryPop(out var currentBinary)) { - // `a?.b(out x) is null or C` - // pattern matches null if either subpattern matches null - var leftNullTest = patternMatchesNull(binary.Left); - return patternMatchesNull(binary.Left) || patternMatchesNull(binary.Right); + if (currentBinary.Disjunction) + { + // `a?.b(out x) is null or C` + // pattern matches null if either subpattern matches null + currentPatternMatchesNull = currentPatternMatchesNull || patternMatchesNull(currentBinary.Right); + continue; + } + + // `a?.b out x is not null and var c` + // pattern matches null only if both subpatterns match null + currentPatternMatchesNull = currentPatternMatchesNull && patternMatchesNull(currentBinary.Right); } - // `a?.b out x is not null and var c` - // pattern matches null only if both subpatterns match null - return patternMatchesNull(binary.Left) && patternMatchesNull(binary.Right); + binaryPatterns.Free(); + return currentPatternMatchesNull; case BoundDeclarationPattern { IsVar: true }: case BoundDiscardPattern: return true; @@ -1027,21 +1036,32 @@ static bool patternMatchesNull(BoundPattern pattern) case BoundNegatedPattern negated: return !isBoolTest(negated.Negated); case BoundBinaryPattern binary: - if (binary.Disjunction) + var binaryPatterns = getBinaryPatterns(binary); + Debug.Assert(binaryPatterns.Peek().Left is not BoundBinaryPattern); + bool? currentBoolTest = isBoolTest(binaryPatterns.Peek().Left); + + while (binaryPatterns.TryPop(out var currentBinary)) { - // `(a != null && a.b(out x)) is true or true` matches `true` - // `(a != null && a.b(out x)) is true or false` matches any boolean - // both subpatterns must have the same bool test for the test to propagate out - var leftNullTest = isBoolTest(binary.Left); - return leftNullTest is null ? null : - leftNullTest != isBoolTest(binary.Right) ? null : - leftNullTest; + if (currentBinary.Disjunction) + { + // `(a != null && a.b(out x)) is true or true` matches `true` + // `(a != null && a.b(out x)) is true or false` matches any boolean + // both subpatterns must have the same bool test for the test to propagate out + var leftNullTest = currentBoolTest; + currentBoolTest = leftNullTest is null ? null : + leftNullTest != isBoolTest(currentBinary.Right) ? null : + leftNullTest; + continue; + } + + // `(a != null && a.b(out x)) is true and true` matches `true` + // `(a != null && a.b(out x)) is true and var x` matches `true` + // `(a != null && a.b(out x)) is true and false` never matches and is a compile error + currentBoolTest ??= isBoolTest(currentBinary.Right); } - // `(a != null && a.b(out x)) is true and true` matches `true` - // `(a != null && a.b(out x)) is true and var x` matches `true` - // `(a != null && a.b(out x)) is true and false` never matches and is a compile error - return isBoolTest(binary.Left) ?? isBoolTest(binary.Right); + binaryPatterns.Free(); + return currentBoolTest; case BoundConstantPattern { ConstantValue: { IsBoolean: false } }: case BoundDiscardPattern: case BoundTypePattern: @@ -1056,6 +1076,28 @@ static bool patternMatchesNull(BoundPattern pattern) throw ExceptionUtilities.UnexpectedValue(pattern.Kind); } } + + static ArrayBuilder getBinaryPatterns(BoundBinaryPattern binaryPattern) + { + // Users (such as ourselves) can have many, many nested binary patterns. To avoid crashing, do left recursion manually. + + var stack = ArrayBuilder.GetInstance(); + + while (true) + { + stack.Push(binaryPattern); + if (binaryPattern.Left is BoundBinaryPattern leftBinaryPattern) + { + binaryPattern = leftBinaryPattern; + } + else + { + break; + } + } + + return stack; + } } public virtual void VisitPattern(BoundPattern pattern) @@ -1069,6 +1111,12 @@ public override BoundNode VisitConstantPattern(BoundConstantPattern node) throw ExceptionUtilities.Unreachable(); } + public override BoundNode VisitBinaryPattern(BoundBinaryPattern node) + { + // All patterns are handled by VisitPattern + throw ExceptionUtilities.Unreachable(); + } + public override BoundNode VisitTupleLiteral(BoundTupleLiteral node) { return VisitTupleExpression(node); @@ -1704,22 +1752,54 @@ protected virtual void AfterVisitConversion(BoundConversion node) { } - public override BoundNode VisitIfStatement(BoundIfStatement node) + public sealed override BoundNode VisitIfStatement(BoundIfStatement node) { // 5.3.3.5 If statements - VisitCondition(node.Condition); - TLocalState trueState = StateWhenTrue; - TLocalState falseState = StateWhenFalse; - SetState(trueState); - VisitStatement(node.Consequence); - trueState = this.State; - SetState(falseState); - if (node.AlternativeOpt != null) + + var stack = ArrayBuilder<(TLocalState, BoundIfStatement)>.GetInstance(); + + TLocalState trueState; + while (true) + { + VisitCondition(node.Condition); + trueState = StateWhenTrue; + TLocalState falseState = StateWhenFalse; + SetState(trueState); + VisitStatement(node.Consequence); + trueState = this.State; + SetState(falseState); + + var alternative = node.AlternativeOpt; + if (alternative is null) + { + break; + } + + if (alternative is BoundIfStatement elseIfStatement) + { + node = elseIfStatement; + stack.Push((trueState, node)); + EnterRegionIfNeeded(node); + } + else + { + VisitStatement(alternative); + break; + } + } + + while (true) { - VisitStatement(node.AlternativeOpt); + Join(ref this.State, ref trueState); + if (!stack.Any()) + { + break; + } + (trueState, node) = stack.Pop(); + LeaveRegionIfNeeded(node); } - Join(ref this.State, ref trueState); + stack.Free(); return null; } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs index 67cae8265b05e..e009b16967e55 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DefiniteAssignment.cs @@ -2064,9 +2064,34 @@ void assignPatternVariablesAndMarkReadFields(BoundPattern pattern, bool definite case BoundKind.BinaryPattern: { var pat = (BoundBinaryPattern)pattern; - bool def = definitely && !pat.Disjunction; - assignPatternVariablesAndMarkReadFields(pat.Left, def); - assignPatternVariablesAndMarkReadFields(pat.Right, def); + + if (pat.Left is not BoundBinaryPattern) + { + bool def = definitely && !pat.Disjunction; + assignPatternVariablesAndMarkReadFields(pat.Left, def); + assignPatternVariablesAndMarkReadFields(pat.Right, def); + break; + } + + // Users (such as ourselves) can have many, many nested binary patterns. To avoid crashing, do left recursion manually. + var stack = ArrayBuilder<(BoundBinaryPattern pattern, bool def)>.GetInstance(); + + do + { + definitely = definitely && !pat.Disjunction; + stack.Push((pat, definitely)); + pat = pat.Left as BoundBinaryPattern; + } while (pat is not null); + + var patAndDef = stack.Pop(); + assignPatternVariablesAndMarkReadFields(patAndDef.pattern.Left, patAndDef.def); + + do + { + assignPatternVariablesAndMarkReadFields(patAndDef.pattern.Right, patAndDef.def); + } while (stack.TryPop(out patAndDef)); + + stack.Free(); break; } default: diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs index 9fad0aeeb0729..e6293be257814 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { @@ -46,7 +47,7 @@ public static void Verify(ImmutableDictionary _incrementalSnapshots[position].snapshot.SharedStateIndex, $"Did not find shared state for {node} `{node.Syntax}`."); + RoslynDebug.Assert(_walkerSharedStates.Length > _incrementalSnapshots[position].snapshot.SharedStateIndex, $"Did not find shared state for {node} `{node.Syntax}`."); } internal void VerifyUpdatedSymbols() @@ -123,10 +123,10 @@ internal void VerifyUpdatedSymbols() foreach (var ((expr, originalSymbol), updatedSymbol) in _updatedSymbolsMap) { var debugText = expr?.Syntax.ToFullString() ?? originalSymbol.ToDisplayString(); - Debug.Assert((object)originalSymbol != updatedSymbol, $"Recorded exact same symbol for {debugText}"); + RoslynDebug.Assert((object)originalSymbol != updatedSymbol, $"Recorded exact same symbol for {debugText}"); RoslynDebug.Assert(originalSymbol is object, $"Recorded null original symbol for {debugText}"); RoslynDebug.Assert(updatedSymbol is object, $"Recorded null updated symbol for {debugText}"); - Debug.Assert(AreCloseEnough(originalSymbol, updatedSymbol), @$"Symbol for `{debugText}` changed: + RoslynDebug.Assert(AreCloseEnough(originalSymbol, updatedSymbol), @$"Symbol for `{debugText}` changed: Was {originalSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} Now {updatedSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}"); } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.Variables.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.Variables.cs index dd3ed1448840d..ec5c3e7789b24 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.Variables.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.Variables.cs @@ -396,8 +396,6 @@ internal Variables GetRootScope() internal Variables? GetVariablesForMethodScope(MethodSymbol method) { - // https://github.com/dotnet/roslyn/issues/73772: is this needed if we also delete the weird cascading in EnterParameters? - method = method.PartialImplementationPart ?? method; var variables = this; while (true) { diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index bf53d801a0d24..c66172792bf96 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -639,8 +639,7 @@ void enforceMemberNotNull(SyntaxNode? syntaxOpt, LocalState state) Debug.Assert(thisParameter is object); thisSlot = GetOrCreateSlot(thisParameter); } - // https://github.com/dotnet/roslyn/issues/46718: give diagnostics on return points, not constructor signature - var exitLocation = method.DeclaringSyntaxReferences.IsEmpty ? null : method.TryGetFirstLocation(); + var exitLocation = method is SynthesizedPrimaryConstructor || method.DeclaringSyntaxReferences.IsEmpty ? null : method.TryGetFirstLocation(); bool constructorEnforcesRequiredMembers = method.ShouldCheckRequiredMembers(); // Required properties can be attributed MemberNotNull, indicating that if the property is set, the field will be set as well. @@ -759,7 +758,10 @@ void checkMemberStateOnConstructorExit(MethodSymbol constructor, Symbol member, return; } - var annotations = symbol.GetFlowAnalysisAnnotations(); + // If 'field' keyword is explicitly used by 'symbol', then use FlowAnalysisAnnotations from the backing field. + // Otherwise, use the FlowAnalysisAnnotations from the user-declared symbol (property or ordinary field). + var usesFieldKeyword = symbol is SourcePropertySymbolBase { UsesFieldKeyword: true }; + var annotations = usesFieldKeyword ? field!.FlowAnalysisAnnotations : symbol.GetFlowAnalysisAnnotations(); if ((annotations & FlowAnalysisAnnotations.AllowNull) != 0) { // We assume that if a member has AllowNull then the user @@ -783,7 +785,8 @@ void checkMemberStateOnConstructorExit(MethodSymbol constructor, Symbol member, : NullableFlowState.MaybeNull; if (memberState >= badState) // is 'memberState' as bad as or worse than 'badState'? { - var info = new CSDiagnosticInfo(ErrorCode.WRN_UninitializedNonNullableField, new object[] { symbol.Kind.Localize(), symbol.Name }, ImmutableArray.Empty, additionalLocations: symbol.Locations); + var errorCode = usesFieldKeyword ? ErrorCode.WRN_UninitializedNonNullableBackingField : ErrorCode.WRN_UninitializedNonNullableField; + var info = new CSDiagnosticInfo(errorCode, new object[] { symbol.Kind.Localize(), symbol.Name }, ImmutableArray.Empty, additionalLocations: symbol.Locations); Diagnostics.Add(info, exitLocation ?? symbol.GetFirstLocationOrNone()); } } @@ -921,7 +924,7 @@ void makeNotNullMembersMaybeNull() continue; case FieldSymbol { IsConst: true }: continue; - case FieldSymbol { AssociatedSymbol: PropertySymbol prop }: + case FieldSymbol { AssociatedSymbol: SourcePropertySymbolBase { UsesFieldKeyword: false } prop }: // this is a property where assigning 'default' causes us to simply update // the state to the output state of the property // thus we skip setting an initial state for it here @@ -1075,7 +1078,7 @@ static IEnumerable getAllMembersToBeDefaulted(Symbol requiredMember) } static Symbol getFieldSymbolToBeInitialized(Symbol requiredMember) - => requiredMember is SourcePropertySymbol { IsAutoPropertyWithGetAccessor: true } prop ? prop.BackingField : requiredMember; + => requiredMember is SourcePropertySymbol { IsAutoProperty: true } prop ? prop.BackingField : requiredMember; } } } @@ -1836,7 +1839,7 @@ private void SetUpdatedSymbol(BoundNode node, Symbol originalSymbol, Symbol upda #if DEBUG Debug.Assert(node is object); - Debug.Assert(AreCloseEnough(originalSymbol, updatedSymbol), $"Attempting to set {node.Syntax} from {originalSymbol.ToDisplayString()} to {updatedSymbol.ToDisplayString()}"); + RoslynDebug.Assert(AreCloseEnough(originalSymbol, updatedSymbol), $"Attempting to set {node.Syntax} from {originalSymbol.ToDisplayString()} to {updatedSymbol.ToDisplayString()}"); #endif if (lambdaIsExactMatch || Symbol.Equals(originalSymbol, updatedSymbol, TypeCompareKind.ConsiderEverything)) @@ -2131,6 +2134,30 @@ protected override int GetOrCreateSlot(Symbol symbol, int containingSlot = 0, bo } } + // Share a slot between backing field and associated property/event in the context of a constructor which owns initialization of that backing field. + if (this._symbol is MethodSymbol constructor + && constructor.IsConstructor() + && constructor.IsStatic == symbol.IsStatic) + { + if ((constructor.IsStatic && containingSlot == 0 && constructor.ContainingType.Equals(symbol.ContainingType)) + || (!constructor.IsStatic && containingSlot > 0 && _variables[containingSlot].Symbol is ThisParameterSymbol)) + { + // If symbol is a backing field, but property does not use the field keyword, + // then use the property to determine initial state and to own the slot. + // Example scenarios: + // - property initializer on normal auto-property + // - property assignment on getter-only auto-property. + // Example test: NullableReferenceTypesTests.ConstructorUsesStateFromInitializers will fail without this. + if (symbol is SynthesizedBackingFieldSymbol { AssociatedSymbol: SourcePropertySymbolBase { UsesFieldKeyword: false } property }) + symbol = property; + // If symbol is a property that uses field keyword, then use field to determine initial state and to own the slot. + else if (symbol is SourcePropertySymbolBase { UsesFieldKeyword: true, BackingField: { } backingField }) + symbol = backingField; + else if (symbol is SourceEventFieldSymbol eventField) + symbol = eventField.AssociatedSymbol; + } + } + return base.GetOrCreateSlot(symbol, containingSlot, forceSlotEvenIfEmpty, createIfMissing); } @@ -2763,10 +2790,6 @@ private void EnterParameters() } } - // The partial definition part may include optional parameters whose default values we want to simulate assigning at the beginning of the method - // https://github.com/dotnet/roslyn/issues/73772: is this actually used/meaningful? - methodSymbol = methodSymbol.PartialDefinitionPart ?? methodSymbol; - var methodParameters = methodSymbol.Parameters; var signatureParameters = (_useDelegateInvokeParameterTypes ? _delegateInvokeMethod! : methodSymbol).Parameters; @@ -3457,12 +3480,17 @@ private void DeclareLocals(ImmutableArray locals) return null; } - protected override BoundExpression? VisitExpressionWithoutStackGuard(BoundExpression node) + protected override BoundNode? VisitExpressionOrPatternWithoutStackGuard(BoundNode node) { + Debug.Assert(node is BoundExpression or BoundPattern); Debug.Assert(!IsConditionalState); SetInvalidResult(); - _ = base.VisitExpressionWithoutStackGuard(node); - VisitExpressionWithoutStackGuardEpilogue(node); + _ = base.VisitExpressionOrPatternWithoutStackGuard(node); + if (node is BoundExpression expr) + { + VisitExpressionWithoutStackGuardEpilogue(expr); + } + return null; } @@ -3702,7 +3730,7 @@ TypeWithState convertCollection(BoundCollectionExpression node, TypeWithAnnotati // Record the final state NullableFlowState resultState = getResultState(node, collectionKind); - var resultTypeWithState = TypeWithState.Create(node.Type, resultState); + var resultTypeWithState = TypeWithState.Create(strippedTargetCollectionType, resultState); SetAnalyzedNullability(node, resultTypeWithState); return resultTypeWithState; } @@ -4570,7 +4598,7 @@ static TypeSymbol setSpanElementType(NamedTypeSymbol namedType, TypeWithAnnotati /// This is done using . All registered completions must be processed /// (ie. analyzed via some conversion) before the nullable analysis completes. /// - private static bool IsTargetTypedExpression(BoundExpression node) + internal static bool IsTargetTypedExpression(BoundExpression node) { return node is BoundConditionalOperator { WasTargetTyped: true } or BoundConvertedSwitchExpression { WasTargetTyped: true } or @@ -5772,6 +5800,11 @@ void makeAndAdjustReceiverSlot(BoundExpression receiver) if (isRef) { + Debug.Assert(node is not BoundConditionalOperator { WasTargetTyped: true }, """ + Unexpected ref target typed conditional operator. + Should not do type inference below in this case. + """); + TypeWithAnnotations consequenceLValue; TypeWithAnnotations alternativeLValue; @@ -5780,20 +5813,28 @@ void makeAndAdjustReceiverSlot(BoundExpression receiver) (alternativeLValue, alternativeRValue) = visitConditionalRefOperand(alternativeState, originalAlternative); Join(ref this.State, ref consequenceState); + var lValueAnnotation = consequenceLValue.NullableAnnotation.EnsureCompatible(alternativeLValue.NullableAnnotation); + var rValueState = consequenceRValue.State.Join(alternativeRValue.State); + TypeSymbol? refResultType = node.Type?.SetUnknownNullabilityForReferenceTypes(); if (IsNullabilityMismatch(consequenceLValue, alternativeLValue)) { - // l-value types must match - ReportNullabilityMismatchInAssignment(node.Syntax, consequenceLValue, alternativeLValue); + // If there is a mismatch between the operands, use type inference to determine the target type. + BoundExpression consequencePlaceholder = CreatePlaceholderIfNecessary(originalConsequence, consequenceLValue); + BoundExpression alternativePlaceholder = CreatePlaceholderIfNecessary(originalAlternative, alternativeLValue); + var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; + refResultType = BestTypeInferrer.InferBestTypeForConditionalOperator(consequencePlaceholder, alternativePlaceholder, _conversions, out _, ref discardedUseSiteInfo); + + // Report warning for each operand that is not convertible to the target type. + var refResultTypeWithAnnotations = TypeWithAnnotations.Create(refResultType, lValueAnnotation); + reportMismatchIfNecessary(originalConsequence, consequenceLValue, refResultTypeWithAnnotations); + reportMismatchIfNecessary(originalAlternative, alternativeLValue, refResultTypeWithAnnotations); } else if (!node.HasErrors) { refResultType = consequenceRValue.Type!.MergeEquivalentTypes(alternativeRValue.Type, VarianceKind.None); } - var lValueAnnotation = consequenceLValue.NullableAnnotation.EnsureCompatible(alternativeLValue.NullableAnnotation); - var rValueState = consequenceRValue.State.Join(alternativeRValue.State); - SetResult(node, TypeWithState.Create(refResultType, rValueState), TypeWithAnnotations.Create(refResultType, lValueAnnotation)); return null; } @@ -5817,6 +5858,14 @@ void makeAndAdjustReceiverSlot(BoundExpression receiver) { resultType = null; } + else if (IsTargetTypedExpression(consequence)) + { + resultType = alternativeRValue.Type; + } + else if (IsTargetTypedExpression(alternative)) + { + resultType = consequenceRValue.Type; + } else { // Determine nested nullability using BestTypeInferrer. @@ -5957,6 +6006,14 @@ void addConvertArmsAsCompletion( TypeWithAnnotations lValueType = VisitLvalueWithAnnotations(operand); return (lValueType, ResultType); } + + void reportMismatchIfNecessary(BoundExpression node, TypeWithAnnotations source, TypeWithAnnotations destination) + { + if (!node.IsSuppressed && IsNullabilityMismatch(source, destination)) + { + ReportNullabilityMismatchInAssignment(node.Syntax, source, destination); + } + } } private TypeWithState ConvertConditionalOperandOrSwitchExpressionArmResult( @@ -9317,14 +9374,17 @@ private void TrackAnalyzedNullabilityThroughConversionGroup(TypeWithState result while (conversionOpt != null && conversionOpt != convertedNode) { Debug.Assert(conversionOpt.ConversionGroupOpt == conversionGroup); - visitResult = withType(visitResult, conversionOpt.Type); + + // https://github.com/dotnet/roslyn/issues/35046 + // SetAnalyzedNullability will drop the type if the visitResult.RValueType.Type differs from conversionOpt.Type. + // (It will use the top-level nullability from visitResult, though.) + // + // Here, the visitResult represents the result of visiting the operand. + // Ideally, we would use the visitResult to reinfer the types of the containing conversions, and store those results here. SetAnalyzedNullability(conversionOpt, visitResult); + conversionOpt = conversionOpt.Operand as BoundConversion; } - - static VisitResult withType(VisitResult visitResult, TypeSymbol newType) => - new VisitResult(TypeWithState.Create(newType, visitResult.RValueType.State), - TypeWithAnnotations.Create(newType, visitResult.LValueType.NullableAnnotation)); } /// @@ -9752,18 +9812,6 @@ private void VisitThisOrBaseReference(BoundExpression node) Debug.Assert(!IsConditionalState); var left = node.Left; - switch (left) - { - // when binding initializers, we treat assignments to auto-properties or field-like events as direct assignments to the underlying field. - // in order to track member state based on these initializers, we need to see the assignment in terms of the associated member - case BoundFieldAccess { ExpressionSymbol: FieldSymbol { AssociatedSymbol: PropertySymbol autoProperty } } fieldAccess: - left = new BoundPropertyAccess(fieldAccess.Syntax, fieldAccess.ReceiverOpt, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, autoProperty, LookupResultKind.Viable, autoProperty.Type, fieldAccess.HasErrors); - break; - case BoundFieldAccess { ExpressionSymbol: FieldSymbol { AssociatedSymbol: EventSymbol @event } } fieldAccess: - left = new BoundEventAccess(fieldAccess.Syntax, fieldAccess.ReceiverOpt, @event, isUsableAsField: true, LookupResultKind.Viable, @event.Type, fieldAccess.HasErrors); - break; - } - var right = node.Right; VisitLValue(left); // we may enter a conditional state for error scenarios on the LHS. @@ -9876,7 +9924,7 @@ private FlowAnalysisAnnotations GetLValueAnnotations(BoundExpression expr) private static FlowAnalysisAnnotations GetFieldAnnotations(FieldSymbol field) { - return field.AssociatedSymbol is PropertySymbol property ? + return field.AssociatedSymbol is SourcePropertySymbolBase { UsesFieldKeyword: false } property ? property.GetFlowAnalysisAnnotations() : field.FlowAnalysisAnnotations; } @@ -10902,7 +10950,8 @@ public override void VisitForEachIterationVariables(BoundForEachStatement node) if (iterationVariable.IsRef) { // foreach (ref DestinationType variable in collection) - if (IsNullabilityMismatch(sourceType, destinationType)) + if (node.Expression is not BoundConversion { Operand.IsSuppressed: true } && + IsNullabilityMismatch(sourceType, destinationType)) { var foreachSyntax = (ForEachStatementSyntax)node.Syntax; ReportNullabilityMismatchInAssignment(foreachSyntax.Type, sourceType, destinationType); @@ -11294,8 +11343,6 @@ private TypeWithState InferResultNullabilityOfBinaryLogicalOperator(BoundExpress } } - // https://github.com/dotnet/roslyn/issues/33344: this fails to produce an updated tuple type for a default expression - // (should produce nullable element types for those elements that are of reference types) SetResultType(node, TypeWithState.ForType(type)); return result; } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs index 6a807427474b0..316bedbc13338 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker_Patterns.cs @@ -111,8 +111,30 @@ public override BoundNode VisitNegatedPattern(BoundNegatedPattern node) public override BoundNode VisitBinaryPattern(BoundBinaryPattern node) { - Visit(node.Left); - Visit(node.Right); + // Users (such as ourselves) can have many, many nested binary patterns. To avoid crashing, do left recursion manually. + + var stack = ArrayBuilder.GetInstance(); + BoundBinaryPattern current = node; + do + { + stack.Push(current); + current = current.Left as BoundBinaryPattern; + } while (current != null); + + current = stack.Pop(); + // We don't need to snapshot on the way down because the left spine of the tree will always have the same span start, and each + // call to TakeIncrementalSnapshot would overwrite the previous one with the new state. This can be a _significant_ performance + // improvement for deeply nested binary patterns; over 10x faster in some pathological cases. + TakeIncrementalSnapshot(current); + Debug.Assert(current.Left is not BoundBinaryPattern); + Visit(current.Left); + + do + { + Visit(current.Right); + } while (stack.TryPop(out current)); + + stack.Free(); return null; } @@ -199,8 +221,24 @@ private void LearnFromAnyNullPatterns( LearnFromAnyNullPatterns(inputSlot, inputType, p.Negated); break; case BoundBinaryPattern p: - LearnFromAnyNullPatterns(inputSlot, inputType, p.Left); - LearnFromAnyNullPatterns(inputSlot, inputType, p.Right); + // Do not use left recursion because we can have many nested binary patterns. + var current = p; + while (true) + { + // We don't need to visit in order here because we're only moving analysis in one direction: + // towards MaybeNull. Visiting the right or left first has no impact on the final state. + LearnFromAnyNullPatterns(inputSlot, inputType, current.Right); + if (current.Left is BoundBinaryPattern left) + { + current = left; + VisitForRewriting(current); + } + else + { + LearnFromAnyNullPatterns(inputSlot, inputType, current.Left); + break; + } + } break; default: throw ExceptionUtilities.UnexpectedValue(pattern); @@ -898,8 +936,11 @@ private void VisitSwitchExpressionCore(BoundSwitchExpression node, bool inferTyp resultTypes.Add(armType); Join(ref endState, ref this.State); - // Build placeholders for inference in order to preserve annotations. - placeholderBuilder.Add(CreatePlaceholderIfNecessary(expression, armType.ToTypeWithAnnotations(compilation))); + if (!IsTargetTypedExpression(expression)) + { + // Build placeholders for inference in order to preserve annotations. + placeholderBuilder.Add(CreatePlaceholderIfNecessary(expression, armType.ToTypeWithAnnotations(compilation))); + } } SetState(endState); diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs index 472832769b0fc..3cbe110e05414 100644 --- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs @@ -69,6 +69,7 @@ internal enum BoundKind : byte UnconvertedConditionalOperator, ConditionalOperator, ArrayAccess, + RefArrayAccess, ArrayLength, AwaitableInfo, AwaitExpression, @@ -2075,6 +2076,35 @@ public BoundArrayAccess Update(BoundExpression expression, ImmutableArray base.Type; + public BoundArrayAccess ArrayAccess { get; } + + [DebuggerStepThrough] + public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitRefArrayAccess(this); + + public BoundRefArrayAccess Update(BoundArrayAccess arrayAccess) + { + if (arrayAccess != this.ArrayAccess) + { + var result = new BoundRefArrayAccess(this.Syntax, arrayAccess, this.HasErrors); + result.CopyAttributes(this); + return result; + } + return this; + } + } + internal sealed partial class BoundArrayLength : BoundExpression { public BoundArrayLength(SyntaxNode syntax, BoundExpression expression, TypeSymbol type, bool hasErrors = false) @@ -7304,7 +7334,7 @@ public BoundHoistedFieldAccess Update(FieldSymbol fieldSymbol, TypeSymbol type) internal sealed partial class BoundPropertyAccess : BoundExpression { - public BoundPropertyAccess(SyntaxNode syntax, BoundExpression? receiverOpt, ThreeState initialBindingReceiverIsSubjectToCloning, PropertySymbol propertySymbol, LookupResultKind resultKind, TypeSymbol type, bool hasErrors = false) + public BoundPropertyAccess(SyntaxNode syntax, BoundExpression? receiverOpt, ThreeState initialBindingReceiverIsSubjectToCloning, PropertySymbol propertySymbol, AccessorKind autoPropertyAccessorKind, LookupResultKind resultKind, TypeSymbol type, bool hasErrors = false) : base(BoundKind.PropertyAccess, syntax, type, hasErrors || receiverOpt.HasErrors()) { @@ -7314,6 +7344,7 @@ public BoundPropertyAccess(SyntaxNode syntax, BoundExpression? receiverOpt, Thre this.ReceiverOpt = receiverOpt; this.InitialBindingReceiverIsSubjectToCloning = initialBindingReceiverIsSubjectToCloning; this.PropertySymbol = propertySymbol; + this.AutoPropertyAccessorKind = autoPropertyAccessorKind; this.ResultKind = resultKind; } @@ -7321,16 +7352,17 @@ public BoundPropertyAccess(SyntaxNode syntax, BoundExpression? receiverOpt, Thre public BoundExpression? ReceiverOpt { get; } public ThreeState InitialBindingReceiverIsSubjectToCloning { get; } public PropertySymbol PropertySymbol { get; } + public AccessorKind AutoPropertyAccessorKind { get; } public override LookupResultKind ResultKind { get; } [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitPropertyAccess(this); - public BoundPropertyAccess Update(BoundExpression? receiverOpt, ThreeState initialBindingReceiverIsSubjectToCloning, PropertySymbol propertySymbol, LookupResultKind resultKind, TypeSymbol type) + public BoundPropertyAccess Update(BoundExpression? receiverOpt, ThreeState initialBindingReceiverIsSubjectToCloning, PropertySymbol propertySymbol, AccessorKind autoPropertyAccessorKind, LookupResultKind resultKind, TypeSymbol type) { - if (receiverOpt != this.ReceiverOpt || initialBindingReceiverIsSubjectToCloning != this.InitialBindingReceiverIsSubjectToCloning || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(propertySymbol, this.PropertySymbol) || resultKind != this.ResultKind || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) + if (receiverOpt != this.ReceiverOpt || initialBindingReceiverIsSubjectToCloning != this.InitialBindingReceiverIsSubjectToCloning || !Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(propertySymbol, this.PropertySymbol) || autoPropertyAccessorKind != this.AutoPropertyAccessorKind || resultKind != this.ResultKind || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything)) { - var result = new BoundPropertyAccess(this.Syntax, receiverOpt, initialBindingReceiverIsSubjectToCloning, propertySymbol, resultKind, type, this.HasErrors); + var result = new BoundPropertyAccess(this.Syntax, receiverOpt, initialBindingReceiverIsSubjectToCloning, propertySymbol, autoPropertyAccessorKind, resultKind, type, this.HasErrors); result.CopyAttributes(this); return result; } @@ -8895,6 +8927,8 @@ internal R VisitInternal(BoundNode node, A arg) return VisitConditionalOperator((BoundConditionalOperator)node, arg); case BoundKind.ArrayAccess: return VisitArrayAccess((BoundArrayAccess)node, arg); + case BoundKind.RefArrayAccess: + return VisitRefArrayAccess((BoundRefArrayAccess)node, arg); case BoundKind.ArrayLength: return VisitArrayLength((BoundArrayLength)node, arg); case BoundKind.AwaitableInfo: @@ -9316,6 +9350,7 @@ internal abstract partial class BoundTreeVisitor public virtual R VisitUnconvertedConditionalOperator(BoundUnconvertedConditionalOperator node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitConditionalOperator(BoundConditionalOperator node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitArrayAccess(BoundArrayAccess node, A arg) => this.DefaultVisit(node, arg); + public virtual R VisitRefArrayAccess(BoundRefArrayAccess node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitArrayLength(BoundArrayLength node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitAwaitableInfo(BoundAwaitableInfo node, A arg) => this.DefaultVisit(node, arg); public virtual R VisitAwaitExpression(BoundAwaitExpression node, A arg) => this.DefaultVisit(node, arg); @@ -9551,6 +9586,7 @@ internal abstract partial class BoundTreeVisitor public virtual BoundNode? VisitUnconvertedConditionalOperator(BoundUnconvertedConditionalOperator node) => this.DefaultVisit(node); public virtual BoundNode? VisitConditionalOperator(BoundConditionalOperator node) => this.DefaultVisit(node); public virtual BoundNode? VisitArrayAccess(BoundArrayAccess node) => this.DefaultVisit(node); + public virtual BoundNode? VisitRefArrayAccess(BoundRefArrayAccess node) => this.DefaultVisit(node); public virtual BoundNode? VisitArrayLength(BoundArrayLength node) => this.DefaultVisit(node); public virtual BoundNode? VisitAwaitableInfo(BoundAwaitableInfo node) => this.DefaultVisit(node); public virtual BoundNode? VisitAwaitExpression(BoundAwaitExpression node) => this.DefaultVisit(node); @@ -9935,6 +9971,11 @@ internal abstract partial class BoundTreeWalker : BoundTreeVisitor this.VisitList(node.Indices); return null; } + public override BoundNode? VisitRefArrayAccess(BoundRefArrayAccess node) + { + this.Visit(node.ArrayAccess); + return null; + } public override BoundNode? VisitArrayLength(BoundArrayLength node) { this.Visit(node.Expression); @@ -11059,6 +11100,12 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor TypeSymbol? type = this.VisitType(node.Type); return node.Update(expression, indices, type); } + public override BoundNode? VisitRefArrayAccess(BoundRefArrayAccess node) + { + BoundArrayAccess arrayAccess = (BoundArrayAccess)this.Visit(node.ArrayAccess); + TypeSymbol? type = this.VisitType(node.Type); + return node.Update(arrayAccess); + } public override BoundNode? VisitArrayLength(BoundArrayLength node) { BoundExpression expression = (BoundExpression)this.Visit(node.Expression); @@ -11893,7 +11940,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor { BoundExpression? receiverOpt = (BoundExpression?)this.Visit(node.ReceiverOpt); TypeSymbol? type = this.VisitType(node.Type); - return node.Update(receiverOpt, node.InitialBindingReceiverIsSubjectToCloning, node.PropertySymbol, node.ResultKind, type); + return node.Update(receiverOpt, node.InitialBindingReceiverIsSubjectToCloning, node.PropertySymbol, node.AutoPropertyAccessorKind, node.ResultKind, type); } public override BoundNode? VisitEventAccess(BoundEventAccess node) { @@ -12867,6 +12914,23 @@ public NullabilityRewriter(ImmutableDictionary new TreeDumperNode("refArrayAccess", null, new TreeDumperNode[] + { + new TreeDumperNode("arrayAccess", null, new TreeDumperNode[] { Visit(node.ArrayAccess, null) }), + new TreeDumperNode("type", node.Type, null), + new TreeDumperNode("isSuppressed", node.IsSuppressed, null), + new TreeDumperNode("hasErrors", node.HasErrors, null) + } + ); public override TreeDumperNode VisitArrayLength(BoundArrayLength node, object? arg) => new TreeDumperNode("arrayLength", null, new TreeDumperNode[] { new TreeDumperNode("expression", null, new TreeDumperNode[] { Visit(node.Expression, null) }), @@ -16652,6 +16724,7 @@ private BoundTreeDumperNodeProducer() new TreeDumperNode("receiverOpt", null, new TreeDumperNode[] { Visit(node.ReceiverOpt, null) }), new TreeDumperNode("initialBindingReceiverIsSubjectToCloning", node.InitialBindingReceiverIsSubjectToCloning, null), new TreeDumperNode("propertySymbol", node.PropertySymbol, null), + new TreeDumperNode("autoPropertyAccessorKind", node.AutoPropertyAccessorKind, null), new TreeDumperNode("resultKind", node.ResultKind, null), new TreeDumperNode("type", node.Type, null), new TreeDumperNode("isSuppressed", node.IsSuppressed, null), diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 index 602ad728c80df..6968dc30e0fb5 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 +++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 @@ -747,6 +747,7 @@ expression | default_expression | element_access_expression | element_binding_expression + | field_expression | implicit_array_creation_expression | implicit_element_access | implicit_stack_alloc_array_creation_expression @@ -891,6 +892,10 @@ element_binding_expression : bracketed_argument_list ; +field_expression + : 'field' + ; + implicit_array_creation_expression : 'new' '[' ','* ']' initializer_expression ; diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs index ed09f4ccd3931..78d8aedb8b8f2 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs @@ -3201,6 +3201,71 @@ internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) => new LiteralExpressionSyntax(this.Kind, this.token, GetDiagnostics(), annotations); } +/// Class which represents the syntax node for a field expression. +internal sealed partial class FieldExpressionSyntax : ExpressionSyntax +{ + internal readonly SyntaxToken token; + + internal FieldExpressionSyntax(SyntaxKind kind, SyntaxToken token, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) + : base(kind, diagnostics, annotations) + { + this.SlotCount = 1; + this.AdjustFlagsAndWidth(token); + this.token = token; + } + + internal FieldExpressionSyntax(SyntaxKind kind, SyntaxToken token, SyntaxFactoryContext context) + : base(kind) + { + this.SetFactoryContext(context); + this.SlotCount = 1; + this.AdjustFlagsAndWidth(token); + this.token = token; + } + + internal FieldExpressionSyntax(SyntaxKind kind, SyntaxToken token) + : base(kind) + { + this.SlotCount = 1; + this.AdjustFlagsAndWidth(token); + this.token = token; + } + + /// SyntaxToken representing the field keyword. + public SyntaxToken Token => this.token; + + internal override GreenNode? GetSlot(int index) + => index == 0 ? this.token : null; + + internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.FieldExpressionSyntax(this, parent, position); + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitFieldExpression(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitFieldExpression(this); + + public FieldExpressionSyntax Update(SyntaxToken token) + { + if (token != this.Token) + { + var newNode = SyntaxFactory.FieldExpression(token); + var diags = GetDiagnostics(); + if (diags?.Length > 0) + newNode = newNode.WithDiagnosticsGreen(diags); + var annotations = GetAnnotations(); + if (annotations?.Length > 0) + newNode = newNode.WithAnnotationsGreen(annotations); + return newNode; + } + + return this; + } + + internal override GreenNode SetDiagnostics(DiagnosticInfo[]? diagnostics) + => new FieldExpressionSyntax(this.Kind, this.token, diagnostics, GetAnnotations()); + + internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) + => new FieldExpressionSyntax(this.Kind, this.token, GetDiagnostics(), annotations); +} + /// Class which represents the syntax node for MakeRef expression. internal sealed partial class MakeRefExpressionSyntax : ExpressionSyntax { @@ -26456,6 +26521,7 @@ internal partial class CSharpSyntaxVisitor public virtual TResult VisitThisExpression(ThisExpressionSyntax node) => this.DefaultVisit(node); public virtual TResult VisitBaseExpression(BaseExpressionSyntax node) => this.DefaultVisit(node); public virtual TResult VisitLiteralExpression(LiteralExpressionSyntax node) => this.DefaultVisit(node); + public virtual TResult VisitFieldExpression(FieldExpressionSyntax node) => this.DefaultVisit(node); public virtual TResult VisitMakeRefExpression(MakeRefExpressionSyntax node) => this.DefaultVisit(node); public virtual TResult VisitRefTypeExpression(RefTypeExpressionSyntax node) => this.DefaultVisit(node); public virtual TResult VisitRefValueExpression(RefValueExpressionSyntax node) => this.DefaultVisit(node); @@ -26703,6 +26769,7 @@ internal partial class CSharpSyntaxVisitor public virtual void VisitThisExpression(ThisExpressionSyntax node) => this.DefaultVisit(node); public virtual void VisitBaseExpression(BaseExpressionSyntax node) => this.DefaultVisit(node); public virtual void VisitLiteralExpression(LiteralExpressionSyntax node) => this.DefaultVisit(node); + public virtual void VisitFieldExpression(FieldExpressionSyntax node) => this.DefaultVisit(node); public virtual void VisitMakeRefExpression(MakeRefExpressionSyntax node) => this.DefaultVisit(node); public virtual void VisitRefTypeExpression(RefTypeExpressionSyntax node) => this.DefaultVisit(node); public virtual void VisitRefValueExpression(RefValueExpressionSyntax node) => this.DefaultVisit(node); @@ -27024,6 +27091,9 @@ public override CSharpSyntaxNode VisitBaseExpression(BaseExpressionSyntax node) public override CSharpSyntaxNode VisitLiteralExpression(LiteralExpressionSyntax node) => node.Update((SyntaxToken)Visit(node.Token)); + public override CSharpSyntaxNode VisitFieldExpression(FieldExpressionSyntax node) + => node.Update((SyntaxToken)Visit(node.Token)); + public override CSharpSyntaxNode VisitMakeRefExpression(MakeRefExpressionSyntax node) => node.Update((SyntaxToken)Visit(node.Keyword), (SyntaxToken)Visit(node.OpenParenToken), (ExpressionSyntax)Visit(node.Expression), (SyntaxToken)Visit(node.CloseParenToken)); @@ -28620,6 +28690,26 @@ public LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxToken to return result; } + public FieldExpressionSyntax FieldExpression(SyntaxToken token) + { +#if DEBUG + if (token == null) throw new ArgumentNullException(nameof(token)); + if (token.Kind != SyntaxKind.FieldKeyword) throw new ArgumentException(nameof(token)); +#endif + + int hash; + var cached = CSharpSyntaxNodeCache.TryGetNode((int)SyntaxKind.FieldExpression, token, this.context, out hash); + if (cached != null) return (FieldExpressionSyntax)cached; + + var result = new FieldExpressionSyntax(SyntaxKind.FieldExpression, token, this.context); + if (hash >= 0) + { + SyntaxNodeCache.AddNode(result, hash); + } + + return result; + } + public MakeRefExpressionSyntax MakeRefExpression(SyntaxToken keyword, SyntaxToken openParenToken, ExpressionSyntax expression, SyntaxToken closeParenToken) { #if DEBUG @@ -33868,6 +33958,26 @@ public static LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxT return result; } + public static FieldExpressionSyntax FieldExpression(SyntaxToken token) + { +#if DEBUG + if (token == null) throw new ArgumentNullException(nameof(token)); + if (token.Kind != SyntaxKind.FieldKeyword) throw new ArgumentException(nameof(token)); +#endif + + int hash; + var cached = SyntaxNodeCache.TryGetNode((int)SyntaxKind.FieldExpression, token, out hash); + if (cached != null) return (FieldExpressionSyntax)cached; + + var result = new FieldExpressionSyntax(SyntaxKind.FieldExpression, token); + if (hash >= 0) + { + SyntaxNodeCache.AddNode(result, hash); + } + + return result; + } + public static MakeRefExpressionSyntax MakeRefExpression(SyntaxToken keyword, SyntaxToken openParenToken, ExpressionSyntax expression, SyntaxToken closeParenToken) { #if DEBUG diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs index fff130e4907ad..0b31bde257994 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs @@ -126,6 +126,9 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a LiteralExpressionSyntax node. public virtual TResult? VisitLiteralExpression(LiteralExpressionSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a FieldExpressionSyntax node. + public virtual TResult? VisitFieldExpression(FieldExpressionSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a MakeRefExpressionSyntax node. public virtual TResult? VisitMakeRefExpression(MakeRefExpressionSyntax node) => this.DefaultVisit(node); @@ -858,6 +861,9 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a LiteralExpressionSyntax node. public virtual void VisitLiteralExpression(LiteralExpressionSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a FieldExpressionSyntax node. + public virtual void VisitFieldExpression(FieldExpressionSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a MakeRefExpressionSyntax node. public virtual void VisitMakeRefExpression(MakeRefExpressionSyntax node) => this.DefaultVisit(node); @@ -1590,6 +1596,9 @@ public partial class CSharpSyntaxRewriter : CSharpSyntaxVisitor public override SyntaxNode? VisitLiteralExpression(LiteralExpressionSyntax node) => node.Update(VisitToken(node.Token)); + public override SyntaxNode? VisitFieldExpression(FieldExpressionSyntax node) + => node.Update(VisitToken(node.Token)); + public override SyntaxNode? VisitMakeRefExpression(MakeRefExpressionSyntax node) => node.Update(VisitToken(node.Keyword), VisitToken(node.OpenParenToken), (ExpressionSyntax?)Visit(node.Expression) ?? throw new ArgumentNullException("expression"), VisitToken(node.CloseParenToken)); @@ -2936,6 +2945,17 @@ public static LiteralExpressionSyntax LiteralExpression(SyntaxKind kind, SyntaxT return (LiteralExpressionSyntax)Syntax.InternalSyntax.SyntaxFactory.LiteralExpression(kind, (Syntax.InternalSyntax.SyntaxToken)token.Node!).CreateRed(); } + /// Creates a new FieldExpressionSyntax instance. + public static FieldExpressionSyntax FieldExpression(SyntaxToken token) + { + if (token.Kind() != SyntaxKind.FieldKeyword) throw new ArgumentException(nameof(token)); + return (FieldExpressionSyntax)Syntax.InternalSyntax.SyntaxFactory.FieldExpression((Syntax.InternalSyntax.SyntaxToken)token.Node!).CreateRed(); + } + + /// Creates a new FieldExpressionSyntax instance. + public static FieldExpressionSyntax FieldExpression() + => SyntaxFactory.FieldExpression(SyntaxFactory.Token(SyntaxKind.FieldKeyword)); + /// Creates a new MakeRefExpressionSyntax instance. public static MakeRefExpressionSyntax MakeRefExpression(SyntaxToken keyword, SyntaxToken openParenToken, ExpressionSyntax expression, SyntaxToken closeParenToken) { diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs index dadef45b3bf3d..0c97b7c25c0a7 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs @@ -2032,6 +2032,46 @@ public LiteralExpressionSyntax Update(SyntaxToken token) public LiteralExpressionSyntax WithToken(SyntaxToken token) => Update(token); } +/// Class which represents the syntax node for a field expression. +/// +/// This node is associated with the following syntax kinds: +/// +/// +/// +/// +public sealed partial class FieldExpressionSyntax : ExpressionSyntax +{ + + internal FieldExpressionSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position) + : base(green, parent, position) + { + } + + /// SyntaxToken representing the field keyword. + public SyntaxToken Token => new SyntaxToken(this, ((InternalSyntax.FieldExpressionSyntax)this.Green).token, Position, 0); + + internal override SyntaxNode? GetNodeSlot(int index) => null; + + internal override SyntaxNode? GetCachedSlot(int index) => null; + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitFieldExpression(this); + public override TResult? Accept(CSharpSyntaxVisitor visitor) where TResult : default => visitor.VisitFieldExpression(this); + + public FieldExpressionSyntax Update(SyntaxToken token) + { + if (token != this.Token) + { + var newNode = SyntaxFactory.FieldExpression(token); + var annotations = GetAnnotations(); + return annotations?.Length > 0 ? newNode.WithAnnotations(annotations) : newNode; + } + + return this; + } + + public FieldExpressionSyntax WithToken(SyntaxToken token) => Update(token); +} + /// Class which represents the syntax node for MakeRef expression. /// /// This node is associated with the following syntax kinds: diff --git a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs index 23ef65e70688e..1d3dab8bda75f 100644 --- a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs @@ -339,6 +339,8 @@ public static bool IsWarning(ErrorCode code) case ErrorCode.WRN_CollectionExpressionRefStructSpreadMayAllocate: case ErrorCode.WRN_ConvertingLock: case ErrorCode.WRN_PartialPropertySignatureDifference: + case ErrorCode.WRN_FieldIsAmbiguous: + case ErrorCode.WRN_UninitializedNonNullableBackingField: return true; default: return false; @@ -368,7 +370,6 @@ public static bool IsInfo(ErrorCode code) { case ErrorCode.INF_UnableToLoadSomeTypesInAnalyzer: case ErrorCode.INF_TooManyBoundLambdas: - case ErrorCode.INF_IdentifierConflictWithContextualKeyword: return true; default: return false; diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncExceptionHandlerRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncExceptionHandlerRewriter.cs index 3bc611d65efdb..3f0fb684273ae 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncExceptionHandlerRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncExceptionHandlerRewriter.cs @@ -139,97 +139,108 @@ public override BoundNode VisitTryStatement(BoundTryStatement node) // that the scenario has been tested with Edit-and-Continue. Debug.Assert(SyntaxBindingUtilities.BindsToTryStatement(tryStatementSyntax)); - BoundStatement finalizedRegion; - BoundBlock rewrittenFinally; + var oldTrySyntax = _F.Syntax; + _F.Syntax = tryStatementSyntax; - var finallyContainsAwaits = _analysis.FinallyContainsAwaits(node); - if (!finallyContainsAwaits) + var result = visitTryStatement(node, tryStatementSyntax); + + _F.Syntax = oldTrySyntax; + return result; + + BoundNode visitTryStatement(BoundTryStatement node, SyntaxNode tryStatementSyntax) { - finalizedRegion = RewriteFinalizedRegion(node); - rewrittenFinally = (BoundBlock)this.Visit(node.FinallyBlockOpt); + BoundStatement finalizedRegion; + BoundBlock rewrittenFinally; - if (rewrittenFinally == null) + var finallyContainsAwaits = _analysis.FinallyContainsAwaits(node); + if (!finallyContainsAwaits) { - return finalizedRegion; - } + finalizedRegion = RewriteFinalizedRegion(node); + rewrittenFinally = (BoundBlock)this.Visit(node.FinallyBlockOpt); - var asTry = finalizedRegion as BoundTryStatement; - if (asTry != null) - { - // since finalized region is a try we can just attach finally to it - Debug.Assert(asTry.FinallyBlockOpt == null); - return asTry.Update(asTry.TryBlock, asTry.CatchBlocks, rewrittenFinally, asTry.FinallyLabelOpt, asTry.PreferFaultHandler); - } - else - { - // wrap finalizedRegion into a Try with a finally. - return _F.Try((BoundBlock)finalizedRegion, ImmutableArray.Empty, rewrittenFinally); + if (rewrittenFinally == null) + { + return finalizedRegion; + } + + var asTry = finalizedRegion as BoundTryStatement; + if (asTry != null) + { + // since finalized region is a try we can just attach finally to it + Debug.Assert(asTry.FinallyBlockOpt == null); + return asTry.Update(asTry.TryBlock, asTry.CatchBlocks, rewrittenFinally, asTry.FinallyLabelOpt, asTry.PreferFaultHandler); + } + else + { + // wrap finalizedRegion into a Try with a finally. + return _F.Try((BoundBlock)finalizedRegion, ImmutableArray.Empty, rewrittenFinally); + } } - } - // rewrite finalized region (try and catches) in the current frame - var frame = PushFrame(node); - finalizedRegion = RewriteFinalizedRegion(node); - rewrittenFinally = (BoundBlock)this.VisitBlock(node.FinallyBlockOpt); - PopFrame(); + // rewrite finalized region (try and catches) in the current frame + var frame = PushFrame(node); + finalizedRegion = RewriteFinalizedRegion(node); + rewrittenFinally = (BoundBlock)this.VisitBlock(node.FinallyBlockOpt); + PopFrame(); + + var exceptionType = _F.SpecialType(SpecialType.System_Object); + var pendingExceptionLocal = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(exceptionType), SynthesizedLocalKind.TryAwaitPendingException, tryStatementSyntax); + var finallyLabel = _F.GenerateLabel("finallyLabel"); + var pendingBranchVar = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(_F.SpecialType(SpecialType.System_Int32)), SynthesizedLocalKind.TryAwaitPendingBranch, tryStatementSyntax); - var exceptionType = _F.SpecialType(SpecialType.System_Object); - var pendingExceptionLocal = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(exceptionType), SynthesizedLocalKind.TryAwaitPendingException, tryStatementSyntax); - var finallyLabel = _F.GenerateLabel("finallyLabel"); - var pendingBranchVar = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(_F.SpecialType(SpecialType.System_Int32)), SynthesizedLocalKind.TryAwaitPendingBranch, tryStatementSyntax); + var catchAll = _F.Catch(_F.Local(pendingExceptionLocal), _F.Block()); - var catchAll = _F.Catch(_F.Local(pendingExceptionLocal), _F.Block()); + var catchAndPendException = _F.Try( + _F.Block( + finalizedRegion, + _F.HiddenSequencePoint(), + _F.Goto(finallyLabel), + PendBranches(frame, pendingBranchVar, finallyLabel)), + ImmutableArray.Create(catchAll), + finallyLabel: finallyLabel); - var catchAndPendException = _F.Try( - _F.Block( - finalizedRegion, + BoundBlock syntheticFinallyBlock = _F.Block( _F.HiddenSequencePoint(), - _F.Goto(finallyLabel), - PendBranches(frame, pendingBranchVar, finallyLabel)), - ImmutableArray.Create(catchAll), - finallyLabel: finallyLabel); - - BoundBlock syntheticFinallyBlock = _F.Block( - _F.HiddenSequencePoint(), - _F.Label(finallyLabel), - rewrittenFinally, - _F.HiddenSequencePoint(), - UnpendException(pendingExceptionLocal), - UnpendBranches( - frame, - pendingBranchVar)); - - BoundStatement syntheticFinally = syntheticFinallyBlock; - if (_F.CurrentFunction.IsAsync && _F.CurrentFunction.IsIterator) - { - // We wrap this block so that it can be processed as a finally block by async-iterator rewriting - syntheticFinally = _F.ExtractedFinallyBlock(syntheticFinallyBlock); - } + _F.Label(finallyLabel), + rewrittenFinally, + _F.HiddenSequencePoint(), + UnpendException(pendingExceptionLocal), + UnpendBranches( + frame, + pendingBranchVar)); - var locals = ArrayBuilder.GetInstance(); - var statements = ArrayBuilder.GetInstance(); + BoundStatement syntheticFinally = syntheticFinallyBlock; + if (_F.CurrentFunction.IsAsync && _F.CurrentFunction.IsIterator) + { + // We wrap this block so that it can be processed as a finally block by async-iterator rewriting + syntheticFinally = _F.ExtractedFinallyBlock(syntheticFinallyBlock); + } - statements.Add(_F.HiddenSequencePoint()); + var locals = ArrayBuilder.GetInstance(); + var statements = ArrayBuilder.GetInstance(); - locals.Add(pendingExceptionLocal); - statements.Add(_F.Assignment(_F.Local(pendingExceptionLocal), _F.Default(pendingExceptionLocal.Type))); - locals.Add(pendingBranchVar); - statements.Add(_F.Assignment(_F.Local(pendingBranchVar), _F.Default(pendingBranchVar.Type))); + statements.Add(_F.HiddenSequencePoint()); - LocalSymbol returnLocal = frame.returnValue; - if (returnLocal != null) - { - locals.Add(returnLocal); - } + locals.Add(pendingExceptionLocal); + statements.Add(_F.Assignment(_F.Local(pendingExceptionLocal), _F.Default(pendingExceptionLocal.Type))); + locals.Add(pendingBranchVar); + statements.Add(_F.Assignment(_F.Local(pendingBranchVar), _F.Default(pendingBranchVar.Type))); - statements.Add(catchAndPendException); - statements.Add(syntheticFinally); + LocalSymbol returnLocal = frame.returnValue; + if (returnLocal != null) + { + locals.Add(returnLocal); + } - var completeTry = _F.Block( - locals.ToImmutableAndFree(), - statements.ToImmutableAndFree()); + statements.Add(catchAndPendException); + statements.Add(syntheticFinally); - return completeTry; + var completeTry = _F.Block( + locals.ToImmutableAndFree(), + statements.ToImmutableAndFree()); + + return completeTry; + } } private BoundBlock PendBranches( diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs index b3fcbcd55aefe..b7a5f29d01940 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -79,7 +80,7 @@ internal AsyncIteratorMethodToStateMachineRewriter( { var asyncDispatch = base.GenerateMissingStateDispatch(); - var iteratorDispatch = _iteratorStateAllocator.GenerateThrowMissingStateDispatch(F, F.Local(cachedState), CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod); + var iteratorDispatch = _iteratorStateAllocator.GenerateThrowMissingStateDispatch(F, F.Local(cachedState), HotReloadExceptionCode.CannotResumeSuspendedIteratorMethod); if (iteratorDispatch == null) { return asyncDispatch; diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs index a81f70357653c..846ada0028176 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -121,8 +122,8 @@ private FieldSymbol GetAwaiterField(TypeSymbol awaiterType) return result; } - protected sealed override string EncMissingStateMessage - => CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod; + protected sealed override HotReloadExceptionCode EncMissingStateErrorCode + => HotReloadExceptionCode.CannotResumeSuspendedAsyncMethod; protected sealed override StateMachineState FirstIncreasingResumableState => StateMachineState.FirstResumableAsyncState; diff --git a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.Analysis.Tree.cs b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.Analysis.Tree.cs index f4413a571f973..a8137e564ae98 100644 --- a/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.Analysis.Tree.cs +++ b/src/Compilers/CSharp/Portable/Lowering/ClosureConversion/ClosureConversion.Analysis.Tree.cs @@ -764,7 +764,7 @@ private void PopScope(Scope scope) return; } - Debug.Assert(scope == _currentScope.Parent, $"{nameof(scope)} must be {nameof(_currentScope)} or {nameof(_currentScope)}.{nameof(_currentScope.Parent)}"); + RoslynDebug.Assert(scope == _currentScope.Parent, $"{nameof(scope)} must be {nameof(_currentScope)} or {nameof(_currentScope)}.{nameof(_currentScope.Parent)}"); // Since it is forbidden to jump into a scope, // we can forget all information we have about labels in the child scope diff --git a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs index 1f401b2ef6eff..fb958d3f42dd2 100644 --- a/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs +++ b/src/Compilers/CSharp/Portable/Lowering/DiagnosticsPass_ExpressionTrees.cs @@ -676,6 +676,28 @@ public override BoundNode VisitBinaryOperator(BoundBinaryOperator node) return null; } + public override BoundNode VisitBinaryPattern(BoundBinaryPattern node) + { + // Do not use left recursion because we can have many nested binary patterns. + + BoundBinaryPattern current = node; + while (true) + { + Visit(current.Right); + if (current.Left is BoundBinaryPattern left) + { + current = left; + } + else + { + Visit(current.Left); + break; + } + } + + return null; + } + public override BoundNode VisitUserDefinedConditionalLogicalOperator(BoundUserDefinedConditionalLogicalOperator node) { CheckLiftedUserDefinedConditionalLogicalOperator(node); @@ -1045,5 +1067,32 @@ public override BoundNode VisitCollectionExpression(BoundCollectionExpression no return base.VisitCollectionExpression(node); } + + public override BoundNode VisitIfStatement(BoundIfStatement node) + { + while (true) + { + this.Visit(node.Condition); + this.Visit(node.Consequence); + + var alternative = node.AlternativeOpt; + if (alternative is null) + { + break; + } + + if (alternative is BoundIfStatement elseIfStatement) + { + node = elseIfStatement; + } + else + { + this.Visit(alternative); + break; + } + } + + return null; + } } } diff --git a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/CodeCoverageInstrumenter.cs b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/CodeCoverageInstrumenter.cs index 7f0e79edfd813..5c57cc091dab8 100644 --- a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/CodeCoverageInstrumenter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/CodeCoverageInstrumenter.cs @@ -371,9 +371,9 @@ public override BoundStatement InstrumentForEachStatementDeconstructionVariables return AddDynamicAnalysis(original, base.InstrumentForEachStatementDeconstructionVariablesDeclaration(original, iterationVarDecl)); } - public override BoundStatement InstrumentIfStatement(BoundIfStatement original, BoundStatement rewritten) + public override BoundStatement InstrumentIfStatementConditionalGoto(BoundIfStatement original, BoundStatement rewritten) { - return AddDynamicAnalysis(original, base.InstrumentIfStatement(original, rewritten)); + return AddDynamicAnalysis(original, base.InstrumentIfStatementConditionalGoto(original, rewritten)); } public override BoundStatement InstrumentWhileStatementConditionalGotoStartOrBreak(BoundWhileStatement original, BoundStatement ifConditionGotoStart) diff --git a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/CompoundInstrumenter.cs b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/CompoundInstrumenter.cs index 82f5dda4cb4b9..289614c47adf9 100644 --- a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/CompoundInstrumenter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/CompoundInstrumenter.cs @@ -131,9 +131,9 @@ public override BoundExpression InstrumentForStatementCondition(BoundForStatemen return Previous.InstrumentForStatementCondition(original, rewrittenCondition, factory); } - public override BoundStatement InstrumentIfStatement(BoundIfStatement original, BoundStatement rewritten) + public override BoundStatement InstrumentIfStatementConditionalGoto(BoundIfStatement original, BoundStatement rewritten) { - return Previous.InstrumentIfStatement(original, rewritten); + return Previous.InstrumentIfStatementConditionalGoto(original, rewritten); } public override BoundExpression InstrumentIfStatementCondition(BoundIfStatement original, BoundExpression rewrittenCondition, SyntheticBoundNodeFactory factory) diff --git a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector.cs b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector.cs index 5f12229415f08..a9fabf63b6b51 100644 --- a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector.cs +++ b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DebugInfoInjector.cs @@ -355,12 +355,12 @@ public override BoundExpression InstrumentForStatementCondition(BoundForStatemen return AddConditionSequencePoint(base.InstrumentForStatementCondition(original, rewrittenCondition, factory), original.Syntax, factory); } - public override BoundStatement InstrumentIfStatement(BoundIfStatement original, BoundStatement rewritten) + public override BoundStatement InstrumentIfStatementConditionalGoto(BoundIfStatement original, BoundStatement rewritten) { var syntax = (IfStatementSyntax)original.Syntax; return new BoundSequencePointWithSpan( syntax, - base.InstrumentIfStatement(original, rewritten), + base.InstrumentIfStatementConditionalGoto(original, rewritten), TextSpan.FromBounds( syntax.IfKeyword.SpanStart, syntax.CloseParenToken.Span.End), diff --git a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/Instrumenter.cs b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/Instrumenter.cs index 561559771f6c2..0114fd9055ac3 100644 --- a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/Instrumenter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/Instrumenter.cs @@ -189,7 +189,7 @@ public virtual BoundExpression InstrumentForStatementCondition(BoundForStatement return rewrittenCondition; } - public virtual BoundStatement InstrumentIfStatement(BoundIfStatement original, BoundStatement rewritten) + public virtual BoundStatement InstrumentIfStatementConditionalGoto(BoundIfStatement original, BoundStatement rewritten) { Debug.Assert(original.Syntax.Kind() == SyntaxKind.IfStatement); return InstrumentStatement(original, rewritten); diff --git a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/ModuleCancellationInstrumenter.cs b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/ModuleCancellationInstrumenter.cs index a99b700defbf9..9862d2b8aec17 100644 --- a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/ModuleCancellationInstrumenter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/ModuleCancellationInstrumenter.cs @@ -198,6 +198,7 @@ public override void InterceptCallAndAdjustArguments( parametersWithCancellationToken.AsSpan(0, methodDefinition.Parameters.Length), typeMap, MemberSignatureComparer.RefKindCompareMode.ConsiderDifferences, + considerDefaultValues: false, TypeComparisonKind) && MemberSignatureComparer.HaveSameReturnTypes( methodDefinition, diff --git a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs index efbfc57120339..a8200be6deb4d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs @@ -54,7 +54,7 @@ internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChang return false; } - internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return false; } diff --git a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs index c753767d55e29..606cde97b5066 100644 --- a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs @@ -11,6 +11,7 @@ using System.Linq; using Roslyn.Utilities; using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.Emit; namespace Microsoft.CodeAnalysis.CSharp { @@ -73,8 +74,8 @@ internal IteratorMethodToStateMachineRewriter( } #nullable disable - protected override string EncMissingStateMessage - => CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod; + protected sealed override HotReloadExceptionCode EncMissingStateErrorCode + => HotReloadExceptionCode.CannotResumeSuspendedIteratorMethod; protected override StateMachineState FirstIncreasingResumableState => StateMachineState.FirstResumableIteratorState; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs index 59cd4fd4afe8a..9a81320dfef8c 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter.cs @@ -270,7 +270,7 @@ private PEModuleBuilder? EmitModule } } - var visited = VisitExpressionWithStackGuard(node); + var visited = (BoundExpression)VisitExpressionOrPatternWithStackGuard(node); // If you *really* need to change the type, consider using an indirect method // like compound assignment does (extra flag only passed when it is an expression @@ -1117,7 +1117,7 @@ internal static bool CanBePassedByReference(BoundExpression expr) return expr is BoundConversion { Conversion: { IsInterpolatedStringHandler: true }, Type: { IsValueType: true } }; } - Debug.Assert(expr is not BoundValuePlaceholderBase, $"Placeholder kind {expr.Kind} must be handled explicitly"); + RoslynDebug.Assert(expr is not BoundValuePlaceholderBase, $"Placeholder kind {expr.Kind} must be handled explicitly"); return false; } @@ -1143,6 +1143,17 @@ private CompoundUseSiteInfo GetNewCompoundUseSiteInfo() /// private sealed class LocalRewritingValidator : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator { + public override BoundNode? Visit(BoundNode? node) + { + if (node is BoundIfStatement) + { + Fail(node); + return null; + } + + return base.Visit(node); + } + /// /// Asserts that no unexpected nodes survived local rewriting. /// @@ -1170,12 +1181,6 @@ public static void Validate(BoundNode node) return null; } - public override BoundNode? VisitIfStatement(BoundIfStatement node) - { - Fail(node); - return null; - } - public override BoundNode? VisitDeconstructionVariablePendingInference(DeconstructionVariablePendingInference node) { Fail(node); @@ -1250,7 +1255,7 @@ public static void Validate(BoundNode node) private void Fail(BoundNode node) { - Debug.Assert(false, $"Bound nodes of kind {node.Kind} should not survive past local rewriting"); + RoslynDebug.Assert(false, $"Bound nodes of kind {node.Kind} should not survive past local rewriting"); } } #endif diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs index 75c23b3592248..9a2d1ec5b9caa 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_AssignmentOperator.cs @@ -281,8 +281,9 @@ private BoundExpression MakePropertyAssignment( if (setMethod is null) { var autoProp = (SourcePropertySymbolBase)property.OriginalDefinition; - Debug.Assert(autoProp.IsAutoPropertyWithGetAccessor, + Debug.Assert(autoProp.IsAutoPropertyOrUsesFieldKeyword, "only autoproperties can be assignable without having setters"); + Debug.Assert(_factory.CurrentFunction.IsConstructor()); Debug.Assert(property.Equals(autoProp, TypeCompareKind.IgnoreNullableModifiersForReferenceTypes)); var backingField = autoProp.BackingField; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs index 8c1b126d3081f..82fe7099eb900 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Call.cs @@ -138,6 +138,7 @@ private void InterceptCallAndAdjustArguments( ref BoundExpression? receiverOpt, ref ImmutableArray arguments, ref ImmutableArray argumentRefKindsOpt, + ref ArrayBuilder temps, bool invokedAsExtensionMethod, Syntax.SimpleNameSyntax? nameSyntax) { @@ -281,11 +282,26 @@ private void InterceptCallAndAdjustArguments( || (!receiverOpt.Type.IsReferenceType && interceptor.Parameters[0].Type.IsReferenceType)); receiverOpt = MakeConversionNode(receiverOpt, interceptor.Parameters[0].Type, @checked: false, markAsChecked: true); + var thisRefKind = methodThisParameter.RefKind; + // Instance call receivers can be implicitly captured to temps in the emit layer, but not static call arguments + // Therefore we may need to explicitly store the receiver to temp here. + if (thisRefKind != RefKind.None + && !Binder.HasHome( + receiverOpt, + thisRefKind == RefKind.Ref ? Binder.AddressKind.Writeable : Binder.AddressKind.ReadOnlyStrict, + _factory.CurrentFunction, + peVerifyCompatEnabled: false, + stackLocalsOpt: null)) + { + var receiverTemp = _factory.StoreToTemp(receiverOpt, out var assignmentToTemp); + temps.Add(receiverTemp.LocalSymbol); + receiverOpt = _factory.Sequence(locals: [], sideEffects: [assignmentToTemp], receiverTemp); + } + arguments = arguments.Insert(0, receiverOpt); receiverOpt = null; // CodeGenerator.EmitArguments requires that we have a fully-filled-out argumentRefKindsOpt for any ref/in/out arguments. - var thisRefKind = methodThisParameter.RefKind; if (argumentRefKindsOpt.IsDefault && thisRefKind != RefKind.None) { argumentRefKindsOpt = method.Parameters.SelectAsArray(static param => param.RefKind); @@ -401,7 +417,7 @@ BoundExpression visitArgumentsAndFinishRewrite(BoundCall node, BoundExpression? ref temps, invokedAsExtensionMethod); - InterceptCallAndAdjustArguments(ref method, ref rewrittenReceiver, ref rewrittenArguments, ref argRefKindsOpt, invokedAsExtensionMethod, node.InterceptableNameSyntax); + InterceptCallAndAdjustArguments(ref method, ref rewrittenReceiver, ref rewrittenArguments, ref argRefKindsOpt, ref temps, invokedAsExtensionMethod, node.InterceptableNameSyntax); if (Instrument) { diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs index f8ec243af6ba1..641913d90b11d 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs @@ -43,9 +43,17 @@ private BoundExpression RewriteCollectionExpressionConversion(Conversion convers switch (collectionTypeKind) { case CollectionExpressionTypeKind.ImplementsIEnumerable: - if (useListOptimization(_compilation, node, out var listElementType)) + if (ConversionsBase.IsSpanOrListType(_compilation, node.Type, WellKnownType.System_Collections_Generic_List_T, out var listElementType)) { - return CreateAndPopulateList(node, listElementType, node.Elements.SelectAsArray(static (element, node) => unwrapListElement(node, element), node)); + if (TryRewriteSingleElementSpreadToList(node, listElementType, out var result)) + { + return result; + } + + if (useListOptimization(_compilation, node)) + { + return CreateAndPopulateList(node, listElementType, node.Elements.SelectAsArray(static (element, node) => unwrapListElement(node, element), node)); + } } return VisitCollectionInitializerCollectionExpression(node, node.Type); case CollectionExpressionTypeKind.Array: @@ -54,15 +62,25 @@ private BoundExpression RewriteCollectionExpressionConversion(Conversion convers Debug.Assert(elementType is { }); return VisitArrayOrSpanCollectionExpression(node, collectionTypeKind, node.Type, TypeWithAnnotations.Create(elementType)); case CollectionExpressionTypeKind.CollectionBuilder: - // If the collection type is ImmutableArray, then construction is optimized to use - // ImmutableCollectionsMarshal.AsImmutableArray. - // The only exception is when collection expression is just `[.. readOnlySpan]` of the same element type, in such cases - // it is more efficient to emit a direct call of `ImmutableArray.Create` - if (ConversionsBase.IsSpanOrListType(_compilation, node.Type, WellKnownType.System_Collections_Immutable_ImmutableArray_T, out var arrayElementType) && - _compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_ImmutableCollectionsMarshal__AsImmutableArray_T) is MethodSymbol asImmutableArray && - !CanOptimizeSingleSpreadAsCollectionBuilderArgument(node, out _)) + // A few special cases when a collection type is an ImmutableArray + if (ConversionsBase.IsSpanOrListType(_compilation, node.Type, WellKnownType.System_Collections_Immutable_ImmutableArray_T, out var arrayElementType)) { - return VisitImmutableArrayCollectionExpression(node, arrayElementType, asImmutableArray); + // For `[]` try to use `ImmutableArray.Empty` singleton if available + if (node.Elements.IsEmpty && + _compilation.GetWellKnownTypeMember(WellKnownMember.System_Collections_Immutable_ImmutableArray_T__Empty) is FieldSymbol immutableArrayOfTEmpty) + { + var immutableArrayOfTargetCollectionTypeEmpty = immutableArrayOfTEmpty.AsMember((NamedTypeSymbol)node.Type); + return _factory.Field(receiver: null, immutableArrayOfTargetCollectionTypeEmpty); + } + + // Otherwise try to optimize construction using `ImmutableCollectionsMarshal.AsImmutableArray`. + // Note, that we skip that path if collection expression is just `[.. readOnlySpan]` of the same element type, + // in such cases it is more efficient to emit a direct call of `ImmutableArray.Create` + if (_compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_ImmutableCollectionsMarshal__AsImmutableArray_T) is MethodSymbol asImmutableArray && + !CanOptimizeSingleSpreadAsCollectionBuilderArgument(node, out _)) + { + return VisitImmutableArrayCollectionExpression(node, arrayElementType, asImmutableArray); + } } return VisitCollectionBuilderCollectionExpression(node); case CollectionExpressionTypeKind.ArrayInterface: @@ -78,12 +96,8 @@ private BoundExpression RewriteCollectionExpressionConversion(Conversion convers // If the collection type is List and items are added using the expected List.Add(T) method, // then construction can be optimized to use CollectionsMarshal methods. - static bool useListOptimization(CSharpCompilation compilation, BoundCollectionExpression node, out TypeWithAnnotations elementType) + static bool useListOptimization(CSharpCompilation compilation, BoundCollectionExpression node) { - if (!ConversionsBase.IsSpanOrListType(compilation, node.Type, WellKnownType.System_Collections_Generic_List_T, out elementType)) - { - return false; - } var elements = node.Elements; if (elements.Length == 0) { @@ -141,6 +155,62 @@ static BoundNode unwrapListElement(BoundCollectionExpression node, BoundNode ele } } + // If we have something like `List l = [.. someEnumerable]` + // try rewrite it using `Enumerable.ToList` member if possible + private bool TryRewriteSingleElementSpreadToList(BoundCollectionExpression node, TypeWithAnnotations listElementType, [NotNullWhen(true)] out BoundExpression? result) + { + result = null; + + if (node.Elements is not [BoundCollectionExpressionSpreadElement singleSpread]) + { + return false; + } + + if (!TryGetWellKnownTypeMember(node.Syntax, WellKnownMember.System_Linq_Enumerable__ToList, out MethodSymbol? toListGeneric, isOptional: true)) + { + return false; + } + + var toListOfElementType = toListGeneric.Construct([listElementType]); + + Debug.Assert(singleSpread.Expression.Type is not null); + + if (!ShouldUseAddRangeOrToListMethod(singleSpread.Expression.Type, toListOfElementType.Parameters[0].Type, singleSpread.EnumeratorInfoOpt?.GetEnumeratorInfo.Method)) + { + return false; + } + + var rewrittenSpreadExpression = VisitExpression(singleSpread.Expression); + result = _factory.Call(receiver: null, toListOfElementType, rewrittenSpreadExpression); + return true; + } + + private bool ShouldUseAddRangeOrToListMethod(TypeSymbol spreadType, TypeSymbol targetEnumerableType, MethodSymbol? getEnumeratorMethod) + { + Debug.Assert(targetEnumerableType.OriginalDefinition == (object)_compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T)); + + var discardedUseSiteInfo = CompoundUseSiteInfo.Discarded; + + Conversion conversion; + + // If collection has a struct enumerator but doesn't implement ICollection + // then manual `foreach` is always more efficient then using `ToList` or `AddRange` methods + if (getEnumeratorMethod?.ReturnType.IsValueType == true) + { + var iCollectionOfTType = _compilation.GetSpecialType(SpecialType.System_Collections_Generic_ICollection_T); + var iCollectionOfElementType = iCollectionOfTType.Construct(((NamedTypeSymbol)targetEnumerableType).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics); + + conversion = _compilation.Conversions.ClassifyBuiltInConversion(spreadType, iCollectionOfElementType, isChecked: false, ref discardedUseSiteInfo); + if (conversion.Kind is not (ConversionKind.Identity or ConversionKind.ImplicitReference)) + { + return false; + } + } + + conversion = _compilation.Conversions.ClassifyImplicitConversionFromType(spreadType, targetEnumerableType, ref discardedUseSiteInfo); + return conversion.Kind is ConversionKind.Identity or ConversionKind.ImplicitReference; + } + private static bool CanOptimizeSingleSpreadAsCollectionBuilderArgument(BoundCollectionExpression node, [NotNullWhen(true)] out BoundExpression? spreadExpression) { spreadExpression = null; @@ -402,7 +472,7 @@ private BoundExpression VisitCollectionBuilderCollectionExpression(BoundCollecti // and that span cannot be captured in a returned ref struct // we can directly use `anotherReadOnlySpan` as collection builder argument and skip the copying assignment. BoundExpression span = CanOptimizeSingleSpreadAsCollectionBuilderArgument(node, out var spreadExpression) - ? spreadExpression + ? VisitExpression(spreadExpression) : VisitArrayOrSpanCollectionExpression(node, CollectionExpressionTypeKind.ReadOnlySpan, spanType, elementType); var invocation = new BoundCall( @@ -1054,22 +1124,18 @@ private BoundExpression CreateAndPopulateList(BoundCollectionExpression node, Ty }, tryOptimizeSpreadElement: (ArrayBuilder sideEffects, BoundExpression listTemp, BoundCollectionExpressionSpreadElement spreadElement, BoundExpression rewrittenSpreadOperand) => { + Debug.Assert(rewrittenSpreadOperand.Type is not null); + if (addRangeMethod is null) return false; - var type = rewrittenSpreadOperand.Type!; - - var useSiteInfo = GetNewCompoundUseSiteInfo(); - var conversion = _compilation.Conversions.ClassifyConversionFromType(type, addRangeMethod.Parameters[0].Type, isChecked: false, ref useSiteInfo); - _diagnostics.Add(rewrittenSpreadOperand.Syntax, useSiteInfo); - if (conversion.IsIdentity || (conversion.IsImplicit && conversion.IsReference)) + if (!ShouldUseAddRangeOrToListMethod(rewrittenSpreadOperand.Type, addRangeMethod.Parameters[0].Type, spreadElement.EnumeratorInfoOpt?.GetEnumeratorInfo.Method)) { - conversion.MarkUnderlyingConversionsCheckedRecursive(); - sideEffects.Add(_factory.Call(listTemp, addRangeMethod, rewrittenSpreadOperand)); - return true; + return false; } - return false; + sideEffects.Add(_factory.Call(listTemp, addRangeMethod, rewrittenSpreadOperand)); + return true; }); } @@ -1261,6 +1327,24 @@ private BoundExpression MakeCollectionExpressionSpreadElement( rewrittenBody); } } + else if (enumeratorInfo is { InlineArraySpanType: not WellKnownType.Unknown }) + { + statement = RewriteForEachStatementAsFor( + node, + getPreamble: GetInlineArrayForEachStatementPreambleDelegate(), + getItem: GetInlineArrayForEachStatementGetItemDelegate(), + getLength: GetInlineArrayForEachStatementGetLengthDelegate(), + arg: null, + convertedExpression.Operand, + enumeratorInfo, + elementPlaceholder: null, + elementConversion: null, + iterationVariables, + deconstructionOpt: null, + breakLabel, + continueLabel, + rewrittenBody); + } else { statement = RewriteForEachEnumerator( diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs index 9cf7b4f388044..6b87177c37ffb 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CompoundAssignmentOperator.cs @@ -599,7 +599,7 @@ private BoundExpression TransformCompoundAssignmentLHS(BoundExpression originalL // This is a temporary object that will be rewritten away before the lowering completes. return propertyAccess.Update(TransformPropertyOrEventReceiver(propertyAccess.PropertySymbol, propertyAccess.ReceiverOpt, isRegularCompoundAssignment, stores, temps), - propertyAccess.InitialBindingReceiverIsSubjectToCloning, propertyAccess.PropertySymbol, propertyAccess.ResultKind, propertyAccess.Type); + propertyAccess.InitialBindingReceiverIsSubjectToCloning, propertyAccess.PropertySymbol, propertyAccess.AutoPropertyAccessorKind, propertyAccess.ResultKind, propertyAccess.Type); } } break; diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs index 1336bde261b7c..306b42bad04f0 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs @@ -404,7 +404,6 @@ private bool TryGetDisposeMethod(SyntaxNode forEachSyntax, ForEachEnumeratorInfo syntax: forEachSyntax, rewrittenCondition: _factory.IsNotNullReference(boundEnumeratorVar), rewrittenConsequence: disposeCallStatement, - rewrittenAlternativeOpt: null, hasErrors: false); } @@ -459,7 +458,6 @@ private bool TryGetDisposeMethod(SyntaxNode forEachSyntax, ForEachEnumeratorInfo resultKind: LookupResultKind.Viable, type: _compilation.GetSpecialType(SpecialType.System_Boolean)), rewrittenConsequence: disposeCallStatement, - rewrittenAlternativeOpt: null, hasErrors: false); // IDisposable d = e as IDisposable; @@ -569,9 +567,45 @@ private BoundExpression SynthesizeCall(MethodArgumentInfo methodArgumentInfo, CS /// private BoundStatement RewriteForEachStatementAsFor(BoundForEachStatement node, GetForEachStatementAsForPreamble? getPreamble, GetForEachStatementAsForItem getItem, GetForEachStatementAsForLength getLength, TArg arg) { - var forEachSyntax = (CommonForEachStatementSyntax)node.Syntax; - BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node, out _); + + BoundStatement? rewrittenBody = VisitStatement(node.Body); + Debug.Assert(rewrittenBody is { }); + + Debug.Assert(node.EnumeratorInfoOpt is not null); + return RewriteForEachStatementAsFor( + node, + getPreamble, + getItem, + getLength, + arg, + collectionExpression, + node.EnumeratorInfoOpt, + node.ElementPlaceholder, + node.ElementConversion, + node.IterationVariables, + node.DeconstructionOpt, + node.BreakLabel, + node.ContinueLabel, + rewrittenBody); + } + + private BoundStatement RewriteForEachStatementAsFor( + BoundNode node, + GetForEachStatementAsForPreamble? getPreamble, + GetForEachStatementAsForItem getItem, + GetForEachStatementAsForLength getLength, + TArg arg, + BoundExpression collectionExpression, + ForEachEnumeratorInfo enumeratorInfo, + BoundValuePlaceholder? elementPlaceholder, + BoundExpression? elementConversion, + ImmutableArray iterationVariables, + BoundForEachDeconstructStep? deconstructionOpt, + GeneratedLabelSymbol breakLabel, + GeneratedLabelSymbol continueLabel, + BoundStatement rewrittenBody) + { NamedTypeSymbol? collectionType = (NamedTypeSymbol?)collectionExpression.Type; Debug.Assert(collectionType is { }); @@ -579,12 +613,11 @@ private BoundStatement RewriteForEachStatementAsFor(BoundForEachStatement TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean); BoundExpression rewrittenExpression = VisitExpression(collectionExpression); - BoundStatement? rewrittenBody = VisitStatement(node.Body); - Debug.Assert(rewrittenBody is { }); + var forEachSyntax = (CSharpSyntaxNode)node.Syntax; LocalSymbol? preambleLocal = null; RefKind collectionTempRefKind = RefKind.None; - BoundStatement? collectionVarInitializationPreamble = getPreamble?.Invoke(this, node, ref rewrittenExpression, out preambleLocal, out collectionTempRefKind); + BoundStatement? collectionVarInitializationPreamble = getPreamble?.Invoke(this, forEachSyntax, enumeratorInfo, ref rewrittenExpression, out preambleLocal, out collectionTempRefKind); // Collection a LocalSymbol collectionTemp = _factory.SynthesizedLocal(collectionType, forEachSyntax, kind: SynthesizedLocalKind.ForEachArray, refKind: collectionTempRefKind); @@ -614,13 +647,12 @@ private BoundStatement RewriteForEachStatementAsFor(BoundForEachStatement // (V)a[p] BoundExpression iterationVarInitValue = ApplyConversionIfNotIdentity( - node.ElementConversion, - node.ElementPlaceholder, - getItem(this, node, boundArrayVar, boundPositionVar, arg)); + elementConversion, + elementPlaceholder, + getItem(this, forEachSyntax, enumeratorInfo, boundArrayVar, boundPositionVar, arg)); // V v = (V)a[p]; /* OR */ (D1 d1, ...) = (V)a[p]; - ImmutableArray iterationVariables = node.IterationVariables; - BoundStatement iterationVariableDecl = LocalOrDeconstructionDeclaration(forEachSyntax, node.DeconstructionOpt, iterationVariables, iterationVarInitValue); + BoundStatement iterationVariableDecl = LocalOrDeconstructionDeclaration(forEachSyntax, deconstructionOpt, iterationVariables, iterationVarInitValue); InstrumentForEachStatementIterationVarDeclaration(node, ref iterationVariableDecl); @@ -628,7 +660,7 @@ private BoundStatement RewriteForEachStatementAsFor(BoundForEachStatement statements: ImmutableArray.Create(arrayVarDecl, positionVarDecl)); // a.Length - BoundExpression arrayLength = getLength(this, node, boundArrayVar, arg); + BoundExpression arrayLength = getLength(this, forEachSyntax, boundArrayVar, arg); // p < a.Length BoundExpression exitCondition = new BoundBinaryOperator( @@ -663,8 +695,8 @@ private BoundStatement RewriteForEachStatementAsFor(BoundForEachStatement rewrittenCondition: exitCondition, rewrittenIncrement: positionIncrement, rewrittenBody: loopBody, - breakLabel: node.BreakLabel, - continueLabel: node.ContinueLabel, + breakLabel: breakLabel, + continueLabel: continueLabel, hasErrors: node.HasErrors); InstrumentForEachStatement(node, ref result); @@ -672,27 +704,27 @@ private BoundStatement RewriteForEachStatementAsFor(BoundForEachStatement return result; } - private delegate BoundStatement? GetForEachStatementAsForPreamble(LocalRewriter rewriter, BoundForEachStatement node, ref BoundExpression rewrittenExpression, out LocalSymbol? preambleLocal, out RefKind collectionTempRefKind); - private delegate BoundExpression GetForEachStatementAsForItem(LocalRewriter rewriter, BoundForEachStatement node, BoundLocal boundArrayVar, BoundLocal boundPositionVar, TArg arg); - private delegate BoundExpression GetForEachStatementAsForLength(LocalRewriter rewriter, BoundForEachStatement node, BoundLocal boundArrayVar, TArg arg); + private delegate BoundStatement? GetForEachStatementAsForPreamble(LocalRewriter rewriter, SyntaxNode syntax, ForEachEnumeratorInfo enumeratorInfo, ref BoundExpression rewrittenExpression, out LocalSymbol? preambleLocal, out RefKind collectionTempRefKind); + private delegate BoundExpression GetForEachStatementAsForItem(LocalRewriter rewriter, SyntaxNode syntax, ForEachEnumeratorInfo enumeratorInfo, BoundLocal boundArrayVar, BoundLocal boundPositionVar, TArg arg); + private delegate BoundExpression GetForEachStatementAsForLength(LocalRewriter rewriter, SyntaxNode syntax, BoundLocal boundArrayVar, TArg arg); private BoundStatement RewriteForEachStatementAsFor(BoundForEachStatement node, MethodSymbol indexerGet, MethodSymbol lengthGet) { return RewriteForEachStatementAsFor(node, getPreamble: null, - getItem: static (LocalRewriter rewriter, BoundForEachStatement node, BoundLocal boundArrayVar, BoundLocal boundPositionVar, (MethodSymbol indexerGet, MethodSymbol lengthGet) arg) => + getItem: static (LocalRewriter rewriter, SyntaxNode syntax, ForEachEnumeratorInfo enumeratorInfo, BoundLocal boundArrayVar, BoundLocal boundPositionVar, (MethodSymbol indexerGet, MethodSymbol lengthGet) arg) => { return BoundCall.Synthesized( - syntax: node.Syntax, + syntax: syntax, receiverOpt: boundArrayVar, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, arg.indexerGet, boundPositionVar); }, - getLength: static (LocalRewriter rewriter, BoundForEachStatement node, BoundLocal boundArrayVar, (MethodSymbol indexerGet, MethodSymbol lengthGet) arg) => + getLength: static (LocalRewriter rewriter, SyntaxNode syntax, BoundLocal boundArrayVar, (MethodSymbol indexerGet, MethodSymbol lengthGet) arg) => { return BoundCall.Synthesized( - syntax: node.Syntax, + syntax: syntax, receiverOpt: boundArrayVar, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, arg.lengthGet); @@ -703,60 +735,70 @@ private BoundStatement RewriteForEachStatementAsFor(BoundForEachStatement node, private BoundStatement RewriteInlineArrayForEachStatementAsFor(BoundForEachStatement node) { return RewriteForEachStatementAsFor(node, - getPreamble: static (LocalRewriter rewriter, BoundForEachStatement node, ref BoundExpression rewrittenExpression, out LocalSymbol? preambleLocal, out RefKind collectionTempRefKind) => - { - var enumeratorInfo = node.EnumeratorInfoOpt; - Debug.Assert(enumeratorInfo is not null); - Debug.Assert(rewrittenExpression.Type is not null); - - BoundStatement? collectionVarInitializationPreamble = null; - preambleLocal = null; - if (enumeratorInfo.InlineArrayUsedAsValue) - { - BoundLocal boundLocal = rewriter._factory.StoreToTemp(rewrittenExpression, out BoundAssignmentOperator? valueStore); - rewrittenExpression = boundLocal; - collectionVarInitializationPreamble = rewriter._factory.ExpressionStatement(valueStore); - preambleLocal = boundLocal.LocalSymbol; - } - - collectionTempRefKind = enumeratorInfo.InlineArraySpanType == WellKnownType.System_Span_T ? RefKind.Ref : RefKindExtensions.StrictIn; - return collectionVarInitializationPreamble; - }, - getItem: static (LocalRewriter rewriter, BoundForEachStatement node, BoundLocal boundArrayVar, BoundLocal boundPositionVar, object? _) => - { - MethodSymbol elementRef; - Debug.Assert(rewriter._factory.ModuleBuilderOpt is { }); - Debug.Assert(rewriter._diagnostics.DiagnosticBag is { }); - - var enumeratorInfo = node.EnumeratorInfoOpt; - Debug.Assert(enumeratorInfo is not null); - - NamedTypeSymbol intType = rewriter._factory.SpecialType(SpecialType.System_Int32); - if (enumeratorInfo.InlineArraySpanType == WellKnownType.System_Span_T) - { - elementRef = rewriter._factory.ModuleBuilderOpt.EnsureInlineArrayElementRefExists(node.Syntax, intType, rewriter._diagnostics.DiagnosticBag); - } - else - { - Debug.Assert(enumeratorInfo.InlineArraySpanType == WellKnownType.System_ReadOnlySpan_T); - elementRef = rewriter._factory.ModuleBuilderOpt.EnsureInlineArrayElementRefReadOnlyExists(node.Syntax, intType, rewriter._diagnostics.DiagnosticBag); - } - - TypeSymbol inlineArrayType = boundArrayVar.Type; - elementRef = elementRef.Construct(inlineArrayType, inlineArrayType.TryGetInlineArrayElementField()!.Type); - - return rewriter._factory.Call(null, elementRef, boundArrayVar, boundPositionVar, useStrictArgumentRefKinds: true); - }, - getLength: static (LocalRewriter rewriter, BoundForEachStatement node, BoundLocal boundArrayVar, object? _) => - { - _ = boundArrayVar.Type.HasInlineArrayAttribute(out int length); - Debug.Assert(length > 0); - BoundExpression arrayLength = rewriter._factory.Literal(length); - return arrayLength; - }, + getPreamble: GetInlineArrayForEachStatementPreambleDelegate(), + getItem: GetInlineArrayForEachStatementGetItemDelegate(), + getLength: GetInlineArrayForEachStatementGetLengthDelegate(), arg: null); } + private static GetForEachStatementAsForPreamble GetInlineArrayForEachStatementPreambleDelegate() + { + return static (LocalRewriter rewriter, SyntaxNode syntax, ForEachEnumeratorInfo enumeratorInfo, ref BoundExpression rewrittenExpression, out LocalSymbol? preambleLocal, out RefKind collectionTempRefKind) => + { + Debug.Assert(rewrittenExpression.Type is not null); + + BoundStatement? collectionVarInitializationPreamble = null; + preambleLocal = null; + if (enumeratorInfo.InlineArrayUsedAsValue) + { + BoundLocal boundLocal = rewriter._factory.StoreToTemp(rewrittenExpression, out BoundAssignmentOperator? valueStore); + rewrittenExpression = boundLocal; + collectionVarInitializationPreamble = rewriter._factory.ExpressionStatement(valueStore); + preambleLocal = boundLocal.LocalSymbol; + } + + collectionTempRefKind = enumeratorInfo.InlineArraySpanType == WellKnownType.System_Span_T ? RefKind.Ref : RefKindExtensions.StrictIn; + return collectionVarInitializationPreamble; + }; + } + + private static GetForEachStatementAsForItem GetInlineArrayForEachStatementGetItemDelegate() + { + return static (LocalRewriter rewriter, SyntaxNode syntax, ForEachEnumeratorInfo enumeratorInfo, BoundLocal boundArrayVar, BoundLocal boundPositionVar, object? _) => + { + MethodSymbol elementRef; + Debug.Assert(rewriter._factory.ModuleBuilderOpt is { }); + Debug.Assert(rewriter._diagnostics.DiagnosticBag is { }); + + NamedTypeSymbol intType = rewriter._factory.SpecialType(SpecialType.System_Int32); + if (enumeratorInfo.InlineArraySpanType == WellKnownType.System_Span_T) + { + elementRef = rewriter._factory.ModuleBuilderOpt.EnsureInlineArrayElementRefExists(syntax, intType, rewriter._diagnostics.DiagnosticBag); + } + else + { + Debug.Assert(enumeratorInfo.InlineArraySpanType == WellKnownType.System_ReadOnlySpan_T); + elementRef = rewriter._factory.ModuleBuilderOpt.EnsureInlineArrayElementRefReadOnlyExists(syntax, intType, rewriter._diagnostics.DiagnosticBag); + } + + TypeSymbol inlineArrayType = boundArrayVar.Type; + elementRef = elementRef.Construct(inlineArrayType, inlineArrayType.TryGetInlineArrayElementField()!.Type); + + return rewriter._factory.Call(null, elementRef, boundArrayVar, boundPositionVar, useStrictArgumentRefKinds: true); + }; + } + + private static GetForEachStatementAsForLength GetInlineArrayForEachStatementGetLengthDelegate() + { + return static (LocalRewriter rewriter, SyntaxNode syntax, BoundLocal boundArrayVar, object? _) => + { + _ = boundArrayVar.Type.HasInlineArrayAttribute(out int length); + Debug.Assert(length > 0); + BoundExpression arrayLength = rewriter._factory.Literal(length); + return arrayLength; + }; + } + /// /// Takes the expression for the current value of the iteration variable and either /// (1) assigns it into a local, or diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IfStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IfStatement.cs index e4f8d4642097b..6bdd62e1dfa93 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IfStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_IfStatement.cs @@ -6,8 +6,6 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Text; -using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.CSharp { @@ -16,87 +14,132 @@ internal sealed partial class LocalRewriter public override BoundNode VisitIfStatement(BoundIfStatement node) { Debug.Assert(node != null); - var rewrittenCondition = VisitExpression(node.Condition); - var rewrittenConsequence = VisitStatement(node.Consequence); - Debug.Assert(rewrittenConsequence is { }); - var rewrittenAlternative = VisitStatement(node.AlternativeOpt); - var syntax = (IfStatementSyntax)node.Syntax; - - // 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 condition are being executed. - if (this.Instrument && !node.WasCompilerGenerated) + + var stack = ArrayBuilder<(BoundIfStatement, GeneratedLabelSymbol, int)>.GetInstance(); + var builder = ArrayBuilder.GetInstance(); + + while (true) { - rewrittenCondition = Instrumenter.InstrumentIfStatementCondition(node, rewrittenCondition, _factory); - } + var rewrittenCondition = VisitExpression(node.Condition); + var rewrittenConsequence = VisitStatement(node.Consequence); + Debug.Assert(rewrittenConsequence is { }); + + // 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 condition are being executed. + if (this.Instrument && !node.WasCompilerGenerated) + { + rewrittenCondition = Instrumenter.InstrumentIfStatementCondition(node, rewrittenCondition, _factory); + } + + var elseIfStatement = node.AlternativeOpt as BoundIfStatement; + BoundStatement? rewrittenAlternative = null; + + if (elseIfStatement is null) + { + rewrittenAlternative = VisitStatement(node.AlternativeOpt); + } + + var afterif = new GeneratedLabelSymbol("afterif"); + stack.Push((node, afterif, builder.Count)); - var result = RewriteIfStatement(syntax, rewrittenCondition, rewrittenConsequence, rewrittenAlternative, node.HasErrors); + if (elseIfStatement is null && rewrittenAlternative is null) + { + // if (condition) + // consequence; + // + // becomes + // + // GotoIfFalse condition afterif; + // consequence; + // afterif: + + builder.Add(new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, afterif)); + builder.Add(rewrittenConsequence); + break; + } + else + { + // if (condition) + // consequence; + // else + // alternative; + // + // becomes + // + // GotoIfFalse condition alt; + // consequence + // goto afterif; + // alt: + // alternative; + // afterif: + + var alt = new GeneratedLabelSymbol("alternative"); + + builder.Add(new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, alt)); + builder.Add(rewrittenConsequence); + builder.Add(BoundSequencePoint.CreateHidden()); + var syntax = (IfStatementSyntax)node.Syntax; + builder.Add(new BoundGotoStatement(syntax, afterif)); + builder.Add(new BoundLabelStatement(syntax, alt)); + + if (rewrittenAlternative is not null) + { + builder.Add(rewrittenAlternative); + break; + } + + Debug.Assert(elseIfStatement is not null); + + node = elseIfStatement; + } + } - // add sequence point before the whole statement - if (this.Instrument && !node.WasCompilerGenerated) + do { - result = Instrumenter.InstrumentIfStatement(node, result); + (node, var afterif, var conditionalGotoIndex) = stack.Pop(); + Debug.Assert(builder[conditionalGotoIndex] is BoundConditionalGoto); + + var syntax = (IfStatementSyntax)node.Syntax; + + builder.Add(BoundSequencePoint.CreateHidden()); + builder.Add(new BoundLabelStatement(syntax, afterif)); + + // add sequence point before the whole statement + if (this.Instrument && !node.WasCompilerGenerated) + { + builder[conditionalGotoIndex] = Instrumenter.InstrumentIfStatementConditionalGoto(node, builder[conditionalGotoIndex]); + } } + while (stack.Any()); - return result; + stack.Free(); + return new BoundStatementList(node.Syntax, builder.ToImmutableAndFree(), node.HasErrors); } private static BoundStatement RewriteIfStatement( SyntaxNode syntax, BoundExpression rewrittenCondition, BoundStatement rewrittenConsequence, - BoundStatement? rewrittenAlternativeOpt, bool hasErrors) { var afterif = new GeneratedLabelSymbol("afterif"); var builder = ArrayBuilder.GetInstance(); - if (rewrittenAlternativeOpt == null) - { - // if (condition) - // consequence; - // - // becomes - // - // GotoIfFalse condition afterif; - // consequence; - // afterif: - - builder.Add(new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, afterif)); - builder.Add(rewrittenConsequence); - builder.Add(BoundSequencePoint.CreateHidden()); - builder.Add(new BoundLabelStatement(syntax, afterif)); - var statements = builder.ToImmutableAndFree(); - return new BoundStatementList(syntax, statements, hasErrors); - } - else - { - // if (condition) - // consequence; - // else - // alternative - // - // becomes - // - // GotoIfFalse condition alt; - // consequence - // goto afterif; - // alt: - // alternative; - // afterif: - - var alt = new GeneratedLabelSymbol("alternative"); - - builder.Add(new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, alt)); - builder.Add(rewrittenConsequence); - builder.Add(BoundSequencePoint.CreateHidden()); - builder.Add(new BoundGotoStatement(syntax, afterif)); - builder.Add(new BoundLabelStatement(syntax, alt)); - builder.Add(rewrittenAlternativeOpt); - builder.Add(BoundSequencePoint.CreateHidden()); - builder.Add(new BoundLabelStatement(syntax, afterif)); - return new BoundStatementList(syntax, builder.ToImmutableAndFree(), hasErrors); - } + // if (condition) + // consequence; + // + // becomes + // + // GotoIfFalse condition afterif; + // consequence; + // afterif: + builder.Add(new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, afterif)); + builder.Add(rewrittenConsequence); + builder.Add(BoundSequencePoint.CreateHidden()); + builder.Add(new BoundLabelStatement(syntax, afterif)); + var statements = builder.ToImmutableAndFree(); + return new BoundStatementList(syntax, statements, hasErrors); } } } diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_LockStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_LockStatement.cs index 7e90157dc9e37..7df64ae2978e2 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_LockStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_LockStatement.cs @@ -58,10 +58,12 @@ public override BoundNode VisitLockStatement(BoundLockStatement node) initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, lockTypeInfo.EnterScopeMethod); + // the temp must be associated with the lock statement to support EnC slot mapping: BoundLocal boundTemp = _factory.StoreToTemp(enterScopeCall, out BoundAssignmentOperator tempAssignment, - syntaxOpt: rewrittenArgument.Syntax, + syntaxOpt: lockSyntax, kind: SynthesizedLocalKind.Using); + var expressionStatement = new BoundExpressionStatement(rewrittenArgument.Syntax, tempAssignment); BoundStatement tryFinally = RewriteUsingStatementTryFinally( @@ -161,7 +163,6 @@ public override BoundNode VisitLockStatement(BoundLockStatement node) lockSyntax, boundLockTakenTemp, exitCall, - null, node.HasErrors); return new BoundBlock( diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PropertyAccess.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PropertyAccess.cs index 4d99b1d246af4..a315c14284fe4 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PropertyAccess.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_PropertyAccess.cs @@ -55,8 +55,8 @@ private BoundExpression MakePropertyAccess( // This node will be rewritten with MakePropertyAssignment when rewriting the enclosing BoundAssignmentOperator. return oldNodeOpt != null ? - oldNodeOpt.Update(rewrittenReceiverOpt, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, propertySymbol, resultKind, type) : - new BoundPropertyAccess(syntax, rewrittenReceiverOpt, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, propertySymbol, resultKind, type); + oldNodeOpt.Update(rewrittenReceiverOpt, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, propertySymbol, autoPropertyAccessorKind: AccessorKind.Unknown, resultKind, type) : + new BoundPropertyAccess(syntax, rewrittenReceiverOpt, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, propertySymbol, autoPropertyAccessorKind: AccessorKind.Unknown, resultKind, type); } else { @@ -83,8 +83,8 @@ private BoundExpression MakePropertyGetAccess( { Debug.Assert(argumentRefKindsOpt.IsDefaultOrEmpty); return oldNodeOpt != null ? - oldNodeOpt.Update(rewrittenReceiver, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, property, LookupResultKind.Viable, property.Type) : - new BoundPropertyAccess(syntax, rewrittenReceiver, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, property, LookupResultKind.Viable, property.Type); + oldNodeOpt.Update(rewrittenReceiver, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, property, autoPropertyAccessorKind: AccessorKind.Unknown, LookupResultKind.Viable, property.Type) : + new BoundPropertyAccess(syntax, rewrittenReceiver, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, property, autoPropertyAccessorKind: AccessorKind.Unknown, LookupResultKind.Viable, property.Type); } else { diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs index 249c7b23c0f1e..a7dcc68c4d583 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs @@ -410,7 +410,6 @@ private BoundStatement RewriteUsingStatementTryFinally( syntax: resourceSyntax, rewrittenCondition: ifCondition, rewrittenConsequence: disposeStatement, - rewrittenAlternativeOpt: null, hasErrors: false); } diff --git a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs index ee4c704645036..1f2fa70219430 100644 --- a/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/MethodToClassRewriter.cs @@ -223,7 +223,7 @@ public override BoundNode VisitPropertyAccess(BoundPropertyAccess node) { var rewrittenPropertySymbol = VisitPropertySymbol(node.PropertySymbol); var rewrittenReceiver = (BoundExpression?)Visit(node.ReceiverOpt); - return node.Update(rewrittenReceiver, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, rewrittenPropertySymbol, node.ResultKind, VisitType(node.Type)); + return node.Update(rewrittenReceiver, initialBindingReceiverIsSubjectToCloning: ThreeState.Unknown, rewrittenPropertySymbol, node.AutoPropertyAccessorKind, node.ResultKind, VisitType(node.Type)); } public override BoundNode VisitCall(BoundCall node) @@ -233,7 +233,11 @@ public override BoundNode VisitCall(BoundCall node) var rewrittenArguments = (ImmutableArray)this.VisitList(node.Arguments); var rewrittenType = this.VisitType(node.Type); - Debug.Assert(rewrittenMethodSymbol.IsMetadataVirtual() == node.Method.IsMetadataVirtual()); +#if DEBUG + // Calling IsMetadataVirtual with intent of getting a fully accurate result requires the symbol to be fully completed first + Debug.Assert(rewrittenMethodSymbol.IsMetadataVirtual(MethodSymbol.IsMetadataVirtualOption.ForceCompleteIfNeeded) + == node.Method.IsMetadataVirtual(MethodSymbol.IsMetadataVirtualOption.ForceCompleteIfNeeded)); +#endif // If the original receiver was a base access and it was rewritten, // change the method to point to the wrapper method diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs index 673a6c968cb4c..c0cd01051e1e0 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -159,7 +160,7 @@ public MethodToStateMachineRewriter( #nullable disable protected abstract StateMachineState FirstIncreasingResumableState { get; } - protected abstract string EncMissingStateMessage { get; } + protected abstract HotReloadExceptionCode EncMissingStateErrorCode { get; } /// /// Generate return statements from the state machine method body. @@ -217,7 +218,7 @@ protected void AddResumableState(ResumableStateMachineStateAllocator allocator, protected void AddStateDebugInfo(SyntaxNode node, AwaitDebugId awaitId, StateMachineState state) { - Debug.Assert(SyntaxBindingUtilities.BindsToResumableStateMachineState(node) || SyntaxBindingUtilities.BindsToTryStatement(node), $"Unexpected syntax: {node.Kind()}"); + RoslynDebug.Assert(SyntaxBindingUtilities.BindsToResumableStateMachineState(node) || SyntaxBindingUtilities.BindsToTryStatement(node), $"Unexpected syntax: {node.Kind()}"); int syntaxOffset = CurrentMethod.CalculateLocalSyntaxOffset(node.SpanStart, node.SyntaxTree); _stateDebugInfoBuilder.Add(new StateMachineStateDebugInfo(syntaxOffset, awaitId, state)); @@ -264,7 +265,7 @@ orderby kv.Value[0] } protected virtual BoundStatement? GenerateMissingStateDispatch() - => _resumableStateAllocator.GenerateThrowMissingStateDispatch(F, F.Local(cachedState), EncMissingStateMessage); + => _resumableStateAllocator.GenerateThrowMissingStateDispatch(F, F.Local(cachedState), EncMissingStateErrorCode); #nullable disable #if DEBUG diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/ResumableStateMachineStateAllocator.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/ResumableStateMachineStateAllocator.cs index 685dc8e1b6fc4..3df1d7d16811b 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/ResumableStateMachineStateAllocator.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/ResumableStateMachineStateAllocator.cs @@ -5,7 +5,11 @@ using System; using System.Diagnostics; using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.CSharp.Emit; +using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Emit; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { @@ -73,8 +77,10 @@ public StateMachineState AllocateState(SyntaxNode awaitOrYieldReturnSyntax, Awai public bool HasMissingStates => _matchedStateCount < Math.Abs((_slotAllocator?.GetFirstUnusedStateMachineState(_increasing) ?? _firstState) - _firstState); - public BoundStatement? GenerateThrowMissingStateDispatch(SyntheticBoundNodeFactory f, BoundExpression cachedState, string message) + public BoundStatement? GenerateThrowMissingStateDispatch(SyntheticBoundNodeFactory f, BoundExpression cachedState, HotReloadExceptionCode errorCode) { + Debug.Assert(f.ModuleBuilderOpt != null); + if (!HasMissingStates) { return null; @@ -88,8 +94,9 @@ public bool HasMissingStates f.Literal(_firstState)), f.Throw( f.New( - f.WellKnownMethod(WellKnownMember.System_InvalidOperationException__ctorString), - f.StringLiteral(ConstantValue.Create(message))))); + (MethodSymbol)f.ModuleBuilderOpt.GetOrCreateHotReloadExceptionConstructorDefinition(), + f.StringLiteral(ConstantValue.Create(errorCode.GetExceptionMessage())), + f.Literal(errorCode.GetExceptionCodeValue())))); } } } diff --git a/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj b/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj index 88fbaa39566d9..5efe2721532a9 100644 --- a/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj +++ b/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj @@ -87,6 +87,7 @@ + diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index 2b7e62c5393bc..715ff1e972c31 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -1801,15 +1801,44 @@ private IEmptyOperation CreateBoundNoOpStatementOperation(BoundNoOpStatement bou private IConditionalOperation CreateBoundIfStatementOperation(BoundIfStatement boundIfStatement) { - IOperation condition = Create(boundIfStatement.Condition); - IOperation whenTrue = Create(boundIfStatement.Consequence); - IOperation? whenFalse = Create(boundIfStatement.AlternativeOpt); - bool isRef = false; - SyntaxNode syntax = boundIfStatement.Syntax; - ITypeSymbol? type = null; - ConstantValue? constantValue = null; - bool isImplicit = boundIfStatement.WasCompilerGenerated; - return new ConditionalOperation(condition, whenTrue, whenFalse, isRef, _semanticModel, syntax, type, constantValue, isImplicit); + var stack = ArrayBuilder.GetInstance(); + + IOperation? whenFalse; + while (true) + { + stack.Push(boundIfStatement); + + var alternative = boundIfStatement.AlternativeOpt; + + if (alternative is BoundIfStatement elseIfStatement) + { + boundIfStatement = elseIfStatement; + } + else + { + whenFalse = Create(alternative); + break; + } + } + + ConditionalOperation result; + do + { + boundIfStatement = stack.Pop(); + IOperation condition = Create(boundIfStatement.Condition); + IOperation whenTrue = Create(boundIfStatement.Consequence); + bool isRef = false; + SyntaxNode syntax = boundIfStatement.Syntax; + ITypeSymbol? type = null; + ConstantValue? constantValue = null; + bool isImplicit = boundIfStatement.WasCompilerGenerated; + result = new ConditionalOperation(condition, whenTrue, whenFalse, isRef, _semanticModel, syntax, type, constantValue, isImplicit); + whenFalse = result; + } + while (stack.Any()); + + stack.Free(); + return result; } private IWhileLoopOperation CreateBoundWhileStatementOperation(BoundWhileStatement boundWhileStatement) @@ -2607,15 +2636,43 @@ private IOperation CreateBoundNegatedPatternOperation(BoundNegatedPattern boundN private IOperation CreateBoundBinaryPatternOperation(BoundBinaryPattern boundBinaryPattern) { - return new BinaryPatternOperation( - boundBinaryPattern.Disjunction ? BinaryOperatorKind.Or : BinaryOperatorKind.And, - (IPatternOperation)Create(boundBinaryPattern.Left), - (IPatternOperation)Create(boundBinaryPattern.Right), - boundBinaryPattern.InputType.GetPublicSymbol(), - boundBinaryPattern.NarrowedType.GetPublicSymbol(), - _semanticModel, - boundBinaryPattern.Syntax, - isImplicit: boundBinaryPattern.WasCompilerGenerated); + if (boundBinaryPattern.Left is not BoundBinaryPattern) + { + return createOperation(this, boundBinaryPattern, left: (IPatternOperation)Create(boundBinaryPattern.Left)); + } + + // Use a manual stack to avoid overflowing on deeply-nested binary patterns + var stack = ArrayBuilder.GetInstance(); + BoundBinaryPattern? current = boundBinaryPattern; + + do + { + stack.Push(current); + current = current.Left as BoundBinaryPattern; + } while (current != null); + + current = stack.Pop(); + var result = (IPatternOperation)Create(current.Left); + do + { + result = createOperation(this, current, result); + } while (stack.TryPop(out current)); + + stack.Free(); + return result; + + static BinaryPatternOperation createOperation(CSharpOperationFactory @this, BoundBinaryPattern boundBinaryPattern, IPatternOperation left) + { + return new BinaryPatternOperation( + boundBinaryPattern.Disjunction ? BinaryOperatorKind.Or : BinaryOperatorKind.And, + left, + (IPatternOperation)@this.Create(boundBinaryPattern.Right), + boundBinaryPattern.InputType.GetPublicSymbol(), + boundBinaryPattern.NarrowedType.GetPublicSymbol(), + @this._semanticModel, + boundBinaryPattern.Syntax, + isImplicit: boundBinaryPattern.WasCompilerGenerated); + } } private ISwitchOperation CreateBoundSwitchStatementOperation(BoundSwitchStatement boundSwitchStatement) diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 887dfabee8fb7..1b2c4707840fb 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -412,6 +412,159 @@ private void ParseNamespaceBody( ref NamespaceBodyBuilder body, ref SyntaxListBuilder? initialBadNodes, SyntaxKind parentKind) + { + ParseNamespaceBodyWorker( + ref openBraceOrSemicolon, ref body, ref initialBadNodes, parentKind, out var sawMemberDeclarationOnlyValidWithinTypeDeclaration); + + // In the common case, we will not see errant type-only member declarations in the namespace itself. In + // that case, we have no extra work to do and can return immediately. + // + // If we do see errant type-only members (like a method/property/constructor/etc.), then see if they follow + // some normal type declaration. If so, it's likely there was a misplaced close curly that preemptively + // ended the type declaration, and the member declaration was supposed to go in it instead. + if (!sawMemberDeclarationOnlyValidWithinTypeDeclaration) + return; + + // In a script file, it can be ok to have these members at the top level. For example, a field is actually + // ok to parse out at the top level as it will become a field on the script global object. + if (IsScript && parentKind == SyntaxKind.CompilationUnit) + return; + + var finalMembers = _pool.Allocate(); + + // Do a single linear sweep, examining each type declaration we run into within the namespace. + for (var currentBodyMemberIndex = 0; currentBodyMemberIndex < body.Members.Count;) + { + var currentMember = body.Members[currentBodyMemberIndex]; + + // If we have a suitable type declaration that ended without problem (has a real close curly and no + // trailing semicolon), then see if there are any type-only members following it that should be moved + // into it. + if (currentMember is TypeDeclarationSyntax + { + SemicolonToken: null, + CloseBraceToken: { IsMissing: false, ContainsDiagnostics: false } + } currentTypeDeclaration) + { + var siblingsToMoveIntoType = determineSiblingsToMoveIntoType(typeDeclarationIndex: currentBodyMemberIndex, body); + if (siblingsToMoveIntoType is (var firstSiblingToMoveInclusive, var lastSiblingToMoveExclusive)) + { + // We found sibling type-only members. Move them into the preceding type declaration. + var finalTypeDeclaration = moveSiblingMembersIntoPrecedingType( + currentTypeDeclaration, body, firstSiblingToMoveInclusive, lastSiblingToMoveExclusive); + finalMembers.Add(finalTypeDeclaration); + + // We moved a sequence of type-only-members into the preceding type declaration. We need to + // continue processing from the end of that sequence. + currentBodyMemberIndex = lastSiblingToMoveExclusive; + continue; + } + } + + // Simple case. A normal namespace member we don't need to do anything with. + finalMembers.Add(currentMember); + currentBodyMemberIndex++; + } + + _pool.Free(body.Members); + body.Members = finalMembers; + + return; + + (int firstSiblingToMoveInclusive, int lastSiblingToMoveExclusive)? determineSiblingsToMoveIntoType( + int typeDeclarationIndex, + in NamespaceBodyBuilder body) + { + var startInclusive = typeDeclarationIndex + 1; + if (startInclusive < body.Members.Count && + IsMemberDeclarationOnlyValidWithinTypeDeclaration(body.Members[startInclusive])) + { + var endExclusive = startInclusive + 1; + + while (endExclusive < body.Members.Count && + IsMemberDeclarationOnlyValidWithinTypeDeclaration(body.Members[endExclusive])) + { + endExclusive++; + } + + return (startInclusive, endExclusive); + } + + return null; + } + + TypeDeclarationSyntax moveSiblingMembersIntoPrecedingType( + TypeDeclarationSyntax typeDeclaration, + in NamespaceBodyBuilder body, + int firstSiblingToMoveInclusive, + int lastSiblingToMoveExclusive) + { + var finalTypeDeclarationMembers = _pool.Allocate(); + finalTypeDeclarationMembers.AddRange(typeDeclaration.Members); + + for (var memberToMoveIndex = firstSiblingToMoveInclusive; memberToMoveIndex < lastSiblingToMoveExclusive; memberToMoveIndex++) + { + var currentSibling = body.Members[memberToMoveIndex]; + if (memberToMoveIndex == firstSiblingToMoveInclusive) + { + // Move the existing close brace token to the first member as a skipped token, with a + // diagnostic saying that it was unexpected. + currentSibling = AddLeadingSkippedSyntax( + currentSibling, + AddError(typeDeclaration.CloseBraceToken, ErrorCode.ERR_InvalidMemberDecl, "}")); + } + + finalTypeDeclarationMembers.Add(currentSibling); + } + + var isLast = lastSiblingToMoveExclusive == body.Members.Count; + + // The existing close brace token is moved to the first member as a skipped token, with a diagnostic saying + // it was unexpected. The type decl will then get a missing close brace token if there are still members + // following. If not, we'll try to eat an actual close brace token. + var finalCloseBraceToken = isLast + ? EatToken(SyntaxKind.CloseBraceToken) + : AddError( + SyntaxFactory.MissingToken(SyntaxKind.CloseBraceToken), ErrorCode.ERR_RbraceExpected); + var newMembers = _pool.ToListAndFree(finalTypeDeclarationMembers); + + return typeDeclaration.UpdateCore( + typeDeclaration.AttributeLists, + typeDeclaration.Modifiers, + typeDeclaration.Keyword, + typeDeclaration.Identifier, + typeDeclaration.TypeParameterList, + typeDeclaration.ParameterList, + typeDeclaration.BaseList, + typeDeclaration.ConstraintClauses, + typeDeclaration.OpenBraceToken, + newMembers, + finalCloseBraceToken, + typeDeclaration.SemicolonToken); + } + } + + private static bool IsMemberDeclarationOnlyValidWithinTypeDeclaration(MemberDeclarationSyntax? memberDeclaration) + { + return memberDeclaration?.Kind + is SyntaxKind.ConstructorDeclaration + or SyntaxKind.ConversionOperatorDeclaration + or SyntaxKind.DestructorDeclaration + or SyntaxKind.EventDeclaration + or SyntaxKind.EventFieldDeclaration + or SyntaxKind.FieldDeclaration + or SyntaxKind.IndexerDeclaration + or SyntaxKind.MethodDeclaration + or SyntaxKind.OperatorDeclaration + or SyntaxKind.PropertyDeclaration; + } + + private void ParseNamespaceBodyWorker( + [NotNullIfNotNull(nameof(openBraceOrSemicolon))] ref SyntaxToken? openBraceOrSemicolon, + ref NamespaceBodyBuilder body, + ref SyntaxListBuilder? initialBadNodes, + SyntaxKind parentKind, + out bool sawMemberDeclarationOnlyValidWithinTypeDeclaration) { // "top-level" expressions and statements should never occur inside an asynchronous context Debug.Assert(!IsInAsync); @@ -424,6 +577,8 @@ private void ParseNamespaceBody( var pendingIncompleteMembers = _pool.Allocate(); bool reportUnexpectedToken = true; + sawMemberDeclarationOnlyValidWithinTypeDeclaration = false; + try { while (true) @@ -561,7 +716,11 @@ private void ParseNamespaceBody( goto default; default: - var memberOrStatement = isGlobal ? this.ParseMemberDeclarationOrStatement(parentKind) : this.ParseMemberDeclaration(parentKind); + var memberOrStatement = isGlobal + ? this.ParseMemberDeclarationOrStatement(parentKind) + : this.ParseMemberDeclaration(parentKind); + + sawMemberDeclarationOnlyValidWithinTypeDeclaration |= IsMemberDeclarationOnlyValidWithinTypeDeclaration(memberOrStatement); if (memberOrStatement == null) { // incomplete members must be processed before we add any nodes to the body: @@ -2474,7 +2633,7 @@ private MemberDeclarationSyntax ParseMemberDeclarationOrStatementCore(SyntaxKind this.Reset(ref afterAttributesPoint); if (this.CurrentToken.Kind is not SyntaxKind.CloseBraceToken and not SyntaxKind.EndOfFileToken && - this.IsPossibleStatement(acceptAccessibilityMods: true)) + this.IsPossibleStatement()) { var saveTerm = _termState; _termState |= TerminatorState.IsPossibleStatementStartOrStop; // partial statements can abort if a new statement starts @@ -2654,7 +2813,7 @@ bool tryParseStatement(SyntaxList attributes, ref ResetPoin this.Reset(ref afterAttributesPoint); - if (this.IsPossibleStatement(acceptAccessibilityMods: false)) + if (this.IsPossibleStatement()) { var saveTerm = _termState; _termState |= TerminatorState.IsPossibleStatementStartOrStop; // partial statements can abort if a new statement starts @@ -3610,12 +3769,41 @@ private SyntaxToken TryEatCheckedOrHandleUnchecked(ref SyntaxToken operatorKeywo return TryEatToken(SyntaxKind.CheckedKeyword); } - private OperatorDeclarationSyntax ParseOperatorDeclaration( + private MemberDeclarationSyntax ParseOperatorDeclaration( SyntaxList attributes, SyntaxListBuilder modifiers, TypeSyntax type, ExplicitInterfaceSpecifierSyntax explicitInterfaceOpt) { + // We can get here after seeing `explicit` or `implicit` or `operator`. `ret-type explicit op ...` is not + // legal though. + var firstToken = this.CurrentToken; + if (firstToken.Kind is SyntaxKind.ExplicitKeyword or SyntaxKind.ImplicitKeyword && + this.PeekToken(1).Kind is SyntaxKind.OperatorKeyword) + { + var conversionOperator = TryParseConversionOperatorDeclaration(attributes, modifiers); + if (conversionOperator is not null) + { + // We need to ensure the type syntax the user provided gets an appropriate error and is placed as + // leading skipped trivia for the explicit/implicit keyword. + var newImplicitOrExplicitKeyword = AddLeadingSkippedSyntax( + conversionOperator.ImplicitOrExplicitKeyword, + AddError(type, ErrorCode.ERR_BadOperatorSyntax, firstToken.Text)); + return conversionOperator.Update( + conversionOperator.AttributeLists, + conversionOperator.Modifiers, + newImplicitOrExplicitKeyword, + conversionOperator.ExplicitInterfaceSpecifier, + conversionOperator.OperatorKeyword, + conversionOperator.CheckedKeyword, + conversionOperator.Type, + conversionOperator.ParameterList, + conversionOperator.Body, + conversionOperator.ExpressionBody, + conversionOperator.SemicolonToken); + } + } + var opKeyword = this.EatToken(SyntaxKind.OperatorKeyword); var checkedKeyword = TryEatCheckedOrHandleUnchecked(ref opKeyword); SyntaxToken opToken; @@ -3781,7 +3969,7 @@ private IndexerDeclarationSyntax ParseIndexerDeclaration( } else { - accessorList = this.ParseAccessorList(isEvent: false); + accessorList = this.ParseAccessorList(AccessorDeclaringKind.Indexer); if (this.CurrentToken.Kind == SyntaxKind.SemicolonToken) { semicolon = this.EatTokenWithPrejudice(ErrorCode.ERR_UnexpectedSemicolon); @@ -3835,7 +4023,7 @@ private PropertyDeclarationSyntax ParsePropertyDeclaration( Debug.Assert(IsStartOfPropertyBody(this.CurrentToken.Kind)); var accessorList = this.CurrentToken.Kind == SyntaxKind.OpenBraceToken - ? this.ParseAccessorList(isEvent: false) + ? this.ParseAccessorList(AccessorDeclaringKind.Property) : null; ArrowExpressionClauseSyntax expressionBody = null; @@ -3844,7 +4032,10 @@ private PropertyDeclarationSyntax ParsePropertyDeclaration( // Check for expression body if (this.CurrentToken.Kind == SyntaxKind.EqualsGreaterThanToken) { - expressionBody = this.ParseArrowExpressionClause(); + using (new FieldKeywordContext(this, isInFieldKeywordContext: true)) + { + expressionBody = this.ParseArrowExpressionClause(); + } } // Check if we have an initializer else if (this.CurrentToken.Kind == SyntaxKind.EqualsToken) @@ -3876,7 +4067,32 @@ private PropertyDeclarationSyntax ParsePropertyDeclaration( semicolon); } - private AccessorListSyntax ParseAccessorList(bool isEvent) + private readonly ref struct FieldKeywordContext : IDisposable + { + private readonly LanguageParser _parser; + private readonly bool _previousInFieldKeywordContext; + + public FieldKeywordContext(LanguageParser parser, bool isInFieldKeywordContext) + { + _parser = parser; + _previousInFieldKeywordContext = parser.IsInFieldKeywordContext; + _parser.IsInFieldKeywordContext = isInFieldKeywordContext; + } + + public void Dispose() + { + _parser.IsInFieldKeywordContext = _previousInFieldKeywordContext; + } + } + + private enum AccessorDeclaringKind + { + Property, + Indexer, + Event, + } + + private AccessorListSyntax ParseAccessorList(AccessorDeclaringKind declaringKind) { var openBrace = this.EatToken(SyntaxKind.OpenBraceToken); var accessors = default(SyntaxList); @@ -3894,11 +4110,11 @@ private AccessorListSyntax ParseAccessorList(bool isEvent) } else if (this.IsPossibleAccessor()) { - var acc = this.ParseAccessorDeclaration(isEvent); + var acc = this.ParseAccessorDeclaration(declaringKind); builder.Add(acc); } else if (this.SkipBadAccessorListTokens(ref openBrace, builder, - isEvent ? ErrorCode.ERR_AddOrRemoveExpected : ErrorCode.ERR_GetOrSetExpected) == PostSkipAction.Abort) + declaringKind == AccessorDeclaringKind.Event ? ErrorCode.ERR_AddOrRemoveExpected : ErrorCode.ERR_GetOrSetExpected) == PostSkipAction.Abort) { break; } @@ -4150,20 +4366,22 @@ private PostSkipAction SkipBadTokensWithErrorCode( return action; } - private AccessorDeclarationSyntax ParseAccessorDeclaration(bool isEvent) + private AccessorDeclarationSyntax ParseAccessorDeclaration(AccessorDeclaringKind declaringKind) { if (this.IsIncrementalAndFactoryContextMatches && SyntaxFacts.IsAccessorDeclaration(this.CurrentNodeKind)) { return (AccessorDeclarationSyntax)this.EatNode(); } + using var __ = new FieldKeywordContext(this, isInFieldKeywordContext: declaringKind is AccessorDeclaringKind.Property); + var accMods = _pool.Allocate(); var accAttrs = this.ParseAttributeDeclarations(inExpressionContext: false); this.ParseModifiers(accMods, forAccessors: true, forTopLevelStatements: false, isPossibleTypeDeclaration: out _); var accessorName = this.EatToken(SyntaxKind.IdentifierToken, - isEvent ? ErrorCode.ERR_AddOrRemoveExpected : ErrorCode.ERR_GetOrSetExpected); + declaringKind == AccessorDeclaringKind.Event ? ErrorCode.ERR_AddOrRemoveExpected : ErrorCode.ERR_GetOrSetExpected); var accessorKind = GetAccessorKind(accessorName); // Only convert the identifier to a keyword if it's a valid one. Otherwise any @@ -4179,7 +4397,7 @@ private AccessorDeclarationSyntax ParseAccessorDeclaration(bool isEvent) if (!accessorName.IsMissing) { accessorName = this.AddError(accessorName, - isEvent ? ErrorCode.ERR_AddOrRemoveExpected : ErrorCode.ERR_GetOrSetExpected); + declaringKind == AccessorDeclaringKind.Event ? ErrorCode.ERR_AddOrRemoveExpected : ErrorCode.ERR_GetOrSetExpected); } else { @@ -4723,7 +4941,7 @@ private EventDeclarationSyntax ParseEventDeclarationWithAccessors( } else { - accessorList = this.ParseAccessorList(isEvent: true); + accessorList = this.ParseAccessorList(AccessorDeclaringKind.Event); } var decl = _syntaxFactory.EventDeclaration( @@ -5581,6 +5799,13 @@ private bool IsCurrentTokenPartialKeywordOfPartialMethodOrType() return false; } + private bool IsCurrentTokenFieldInKeywordContext() + { + return CurrentToken.ContextualKind == SyntaxKind.FieldKeyword && + IsInFieldKeywordContext && + IsFeatureEnabled(MessageID.IDS_FeatureFieldKeyword); + } + private TypeParameterListSyntax ParseTypeParameterList() { if (this.CurrentToken.Kind != SyntaxKind.LessThanToken) @@ -7126,33 +7351,17 @@ private TypeSyntax ParseTypeCore(ParseTypeMode mode) { switch (this.CurrentToken.Kind) { - case SyntaxKind.QuestionToken when canBeNullableType(): + case SyntaxKind.QuestionToken: { - var question = EatNullableQualifierIfApplicable(mode); + var question = TryEatNullableQualifierIfApplicable(type, mode); if (question != null) { type = _syntaxFactory.NullableType(type, question); continue; } - goto done; // token not consumed - } - bool canBeNullableType() - { - // These are the fast tests for (in)applicability. - // More expensive tests are in `EatNullableQualifierIfApplicable` - if (type.Kind == SyntaxKind.NullableType || type.Kind == SyntaxKind.PointerType) - return false; - if (this.PeekToken(1).Kind == SyntaxKind.OpenBracketToken) - return true; - if (mode == ParseTypeMode.DefinitePattern) - return true; // Permit nullable type parsing and report while binding for a better error message - if (mode == ParseTypeMode.NewExpression && type.Kind == SyntaxKind.TupleType && - this.PeekToken(1).Kind is not SyntaxKind.OpenParenToken and not SyntaxKind.OpenBraceToken) - { - return false; // Permit `new (int, int)?(t)` (creation) and `new (int, int) ? x : y` (conditional) - } - return true; + // token not consumed + break; } case SyntaxKind.AsteriskToken: switch (mode) @@ -7177,7 +7386,9 @@ bool canBeNullableType() type = this.ParsePointerTypeMods(type); continue; } - goto done; // token not consumed + + // token not consumed + break; case SyntaxKind.OpenBracketToken: // Now check for arrays. { @@ -7192,25 +7403,37 @@ bool canBeNullableType() continue; } default: - goto done; // token not consumed + // token not consumed + break; } + + // token not consumed + break; } -done:; Debug.Assert(type != null); return type; } - private SyntaxToken EatNullableQualifierIfApplicable(ParseTypeMode mode) + private SyntaxToken TryEatNullableQualifierIfApplicable( + TypeSyntax typeParsedSoFar, ParseTypeMode mode) { Debug.Assert(this.CurrentToken.Kind == SyntaxKind.QuestionToken); - using var resetPoint = this.GetDisposableResetPoint(resetOnDispose: false); + + // These are the fast tests for (in)applicability. More expensive tests are follow. + // + // If we already have `x?` or `x*` then do not parse out a nullable type if we see `x??` or `x*?`. These + // are never legal as types in the language, so we can fast bail out. + if (typeParsedSoFar.Kind is SyntaxKind.NullableType or SyntaxKind.PointerType) + return null; + + using var outerResetPoint = this.GetDisposableResetPoint(resetOnDispose: false); var questionToken = this.EatToken(); if (!canFollowNullableType()) { // Restore current token index - resetPoint.Reset(); + outerResetPoint.Reset(); return null; } @@ -7218,6 +7441,43 @@ private SyntaxToken EatNullableQualifierIfApplicable(ParseTypeMode mode) bool canFollowNullableType() { + if (mode == ParseTypeMode.AfterIs && this.CurrentToken.Kind is SyntaxKind.OpenBracketToken) + { + // T?[ + // + // This could be a array of nullable types (e.g. `is T?[]` or `is T?[,]`) or it's a + // conditional with a collection expression or lambda (e.g. `is T ? [...] :` or `is T ? [Attr]() => ...`) + // + // Note: `is T?[]` could be the start of either. So we have to look to see if we have a + // `:` to know which case we're in. + + switch (this.PeekToken(1).Kind) + { + // `is T?[,]`. Definitely an array of nullable type. + case SyntaxKind.CommaToken: + return true; + + // `is T?[]`. Could be an array of a nullable type, or a conditional. Have to + // see if it is followed by `:` to find out. If there is a colon, it's a + // conditional. + case SyntaxKind.CloseBracketToken: + { + using var _ = this.GetDisposableResetPoint(resetOnDispose: true); + + // Consume the expression after the `?`. + var whenTrue = this.ParsePossibleRefExpression(); + + // Now see if we have a ':' following. If so, this is a conditional. If not, it's a nullable type. + return this.CurrentToken.Kind != SyntaxKind.ColonToken; + } + + // `is T ? [...`. Not an array. This is a conditional with a collection expr + // or attributed lambda. + default: + return false; + } + } + switch (mode) { case ParseTypeMode.AfterIs: @@ -7237,16 +7497,23 @@ bool canFollowNullableType() // nullable-typed pattern if (IsTrueIdentifier(this.CurrentToken)) { - // In a non-async method, `await` is a simple identifier. However, if we see `x ? await` + // 1. `async` can start a simple lambda in a conditional expression + // (e.g. `x is Y ? async a => ...`). The correct behavior is to treat `async` as a keyword + // 2. In a non-async method, `await` is a simple identifier. However, if we see `x ? await` // it's almost certainly the start of an `await expression` in a conditional expression // (e.g. `x is Y ? await ...`), not a nullable type pattern (since users would not use // 'await' as the name of a variable). So just treat this as a conditional expression. - // Similarly, `async` can start a simple lambda in a conditional expression - // (e.g. `x is Y ? async a => ...`). The correct behavior is to treat `async` as a keyword - if (this.CurrentToken.ContextualKind is SyntaxKind.AsyncKeyword or SyntaxKind.AwaitKeyword) + // 3. `from` most likely starts a linq query: `x is Y ? from item in collection select item : ...` + if (this.CurrentToken.ContextualKind is SyntaxKind.AsyncKeyword or SyntaxKind.AwaitKeyword or SyntaxKind.FromKeyword) + return false; + + var nextToken = PeekToken(1); + + // Cases like `x is Y ? someRecord with { } : ...` + if (nextToken.ContextualKind == SyntaxKind.WithKeyword) return false; - var nextTokenKind = PeekToken(1).Kind; + var nextTokenKind = nextToken.Kind; // These token either 100% end a pattern or start a new one: @@ -7291,7 +7558,10 @@ bool canFollowNullableType() // If nothing from above worked permit the nullable qualifier if it is followed by a token that // could not start an expression. If we have `T?[]` we do want to treat that as an array of // nullables (following existing parsing), not a conditional that returns a list. - return !CanStartExpression() || this.CurrentToken.Kind is SyntaxKind.OpenBracketToken; + if (this.CurrentToken.Kind is SyntaxKind.OpenBracketToken) + return true; + + return !CanStartExpression(); case ParseTypeMode.NewExpression: // A nullable qualifier is permitted as part of the type in a `new` expression. e.g. `new // int?()` is allowed. It creates a null value of type `Nullable`. Similarly `new int? {}` @@ -7750,9 +8020,9 @@ or SyntaxKind.MinusMinusToken /// Those will instead be parsed out as script-fields/methods. private StatementSyntax ParseStatementCore(SyntaxList attributes, bool isGlobal) { - if (canReuseStatement(attributes, isGlobal)) + if (TryReuseStatement(attributes, isGlobal) is { } reused) { - return (StatementSyntax)this.EatNode(); + return reused; } ResetPoint resetPointBeforeStatement = this.GetResetPoint(); @@ -7828,14 +8098,19 @@ private StatementSyntax ParseStatementCore(SyntaxList attri _recursionDepth--; this.Release(ref resetPointBeforeStatement); } + } - bool canReuseStatement(SyntaxList attributes, bool isGlobal) + private StatementSyntax TryReuseStatement(SyntaxList attributes, bool isGlobal) + { + if (this.IsIncrementalAndFactoryContextMatches && + this.CurrentNode is Syntax.StatementSyntax && + !isGlobal && // Top-level statements are reused by ParseMemberDeclarationOrStatementCore when possible. + attributes.Count == 0) { - return this.IsIncrementalAndFactoryContextMatches && - this.CurrentNode is Syntax.StatementSyntax && - !isGlobal && // Top-level statements are reused by ParseMemberDeclarationOrStatementCore when possible. - attributes.Count == 0; + return (StatementSyntax)this.EatNode(); } + + return null; } private StatementSyntax ParseStatementCoreRest(SyntaxList attributes, bool isGlobal, ref ResetPoint resetPointBeforeStatement) @@ -8540,7 +8815,7 @@ private void ParseStatements(ref CSharpSyntaxNode previousNode, SyntaxListBuilde && !(stopOnSwitchSections && this.IsPossibleSwitchSection()) && IsMakingProgress(ref lastTokenPosition)) { - if (this.IsPossibleStatement(acceptAccessibilityMods: true)) + if (this.IsPossibleStatement()) { var statement = this.ParsePossiblyAttributedStatement(); if (statement != null) @@ -8569,7 +8844,7 @@ private void ParseStatements(ref CSharpSyntaxNode previousNode, SyntaxListBuilde private bool IsPossibleStatementStartOrStop() { return this.CurrentToken.Kind == SyntaxKind.SemicolonToken - || this.IsPossibleStatement(acceptAccessibilityMods: true); + || this.IsPossibleStatement(); } private PostSkipAction SkipBadStatementListTokens(SyntaxListBuilder statements, SyntaxKind expected, out GreenNode trailingTrivia) @@ -8579,14 +8854,14 @@ private PostSkipAction SkipBadStatementListTokens(SyntaxListBuilder !p.IsPossibleStatement(acceptAccessibilityMods: false), + static p => !p.IsPossibleStatement(), static (p, _) => p.CurrentToken.Kind == SyntaxKind.CloseBraceToken, expected, closeKind: SyntaxKind.None, out trailingTrivia); } - private bool IsPossibleStatement(bool acceptAccessibilityMods) + private bool IsPossibleStatement() { var tk = this.CurrentToken.Kind; switch (tk) @@ -8625,14 +8900,6 @@ private bool IsPossibleStatement(bool acceptAccessibilityMods) case SyntaxKind.IdentifierToken: return IsTrueIdentifier(); - // Accessibility modifiers are not legal in a statement, - // but a common mistake for local functions. Parse to give a - // better error message. - case SyntaxKind.PublicKeyword: - case SyntaxKind.InternalKeyword: - case SyntaxKind.ProtectedKeyword: - case SyntaxKind.PrivateKeyword: - return acceptAccessibilityMods; default: return IsPredefinedType(tk) || IsPossibleExpression(); @@ -9357,14 +9624,65 @@ private IfStatementSyntax ParseIfStatement(SyntaxList attri { Debug.Assert(this.CurrentToken.Kind == SyntaxKind.IfKeyword); - return _syntaxFactory.IfStatement( - attributes, - this.EatToken(SyntaxKind.IfKeyword), - this.EatToken(SyntaxKind.OpenParenToken), - this.ParseExpressionCore(), - this.EatToken(SyntaxKind.CloseParenToken), - this.ParseEmbeddedStatement(), - this.ParseElseClauseOpt()); + var stack = ArrayBuilder<(SyntaxToken, SyntaxToken, ExpressionSyntax, SyntaxToken, StatementSyntax, SyntaxToken)>.GetInstance(); + + StatementSyntax alternative = null; + while (true) + { + var ifKeyword = this.EatToken(SyntaxKind.IfKeyword); + var openParen = this.EatToken(SyntaxKind.OpenParenToken); + var condition = this.ParseExpressionCore(); + var closeParen = this.EatToken(SyntaxKind.CloseParenToken); + var consequence = this.ParseEmbeddedStatement(); + + var elseKeyword = this.CurrentToken.Kind != SyntaxKind.ElseKeyword ? + null : + this.EatToken(SyntaxKind.ElseKeyword); + stack.Push((ifKeyword, openParen, condition, closeParen, consequence, elseKeyword)); + + if (elseKeyword is null) + { + alternative = null; + break; + } + + if (this.CurrentToken.Kind != SyntaxKind.IfKeyword) + { + alternative = this.ParseEmbeddedStatement(); + break; + } + + alternative = TryReuseStatement(attributes: default, isGlobal: false); + if (alternative is not null) + { + break; + } + } + + IfStatementSyntax ifStatement; + do + { + var (ifKeyword, openParen, condition, closeParen, consequence, elseKeyword) = stack.Pop(); + var elseClause = alternative is null ? + null : + _syntaxFactory.ElseClause( + elseKeyword, + alternative); + ifStatement = _syntaxFactory.IfStatement( + attributeLists: stack.Any() ? default : attributes, + ifKeyword, + openParen, + condition, + closeParen, + consequence, + elseClause); + alternative = ifStatement; + } + while (stack.Any()); + + stack.Free(); + + return ifStatement; } private IfStatementSyntax ParseMisplacedElse(SyntaxList attributes) @@ -10572,6 +10890,7 @@ private static Precedence GetPrecedence(SyntaxKind op) case SyntaxKind.DefaultLiteralExpression: case SyntaxKind.ElementAccessExpression: case SyntaxKind.FalseLiteralExpression: + case SyntaxKind.FieldExpression: case SyntaxKind.GenericName: case SyntaxKind.IdentifierName: case SyntaxKind.ImplicitArrayCreationExpression: @@ -10973,13 +11292,16 @@ private ExpressionSyntax ParseExpressionContinued(ExpressionSyntax leftOperand, } } - // From the language spec: + // https://github.com/dotnet/csharpstandard/blob/standard-v6/standard/expressions.md#1115-conditional-operator: // - // conditional-expression: - // null-coalescing-expression - // null-coalescing-expression ? expression : expression + // conditional_expression + // : null_coalescing_expression + // | null_coalescing_expression '?' expression ':' expression + // ; // - // Only take the conditional if we're at or below its precedence. + // 1. Only take the conditional part of the expression if we're at or below its precedence. + // 2. When parsing the branches of the expression, parse at the highest precedence again ('expression'). + // This allows for things like assignments/lambdas in the branches of the conditional. if (CurrentToken.Kind != SyntaxKind.QuestionToken || precedence > Precedence.Conditional) return leftOperand; @@ -11163,6 +11485,10 @@ private ExpressionSyntax ParseTermWithoutPostfix(Precedence precedence) { return ParseDeclarationExpression(ParseTypeMode.Normal, isScoped: false); } + else if (IsCurrentTokenFieldInKeywordContext() && PeekToken(1).Kind != SyntaxKind.ColonColonToken) + { + return _syntaxFactory.FieldExpression(this.EatContextualToken(SyntaxKind.FieldKeyword)); + } else { return this.ParseAliasQualifiedName(NameOptions.InExpression); @@ -13553,7 +13879,8 @@ private bool IsIncrementalAndFactoryContextMatches internal static bool MatchesFactoryContext(GreenNode green, SyntaxFactoryContext context) { return context.IsInAsync == green.ParsedInAsync && - context.IsInQuery == green.ParsedInQuery; + context.IsInQuery == green.ParsedInQuery && + context.IsInFieldKeywordContext == green.ParsedInFieldKeywordContext; } private bool IsInAsync @@ -13574,6 +13901,12 @@ private bool IsInQuery set => _syntaxFactoryContext.IsInQuery = value; } + private bool IsInFieldKeywordContext + { + get => _syntaxFactoryContext.IsInFieldKeywordContext; + set => _syntaxFactoryContext.IsInFieldKeywordContext = value; + } + private delegate PostSkipAction SkipBadTokens( LanguageParser parser, ref SyntaxToken openToken, SeparatedSyntaxListBuilder builder, SyntaxKind expectedKind, SyntaxKind closeTokenKind) where TNode : GreenNode; @@ -13736,7 +14069,8 @@ private DisposableResetPoint GetDisposableResetPoint(bool resetOnDispose) base.GetResetPoint(), _termState, IsInAsync, - IsInQuery); + IsInQuery, + IsInFieldKeywordContext); } private void Reset(ref ResetPoint state) @@ -13744,6 +14078,7 @@ private void Reset(ref ResetPoint state) _termState = state.TerminatorState; IsInAsync = state.IsInAsync; IsInQuery = state.IsInQuery; + IsInFieldKeywordContext = state.IsInFieldKeywordContext; base.Reset(ref state.BaseResetPoint); } @@ -13783,17 +14118,20 @@ public void Dispose() internal readonly TerminatorState TerminatorState; internal readonly bool IsInAsync; internal readonly bool IsInQuery; + internal readonly bool IsInFieldKeywordContext; internal ResetPoint( SyntaxParser.ResetPoint resetPoint, TerminatorState terminatorState, bool isInAsync, - bool isInQuery) + bool isInQuery, + bool isInFieldKeywordContext) { this.BaseResetPoint = resetPoint; this.TerminatorState = terminatorState; this.IsInAsync = isInAsync; this.IsInQuery = isInQuery; + this.IsInFieldKeywordContext = isInFieldKeywordContext; } } diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser_InterpolatedString.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser_InterpolatedString.cs index a411e508c9d1d..782da84abe473 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser_InterpolatedString.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser_InterpolatedString.cs @@ -345,7 +345,7 @@ private static int ConsumeRemainingContentThroughNewLine(StringBuilder content, } var slice = text[start..currentIndex]; -#if NETCOREAPP +#if NET content.Append(slice); #else unsafe diff --git a/src/Compilers/CSharp/Portable/Parser/Lexer_RawStringLiteral.cs b/src/Compilers/CSharp/Portable/Parser/Lexer_RawStringLiteral.cs index 569d7bfb563be..067f78a2e77d1 100644 --- a/src/Compilers/CSharp/Portable/Parser/Lexer_RawStringLiteral.cs +++ b/src/Compilers/CSharp/Portable/Parser/Lexer_RawStringLiteral.cs @@ -367,7 +367,7 @@ private void AddMultiLineRawStringLiteralLineContents( // Skip the leading whitespace that matches the terminator line and add any whitespace past that to the // string value. Note: if the current line is shorter than the indentation whitespace, this will // intentionally copy nothing. -#if NETCOREAPP +#if NET _builder.Append(currentLineWhitespace, startIndex: indentationWhitespace.Length, count: Math.Max(0, currentLineWhitespace.Length - indentationWhitespace.Length)); #else for (var i = indentationWhitespace.Length; i < currentLineWhitespace.Length; i++) diff --git a/src/Compilers/CSharp/Portable/Parser/SyntaxFactoryContext.cs b/src/Compilers/CSharp/Portable/Parser/SyntaxFactoryContext.cs index 0dc984500c138..62204730e84ce 100644 --- a/src/Compilers/CSharp/Portable/Parser/SyntaxFactoryContext.cs +++ b/src/Compilers/CSharp/Portable/Parser/SyntaxFactoryContext.cs @@ -34,5 +34,11 @@ internal class SyntaxFactoryContext /// may need to be reinterpreted as query keywords. /// internal bool IsInQuery; + + /// + /// If an accessor kind changes, "field" within the accessor may need to be reinterpreted, + /// to determine whether the token is a keyword or an identifier. + /// + internal bool IsInFieldKeywordContext; } } diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 0c455f5f0421f..d1755de0d604a 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -52,3 +52,15 @@ virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAllowsConstraintC virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefStructConstraint(Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitAllowsConstraintClause(Microsoft.CodeAnalysis.CSharp.Syntax.AllowsConstraintClauseSyntax! node) -> TResult? virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitRefStructConstraint(Microsoft.CodeAnalysis.CSharp.Syntax.RefStructConstraintSyntax! node) -> TResult? +Microsoft.CodeAnalysis.CSharp.SyntaxKind.FieldExpression = 8757 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! node) -> TResult? +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFieldExpression(Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! node) -> void +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldExpression() -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FieldExpression(Microsoft.CodeAnalysis.SyntaxToken token) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Token.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken token) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax.WithToken(Microsoft.CodeAnalysis.SyntaxToken token) -> Microsoft.CodeAnalysis.CSharp.Syntax.FieldExpressionSyntax! diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplay.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplay.cs index 8f567a2721ebf..dddb063e87bad 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplay.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplay.cs @@ -281,7 +281,6 @@ private static ArrayBuilder PopulateDisplayParts( symbol.Accept(visitor); visitor.Free(); } - return builder; } diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.cs index 2a6b4ef328568..de1d50677f572 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.cs @@ -93,8 +93,20 @@ protected override void FreeNotFirstVisitor(AbstractSymbolDisplayVisitor visitor internal SymbolDisplayPart CreatePart(SymbolDisplayPartKind kind, ISymbol? symbol, string text) { - text = (text == null) ? "?" : - (_escapeKeywordIdentifiers && IsEscapable(kind)) ? EscapeIdentifier(text) : text; + if (text == null) + { + return new SymbolDisplayPart(kind, symbol, "?"); + } + + if (!_escapeKeywordIdentifiers) + { + return new SymbolDisplayPart(kind, symbol, text); + } + + if (IsEscapable(kind)) + { + text = EscapeIdentifier(text, symbol?.Kind is SymbolKind.NamedType or SymbolKind.Alias); + } return new SymbolDisplayPart(kind, symbol, text); } @@ -124,12 +136,16 @@ private static bool IsEscapable(SymbolDisplayPartKind kind) } } - private static string EscapeIdentifier(string identifier) + private static string EscapeIdentifier(string identifier, bool isNamedTypeOrAliasName) { - var kind = SyntaxFacts.GetKeywordKind(identifier); - return kind == SyntaxKind.None - ? identifier - : $"@{identifier}"; + SyntaxKind kind = SyntaxFacts.GetKeywordKind(identifier); + + if (kind is SyntaxKind.None && isNamedTypeOrAliasName && StringComparer.Ordinal.Equals(identifier, "record")) + { + kind = SyntaxKind.RecordKeyword; + } + + return kind == SyntaxKind.None ? identifier : $"@{identifier}"; } public override void VisitAssembly(IAssemblySymbol symbol) diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.ConstructorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.ConstructorSymbol.cs index abd52b0b285c8..6fe4d76a8736f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.ConstructorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.ConstructorSymbol.cs @@ -70,7 +70,7 @@ public override bool IsOverride get { return false; } } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return false; } 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 c38b16243af25..b7749ddcd7867 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs @@ -40,7 +40,7 @@ internal AnonymousDelegateTemplateSymbol( Debug.Assert(refKinds.IsNull || parameterCount == refKinds.Capacity - (voidReturnTypeOpt is { } ? 0 : 1)); HasIndexedName = false; - TypeParameters = CreateTypeParameters(this, parameterCount, returnsVoid: voidReturnTypeOpt is { }); + TypeParameters = CreateTypeParameters(this, parameterCount, returnsVoid: voidReturnTypeOpt is { }, hasParamsArray: false); NameAndIndex = new NameAndIndex(name, index: 0); var constructor = new SynthesizedDelegateConstructor(this, objectType, intPtrType); @@ -70,17 +70,20 @@ static SynthesizedDelegateInvokeMethod createInvokeMethod(AnonymousDelegateTempl } } - private static ImmutableArray CreateTypeParameters(AnonymousDelegateTemplateSymbol containingType, int parameterCount, bool returnsVoid) + private static ImmutableArray CreateTypeParameters(AnonymousDelegateTemplateSymbol containingType, int parameterCount, bool returnsVoid, bool hasParamsArray) { + var allowRefLikeTypes = containingType.ContainingAssembly.RuntimeSupportsByRefLikeGenerics; + var typeParameters = ArrayBuilder.GetInstance(parameterCount + (returnsVoid ? 0 : 1)); for (int i = 0; i < parameterCount; i++) { - typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(containingType, i, "T" + (i + 1))); + typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(containingType, i, "T" + (i + 1), + allowsRefLikeType: allowRefLikeTypes && (!hasParamsArray || i != parameterCount - 1))); } if (!returnsVoid) { - typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(containingType, parameterCount, "TResult")); + typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(containingType, parameterCount, "TResult", allowsRefLikeType: allowRefLikeTypes)); } return typeParameters.ToImmutableAndFree(); @@ -103,7 +106,8 @@ internal AnonymousDelegateTemplateSymbol(AnonymousTypeManager manager, Anonymous TypeParameters = CreateTypeParameters( this, parameterCount: typeDescr.Fields.Length - 1, - returnsVoid: typeDescr.Fields[^1].Type.IsVoidType()); + returnsVoid: typeDescr.Fields[^1].Type.IsVoidType(), + hasParamsArray: typeDescr.Fields is [.., { IsParams: true }, _]); var constructor = new SynthesizedDelegateConstructor(this, manager.System_Object, manager.System_IntPtr); // https://github.com/dotnet/roslyn/issues/56808: Synthesized delegates should include BeginInvoke() and EndInvoke(). @@ -172,7 +176,8 @@ internal AnonymousDelegateTemplateSymbol(AnonymousTypeManager manager, Anonymous var typeParameters = ArrayBuilder.GetInstance(typeParameterCount); for (int i = 0; i < typeParameterCount; i++) { - typeParameters.Add(new AnonymousTypeParameterSymbol(this, i, "T" + (i + 1))); + typeParameters.Add(new AnonymousTypeParameterSymbol(this, i, "T" + (i + 1), + allowsRefLikeType: typeParametersToSubstitute[i].AllowsRefLikeType)); } TypeParameters = typeParameters.ToImmutableAndFree(); typeMap = new TypeMap(typeParametersToSubstitute, TypeParameters, allowAlpha: true); diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.EqualsMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.EqualsMethodSymbol.cs index 9712e270b0483..d078f04dada47 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.EqualsMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.EqualsMethodSymbol.cs @@ -55,7 +55,7 @@ public override bool IsOverride get { return true; } } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return true; } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.GetHashCodeMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.GetHashCodeMethodSymbol.cs index db805f5c676d5..bbaacdcf46e4c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.GetHashCodeMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.GetHashCodeMethodSymbol.cs @@ -59,7 +59,7 @@ public override bool IsOverride get { return true; } } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return true; } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertyAccessorSymbol.cs index a378c643d3922..afbca6b840301 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertyAccessorSymbol.cs @@ -70,7 +70,7 @@ public override bool IsOverride get { return false; } } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs index 5c3dce114585a..ce0f158b7a4a4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs @@ -56,7 +56,7 @@ internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousType // Add a type parameter AnonymousTypeParameterSymbol typeParameter = - new AnonymousTypeParameterSymbol(this, fieldIndex, GeneratedNames.MakeAnonymousTypeParameterName(field.Name)); + new AnonymousTypeParameterSymbol(this, fieldIndex, GeneratedNames.MakeAnonymousTypeParameterName(field.Name), allowsRefLikeType: false); typeParametersBuilder.Add(typeParameter); // Add a property diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.ToStringMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.ToStringMethodSymbol.cs index 57451b0e40c74..b6ec56ec0f090 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.ToStringMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.ToStringMethodSymbol.cs @@ -59,7 +59,7 @@ public override bool IsOverride get { return true; } } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return true; } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs index b7a14cc207bbf..3f3e9f125b2d0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TypeParameterSymbol.cs @@ -20,8 +20,9 @@ internal sealed class AnonymousTypeParameterSymbol : TypeParameterSymbol private readonly AnonymousTypeOrDelegateTemplateSymbol _container; private readonly int _ordinal; private readonly string _name; + private readonly bool _allowsRefLikeType; - public AnonymousTypeParameterSymbol(AnonymousTypeOrDelegateTemplateSymbol container, int ordinal, string name) + public AnonymousTypeParameterSymbol(AnonymousTypeOrDelegateTemplateSymbol container, int ordinal, string name, bool allowsRefLikeType) { Debug.Assert((object)container != null); Debug.Assert(!string.IsNullOrEmpty(name)); @@ -29,6 +30,7 @@ public AnonymousTypeParameterSymbol(AnonymousTypeOrDelegateTemplateSymbol contai _container = container; _ordinal = ordinal; _name = name; + _allowsRefLikeType = allowsRefLikeType; } public override TypeParameterKind TypeParameterKind @@ -91,13 +93,7 @@ public override bool HasValueTypeConstraint get { return false; } } - public override bool AllowsRefLikeType - { - get - { - return _container.IsDelegateType() && ContainingAssembly.RuntimeSupportsByRefLikeGenerics; - } - } + public override bool AllowsRefLikeType => _allowsRefLikeType; public override bool IsValueTypeFromConstraintTypes { diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs index 4e36c871c7ab4..a18307dfcc0cc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs @@ -216,7 +216,7 @@ internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementati return false; } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs index 53cb47531de8b..760b4fe8674e9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs @@ -846,7 +846,7 @@ public override bool IsVararg public override ImmutableHashSet ReturnNotNullIfParameterNotNull => ImmutableHashSet.Empty; public override FlowAnalysisAnnotations FlowAnalysisAnnotations => FlowAnalysisAnnotations.None; internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) => false; - internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) => false; + internal override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) => false; internal sealed override UnmanagedCallersOnlyAttributeData? GetUnmanagedCallersOnlyAttributeData(bool forceComplete) => null; internal override bool GenerateDebugInfo => throw ExceptionUtilities.Unreachable(); diff --git a/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs b/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs index 49e600be59c0e..2ee050ccc2797 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MemberSignatureComparer.cs @@ -337,6 +337,7 @@ internal sealed class MemberSignatureComparer : IEqualityComparer refKindCompareMode: RefKindCompareMode.ConsiderDifferences, considerCallingConvention: false, considerArity: true, + considerDefaultValues: true, typeComparison: TypeCompareKind.AllIgnoreOptions); /// @@ -350,6 +351,7 @@ internal sealed class MemberSignatureComparer : IEqualityComparer refKindCompareMode: RefKindCompareMode.ConsiderDifferences, considerCallingConvention: false, considerArity: false, + considerDefaultValues: true, typeComparison: TypeCompareKind.AllIgnoreOptions); // Compare the "unqualified" part of the member name (no explicit part) @@ -370,6 +372,9 @@ internal sealed class MemberSignatureComparer : IEqualityComparer // Compare the full calling conventions. Still compares varargs if false. private readonly bool _considerCallingConvention; + // Compare explicit default values + private readonly bool _considerDefaultValues; + private readonly RefKindCompareMode _refKindCompareMode; // Equality options for parameter types and return types (if return is considered). @@ -383,6 +388,7 @@ private MemberSignatureComparer( bool considerCallingConvention, RefKindCompareMode refKindCompareMode, bool considerArity = true, + bool considerDefaultValues = false, TypeCompareKind typeComparison = TypeCompareKind.IgnoreDynamic | TypeCompareKind.IgnoreNativeIntegers) { Debug.Assert(!considerExplicitlyImplementedInterfaces || considerName, "Doesn't make sense to consider interfaces separately from name."); @@ -395,6 +401,7 @@ private MemberSignatureComparer( _considerCallingConvention = considerCallingConvention; _refKindCompareMode = refKindCompareMode; _considerArity = considerArity; + _considerDefaultValues = considerDefaultValues; _typeComparison = typeComparison; Debug.Assert((_typeComparison & TypeCompareKind.FunctionPointerRefMatchesOutInRefReadonly) == 0, $"Rely on the {nameof(refKindCompareMode)} flag to set this to ensure all cases are handled."); @@ -459,7 +466,7 @@ public bool Equals(Symbol? member1, Symbol? member2) } if (member1.GetParameterCount() > 0 && !HaveSameParameterTypes(member1.GetParameters().AsSpan(), typeMap1, member2.GetParameters().AsSpan(), typeMap2, - _refKindCompareMode, _typeComparison)) + _refKindCompareMode, considerDefaultValues: _considerDefaultValues, _typeComparison)) { return false; } @@ -755,6 +762,7 @@ internal static bool HaveSameParameterTypes( ReadOnlySpan params2, TypeMap? typeMap2, RefKindCompareMode refKindCompareMode, + bool considerDefaultValues, TypeCompareKind typeComparison) { Debug.Assert(params1.Length == params2.Length); @@ -774,6 +782,11 @@ internal static bool HaveSameParameterTypes( return false; } + if (considerDefaultValues && param1.ExplicitDefaultConstantValue != param2.ExplicitDefaultConstantValue) + { + return false; + } + if ((typeComparison & TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) == 0 && !HaveSameCustomModifiers(param1.RefCustomModifiers, typeMap1, param2.RefCustomModifiers, typeMap2)) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs index 4dd568eb77069..c530ef5ba6398 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs @@ -279,8 +279,27 @@ public void SetIsOverloadResolutionPriorityPopulated() } /// - /// Holds infrequently accessed fields. See for an explanation. + /// This type is used to hold lazily-initialized fields that many methods will not need. We avoid creating it unless one of the fields is needed; + /// unfortunately, this means that we need to be careful of data races. The general pattern that we use is to check for a flag in . + /// If the flag for that field is set, and there was a positive result (ie, there are indeed custom attributes, or there is obsolete data), then it + /// is safe to rely on the data in the field. If the flag for a field is set but the result is empty (ie, there is no obsolete data), then we can be in + /// one of 3 scenarios: + /// + /// is itself null. In this case, no race has occurred, and the consuming code can safely handle the lack of + /// however it chooses. + /// is not null, and the backing field has been initialized to some empty value, such as + /// . In this case, again, no race has occurred, and the consuming code can simply trust the empty value. + /// is not null, and the backing field is uninitialized, either being , or is some + /// kind of sentinel value. In this case, a data race has occurred, and the consuming code must initialize the field to empty to bring it back + /// into scenario 2. + /// /// + /// + /// The initialization pattern for this type must follow the following pattern to make the safety guarantees above: + /// If the field initialization code determines that the backing field needs to be set to some non-empty value, it must first call , + /// set the backing field using an atomic operation, and then set the flag in . This ensures that the field is always set before the flag is set. + /// If this order is reversed, the consuming code may see the flag set, but the field not initialized, and incorrectly assume that there is no data. + /// private sealed class UncommonFields { public ParameterSymbol _lazyThisParameter; @@ -298,64 +317,64 @@ private sealed class UncommonFields public int _lazyOverloadResolutionPriority; } - private UncommonFields CreateUncommonFields() + private UncommonFields AccessUncommonFields() { - var retVal = new UncommonFields(); - if (!_packedFlags.IsObsoleteAttributePopulated) - { - retVal._lazyObsoleteAttributeData = ObsoleteAttributeData.Uninitialized; - } + var retVal = _uncommonFields; + return retVal ?? InterlockedOperations.Initialize(ref _uncommonFields, createUncommonFields()); - if (!_packedFlags.IsUnmanagedCallersOnlyAttributePopulated) + UncommonFields createUncommonFields() { - retVal._lazyUnmanagedCallersOnlyAttributeData = UnmanagedCallersOnlyAttributeData.Uninitialized; - } - - // - // Do not set _lazyUseSiteDiagnostic !!!! - // - // "null" Indicates "no errors" or "unknown state", - // and we know which one of the states we have from IsUseSiteDiagnosticPopulated - // - // Setting _lazyUseSiteDiagnostic to a sentinel value here would introduce - // a number of extra states for various permutations of IsUseSiteDiagnosticPopulated, UncommonFields and _lazyUseSiteDiagnostic - // Some of them, in tight races, may lead to returning the sentinel as the diagnostics. - // + var retVal = new UncommonFields(); + if (!_packedFlags.IsObsoleteAttributePopulated) + { + retVal._lazyObsoleteAttributeData = ObsoleteAttributeData.Uninitialized; + } - if (_packedFlags.IsCustomAttributesPopulated) - { - retVal._lazyCustomAttributes = ImmutableArray.Empty; - } + if (!_packedFlags.IsUnmanagedCallersOnlyAttributePopulated) + { + retVal._lazyUnmanagedCallersOnlyAttributeData = UnmanagedCallersOnlyAttributeData.Uninitialized; + } - if (_packedFlags.IsConditionalPopulated) - { - retVal._lazyConditionalAttributeSymbols = ImmutableArray.Empty; - } + // + // Do not set _lazyUseSiteDiagnostic !!!! + // + // "null" Indicates "no errors" or "unknown state", + // and we know which one of the states we have from IsUseSiteDiagnosticPopulated + // + // Setting _lazyUseSiteDiagnostic to a sentinel value here would introduce + // a number of extra states for various permutations of IsUseSiteDiagnosticPopulated, UncommonFields and _lazyUseSiteDiagnostic + // Some of them, in tight races, may lead to returning the sentinel as the diagnostics. + // + + if (_packedFlags.IsCustomAttributesPopulated) + { + retVal._lazyCustomAttributes = ImmutableArray.Empty; + } - if (_packedFlags.IsOverriddenOrHiddenMembersPopulated) - { - retVal._lazyOverriddenOrHiddenMembersResult = OverriddenOrHiddenMembersResult.Empty; - } + if (_packedFlags.IsConditionalPopulated) + { + retVal._lazyConditionalAttributeSymbols = ImmutableArray.Empty; + } - if (_packedFlags.IsMemberNotNullPopulated) - { - retVal._lazyNotNullMembers = ImmutableArray.Empty; - retVal._lazyNotNullMembersWhenTrue = ImmutableArray.Empty; - retVal._lazyNotNullMembersWhenFalse = ImmutableArray.Empty; - } + if (_packedFlags.IsOverriddenOrHiddenMembersPopulated) + { + retVal._lazyOverriddenOrHiddenMembersResult = OverriddenOrHiddenMembersResult.Empty; + } - if (_packedFlags.IsExplicitOverrideIsPopulated) - { - retVal._lazyExplicitClassOverride = null; - } + if (_packedFlags.IsMemberNotNullPopulated) + { + retVal._lazyNotNullMembers = ImmutableArray.Empty; + retVal._lazyNotNullMembersWhenTrue = ImmutableArray.Empty; + retVal._lazyNotNullMembersWhenFalse = ImmutableArray.Empty; + } - return retVal; - } + if (_packedFlags.IsExplicitOverrideIsPopulated) + { + retVal._lazyExplicitClassOverride = null; + } - private UncommonFields AccessUncommonFields() - { - var retVal = _uncommonFields; - return retVal ?? InterlockedOperations.Initialize(ref _uncommonFields, CreateUncommonFields()); + return retVal; + } } private readonly MethodDefinitionHandle _handle; @@ -576,7 +595,7 @@ public override int Arity public override bool IsStatic => HasFlag(MethodAttributes.Static); - internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) => HasFlag(MethodAttributes.Virtual); + internal override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) => HasFlag(MethodAttributes.Virtual); internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) => HasFlag(MethodAttributes.NewSlot); diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs index 9aca739230ce6..a5f273713f236 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs @@ -152,6 +152,28 @@ public void SetOverloadResolutionPriorityPopulated() public readonly bool IsOverloadResolutionPriorityPopulated => (_bits & IsOverloadResolutionPriorityPopulatedBit) != 0; } + /// + /// This type is used to hold lazily-initialized fields that many properties will not need. We avoid creating it unless one of the fields is needed; + /// unfortunately, this means that we need to be careful of data races. The general pattern that we use is to check for a flag in . + /// If the flag for that field is set, and there was a positive result (ie, there are indeed custom attributes, or there is obsolete data), then it + /// is safe to rely on the data in the field. If the flag for a field is set but the result is empty (ie, there is no obsolete data), then we can be in + /// one of 3 scenarios: + /// + /// is itself null. In this case, no race has occurred, and the consuming code can safely handle the lack of + /// however it chooses. + /// is not null, and the backing field has been initialized to some empty value, such as + /// . In this case, again, no race has occurred, and the consuming code can simply trust the empty value. + /// is not null, and the backing field is uninitialized, either being , or is some + /// kind of sentinel value. In this case, a data race has occurred, and the consuming code must initialize the field to empty to bring it back + /// into scenario 2. + /// + /// + /// + /// The initialization pattern for this type must follow the following pattern to make the safety guarantees above: + /// If the field initialization code determines that the backing field needs to be set to some non-empty value, it must first call , + /// set the backing field using an atomic operation, and then set the flag in . This ensures that the field is always set before the flag is set. + /// If this order is reversed, the consuming code may see the flag set, but the field not initialized, and incorrectly assume that there is no data. + /// private sealed class UncommonFields { public ImmutableArray _lazyCustomAttributes; @@ -322,31 +344,31 @@ static bool anyUnexpectedRequiredModifiers(ParamInfo[] propertyParam } } - private UncommonFields CreateUncommonFields() + private UncommonFields AccessUncommonFields() { - var retVal = new UncommonFields(); - if (!_flags.IsObsoleteAttributePopulated) - { - retVal._lazyObsoleteAttributeData = ObsoleteAttributeData.Uninitialized; - } + var retVal = _uncommonFields; + return retVal ?? InterlockedOperations.Initialize(ref _uncommonFields, createUncommonFields()); - if (!_flags.IsUseSiteDiagnosticPopulated) + UncommonFields createUncommonFields() { - retVal._lazyCachedUseSiteInfo = CachedUseSiteInfo.Uninitialized; - } + var retVal = new UncommonFields(); + if (!_flags.IsObsoleteAttributePopulated) + { + retVal._lazyObsoleteAttributeData = ObsoleteAttributeData.Uninitialized; + } - if (_flags.IsCustomAttributesPopulated) - { - retVal._lazyCustomAttributes = ImmutableArray.Empty; - } + if (!_flags.IsUseSiteDiagnosticPopulated) + { + retVal._lazyCachedUseSiteInfo = CachedUseSiteInfo.Uninitialized; + } - return retVal; - } + if (_flags.IsCustomAttributesPopulated) + { + retVal._lazyCustomAttributes = ImmutableArray.Empty; + } - private UncommonFields AccessUncommonFields() - { - var retVal = _uncommonFields; - return retVal ?? InterlockedOperations.Initialize(ref _uncommonFields, CreateUncommonFields()); + return retVal; + } } private bool MustCallMethodsDirectlyCore() diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs index f75a1d8d2729d..e1fcf1786b6cc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs @@ -1201,7 +1201,6 @@ MethodKind is MethodKind.Ordinary or MethodKind.Constructor or MethodKind.UserDefinedOperator or MethodKind.ReducedExtension - or MethodKind.LocalFunction && !IsOverride; #region IMethodSymbolInternal diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index b1fee8aae96ac..b1fe41e662a54 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -43,7 +43,7 @@ public static bool IsRuntimeFinalizer(this MethodSymbol method, bool skipFirstMe // IsMetadataVirtualIgnoringInterfaceImplementationChanges. This also has the advantage of making // this method safe to call before declaration diagnostics have been computed. if ((object)method == null || method.Name != WellKnownMemberNames.DestructorName || - method.ParameterCount != 0 || method.Arity != 0 || !method.IsMetadataVirtual(ignoreInterfaceImplementationChanges: true)) + method.ParameterCount != 0 || method.Arity != 0 || !method.IsMetadataVirtual(MethodSymbol.IsMetadataVirtualOption.IgnoreInterfaceImplementationChanges)) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/OverriddenOrHiddenMembersHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/OverriddenOrHiddenMembersHelpers.cs index 2597633084c75..a0b6aea368c44 100644 --- a/src/Compilers/CSharp/Portable/Symbols/OverriddenOrHiddenMembersHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/OverriddenOrHiddenMembersHelpers.cs @@ -1016,7 +1016,7 @@ internal static MethodSymbol GetFirstRuntimeOverriddenMethodIgnoringNewSlot(this // be computed, then it is important for us to pass ignoreInterfaceImplementationChanges: true // (see MethodSymbol.IsMetadataVirtual for details). // Since we are only concerned with overrides (of class methods), interface implementations can be ignored. - const bool ignoreInterfaceImplementationChanges = true; + const MethodSymbol.IsMetadataVirtualOption ignoreInterfaceImplementationChanges = MethodSymbol.IsMetadataVirtualOption.IgnoreInterfaceImplementationChanges; wasAmbiguous = false; if (!method.IsMetadataVirtual(ignoreInterfaceImplementationChanges) || method.IsStatic) diff --git a/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs index 94d59417b4c61..329beb975e807 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs @@ -8,6 +8,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols @@ -15,7 +16,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols /// /// Represents a property or indexer. /// - internal abstract partial class PropertySymbol : Symbol + internal abstract partial class PropertySymbol : Symbol, IPropertySymbolInternal { /// /// As a performance optimization, cache parameter types and refkinds - overload resolution uses them a lot. @@ -321,6 +322,14 @@ internal virtual bool IsExplicitInterfaceImplementation /// public abstract ImmutableArray ExplicitInterfaceImplementations { get; } +#nullable enable + internal virtual PropertySymbol? PartialImplementationPart => null; + internal virtual PropertySymbol? PartialDefinitionPart => null; + + IPropertySymbolInternal? IPropertySymbolInternal.PartialImplementationPart => PartialImplementationPart; + IPropertySymbolInternal? IPropertySymbolInternal.PartialDefinitionPart => PartialDefinitionPart; +#nullable disable + /// /// Gets the kind of this symbol. /// diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/AssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/AssemblySymbol.cs index 7d09577dd59ac..d1fd20a05ed2f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/AssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/AssemblySymbol.cs @@ -4,21 +4,18 @@ #nullable disable -using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Globalization; using System.Linq; -using System.Threading; -using Microsoft.CodeAnalysis.Collections; -using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel { internal abstract class AssemblySymbol : Symbol, IAssemblySymbol { + private IEnumerable _lazyModules; + internal abstract Symbols.AssemblySymbol UnderlyingAssemblySymbol { get; } INamespaceSymbol IAssemblySymbol.GlobalNamespace @@ -33,10 +30,10 @@ IEnumerable IAssemblySymbol.Modules { get { - foreach (var module in UnderlyingAssemblySymbol.Modules) - { - yield return module.GetPublicSymbol(); - } + return InterlockedOperations.Initialize( + ref _lazyModules, + static self => self.UnderlyingAssemblySymbol.Modules.SelectAsArray(static module => module.GetPublicSymbol()), + this); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs index 3072bfb1875da..4179ba6c272b9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs @@ -110,9 +110,9 @@ ImmutableArray IPropertySymbol.RefCustomModifiers RefKind IPropertySymbol.RefKind => _underlying.RefKind; #nullable enable - IPropertySymbol? IPropertySymbol.PartialDefinitionPart => (_underlying as SourcePropertySymbol)?.PartialDefinitionPart.GetPublicSymbol(); + IPropertySymbol? IPropertySymbol.PartialDefinitionPart => _underlying.PartialDefinitionPart.GetPublicSymbol(); - IPropertySymbol? IPropertySymbol.PartialImplementationPart => (_underlying as SourcePropertySymbol)?.PartialImplementationPart.GetPublicSymbol(); + IPropertySymbol? IPropertySymbol.PartialImplementationPart => _underlying.PartialImplementationPart.GetPublicSymbol(); bool IPropertySymbol.IsPartialDefinition => (_underlying as SourcePropertySymbol)?.IsPartialDefinition ?? false; #nullable disable diff --git a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs index 497a706d4d6fd..55f514fae9519 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs @@ -423,7 +423,7 @@ internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementati return false; } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs index 6e07b286192b3..c71b5cbcb5bc8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs @@ -162,7 +162,7 @@ internal sealed override bool HasAsyncMethodBuilderAttribute(out TypeSymbol buil internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) { throw ExceptionUtilities.Unreachable(); } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) { throw ExceptionUtilities.Unreachable(); } + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { throw ExceptionUtilities.Unreachable(); } internal override bool IsMetadataFinal { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index 5c207d6571472..217699cef51bf 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -114,7 +114,7 @@ internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementati return false; } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index 365ff44b2d4f9..3c962f0b90f64 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -378,7 +378,7 @@ protected override void NoteAttributesComplete(bool forReturnType) { } internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) => false; - internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) => false; + internal override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) => false; internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs index 4cc4a464d7977..90af0833df5fe 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs @@ -136,7 +136,7 @@ public sealed override ImmutableArray Parameters { get { - Debug.Assert(!_parameters.IsDefault, $"Expected {nameof(InitializeParameters)} prior to accessing this property."); + RoslynDebug.Assert(!_parameters.IsDefault, $"Expected {nameof(InitializeParameters)} prior to accessing this property."); return _parameters.NullToEmpty(); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs index 0d41e34db2617..bebafb570db77 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs @@ -154,7 +154,7 @@ internal override OneOrMany> GetReturnTypeAttrib return OneOrMany.Create(default(SyntaxList)); } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return true; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index 40e7f04cc0ebf..8e64bfd4ed0ae 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -1772,6 +1772,8 @@ private Dictionary, ImmutableArray> GetMembersByNam return _lazyMembersDictionary; } + internal bool AreMembersComplete => state.HasComplete(CompletionPart.Members); + internal override IEnumerable GetInstanceFieldsAndEvents() { var membersAndInitializers = this.GetMembersAndInitializers(); @@ -2734,7 +2736,7 @@ private void CheckSequentialOnPartialType(BindingDiagnosticBag diagnostics) foreach (var m in syntax.Members) { - if (HasInstanceData(m)) + if (hasInstanceData(m)) { if (whereFoundField != null && whereFoundField != syntaxRef) { @@ -2754,35 +2756,36 @@ private void CheckSequentialOnPartialType(BindingDiagnosticBag diagnostics) diagnostics.Add(ErrorCode.WRN_SequentialOnPartialClass, GetFirstLocation(), this); return; } - } - private static bool HasInstanceData(MemberDeclarationSyntax m) - { - switch (m.Kind()) - { - case SyntaxKind.FieldDeclaration: - var fieldDecl = (FieldDeclarationSyntax)m; - return - !ContainsModifier(fieldDecl.Modifiers, SyntaxKind.StaticKeyword) && - !ContainsModifier(fieldDecl.Modifiers, SyntaxKind.ConstKeyword); - case SyntaxKind.PropertyDeclaration: - // auto-property - var propertyDecl = (PropertyDeclarationSyntax)m; - return - !ContainsModifier(propertyDecl.Modifiers, SyntaxKind.StaticKeyword) && - !ContainsModifier(propertyDecl.Modifiers, SyntaxKind.AbstractKeyword) && - !ContainsModifier(propertyDecl.Modifiers, SyntaxKind.ExternKeyword) && - propertyDecl.AccessorList != null && - All(propertyDecl.AccessorList.Accessors, a => a.Body == null && a.ExpressionBody == null); - case SyntaxKind.EventFieldDeclaration: - // field-like event declaration - var eventFieldDecl = (EventFieldDeclarationSyntax)m; - return - !ContainsModifier(eventFieldDecl.Modifiers, SyntaxKind.StaticKeyword) && - !ContainsModifier(eventFieldDecl.Modifiers, SyntaxKind.AbstractKeyword) && - !ContainsModifier(eventFieldDecl.Modifiers, SyntaxKind.ExternKeyword); - default: - return false; + static bool hasInstanceData(MemberDeclarationSyntax m) + { + switch (m.Kind()) + { + case SyntaxKind.FieldDeclaration: + var fieldDecl = (FieldDeclarationSyntax)m; + return + !ContainsModifier(fieldDecl.Modifiers, SyntaxKind.StaticKeyword) && + !ContainsModifier(fieldDecl.Modifiers, SyntaxKind.ConstKeyword); + case SyntaxKind.PropertyDeclaration: + // auto-property + var propertyDecl = (PropertyDeclarationSyntax)m; + return + !ContainsModifier(propertyDecl.Modifiers, SyntaxKind.StaticKeyword) && + !ContainsModifier(propertyDecl.Modifiers, SyntaxKind.AbstractKeyword) && + !ContainsModifier(propertyDecl.Modifiers, SyntaxKind.ExternKeyword) && + !ContainsModifier(propertyDecl.Modifiers, SyntaxKind.PartialKeyword) && + propertyDecl.AccessorList != null && + All(propertyDecl.AccessorList.Accessors, a => a.Body == null && a.ExpressionBody == null); + case SyntaxKind.EventFieldDeclaration: + // field-like event declaration + var eventFieldDecl = (EventFieldDeclarationSyntax)m; + return + !ContainsModifier(eventFieldDecl.Modifiers, SyntaxKind.StaticKeyword) && + !ContainsModifier(eventFieldDecl.Modifiers, SyntaxKind.AbstractKeyword) && + !ContainsModifier(eventFieldDecl.Modifiers, SyntaxKind.ExternKeyword); + default: + return false; + } } } @@ -3667,13 +3670,8 @@ void mergePartialMethods(ref Dictionary, ImmutableArray, ImmutableArray>(membersByName, ReadOnlyMemoryOfCharComparer.Instance); - } - - membersByName[name] = FixPartialMember(membersByName[name], prevMethod, currentMethod); + DuplicateMembersByNameIfCached(ref membersByName); + membersByName[name] = FixPartialMethod(membersByName[name], prevMethod, currentMethod); } } @@ -3691,40 +3689,28 @@ void mergePartialProperties(ref Dictionary, ImmutableArray< } else { - var (currentGet, prevGet) = ((SourcePropertyAccessorSymbol?)currentProperty.GetMethod, (SourcePropertyAccessorSymbol?)prevProperty.GetMethod); - if (currentGet != null || prevGet != null) + if (hasInitializer(prevProperty) && hasInitializer(currentProperty)) { - var accessorName = (currentGet ?? prevGet)!.Name.AsMemory(); - mergeAccessors(ref membersByName, accessorName, currentGet, prevGet); + diagnostics.Add(ErrorCode.ERR_PartialPropertyDuplicateInitializer, currentProperty.GetFirstLocation()); } - var (currentSet, prevSet) = ((SourcePropertyAccessorSymbol?)currentProperty.SetMethod, (SourcePropertyAccessorSymbol?)prevProperty.SetMethod); - if (currentSet != null || prevSet != null) - { - var accessorName = (currentSet ?? prevSet)!.Name.AsMemory(); - mergeAccessors(ref membersByName, accessorName, currentSet, prevSet); - } - - if ((object)membersByName == _lazyEarlyAttributeDecodingMembersDictionary) - { - // Avoid mutating the cached dictionary and especially avoid doing this possibly on multiple threads in parallel. - membersByName = new Dictionary, ImmutableArray>(membersByName, ReadOnlyMemoryOfCharComparer.Instance); - } - - membersByName[name] = FixPartialMember(membersByName[name], prevProperty, currentProperty); + DuplicateMembersByNameIfCached(ref membersByName); + mergeAccessors(ref membersByName, (SourcePropertyAccessorSymbol?)currentProperty.GetMethod, (SourcePropertyAccessorSymbol?)prevProperty.GetMethod); + mergeAccessors(ref membersByName, (SourcePropertyAccessorSymbol?)currentProperty.SetMethod, (SourcePropertyAccessorSymbol?)prevProperty.SetMethod); + FixPartialProperty(ref membersByName, name, prevProperty, currentProperty); } - void mergeAccessors(ref Dictionary, ImmutableArray> membersByName, ReadOnlyMemory name, SourcePropertyAccessorSymbol? currentAccessor, SourcePropertyAccessorSymbol? prevAccessor) + void mergeAccessors(ref Dictionary, ImmutableArray> membersByName, SourcePropertyAccessorSymbol? currentAccessor, SourcePropertyAccessorSymbol? prevAccessor) { - Debug.Assert(currentAccessor != null || prevAccessor != null); - if (currentAccessor != null && prevAccessor != null) + if (currentAccessor is { } && prevAccessor is { }) { + var name = currentAccessor.Name.AsMemory(); var implementationAccessor = currentProperty.IsPartialDefinition ? prevAccessor : currentAccessor; membersByName[name] = Remove(membersByName[name], implementationAccessor); } - else + else if (currentAccessor is { } || prevAccessor is { }) { - var (foundAccessor, containingProperty, otherProperty) = prevAccessor != null ? (prevAccessor, prevProperty, currentProperty) : (currentAccessor!, currentProperty, prevProperty); + var (foundAccessor, containingProperty, otherProperty) = prevAccessor is { } ? (prevAccessor, prevProperty, currentProperty) : (currentAccessor!, currentProperty, prevProperty); // When an accessor is present on definition but not on implementation, the accessor is said to be missing on the implementation. // When an accessor is present on implementation but not on definition, the accessor is said to be unexpected on the implementation. var (errorCode, propertyToBlame) = foundAccessor.IsPartialDefinition @@ -3733,11 +3719,25 @@ void mergeAccessors(ref Dictionary, ImmutableArray> diagnostics.Add(errorCode, propertyToBlame.GetFirstLocation(), foundAccessor); } } + + static bool hasInitializer(SourcePropertySymbol property) + { + return property.DeclaredBackingField?.HasInitializer == true; + } + } + } + + private void DuplicateMembersByNameIfCached(ref Dictionary, ImmutableArray> membersByName) + { + if ((object)membersByName == _lazyEarlyAttributeDecodingMembersDictionary) + { + // Avoid mutating the cached dictionary and especially avoid doing this possibly on multiple threads in parallel. + membersByName = new Dictionary, ImmutableArray>(membersByName, ReadOnlyMemoryOfCharComparer.Instance); } } /// Links together the definition and implementation parts of a partial method. Returns a member list which has the implementation part removed. - private static ImmutableArray FixPartialMember(ImmutableArray symbols, SourceOrdinaryMethodSymbol part1, SourceOrdinaryMethodSymbol part2) + private static ImmutableArray FixPartialMethod(ImmutableArray symbols, SourceOrdinaryMethodSymbol part1, SourceOrdinaryMethodSymbol part2) { SourceOrdinaryMethodSymbol definition; SourceOrdinaryMethodSymbol implementation; @@ -3759,7 +3759,7 @@ private static ImmutableArray FixPartialMember(ImmutableArray sy } /// Links together the definition and implementation parts of a partial property. Returns a member list which has the implementation part removed. - private static ImmutableArray FixPartialMember(ImmutableArray symbols, SourcePropertySymbol part1, SourcePropertySymbol part2) + private static void FixPartialProperty(ref Dictionary, ImmutableArray> membersByName, ReadOnlyMemory name, SourcePropertySymbol part1, SourcePropertySymbol part2) { SourcePropertySymbol definition; SourcePropertySymbol implementation; @@ -3774,10 +3774,17 @@ private static ImmutableArray FixPartialMember(ImmutableArray sy implementation = part1; } + if (implementation.DeclaredBackingField is { } implementationField && + definition.DeclaredBackingField is { }) + { + var fieldName = implementationField.Name.AsMemory(); + membersByName[fieldName] = Remove(membersByName[fieldName], implementationField); + } + SourcePropertySymbol.InitializePartialPropertyParts(definition, implementation); // a partial property is represented in the member list by its definition part: - return Remove(symbols, implementation); + membersByName[name] = Remove(membersByName[name], implementation); } private static ImmutableArray Remove(ImmutableArray symbols, Symbol symbol) @@ -4550,7 +4557,9 @@ void addProperty(SynthesizedRecordPropertySymbol property) Debug.Assert(property.SetMethod is object); members.Add(property.GetMethod); members.Add(property.SetMethod); - members.Add(property.BackingField); + var backingField = property.DeclaredBackingField; + Debug.Assert(backingField is object); + members.Add(backingField); builder.AddInstanceInitializerForPositionalMembers(new FieldOrPropertyInitializer(property.BackingField, paramList.Parameters[param.Ordinal])); addedCount++; @@ -4990,13 +4999,13 @@ private void AddNonTypeMembers( AddAccessorIfAvailable(builder.NonTypeMembers, property.GetMethod); AddAccessorIfAvailable(builder.NonTypeMembers, property.SetMethod); - FieldSymbol backingField = property.BackingField; + FieldSymbol? backingField = property.DeclaredBackingField; // TODO: can we leave this out of the member list? // From the 10/12/11 design notes: // In addition, we will change autoproperties to behavior in // a similar manner and make the autoproperty fields private. - if ((object)backingField != null) + if (backingField is { }) { builder.NonTypeMembers.Add(backingField); builder.UpdateIsNullableEnabledForConstructorsAndFields(useStatic: backingField.IsStatic, compilation, propertySyntax); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs index 5de47162157d9..0f2216f4fef46 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs @@ -114,7 +114,7 @@ private SynthesizedExplicitImplementations ComputeInterfaceImplementations( var forwardingMethods = ArrayBuilder.GetInstance(); var methodImpls = ArrayBuilder<(MethodSymbol Body, MethodSymbol Implemented)>.GetInstance(); - // NOTE: We can't iterator over this collection directly, since it is not ordered. Instead we + // NOTE: We can't iterate over this collection directly, since it is not ordered. Instead we // iterate over AllInterfaces and filter out the interfaces that are not in this set. This is // preferable to doing the DFS ourselves because both AllInterfaces and // InterfacesAndTheirBaseInterfaces are cached and used in multiple places. @@ -1838,7 +1838,7 @@ private void CheckInterfaceUnification(BindingDiagnosticBag diagnostics) needSynthesizedImplementation = false; } } - else if (implementingMethod.IsMetadataVirtual(ignoreInterfaceImplementationChanges: true)) + else if (implementingMethod.IsMetadataVirtual(MethodSymbol.IsMetadataVirtualOption.IgnoreInterfaceImplementationChanges)) { // If the signatures match and the implementation method is definitely virtual, then we're set. needSynthesizedImplementation = false; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index 8fb5c2a4a1e30..92424e5eaffa4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -554,13 +554,20 @@ internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChang // in NamedTypeSymbolAdapter.cs). return this.IsOverride ? this.RequiresExplicitOverride(out _) : - !this.IsStatic && this.IsMetadataVirtual(ignoreInterfaceImplementationChanges); + !this.IsStatic && this.IsMetadataVirtual(ignoreInterfaceImplementationChanges ? IsMetadataVirtualOption.IgnoreInterfaceImplementationChanges : IsMetadataVirtualOption.None); } // TODO (tomat): sealed? - internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { - return this.flags.IsMetadataVirtual(ignoreInterfaceImplementationChanges); +#if DEBUG + if (option == IsMetadataVirtualOption.ForceCompleteIfNeeded && !this.flags.IsMetadataVirtualLocked) + { + this.ContainingSymbol.ForceComplete(locationOpt: null, filter: null, cancellationToken: CancellationToken.None); + } +#endif + + return this.flags.IsMetadataVirtual(ignoreInterfaceImplementationChanges: option == IsMetadataVirtualOption.IgnoreInterfaceImplementationChanges); } internal void EnsureMetadataVirtual() diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 64791d2be8f46..bb5183e3e9d75 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -1020,7 +1020,7 @@ private void DecodeInterceptsLocationChecksumBased(DecodeWellKnownAttributeArgum return; } - var interceptorsNamespaces = ((CSharpParseOptions)attributeNameSyntax.SyntaxTree.Options).InterceptorsPreviewNamespaces; + var interceptorsNamespaces = ((CSharpParseOptions)attributeNameSyntax.SyntaxTree.Options).InterceptorsNamespaces; var thisNamespaceNames = getNamespaceNames(this); var foundAnyMatch = interceptorsNamespaces.Any(static (ns, thisNamespaceNames) => isDeclaredInNamespace(thisNamespaceNames, ns), thisNamespaceNames); if (!foundAnyMatch) @@ -1149,7 +1149,7 @@ static void reportFeatureNotEnabled(BindingDiagnosticBag diagnostics, Location a } else { - var recommendedProperty = $"$(InterceptorsPreviewNamespaces);{string.Join(".", namespaceNames)}"; + var recommendedProperty = $"$(InterceptorsNamespaces);{string.Join(".", namespaceNames)}"; diagnostics.Add(ErrorCode.ERR_InterceptorsFeatureNotEnabled, attributeLocation, recommendedProperty); } } @@ -1170,7 +1170,7 @@ private void DecodeInterceptsLocationAttributeExperimentalCompat( const int lineNumberParameterIndex = 1; const int characterNumberParameterIndex = 2; - var interceptorsNamespaces = ((CSharpParseOptions)attributeSyntax.SyntaxTree.Options).InterceptorsPreviewNamespaces; + var interceptorsNamespaces = ((CSharpParseOptions)attributeSyntax.SyntaxTree.Options).InterceptorsNamespaces; var thisNamespaceNames = getNamespaceNames(); var foundAnyMatch = interceptorsNamespaces.Any(ns => isDeclaredInNamespace(thisNamespaceNames, ns)); if (!foundAnyMatch) @@ -1362,7 +1362,7 @@ static void reportFeatureNotEnabled(BindingDiagnosticBag diagnostics, AttributeS } else { - var recommendedProperty = $"$(InterceptorsPreviewNamespaces);{string.Join(".", namespaceNames)}"; + var recommendedProperty = $"$(InterceptorsNamespaces);{string.Join(".", namespaceNames)}"; diagnostics.Add(ErrorCode.ERR_InterceptorsFeatureNotEnabled, attributeSyntax, recommendedProperty); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs index 229f61355c2dd..11a59bf87bafd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs @@ -343,7 +343,7 @@ void discoverInterceptors() var toVisit = ArrayBuilder.GetInstance(); // Search the namespaces which were indicated to contain interceptors. - ImmutableArray> interceptorsNamespaces = ((CSharpParseOptions)location.SourceTree.Options).InterceptorsPreviewNamespaces; + ImmutableArray> interceptorsNamespaces = ((CSharpParseOptions)location.SourceTree.Options).InterceptorsNamespaces; foreach (ImmutableArray namespaceParts in interceptorsNamespaces) { if (namespaceParts is ["global"]) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index bbdec6de9a01e..9e4cca64413c5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -1796,27 +1796,30 @@ protected override void AfterMembersCompletedChecks(BindingDiagnosticBag diagnos Debug.Assert(ObsoleteKind != ObsoleteAttributeKind.Uninitialized); Debug.Assert(GetMembers().All(m => m.ObsoleteKind != ObsoleteAttributeKind.Uninitialized)); - if (ObsoleteKind != ObsoleteAttributeKind.None - || GetMembers().All(m => m is not MethodSymbol { MethodKind: MethodKind.Constructor, ObsoleteKind: ObsoleteAttributeKind.None } method + if (ObsoleteKind == ObsoleteAttributeKind.None + && !GetMembers().All(m => m is not MethodSymbol { MethodKind: MethodKind.Constructor, ObsoleteKind: ObsoleteAttributeKind.None } method || !method.ShouldCheckRequiredMembers())) { - return; - } - - foreach (var member in GetMembers()) - { - if (!member.IsRequired()) + foreach (var member in GetMembers()) { - continue; - } + if (!member.IsRequired()) + { + continue; + } - if (member.ObsoleteKind != ObsoleteAttributeKind.None) - { - // Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. - diagnostics.Add(ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired, member.GetFirstLocation(), member); + if (member.ObsoleteKind != ObsoleteAttributeKind.None) + { + // Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + diagnostics.Add(ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired, member.GetFirstLocation(), member); + } } } + if (Indexers.FirstOrDefault() is PropertySymbol indexerSymbol) + { + Binder.GetWellKnownTypeMember(DeclaringCompilation, WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor, diagnostics, indexerSymbol.TryGetFirstLocation() ?? GetFirstLocation()); + } + if (TypeKind == TypeKind.Struct && !IsRecordStruct && HasInlineArrayAttribute(out _)) { if (Layout.Kind == LayoutKind.Explicit) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs index dc1f91d9fe98d..d57ad4859e972 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs @@ -485,6 +485,8 @@ internal sealed override bool IsDeclaredReadOnly } } + internal bool IsAutoPropertyAccessor => _isAutoPropertyAccessor; + internal sealed override bool IsInitOnly => !IsStatic && _usesInit; private static DeclarationModifiers MakeModifiers(NamedTypeSymbol containingType, SyntaxTokenList modifiers, bool isExplicitInterfaceImplementation, diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index 2deeefb254519..a76fc7bd75edf 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -40,12 +40,15 @@ private static SourcePropertySymbol Create( GetAccessorDeclarations( syntax, diagnostics, - out bool hasAccessorList, - out bool accessorsHaveImplementation, - out bool isInitOnly, + out bool isExpressionBodied, + out bool hasGetAccessorImplementation, + out bool hasSetAccessorImplementation, + out bool usesFieldKeyword, out var getSyntax, out var setSyntax); + bool accessorsHaveImplementation = hasGetAccessorImplementation || hasSetAccessorImplementation; + var explicitInterfaceSpecifier = GetExplicitInterfaceSpecifier(syntax); SyntaxTokenList modifiersTokenList = GetModifierTokensSyntax(syntax); bool isExplicitInterfaceImplementation = explicitInterfaceSpecifier is object; @@ -59,8 +62,11 @@ private static SourcePropertySymbol Create( diagnostics, out _); - bool isAutoProperty = (modifiers & DeclarationModifiers.Partial) == 0 && !accessorsHaveImplementation; - bool isExpressionBodied = !hasAccessorList && GetArrowExpression(syntax) != null; + bool allowAutoPropertyAccessors = (modifiers & (DeclarationModifiers.Abstract | DeclarationModifiers.Extern | DeclarationModifiers.Indexer)) == 0 && + (!containingType.IsInterface || hasGetAccessorImplementation || hasSetAccessorImplementation || (modifiers & DeclarationModifiers.Static) != 0) && + ((modifiers & DeclarationModifiers.Partial) == 0 || hasGetAccessorImplementation || hasSetAccessorImplementation); + bool hasAutoPropertyGet = allowAutoPropertyAccessors && getSyntax != null && !hasGetAccessorImplementation; + bool hasAutoPropertySet = allowAutoPropertyAccessors && setSyntax != null && !hasSetAccessorImplementation; binder = binder.SetOrClearUnsafeRegionIfNecessary(modifiersTokenList); TypeSymbol? explicitInterfaceType; @@ -77,10 +83,11 @@ private static SourcePropertySymbol Create( aliasQualifierOpt, modifiers, hasExplicitAccessMod: hasExplicitAccessMod, - isAutoProperty: isAutoProperty, + hasAutoPropertyGet: hasAutoPropertyGet, + hasAutoPropertySet: hasAutoPropertySet, isExpressionBodied: isExpressionBodied, - isInitOnly: isInitOnly, accessorsHaveImplementation: accessorsHaveImplementation, + usesFieldKeyword: usesFieldKeyword, memberName, location, diagnostics); @@ -96,28 +103,30 @@ private SourcePropertySymbol( string? aliasQualifierOpt, DeclarationModifiers modifiers, bool hasExplicitAccessMod, - bool isAutoProperty, + bool hasAutoPropertyGet, + bool hasAutoPropertySet, bool isExpressionBodied, - bool isInitOnly, bool accessorsHaveImplementation, + bool usesFieldKeyword, string memberName, Location location, BindingDiagnosticBag diagnostics) : base( containingType, syntax, - hasGetAccessor, - hasSetAccessor, + hasGetAccessor: hasGetAccessor, + hasSetAccessor: hasSetAccessor, isExplicitInterfaceImplementation, explicitInterfaceType, aliasQualifierOpt, modifiers, hasInitializer: HasInitializer(syntax), hasExplicitAccessMod: hasExplicitAccessMod, - isAutoProperty: isAutoProperty, + hasAutoPropertyGet: hasAutoPropertyGet, + hasAutoPropertySet: hasAutoPropertySet, isExpressionBodied: isExpressionBodied, - isInitOnly: isInitOnly, accessorsHaveImplementation: accessorsHaveImplementation, + usesFieldKeyword: usesFieldKeyword, syntax.Type.SkipScoped(out _).GetRefKindInLocalOrReturn(diagnostics), memberName, syntax.AttributeLists, @@ -126,11 +135,13 @@ private SourcePropertySymbol( { Debug.Assert(syntax.Type is not ScopedTypeSyntax); - if (IsAutoProperty) + if (hasAutoPropertyGet || hasAutoPropertySet) { Binder.CheckFeatureAvailability( syntax, - (hasGetAccessor && !hasSetAccessor) ? MessageID.IDS_FeatureReadonlyAutoImplementedProperties : MessageID.IDS_FeatureAutoImplementedProperties, + hasGetAccessor && hasSetAccessor ? + (hasAutoPropertyGet && hasAutoPropertySet ? MessageID.IDS_FeatureAutoImplementedProperties : MessageID.IDS_FeatureFieldKeyword) : + (hasAutoPropertyGet ? MessageID.IDS_FeatureReadonlyAutoImplementedProperties : MessageID.IDS_FeatureAutoImplementedProperties), diagnostics, location); } @@ -175,11 +186,10 @@ public override OneOrMany> GetAttributeDeclarati // Attributes on partial properties are owned by the definition part. // If this symbol has a non-null PartialDefinitionPart, we should have accessed this method through that definition symbol instead Debug.Assert(PartialDefinitionPart is null - // We might still get here when asking for the attributes on a backing field. - // This is an error scenario (requires using a property initializer and field-targeted attributes on partial property implementation part). + // We might still get here when asking for the attributes on a backing field in error scenarios. || this.BackingField is not null); - if (PartialImplementationPart is { } implementationPart) + if (SourcePartialImplementationPart is { } implementationPart) { return OneOrMany.Create( ((BasePropertyDeclarationSyntax)CSharpSyntaxNode).AttributeLists, @@ -191,28 +201,30 @@ public override OneOrMany> GetAttributeDeclarati } } - protected override SourcePropertySymbolBase? BoundAttributesSource => PartialDefinitionPart; + protected override SourcePropertySymbolBase? BoundAttributesSource => SourcePartialDefinitionPart; public override IAttributeTargetSymbol AttributesOwner => this; private static void GetAccessorDeclarations( CSharpSyntaxNode syntaxNode, BindingDiagnosticBag diagnostics, - out bool hasAccessorList, - out bool accessorsHaveImplementation, - out bool isInitOnly, - out CSharpSyntaxNode? getSyntax, - out CSharpSyntaxNode? setSyntax) + out bool isExpressionBodied, + out bool hasGetAccessorImplementation, + out bool hasSetAccessorImplementation, + out bool usesFieldKeyword, + out AccessorDeclarationSyntax? getSyntax, + out AccessorDeclarationSyntax? setSyntax) { var syntax = (BasePropertyDeclarationSyntax)syntaxNode; - hasAccessorList = syntax.AccessorList != null; + isExpressionBodied = syntax.AccessorList is null; getSyntax = null; setSyntax = null; - isInitOnly = false; - if (hasAccessorList) + if (!isExpressionBodied) { - accessorsHaveImplementation = false; + usesFieldKeyword = false; + hasGetAccessorImplementation = false; + hasSetAccessorImplementation = false; foreach (var accessor in syntax.AccessorList!.Accessors) { switch (accessor.Kind()) @@ -221,6 +233,7 @@ private static void GetAccessorDeclarations( if (getSyntax == null) { getSyntax = accessor; + hasGetAccessorImplementation = hasImplementation(accessor); } else { @@ -232,10 +245,7 @@ private static void GetAccessorDeclarations( if (setSyntax == null) { setSyntax = accessor; - if (accessor.Keyword.IsKind(SyntaxKind.InitKeyword)) - { - isInitOnly = true; - } + hasSetAccessorImplementation = hasImplementation(accessor); } else { @@ -254,16 +264,34 @@ private static void GetAccessorDeclarations( throw ExceptionUtilities.UnexpectedValue(accessor.Kind()); } - if (accessor.Body != null || accessor.ExpressionBody != null) - { - accessorsHaveImplementation = true; - } + usesFieldKeyword = usesFieldKeyword || containsFieldKeyword(accessor); } } else { - accessorsHaveImplementation = GetArrowExpression(syntax) is object; - Debug.Assert(accessorsHaveImplementation); // it's not clear how this even parsed as a property if it has no accessor list and no arrow expression. + var body = GetArrowExpression(syntax); + hasGetAccessorImplementation = body is object; + hasSetAccessorImplementation = false; + usesFieldKeyword = body is { } && containsFieldKeyword(body); + Debug.Assert(hasGetAccessorImplementation); // it's not clear how this even parsed as a property if it has no accessor list and no arrow expression. + } + + static bool hasImplementation(AccessorDeclarationSyntax accessor) + { + var body = (SyntaxNode?)accessor.Body ?? accessor.ExpressionBody; + return body != null; + } + + static bool containsFieldKeyword(SyntaxNode syntax) + { + foreach (var node in syntax.Green.EnumerateNodes()) + { + if (node.RawKind == (int)SyntaxKind.FieldKeyword) + { + return true; + } + } + return false; } } @@ -727,9 +755,11 @@ private void PartialPropertyChecks(SourcePropertySymbol implementation, BindingD internal bool IsPartialImplementation => IsPartial && (AccessorsHaveImplementation || HasExternModifier); - internal SourcePropertySymbol? PartialDefinitionPart => IsPartialImplementation ? OtherPartOfPartial : null; + internal SourcePropertySymbol? SourcePartialDefinitionPart => IsPartialImplementation ? OtherPartOfPartial : null; + internal SourcePropertySymbol? SourcePartialImplementationPart => IsPartialDefinition ? OtherPartOfPartial : null; - internal SourcePropertySymbol? PartialImplementationPart => IsPartialDefinition ? OtherPartOfPartial : null; + internal override PropertySymbol? PartialDefinitionPart => SourcePartialDefinitionPart; + internal override PropertySymbol? PartialImplementationPart => SourcePartialImplementationPart; internal static void InitializePartialPropertyParts(SourcePropertySymbol definition, SourcePropertySymbol implementation) { @@ -744,6 +774,11 @@ internal static void InitializePartialPropertyParts(SourcePropertySymbol definit Debug.Assert(definition._otherPartOfPartial == implementation); Debug.Assert(implementation._otherPartOfPartial == definition); + + // Use the same backing field for both parts. + var backingField = definition.DeclaredBackingField ?? implementation.DeclaredBackingField; + definition.SetMergedBackingField(backingField); + implementation.SetMergedBackingField(backingField); } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index e6a081ac788c1..aca35156e28ea 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -5,15 +5,12 @@ #nullable disable using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Emit; -using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -29,14 +26,17 @@ internal abstract class SourcePropertySymbolBase : PropertySymbol, IAttributeTar /// so that we do not have to go back to source to compute this data. /// [Flags] - private enum Flags : byte + private enum Flags : ushort { IsExpressionBodied = 1 << 0, - IsAutoProperty = 1 << 1, - IsExplicitInterfaceImplementation = 1 << 2, - HasInitializer = 1 << 3, - AccessorsHaveImplementation = 1 << 4, - HasExplicitAccessModifier = 1 << 5, + HasAutoPropertyGet = 1 << 1, + HasAutoPropertySet = 1 << 2, + UsesFieldKeyword = 1 << 3, + IsExplicitInterfaceImplementation = 1 << 4, + HasInitializer = 1 << 5, + AccessorsHaveImplementation = 1 << 6, + HasExplicitAccessModifier = 1 << 7, + RequiresBackingField = 1 << 8, } // TODO (tomat): consider splitting into multiple subclasses/rare data. @@ -72,6 +72,9 @@ private enum Flags : byte public Location Location { get; } #nullable enable + private SynthesizedBackingFieldSymbol? _lazyDeclaredBackingField; + private SynthesizedBackingFieldSymbol? _lazyMergedBackingField; + protected SourcePropertySymbolBase( SourceMemberContainerTypeSymbol containingType, CSharpSyntaxNode syntax, @@ -83,17 +86,18 @@ protected SourcePropertySymbolBase( DeclarationModifiers modifiers, bool hasInitializer, bool hasExplicitAccessMod, - bool isAutoProperty, + bool hasAutoPropertyGet, + bool hasAutoPropertySet, bool isExpressionBodied, - bool isInitOnly, bool accessorsHaveImplementation, + bool usesFieldKeyword, RefKind refKind, string memberName, SyntaxList indexerNameAttributeLists, Location location, BindingDiagnosticBag diagnostics) { - Debug.Assert(!isExpressionBodied || !isAutoProperty); + Debug.Assert(!isExpressionBodied || !(hasAutoPropertyGet || hasAutoPropertySet)); Debug.Assert(!isExpressionBodied || !hasInitializer); Debug.Assert(!isExpressionBodied || accessorsHaveImplementation); Debug.Assert((modifiers & DeclarationModifiers.Required) == 0 || this is SourcePropertySymbol); @@ -114,17 +118,24 @@ protected SourcePropertySymbolBase( _lazyExplicitInterfaceImplementations = ImmutableArray.Empty; } - bool isIndexer = IsIndexer; - isAutoProperty = isAutoProperty && !(containingType.IsInterface && !IsStatic) && !IsAbstract && !IsExtern && !isIndexer; - if (hasExplicitAccessMod) { _propertyFlags |= Flags.HasExplicitAccessModifier; } - if (isAutoProperty) + if (hasAutoPropertyGet) + { + _propertyFlags |= Flags.HasAutoPropertyGet; + } + + if (hasAutoPropertySet) { - _propertyFlags |= Flags.IsAutoProperty; + _propertyFlags |= Flags.HasAutoPropertySet; + } + + if (usesFieldKeyword) + { + _propertyFlags |= Flags.UsesFieldKeyword; } if (hasInitializer) @@ -142,7 +153,7 @@ protected SourcePropertySymbolBase( _propertyFlags |= Flags.AccessorsHaveImplementation; } - if (isIndexer) + if (IsIndexer) { if (indexerNameAttributeLists.Count == 0 || isExplicitInterfaceImplementation) { @@ -160,26 +171,24 @@ protected SourcePropertySymbolBase( _name = _lazySourceName = memberName; } - if ((isAutoProperty && hasGetAccessor) || hasInitializer) + if (usesFieldKeyword || hasAutoPropertyGet || hasAutoPropertySet || hasInitializer) { Debug.Assert(!IsIndexer); - string fieldName = GeneratedNames.MakeBackingFieldName(_name); - BackingField = new SynthesizedBackingFieldSymbol(this, - fieldName, - isReadOnly: (hasGetAccessor && !hasSetAccessor) || isInitOnly, - this.IsStatic, - hasInitializer); + _propertyFlags |= Flags.RequiresBackingField; } if (hasGetAccessor) { - _getMethod = CreateGetAccessorSymbol(isAutoPropertyAccessor: isAutoProperty, diagnostics); + _getMethod = CreateGetAccessorSymbol(hasAutoPropertyGet, diagnostics); } if (hasSetAccessor) { - _setMethod = CreateSetAccessorSymbol(isAutoPropertyAccessor: isAutoProperty, diagnostics); + _setMethod = CreateSetAccessorSymbol(hasAutoPropertySet, diagnostics); } + + // We shouldn't calculate the backing field before the accessors above are created. + Debug.Assert(_lazyDeclaredBackingField is null); } private void EnsureSignatureGuarded(BindingDiagnosticBag diagnostics) @@ -290,7 +299,7 @@ protected void CheckInitializerIfNeeded(BindingDiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_InstancePropertyInitializerInInterface, Location); } - else if (!IsAutoProperty) + else if (!IsAutoPropertyOrUsesFieldKeyword) { diagnostics.Add(ErrorCode.ERR_InitializerOnNonAutoProperty, Location); } @@ -638,23 +647,132 @@ public bool HasSkipLocalsInitAttribute } } - internal bool IsAutoPropertyWithGetAccessor - => IsAutoProperty && _getMethod is object; + internal bool IsAutoPropertyOrUsesFieldKeyword + => IsSetOnEitherPart(Flags.HasAutoPropertyGet | Flags.HasAutoPropertySet | Flags.UsesFieldKeyword); + + internal bool UsesFieldKeyword + => IsSetOnEitherPart(Flags.UsesFieldKeyword); protected bool HasExplicitAccessModifier => (_propertyFlags & Flags.HasExplicitAccessModifier) != 0; - protected bool IsAutoProperty - => (_propertyFlags & Flags.IsAutoProperty) != 0; + internal bool IsAutoProperty + => IsSetOnEitherPart(Flags.HasAutoPropertyGet | Flags.HasAutoPropertySet); + + internal bool HasAutoPropertyGet + => IsSetOnEitherPart(Flags.HasAutoPropertyGet); + + internal bool HasAutoPropertySet + => IsSetOnEitherPart(Flags.HasAutoPropertySet); + + /// + /// True if the property has a synthesized backing field, and + /// either no accessor or the accessor is auto-implemented. + /// + internal bool CanUseBackingFieldDirectlyInConstructor(bool useAsLvalue) + { + if (BackingField is null) + { + return false; + } + if (useAsLvalue) + { + return SetMethod is null || HasAutoPropertySet; + } + else + { + return GetMethod is null || HasAutoPropertyGet; + } + } + + private bool IsSetOnEitherPart(Flags flags) + { + return (_propertyFlags & flags) != 0 || + (this is SourcePropertySymbol { OtherPartOfPartial: { } otherPart } && (otherPart._propertyFlags & flags) != 0); + } protected bool AccessorsHaveImplementation => (_propertyFlags & Flags.AccessorsHaveImplementation) != 0; /// - /// Backing field for automatically implemented property, or - /// for a property with an initializer. + /// Backing field for an automatically implemented property, or + /// a property with an accessor using the 'field' keyword, or + /// a property with an initializer. /// - internal SynthesizedBackingFieldSymbol BackingField { get; } + internal SynthesizedBackingFieldSymbol BackingField +#nullable enable + { + get + { + if (_lazyMergedBackingField is null) + { + var backingField = DeclaredBackingField; + // The property should only be used after members in the containing + // type are complete, and partial members have been merged. + if (!_containingType.AreMembersComplete) + { + // When calling through the SemanticModel, partial members are not + // necessarily merged when the containing type includes a primary + // constructor - see https://github.com/dotnet/roslyn/issues/75002. + Debug.Assert(_containingType.PrimaryConstructor is { }); + return backingField; + } + Interlocked.CompareExchange(ref _lazyMergedBackingField, backingField, null); + } + return _lazyMergedBackingField; + } + } + + internal SynthesizedBackingFieldSymbol? DeclaredBackingField + { + get + { + if (_lazyDeclaredBackingField is null && + (_propertyFlags & Flags.RequiresBackingField) != 0) + { + Interlocked.CompareExchange(ref _lazyDeclaredBackingField, CreateBackingField(), null); + } + return _lazyDeclaredBackingField; + } + } + + internal void SetMergedBackingField(SynthesizedBackingFieldSymbol? backingField) + { + Interlocked.CompareExchange(ref _lazyMergedBackingField, backingField, null); + Debug.Assert((object?)_lazyMergedBackingField == backingField); + } + + private SynthesizedBackingFieldSymbol CreateBackingField() + { + string fieldName = GeneratedNames.MakeBackingFieldName(_name); + + // The backing field is readonly if any of the following holds: + // - The containing type is declared readonly and the property is an instance property. + bool isReadOnly; + if (!IsStatic && ContainingType.IsReadOnly) + { + isReadOnly = true; + } + // - The property is declared readonly. + else if (HasReadOnlyModifier) + { + isReadOnly = true; + } + // - The property has no set accessor or is initonly or is declared readonly, and + // the get accessor, if any, is automatically implemented, or declared readonly. + else if ((_setMethod is null || _setMethod.IsInitOnly || _setMethod.IsDeclaredReadOnly) && + (_getMethod is null || (_propertyFlags & Flags.HasAutoPropertyGet) != 0 || _getMethod.IsDeclaredReadOnly)) + { + isReadOnly = true; + } + else + { + isReadOnly = false; + } + + return new SynthesizedBackingFieldSymbol(this, fieldName, isReadOnly: isReadOnly, isStatic: this.IsStatic, hasInitializer: (_propertyFlags & Flags.HasInitializer) != 0); + } +#nullable disable internal override bool MustCallMethodsDirectly { @@ -700,11 +818,9 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, diagnostics.Add(ErrorCode.ERR_RefReturningPropertiesCannotBeRequired, Location); } - if (IsAutoPropertyWithGetAccessor) + if (IsAutoPropertyOrUsesFieldKeyword) { - Debug.Assert(GetMethod is object); - - if (!IsStatic && SetMethod is { IsInitOnly: false }) + if (!IsStatic && ((_propertyFlags & Flags.HasAutoPropertySet) != 0) && SetMethod is { IsInitOnly: false }) { if (ContainingType.IsReadOnly) { @@ -725,13 +841,28 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, diagnostics.Add(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, Location); } - // get-only auto property should not override settable properties - if (this.IsOverride && SetMethod is null && !this.IsReadOnly) + // Auto property should override both accessors. + if (this.IsOverride) { - diagnostics.Add(ErrorCode.ERR_AutoPropertyMustOverrideSet, Location); + var overriddenProperty = (PropertySymbol)this.GetLeastOverriddenMember(this.ContainingType); + if ((overriddenProperty.GetMethod is { } && GetMethod is null) || + (overriddenProperty.SetMethod is { } && SetMethod is null)) + { + diagnostics.Add(ErrorCode.ERR_AutoPropertyMustOverrideSet, Location); + } } } + if (!IsStatic && + ContainingType.IsInterface && + IsSetOnEitherPart(Flags.RequiresBackingField) && + // Should probably ignore initializer (and report ERR_InterfacesCantContainFields) if the + // property uses 'field' or has an auto-implemented accessor. + !IsSetOnEitherPart(Flags.HasInitializer)) + { + diagnostics.Add(ErrorCode.ERR_InterfacesCantContainFields, Location); + } + if (!IsExpressionBodied) { bool hasGetAccessor = GetMethod is object; @@ -776,8 +907,11 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, diagnostics.Add(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, Location); } } - else if (!hasGetAccessor && IsAutoProperty) + else if (!hasGetAccessor && HasAutoPropertySet) { + // The only forms of auto-property that are disallowed are { set; } and { init; }. + // Other forms of auto- or manually-implemented accessors are allowed + // including equivalent field cases such as { set { field = value; } }. diagnostics.Add(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, _setMethod!.GetFirstLocation()); } @@ -1082,7 +1216,7 @@ private SynthesizedSealedPropertyAccessor MakeSynthesizedSealedAccessor() AttributeLocation IAttributeTargetSymbol.DefaultAttributeLocation => AttributeLocation.Property; AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations - => IsAutoPropertyWithGetAccessor + => IsAutoPropertyOrUsesFieldKeyword ? AttributeLocation.Property | AttributeLocation.Field : AttributeLocation.Property; @@ -1106,17 +1240,11 @@ private CustomAttributesBag GetAttributesBag() Debug.Assert(!ReferenceEquals(copyFrom, this)); // The property is responsible for completion of the backing field - // NB: when the **field keyword feature** is implemented, it's possible that synthesized field symbols will also be merged or shared between partial property parts. - // If we do that then this check should possibly be moved, and asserts adjusted accordingly. _ = BackingField?.GetAttributes(); bool bagCreatedOnThisThread; if (copyFrom is not null) { - // When partial properties get the ability to have a backing field, - // the implementer will have to decide how the BackingField symbol works in 'copyFrom' scenarios. - Debug.Assert(!IsAutoProperty); - var attributesBag = copyFrom.GetAttributesBag(); bagCreatedOnThisThread = Interlocked.CompareExchange(ref _lazyCustomAttributesBag, attributesBag, null) == null; } @@ -1591,6 +1719,15 @@ internal override void ForceComplete(SourceLocation? locationOpt, Predicate= 0 && closeBracketOffset + 1 < name.Length) { int c = name[closeBracketOffset + 1]; - if (c is >= '1' and <= '9' or >= 'a' and <= 'z') // Note '0' is not special. + if (c is >= '1' and <= '9' or >= 'a' and <= 'z' or >= 'A' and <= 'Z') // Note '0' is not special. { kind = (GeneratedNameKind)c; return true; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs index bf7b4599dc6e0..3b55781ebc14a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs @@ -8,6 +8,7 @@ using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -916,6 +917,12 @@ internal override bool GetGuidString(out string? guidString) return false; } + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + AddSynthesizedAttribute(ref attributes, DeclaringCompilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + } + internal override bool HasCollectionBuilderAttribute(out TypeSymbol? builderType, out string? methodName) { builderType = null; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs index 1dc7444d03efb..25d605aae2452 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordEqualityContractProperty.cs @@ -32,10 +32,11 @@ public SynthesizedRecordEqualityContractProperty(SourceMemberContainerTypeSymbol }, hasInitializer: false, hasExplicitAccessMod: false, - isAutoProperty: false, + hasAutoPropertyGet: false, + hasAutoPropertySet: false, isExpressionBodied: false, - isInitOnly: false, accessorsHaveImplementation: true, + usesFieldKeyword: false, RefKind.None, PropertyName, indexerNameAttributeLists: new SyntaxList(), diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPropertySymbol.cs index 2d905f6daf0f8..898b4c160e30a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordPropertySymbol.cs @@ -30,10 +30,11 @@ public SynthesizedRecordPropertySymbol( modifiers: DeclarationModifiers.Public | (isOverride ? DeclarationModifiers.Override : DeclarationModifiers.None), hasInitializer: true, // Synthesized record properties always have a synthesized initializer hasExplicitAccessMod: false, - isAutoProperty: true, + hasAutoPropertyGet: true, + hasAutoPropertySet: true, isExpressionBodied: false, - isInitOnly: ShouldUseInit(containingType), accessorsHaveImplementation: true, + usesFieldKeyword: false, RefKind.None, backingParameter.Name, indexerNameAttributeLists: new SyntaxList(), diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs index 323447d1aa226..ba0d9afc70e4b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs @@ -101,7 +101,13 @@ internal override Location ErrorLocation => _property.Location; protected override OneOrMany> GetAttributeDeclarations() - => _property.GetAttributeDeclarations(); + { + // The backing field for a partial property may have been calculated for either + // the definition part or the implementation part. Regardless, we should use + // the attributes from the definition part. + var property = (_property as SourcePropertySymbol)?.SourcePartialDefinitionPart ?? _property; + return property.GetAttributeDeclarations(); + } public override Symbol AssociatedSymbol => _property; @@ -149,7 +155,7 @@ internal override void PostDecodeWellKnownAttributes(ImmutableArray TypeParameters { get { - Debug.Assert(!_typeParameters.IsDefault, $"Expected {nameof(SetTypeParameters)} prior to accessing this property."); + RoslynDebug.Assert(!_typeParameters.IsDefault, $"Expected {nameof(SetTypeParameters)} prior to accessing this property."); if (_typeParameters.IsDefault) { return ImmutableArray.Empty; @@ -173,7 +173,7 @@ public override ImmutableArray Parameters { get { - Debug.Assert(!_parameters.IsDefault, $"Expected {nameof(SetParameters)} prior to accessing this property."); + RoslynDebug.Assert(!_parameters.IsDefault, $"Expected {nameof(SetParameters)} prior to accessing this property."); if (_parameters.IsDefault) { return ImmutableArray.Empty; @@ -291,7 +291,7 @@ internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementati return false; } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionConstructorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionConstructorSymbol.cs new file mode 100644 index 0000000000000..7af8299ab93d2 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionConstructorSymbol.cs @@ -0,0 +1,68 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Emit; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + internal sealed class SynthesizedHotReloadExceptionConstructorSymbol : SynthesizedInstanceConstructor + { + private readonly ImmutableArray _parameters; + + internal SynthesizedHotReloadExceptionConstructorSymbol(NamedTypeSymbol containingType, TypeSymbol stringType, TypeSymbol intType) : + base(containingType) + { + _parameters = + [ + SynthesizedParameterSymbol.Create(this, TypeWithAnnotations.Create(stringType), ordinal: 0, RefKind.None), + SynthesizedParameterSymbol.Create(this, TypeWithAnnotations.Create(intType), ordinal: 1, RefKind.None) + ]; + } + + public override ImmutableArray Parameters => _parameters; + + /// + /// Exception message. + /// + public ParameterSymbol MessageParameter => _parameters[0]; + + /// + /// Integer value of . + /// + public ParameterSymbol CodeParameter => _parameters[1]; + + internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) + { + var containingType = (SynthesizedHotReloadExceptionSymbol)ContainingType; + + var factory = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); + factory.CurrentFunction = this; + + var exceptionConstructor = (MethodSymbol?)factory.WellKnownMember(WellKnownMember.System_Exception__ctorString, isOptional: true); + if (exceptionConstructor is null) + { + diagnostics.Add(ErrorCode.ERR_EncUpdateFailedMissingSymbol, + Location.None, + CodeAnalysisResources.Constructor, + "System.Exception..ctor(string)"); + + factory.CloseMethod(factory.Block()); + return; + } + + var block = factory.Block( + ImmutableArray.Create( + factory.ExpressionStatement(factory.Call( + factory.This(), + exceptionConstructor, + factory.Parameter(MessageParameter))), + factory.Assignment(factory.Field(factory.This(), containingType.CodeField), factory.Parameter(CodeParameter)), + factory.Return() + )); + + factory.CloseMethod(block); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs new file mode 100644 index 0000000000000..c98708ef4cd6a --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedHotReloadExceptionSymbol.cs @@ -0,0 +1,162 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Cci; +using Roslyn.Utilities; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Emit; +using Microsoft.CodeAnalysis.PooledObjects; +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + internal sealed class SynthesizedHotReloadExceptionSymbol : NamedTypeSymbol + { + public const string NamespaceName = "System.Runtime.CompilerServices"; + public const string TypeName = "HotReloadException"; + public const string CodeFieldName = "Code"; + + private readonly NamedTypeSymbol _baseType; + private readonly NamespaceSymbol _namespace; + + // constructor and field: + private readonly ImmutableArray _members; + + public SynthesizedHotReloadExceptionSymbol( + NamespaceSymbol containingNamespace, + NamedTypeSymbol exceptionType, + TypeSymbol stringType, + TypeSymbol intType) + { + _namespace = containingNamespace; + _baseType = exceptionType; + + _members = + [ + new SynthesizedHotReloadExceptionConstructorSymbol(this, stringType, intType), + new SynthesizedFieldSymbol(this, intType, CodeFieldName, isPublic: true, isReadOnly: true, isStatic: false) + ]; + } + + public MethodSymbol Constructor + => (MethodSymbol)_members[0]; + + public FieldSymbol CodeField + => (FieldSymbol)_members[1]; + + public override ImmutableArray GetMembers() + => _members; + + public override ImmutableArray GetMembers(string name) + => name switch + { + WellKnownMemberNames.InstanceConstructorName => [Constructor], + CodeFieldName => [CodeField], + _ => [] + }; + + public override IEnumerable MemberNames + => _members.Select(static m => m.Name); + + internal override IEnumerable GetFieldsToEmit() + => [CodeField]; + + public override ImmutableArray GetTypeMembers() => []; + public override ImmutableArray GetTypeMembers(ReadOnlyMemory name) => []; + public override ImmutableArray GetTypeMembers(ReadOnlyMemory name, int arity) => []; + + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + + AddSynthesizedAttribute( + ref attributes, + moduleBuilder.Compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + } + + public override string Name => TypeName; + public override int Arity => 0; + public override ImmutableArray TypeParameters => []; + public override bool IsImplicitlyDeclared => true; + internal override ManagedKind GetManagedKind(ref CompoundUseSiteInfo useSiteInfo) => ManagedKind.Managed; + public override NamedTypeSymbol ConstructedFrom => this; + public override bool MightContainExtensionMethods => false; + internal override bool HasDeclaredRequiredMembers => false; + public override Accessibility DeclaredAccessibility => Accessibility.Internal; + public override TypeKind TypeKind => TypeKind.Class; + public override Symbol ContainingSymbol => _namespace; + public override NamespaceSymbol ContainingNamespace => _namespace; + public override ImmutableArray Locations => []; + public override ImmutableArray DeclaringSyntaxReferences => []; + public override bool IsStatic => false; + public override bool IsRefLikeType => false; + public override bool IsReadOnly => false; + public override bool IsAbstract => false; + public override bool IsSealed => true; + internal override ImmutableArray TypeArgumentsWithAnnotationsNoUseSiteDiagnostics => []; + internal override bool MangleName => false; + internal sealed override bool IsFileLocal => false; + internal sealed override FileIdentifier? AssociatedFileIdentifier => null; + internal override bool HasCodeAnalysisEmbeddedAttribute => true; + internal override bool IsInterpolatedStringHandlerType => false; + internal override bool HasSpecialName => false; + internal override bool IsComImport => false; + internal override bool IsWindowsRuntimeImport => false; + internal override bool ShouldAddWinRTMembers => false; + public override bool IsSerializable => false; + public sealed override bool AreLocalsZeroed => ContainingModule.AreLocalsZeroed; + internal override TypeLayout Layout => default; + internal override CharSet MarshallingCharSet => DefaultMarshallingCharSet; + internal override bool HasDeclarativeSecurity => false; + internal override bool IsInterface => false; + internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics => _baseType; + internal override ObsoleteAttributeData? ObsoleteAttributeData => null; + protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) => throw ExceptionUtilities.Unreachable(); + internal override ImmutableArray GetAppliedConditionalSymbols() => []; + internal override AttributeUsageInfo GetAttributeUsageInfo() => AttributeUsageInfo.Default; + internal override NamedTypeSymbol GetDeclaredBaseType(ConsList basesBeingResolved) => _baseType; + internal override ImmutableArray GetDeclaredInterfaces(ConsList basesBeingResolved) => []; + internal override ImmutableArray GetEarlyAttributeDecodingMembers() => GetMembers(); + internal override ImmutableArray GetEarlyAttributeDecodingMembers(string name) => GetMembers(name); + internal override ImmutableArray GetInterfacesToEmit() => []; + internal override IEnumerable? GetSecurityInformation() => null; + internal override ImmutableArray InterfacesNoUseSiteDiagnostics(ConsList? basesBeingResolved = null) => []; + internal sealed override bool IsRecord => false; + internal sealed override bool IsRecordStruct => false; + internal sealed override bool HasPossibleWellKnownCloneMethod() => false; + internal sealed override NamedTypeSymbol AsNativeInteger() => throw ExceptionUtilities.Unreachable(); + internal sealed override NamedTypeSymbol? NativeIntegerUnderlyingType => null; + internal sealed override IEnumerable<(MethodSymbol Body, MethodSymbol Implemented)> SynthesizedInterfaceMethodImpls() => []; + + internal override bool GetGuidString([NotNullWhen(true)] out string? guidString) + { + guidString = null; + return false; + } + + internal sealed override bool HasInlineArrayAttribute(out int length) + { + length = 0; + return false; + } + + internal sealed override bool HasCollectionBuilderAttribute(out TypeSymbol? builderType, out string? methodName) + { + builderType = null; + methodName = null; + return false; + } + + internal sealed override bool HasAsyncMethodBuilderAttribute(out TypeSymbol? builderArgument) + { + builderArgument = null; + return false; + } + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs index f962d2ddf1f0b..cdde99030bca4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs @@ -223,7 +223,7 @@ internal sealed override bool RequiresSecurityObject get { return _interfaceMethod.RequiresSecurityObject; } } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return !IsStatic; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs index c3bf55e2bd866..e173fa2d011ef 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs @@ -240,7 +240,7 @@ internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementati return false; } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return false; } @@ -289,7 +289,7 @@ protected void GenerateMethodBodyCore(TypeCompilationState compilationState, Bin factory.CurrentFunction = this; if (ContainingType.BaseTypeNoUseSiteDiagnostics is MissingMetadataTypeSymbol) { - // System_Attribute was not found or was inaccessible + // Containing type was not found or was inaccessible factory.CloseMethod(factory.Block()); return; } @@ -297,7 +297,7 @@ protected void GenerateMethodBodyCore(TypeCompilationState compilationState, Bin var baseConstructorCall = Binder.GenerateBaseParameterlessConstructorInitializer(this, diagnostics); if (baseConstructorCall == null) { - // Attribute..ctor was not found or was inaccessible + // .ctor was not found or was inaccessible factory.CloseMethod(factory.Block()); return; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs index b182525234b3e..19e7b4476dcc7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs @@ -225,7 +225,7 @@ internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChang return false; } - internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs index fe9053b3d2ad8..a596adb68da1f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs @@ -97,7 +97,7 @@ internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChang return false; } - internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSealedPropertyAccessor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSealedPropertyAccessor.cs index a6380e8ce78e7..3896f75f165f4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSealedPropertyAccessor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSealedPropertyAccessor.cs @@ -307,7 +307,7 @@ internal override System.Reflection.MethodImplAttributes ImplementationAttribute } } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return true; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs index 7533be1e448e6..e7e49a20ee75c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs @@ -314,7 +314,7 @@ internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementati return false; } - internal sealed override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal sealed override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs index 00df312f7b719..0dcfcb6163033 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs @@ -186,9 +186,9 @@ public override bool IsImplicitlyDeclared } } - internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) + internal override bool IsMetadataVirtual(IsMetadataVirtualOption option = IsMetadataVirtualOption.None) { - return UnderlyingMethod.IsMetadataVirtual(ignoreInterfaceImplementationChanges); + return UnderlyingMethod.IsMetadataVirtual(option); } internal override bool IsMetadataFinal diff --git a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNode.cs b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNode.cs index 19869a60ef521..39479fcba12c6 100644 --- a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNode.cs +++ b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNode.cs @@ -230,21 +230,11 @@ protected void SetFactoryContext(SyntaxFactoryContext context) { SetFlags(NodeFlags.FactoryContextIsInQuery); } - } - - internal static NodeFlags SetFactoryContext(NodeFlags flags, SyntaxFactoryContext context) - { - if (context.IsInAsync) - { - flags |= NodeFlags.FactoryContextIsInAsync; - } - if (context.IsInQuery) + if (context.IsInFieldKeywordContext) { - flags |= NodeFlags.FactoryContextIsInQuery; + SetFlags(NodeFlags.FactoryContextIsInFieldKeywordContext); } - - return flags; } public sealed override CodeAnalysis.SyntaxToken CreateSeparator(SyntaxNode element) diff --git a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNodeCache.cs b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNodeCache.cs index a7787fec446e0..fc4d86ef66ac6 100644 --- a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNodeCache.cs +++ b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/CSharpSyntaxNodeCache.cs @@ -39,6 +39,11 @@ private static GreenNode.NodeFlags GetNodeFlags(SyntaxFactoryContext context) flags |= GreenNode.NodeFlags.FactoryContextIsInQuery; } + if (context.IsInFieldKeywordContext) + { + flags |= GreenNode.NodeFlags.FactoryContextIsInFieldKeywordContext; + } + return flags; } } diff --git a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs new file mode 100644 index 0000000000000..b41530c1f7a5d --- /dev/null +++ b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs @@ -0,0 +1,156 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using CoreSyntax = Microsoft.CodeAnalysis.Syntax.InternalSyntax; + +namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax +{ + internal abstract partial class TypeDeclarationSyntax + { + public abstract TypeDeclarationSyntax UpdateCore( + CoreSyntax.SyntaxList attributeLists, + CoreSyntax.SyntaxList modifiers, + SyntaxToken keyword, + SyntaxToken identifier, + TypeParameterListSyntax typeParameterList, + ParameterListSyntax parameterList, + BaseListSyntax baseList, + CoreSyntax.SyntaxList constraintClauses, + SyntaxToken openBraceToken, + CoreSyntax.SyntaxList members, + SyntaxToken closeBraceToken, + SyntaxToken semicolonToken); + } + + internal partial class ClassDeclarationSyntax + { + public override TypeDeclarationSyntax UpdateCore( + CoreSyntax.SyntaxList attributeLists, + CoreSyntax.SyntaxList modifiers, + SyntaxToken keyword, + SyntaxToken identifier, + TypeParameterListSyntax typeParameterList, + ParameterListSyntax parameterList, + BaseListSyntax baseList, + CoreSyntax.SyntaxList constraintClauses, + SyntaxToken openBraceToken, + CoreSyntax.SyntaxList members, + SyntaxToken closeBraceToken, + SyntaxToken semicolonToken) + { + return this.Update( + attributeLists, + modifiers, + keyword, + identifier, + typeParameterList, + parameterList, + baseList, + constraintClauses, + openBraceToken, + members, + closeBraceToken, + semicolonToken); + } + } + + internal partial class InterfaceDeclarationSyntax + { + public override TypeDeclarationSyntax UpdateCore( + CoreSyntax.SyntaxList attributeLists, + CoreSyntax.SyntaxList modifiers, + SyntaxToken keyword, + SyntaxToken identifier, + TypeParameterListSyntax typeParameterList, + ParameterListSyntax parameterList, + BaseListSyntax baseList, + CoreSyntax.SyntaxList constraintClauses, + SyntaxToken openBraceToken, + CoreSyntax.SyntaxList members, + SyntaxToken closeBraceToken, + SyntaxToken semicolonToken) + { + return this.Update( + attributeLists, + modifiers, + keyword, + identifier, + typeParameterList, + parameterList, + baseList, + constraintClauses, + openBraceToken, + members, + closeBraceToken, + semicolonToken); + } + } + + internal partial class RecordDeclarationSyntax + { + public override TypeDeclarationSyntax UpdateCore( + CoreSyntax.SyntaxList attributeLists, + CoreSyntax.SyntaxList modifiers, + SyntaxToken keyword, + SyntaxToken identifier, + TypeParameterListSyntax typeParameterList, + ParameterListSyntax parameterList, + BaseListSyntax baseList, + CoreSyntax.SyntaxList constraintClauses, + SyntaxToken openBraceToken, + CoreSyntax.SyntaxList members, + SyntaxToken closeBraceToken, + SyntaxToken semicolonToken) + { + return this.Update( + attributeLists, + modifiers, + keyword, + this.ClassOrStructKeyword, + identifier, + typeParameterList, + parameterList, + baseList, + constraintClauses, + openBraceToken, + members, + closeBraceToken, + semicolonToken); + } + } + + internal partial class StructDeclarationSyntax + { + public override TypeDeclarationSyntax UpdateCore( + CoreSyntax.SyntaxList attributeLists, + CoreSyntax.SyntaxList modifiers, + SyntaxToken keyword, + SyntaxToken identifier, + TypeParameterListSyntax typeParameterList, + ParameterListSyntax parameterList, + BaseListSyntax baseList, + CoreSyntax.SyntaxList constraintClauses, + SyntaxToken openBraceToken, + CoreSyntax.SyntaxList members, + SyntaxToken closeBraceToken, + SyntaxToken semicolonToken) + { + return this.Update( + attributeLists, + modifiers, + keyword, + identifier, + typeParameterList, + parameterList, + baseList, + constraintClauses, + openBraceToken, + members, + closeBraceToken, + semicolonToken); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Syntax/LambdaUtilities.cs b/src/Compilers/CSharp/Portable/Syntax/LambdaUtilities.cs index dce50e032dd1e..9e17e5ecf689b 100644 --- a/src/Compilers/CSharp/Portable/Syntax/LambdaUtilities.cs +++ b/src/Compilers/CSharp/Portable/Syntax/LambdaUtilities.cs @@ -396,6 +396,7 @@ internal static bool IsClosureScope(SyntaxNode node) case SyntaxKind.ForEachStatement: case SyntaxKind.ForEachVariableStatement: case SyntaxKind.UsingStatement: + case SyntaxKind.TryStatement: // ctor parameter captured by a lambda in a ctor initializer case SyntaxKind.ConstructorDeclaration: diff --git a/src/Compilers/CSharp/Portable/Syntax/LookupPosition.cs b/src/Compilers/CSharp/Portable/Syntax/LookupPosition.cs index 9015176b4b586..04d606e0d09c5 100644 --- a/src/Compilers/CSharp/Portable/Syntax/LookupPosition.cs +++ b/src/Compilers/CSharp/Portable/Syntax/LookupPosition.cs @@ -403,9 +403,7 @@ internal static SyntaxToken GetFirstExcludedToken(StatementSyntax statement) case SyntaxKind.GotoStatement: return ((GotoStatementSyntax)statement).SemicolonToken; case SyntaxKind.IfStatement: - IfStatementSyntax ifStmt = (IfStatementSyntax)statement; - ElseClauseSyntax? elseOpt = ifStmt.Else; - return GetFirstExcludedToken(elseOpt == null ? ifStmt.Statement : elseOpt.Statement); + return GetFirstExcludedIfStatementToken((IfStatementSyntax)statement); case SyntaxKind.LabeledStatement: return GetFirstExcludedToken(((LabeledStatementSyntax)statement).Statement); case SyntaxKind.LockStatement: @@ -452,6 +450,26 @@ internal static SyntaxToken GetFirstExcludedToken(StatementSyntax statement) } } + private static SyntaxToken GetFirstExcludedIfStatementToken(IfStatementSyntax ifStmt) + { + while (true) + { + ElseClauseSyntax? elseOpt = ifStmt.Else; + if (elseOpt is null) + { + return GetFirstExcludedToken(ifStmt.Statement); + } + if (elseOpt.Statement is IfStatementSyntax nestedIf) + { + ifStmt = nestedIf; + } + else + { + return GetFirstExcludedToken(elseOpt.Statement); + } + } + } + internal static bool IsInAnonymousFunctionOrQuery(int position, SyntaxNode lambdaExpressionOrQueryNode) { Debug.Assert(lambdaExpressionOrQueryNode.IsAnonymousFunction() || lambdaExpressionOrQueryNode.IsQuery()); diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index 6dc00ef5262e5..8e05ae9fee8b7 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -910,6 +910,21 @@ Creates a LiteralExpressionSyntax node. + + + + + + SyntaxToken representing the field keyword. + + + + Class which represents the syntax node for a field expression. + + + Creates a FieldExpressionSyntax node. + + diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs index cba16e079df44..8d4f888666a69 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxEquivalence.cs @@ -13,6 +13,9 @@ namespace Microsoft.CodeAnalysis.CSharp.Syntax internal static class SyntaxEquivalence { + private static readonly ObjectPool> s_equivalenceCheckStack = + new ObjectPool>(() => new Stack<(GreenNode?, GreenNode?)>()); + internal static bool AreEquivalent(SyntaxTree? before, SyntaxTree? after, Func? ignoreChildNode, bool topLevel) { if (before == after) @@ -102,13 +105,14 @@ private static bool AreTokensEquivalent(GreenNode? before, GreenNode? after, Fun private static bool AreEquivalentRecursive(GreenNode? before, GreenNode? after, Func? ignoreChildNode, bool topLevel) { // Use an explicit stack so we can walk down deep trees without blowing the real stack. - var stack = ArrayBuilder<(GreenNode? before, GreenNode? after)>.GetInstance(); + var stack = s_equivalenceCheckStack.Allocate(); stack.Push((before, after)); try { - while (stack.TryPop(out var current)) + while (stack.Count > 0) { + var current = stack.Pop(); if (!areEquivalentSingleLevel(current.before, current.after)) return false; } @@ -117,7 +121,8 @@ private static bool AreEquivalentRecursive(GreenNode? before, GreenNode? after, } finally { - stack.Free(); + stack.Clear(); + s_equivalenceCheckStack.Free(stack); } bool areEquivalentSingleLevel(GreenNode? before, GreenNode? after) diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs index bd23d70560c3d..5c7b02cdd3254 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs @@ -716,7 +716,7 @@ public static XmlEmptyElementSyntax XmlSeeAlsoElement(CrefSyntax cref) public static XmlElementSyntax XmlSeeAlsoElement(Uri linkAddress, SyntaxList linkText) { XmlElementSyntax element = XmlElement(DocumentationCommentXmlNames.SeeAlsoElementName, linkText); - return element.WithStartTag(element.StartTag.AddAttributes(XmlTextAttribute(DocumentationCommentXmlNames.CrefAttributeName, linkAddress.ToString()))); + return element.WithStartTag(element.StartTag.AddAttributes(XmlTextAttribute(DocumentationCommentXmlNames.HrefAttributeName, linkAddress.ToString()))); } /// diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index f5c5b69c74910..d697c4c2202be 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -699,6 +699,7 @@ public enum SyntaxKind : ushort NullLiteralExpression = 8754, DefaultLiteralExpression = 8755, Utf8StringLiteralExpression = 8756, + FieldExpression = 8757, // primary function expressions TypeOfExpression = 8760, diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 539e55b64f947..22f29516987a3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -287,11 +287,6 @@ Člen záznamu {0} musí být čitelná vlastnost instance nebo pole typu {1}, která se bude shodovat s pozičním parametrem {2}. - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - Výraz foreach nejde použít na enumerátorech typu {0} v asynchronních metodách nebo metodách iterátoru, protože {0} je ref struct nebo parametr typu umožňující struktury ref struct. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Parametry typu {0} nemůžou být deklarované v asynchronních metodách nebo asynchronních výrazech lambda. @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + U tohoto členu nelze použít OverloadResolutionPriorityAttribute. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + U přepisujících členů nelze použít OverloadResolutionPriorityAttribute. @@ -507,6 +502,11 @@ Typ {0} nelze inicializovat pomocí výrazu kolekce, protože typ není konstruovatelný. + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' Parametr typu {1} má omezení unmanaged, takže není možné používat {1} jako omezení pro {0}. @@ -632,6 +632,11 @@ Příkaz nemůže začínat na else. + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Vstupní body aplikací nemůžou mít atribut UnmanagedCallersOnly. @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + Funkce {0} není v jazyce C# 13.0 dostupná. Použijte prosím verzi jazyka {1} nebo vyšší. @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - Experimentální funkce interceptors není v tomto oboru názvů povolená. Přidejte do projektu {0}. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - {0}: typ použitý v asynchronním příkazu using musí být implicitně převoditelný na System.IAsyncDisposable nebo musí implementovat odpovídající metodu DisposeAsync. Měli jste v úmyslu použít using nebo await using? + {0}: Typ použitý v asynchronním příkazu using musí implementovat rozhraní System.IAsyncDisposable nebo odpovídající metodu DisposeAsync. Nechtěli jste místo příkazu await using použít příkaz using? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - {0}: Typ použitý v příkazu using musí být implicitně převoditelný na System.IDisposable. Neměli jste v úmyslu použít await using místo using? + {0}: Typ použitý v příkazu using musí implementovat rozhraní System.IDisposable. Nechtěli jste místo příkazu using použít příkaz await using? @@ -1737,6 +1742,11 @@ Částečná vlastnost nesmí mít víc implementujících deklarací. + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. + + Property accessor '{0}' must be '{1}' to match the definition part Přístupový objekt vlastnosti {0} musí být {1}, aby odpovídal definiční části. @@ -2397,9 +2407,9 @@ vzory rozšířených vlastností - - field and value keywords - klíčová slova pole a hodnoty + + field keyword + klíčové slovo pole @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + priorita řešení přetížení @@ -2637,11 +2647,6 @@ ukazatel - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - {0} je kontextové klíčové slovo v přístupových objektech vlastností počínaje jazykovou verzí {1}. Místo toho použijte @{0}. - - Identifier is a contextual keyword, with a specific meaning, in a later language version. Identifikátor je kontextové klíčové slovo se specifickým významem v novější jazykové verzi. @@ -2932,6 +2937,16 @@ Použití proměnné v tomto kontextu může vystavit odkazované proměnné mimo rozsah jejich oboru. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. Operátor převodu vloženého pole se nepoužije pro převod z výrazu deklarujícího typu. @@ -5278,6 +5293,16 @@ Člen asynchronního iterátoru má jeden nebo více parametrů typu CancellationToken, ale žádný z nich není dekorovaný atributem EnumeratorCancellation, takže parametr tokenu zrušení z vygenerovaného výrazu IAsyncEnumerable<>.GetAsyncEnumerator se nespotřebuje. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. Proměnná {0} {1}, která nemůže být null, musí při ukončování konstruktoru obsahovat hodnotu, která není null. Zvažte přidání modifikátoru required nebo deklaraci {0} s možnou hodnotou null. @@ -7592,11 +7617,6 @@ Pokud se taková třída používá jako základní třída a pokud odvozující Pro metodu s deklarací static a extern musí být zadaný atribut DllImport. - - Cannot update '{0}'; attribute '{1}' is missing. - Nelze aktualizovat {0}; chybí atribut {1}. - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. Atribut DllImport se nedá použít u metody, která je obecná nebo obsažená v obecné metodě nebo typu. @@ -9583,7 +9603,7 @@ Blok catch() po bloku catch (System.Exception e) může zachytit výjimky, kter '{0}': type used in a using statement must implement 'System.IDisposable'. - {0}: Typ použitý v příkazu using musí být implicitně převeditelný na System.IDisposable. + {0}: Typ použitý v příkazu using musí implementovat rozhraní System.IDisposable. @@ -12160,8 +12180,8 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference - Only auto-implemented properties can have initializers. - Jenom automaticky implementované vlastnosti můžou mít inicializátory. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - Informace o ladění metody {0} (token 0x{1:X8}) ze sestavení {2} nelze přečíst. + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - {0}: typ použitý v asynchronním příkazu using musí být implicitně převoditelný na System.IAsyncDisposable nebo musí implementovat odpovídající metodu DisposeAsync. + {0}: Typ použitý v asynchronním příkazu using musí implementovat rozhraní System.IAsyncDisposable nebo odpovídající metodu DisposeAsync. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index fd88c2dfb3393..c90f3593dbf38 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -287,11 +287,6 @@ Das Datensatzelement "{0}" muss eine lesbare Instanzeigenschaft oder ein Feld vom Typ "{1}" sein, um dem Positionsparameter "{2}" zu entsprechen. - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - Die Anweisung „foreach“ kann nicht für Enumeratoren vom Typ „{0}“ in asynchronen oder Enumeratormethoden verwendet werden, da „{0}“ eine Verweisstruktur oder ein Typparameter ist, der eine Verweisstruktur zulässt. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Parameter vom Typ „{0}“ können nicht in asynchronen Methoden oder asynchronen Lambdaausdrücken deklariert werden. @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + „OverloadResolutionPriorityAttribute“ kann für dieses Element nicht verwendet werden. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + „OverloadResolutionPriorityAttribute“ kann nicht für ein überschriebenes Element verwendet werden. @@ -507,6 +502,11 @@ Der Typ "{0}" kann nicht mit einem Sammlungsausdruck initialisiert werden, da der Typ nicht konstruiert werden kann. + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' Der {1}-Typparameter enthält die Einschränkung "unmanaged". "{1}" kann daher nicht als Einschränkung für "{0}" verwendet werden. @@ -632,6 +632,11 @@ Eine Anweisung kann nicht mit "else" beginnen. + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Anwendungseinstiegspunkte können nicht mit dem Attribut "UnmanagedCallersOnly" versehen werden. @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + Die Funktion „{0}“ ist in C# 13.0 nicht verfügbar. Verwenden Sie Sprachversion {1} oder höher. @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - Das experimentelle Feature "Interceptors" ist nicht in diesem Namespace aktiviert. Fügen Sie Ihrem Projekt "{0}" hinzu. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - "{0}": Der in einer asynchronen using-Anweisung verwendete Typ muss implizit in "System.IAsyncDisposable" konvertiert werden können oder eine geeignete DisposeAsync-Methode implementieren. Meinten Sie "using" anstelle von "await using"? + „{0}“: Der in einer asynchronen using-Anweisung verwendete Typ muss "System.IAsyncDisposable" implementieren oder eine geeignete „DisposeAsync“-Methode implementieren. Meinten Sie "using" anstelle von "await using"? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - "{0}": Der in einer using-Anweisung verwendete Typ muss implizit in "System.IDisposable" konvertierbar sein. Meinten Sie "await using" anstelle von "using"? + „{0}“: Der in einer using-Anweisung verwendete Typ muss „System.IDisposable“ implementieren. Meinten Sie „await using“ anstelle von „using“? @@ -1737,6 +1742,11 @@ Eine partielle Eigenschaft darf nicht über mehrere implementierende Deklarationen verfügen. + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. + + Property accessor '{0}' must be '{1}' to match the definition part Der Eigenschaftenaccessor "{0}" muss "{1}" sein, damit er mit dem Definitionsteil übereinstimmt. @@ -2397,9 +2407,9 @@ Muster für erweiterte Eigenschaften - - field and value keywords - Schlüsselwörter für Feld und Wert + + field keyword + Feld Schlüsselwort @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + Priorität der Überladungsauflösung @@ -2637,11 +2647,6 @@ Zeiger - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - "{0}" ist ein kontextbezogenes Schlüsselwort in Eigenschaftenaccessoren ab Sprachversion {1}. Verwenden Sie stattdessen "@{0}". - - Identifier is a contextual keyword, with a specific meaning, in a later language version. Der Bezeichner ist ein kontextbezogenes Schlüsselwort mit einer bestimmten Bedeutung in einer späteren Sprachversion. @@ -2932,6 +2937,16 @@ Die Verwendung der Variablen in diesem Kontext kann dazu führen, dass referenzierte Variablen außerhalb ihres Deklarationsbereichs verfügbar gemacht werden. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. Der Inlinearray-Konvertierungsoperator wird nicht für die Konvertierung aus einem Ausdruck des deklarierenden Typs verwendet. @@ -5278,6 +5293,16 @@ Der Async-Iterator-Member weist mindestens einen Parameter vom Typ "CancellationToken" auf, aber keiner der Parameter umfasst das Attribut "EnumeratorCancellation", deshalb wird der Parameter für das Abbruchtoken aus dem generierten "IAsyncEnumerable<>.GetAsyncEnumerator" nicht verwendet. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. Non-Nullable-{0} „{1}“ muss beim Beenden des Konstruktors einen Wert ungleich NULL enthalten. Fügen Sie ggf. den „erforderlichen“ Modifizierer hinzu, oder deklarieren Sie den {0} als NULL-Werte zulassend. @@ -7592,11 +7617,6 @@ Wenn solch eine Klasse als Basisklasse verwendet wird und die ableitende Klasse Das DllImport-Attribut muss für eine Methode angegeben werden, die als "static" und "extern" markiert ist. - - Cannot update '{0}'; attribute '{1}' is missing. - "{0}" kann nicht aktualisiert werden. Das Attribut "{1}" fehlt. - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. Das DllImport-Attribut kann nicht auf eine Methode angewendet werden, die generisch ist oder in einer generischen Methode oder einem generischen Typ enthalten ist. @@ -9583,7 +9603,7 @@ Ein catch()-Block nach einem catch (System.Exception e)-Block kann nicht-CLS-Aus '{0}': type used in a using statement must implement 'System.IDisposable'. - "{0}": Der in einer using-Anweisung verwendete Typ muss implizit in "System.IDisposable" konvertierbar sein. + „{0}“: Der in einer using-Anweisung verwendete Typ muss „System.IDisposable“ implementieren. @@ -12160,8 +12180,8 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett - Only auto-implemented properties can have initializers. - Nur automatisch implementierte Eigenschaften können Initialisierer aufweisen. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - Die Debuginformationen der Methode "{0}" (Token 0x{1:X8}) können nicht aus der Assembly "{2}" gelesen werden. + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - "{0}": Der in einer asynchronen using-Anweisung verwendete Typ muss implizit in "System.IAsyncDisposable" konvertiert werden können oder eine geeignete DisposeAsync-Methode implementieren. + „{0}“: Der in einer asynchronen using-Anweisung verwendete Typ muss "System.IAsyncDisposable" implementieren oder eine geeignete „DisposeAsync“-Methode implementieren. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index f46c7ebdbe906..e3a2412694d3f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -287,11 +287,6 @@ El miembro de registro '{0}' debe ser una propiedad de instancia legible o un campo de tipo '{1}' para coincidir con el parámetro posicional '{2}'. - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - La instrucción foreach no puede funcionar en enumeradores de tipo "{0}" en métodos asincrónicos o iteradores porque "{0}" es un valor ref struct o un parámetro de tipo que permite ref struct. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Los parámetros de tipo "{0}" no pueden declararse en expresiones lambda o métodos asincrónicos. @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + No se puede usar "OverloadResolutionPriorityAttribute" en este miembro. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + No se puede usar "OverloadResolutionPriorityAttribute" en un miembro de reemplazo. @@ -507,6 +502,11 @@ No se puede inicializar el tipo "{0}" con una expresión de colección porque el tipo no se puede construir. + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' El parámetro de tipo "{1}" tiene la restricción "unmanaged"; por tanto, "{1}" no se puede usar como restricción para "{0}" @@ -632,6 +632,11 @@ “else” no puede iniciar una instrucción. + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Los puntos de entrada de la aplicación no se pueden atribuir con "UnmanagedCallersOnly". @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + La característica "{0}" no está disponible en C# 13.0. Use la versión de lenguaje {1} u otra superior. @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - La característica experimental "interceptores" no está habilitada en este espacio de nombres. Agregue '{0}' al proyecto. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - "{0}": el tipo usado en una instrucción using asincrónica debe poder convertirse de forma implícita en "System.IAsyncDisposable" o implementar un método "DisposeAsync" adecuado. ¿Quiso decir "using" en lugar de "await using"? + "{0}": el tipo usado en una instrucción using asincrónica debe implementar "System.IAsyncDisposable" o un método "DisposeAsync" adecuado. ¿Ha querido decir "using" en lugar de "await using"? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - "{0}": el tipo usado en una instrucción using debe poder convertirse implícitamente en "System.IDisposable". ¿Quiso decir "await using" en lugar de "using"? + "{0}": el tipo usado en una instrucción using debe implementar "System.IDisposable". ¿Ha querido decir "await using" en lugar de "using"? @@ -1737,6 +1742,11 @@ Una propiedad parcial no puede tener varias declaraciones de implementación + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. + + Property accessor '{0}' must be '{1}' to match the definition part El descriptor de acceso de propiedad '{0}' debe ser '{1}' para que coincida con la parte de definición @@ -2397,9 +2407,9 @@ patrones de propiedad extendidos - - field and value keywords - palabras clave de campo y valor + + field keyword + palabra clave field @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + prioridad de resolución de sobrecarga @@ -2637,11 +2647,6 @@ puntero - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - '{0}' es una palabra clave contextual en descriptores de acceso de propiedad a partir de la versión de idioma {1}. Use '@{0}' en su lugar. - - Identifier is a contextual keyword, with a specific meaning, in a later language version. El identificador es una palabra clave contextual, con un significado específico, en una versión posterior del lenguaje. @@ -2932,6 +2937,16 @@ Usar la variable en este contexto puede exponer variables a las que se hace referencia fuera de su ámbito de declaración + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. El operador de conversión de matriz en línea no se utilizará para la conversión de una expresión del tipo declarante. @@ -5278,6 +5293,16 @@ El miembro del iterador de asincronía tiene uno o más parámetros de tipo "CancellationToken", pero en ninguno se incluye el atributo "EnumeratorCancellation", por lo que el parámetro de token de cancelación del objeto "IAsyncEnumerable<>.GetAsyncEnumerator" generado no se consumirá + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. El elemento {0} "{1}" que no acepta valores NULL debe contener un valor distinto de NULL al salir del constructor. Considere la posibilidad de agregar el modificador "required'"o declarar el {0} como un valor que acepta valores NULL. @@ -7592,11 +7617,6 @@ Si se utiliza una clase de este tipo como clase base y si la clase derivada defi El atributo DllImport se debe especificar en un método marcado como 'static' y 'extern' - - Cannot update '{0}'; attribute '{1}' is missing. - No se puede actualizar '{0}'; falta el atributo '{1}'. - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. El atributo DllImport no se puede aplicar a un método que sea genérico o que esté contenido en un tipo o método genérico. @@ -9583,7 +9603,7 @@ Un bloque catch() después de un bloque catch (System.Exception e) puede abarcar '{0}': type used in a using statement must implement 'System.IDisposable'. - "{0}": el tipo usado en una instrucción using debe poder convertirse implícitamente en "System.IDisposable". + "{0}": el tipo usado en una instrucción using debe implementar "System.IDisposable". @@ -12160,8 +12180,8 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe - Only auto-implemented properties can have initializers. - Solo las propiedades implementadas automáticamente pueden tener inicializadores. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - No se puede leer la información de depuración del método "{0}" (token 0x{1:X8}) desde el ensamblado "{2}". + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - "{0}": el tipo usado en una instrucción using asincrónica debe poder convertirse de forma implícita en "System.IAsyncDisposable" o implementar un método "DisposeAsync" adecuado. + "{0}": el tipo usado en una instrucción using asincrónica debe implementar "System.IAsyncDisposable" o un método "DisposeAsync" adecuado. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index f804fae727f49..fd279067595c1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -287,11 +287,6 @@ Le membre d'enregistrement '{0}' doit être une propriété d'instance our champ lisible de type '{1}' pour correspondre au paramètre positionnel '{2}'. - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - L’instruction foreach ne peut pas fonctionner sur les énumérateurs de type « {0} » dans les méthodes asynchrones ou les méthodes d’itérateurs, car « {0} » est un type ref struct. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Les paramètres de type « {0} » ne peuvent pas être déclarés dans des méthodes asynchrones ou des expressions lambda asynchrones. @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Impossible d'utiliser « OverloadResolutionPriorityAttribute » sur ce membre. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Impossible d'utiliser « OverloadResolutionPriorityAttribute » sur un membre de substitution. @@ -507,6 +502,11 @@ Désolé... Nous ne pouvons pas initialiser le type « {0} » avec une expression de collection, car le type n’est pas constructible. + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' Le paramètre de type '{1}' a la contrainte 'unmanaged'. '{1}' ne peut donc pas être utilisé comme contrainte pour '{0}' @@ -632,6 +632,11 @@ 'else' ne peut pas démarrer d'instruction. + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Les points d'entrée d'application ne peuvent pas être attribués avec 'UnmanagedCallersOnly'. @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + La fonctionnalité '{0}' n'est pas disponible dans C# 13.0. Veuillez utiliser la version linguistique {1} ou supérieure. @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - La fonctionnalité expérimentale « intercepteurs » n'est pas activée dans cet espace de noms. Ajoutez « {0} » à votre projet. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - '{0}' : le type utilisé dans une instruction using asynchrone doit être implicitement convertible en 'System.IAsyncDisposable' ou doit implémenter une méthode 'DisposeAsync' appropriée. Est-ce qu'il ne s'agit pas plutôt de 'using' au lieu de 'await using' ? + '{0}' : le type utilisé dans une instruction en utilisant asynchrone doit implémenter « System.IAsyncDisposable » ou implémenter une méthode « DisposeAsync » appropriée. Vouliez-vous dire « utiliser » plutôt que « attendre d’utiliser » ? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - '{0}' : le type utilisé dans une instruction using doit être implicitement convertible en 'System.IDisposable'. Est-ce qu'il ne s'agit pas plutôt de 'await using' au lieu de 'using' ? + '{0}' : le type utilisé dans une instruction en utilisant doit implémenter « System.IDisposable ». Vouliez-vous dire « attendre d'utiliser » plutôt que « utiliser » ? @@ -1737,6 +1742,11 @@ Une propriété partielle ne peut pas avoir plusieurs déclarations d'implémentation + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. + + Property accessor '{0}' must be '{1}' to match the definition part L’accesseur de propriété « {0} » doit être « {1} » pour correspondre à la partie définition @@ -2397,9 +2407,9 @@ modèles de propriétés étendues - - field and value keywords - mots clés de champ et de valeur + + field keyword + mot-clé du champ @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + priorité de résolution de surcharge @@ -2637,11 +2647,6 @@ aiguille - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - « {0} » est un mot clé contextuel dans les accesseurs de propriété commençant dans la version de langage {1}. Utilisez {0} à la place. - - Identifier is a contextual keyword, with a specific meaning, in a later language version. L’identificateur est un mot clé contextuel, avec une signification spécifique, dans une version de langage ultérieure. @@ -2932,6 +2937,16 @@ Utiliser la variable dans ce contexte peut exposer des variables de référence en dehors de leur étendue de déclaration + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. L’opérateur de conversion de tableau inlined ne sera pas utilisé pour la conversion à partir de l’expression du type déclarant. @@ -5278,6 +5293,16 @@ Le membre d'itérateur asynchrone a un ou plusieurs paramètres de type 'CancellationToken' mais aucun d'entre eux n'est décoré avec l'attribut 'EnumeratorCancellation'. Le paramètre de jeton d'annulation du 'IAsyncEnumerable<>.GetAsyncEnumerator' généré n'est donc pas consommé + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. Le {0} « {1} » non-nullable doit contenir une valeur autre que Null lors de la fermeture du constructeur. Envisagez d’ajouter le modificateur « required » ou de déclarer le {0} comme pouvant accepter la valeur Null. @@ -7592,11 +7617,6 @@ Si une telle classe est utilisée en tant que classe de base et si la classe dé L'attribut DllImport doit être spécifié sur une méthode marquée 'static' et 'extern' - - Cannot update '{0}'; attribute '{1}' is missing. - Impossible de mettre à jour '{0}' ; l'attribut '{1}' est manquant. - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. Impossible d'appliquer l'attribut DllImport à une méthode générique ou contenue dans une méthode ou un type générique. @@ -9583,7 +9603,7 @@ Un bloc catch() après un bloc catch (System.Exception e) peut intercepter des e '{0}': type used in a using statement must implement 'System.IDisposable'. - '{0}' : le type utilisé dans une instruction using doit être implicitement convertible en 'System.IDisposable'. + '{0}' : le type utilisé dans une instruction en utilisant doit implémenter « System.IDisposable ». @@ -12160,8 +12180,8 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé - Only auto-implemented properties can have initializers. - Seules les propriétés implémentées automatiquement peuvent avoir des initialiseurs. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - Impossible de lire les informations de débogage de la méthode '{0}' (jeton 0x{1:X8}) dans l'assembly '{2}' + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - '{0}' : le type utilisé dans une instruction using asynchrone doit être implicitement convertible en 'System.IAsyncDisposable' ou doit implémenter une méthode 'DisposeAsync' appropriée. + '{0}' : le type utilisé dans une instruction en utilisant asynchrone doit implémenter « System.IAsyncDisposable » ou implémenter une méthode « DisposeAsync » appropriée. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index f9c1cc4235173..c6ee6c19e26cc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -287,11 +287,6 @@ Il membro di record '{0}' deve essere una proprietà di istanza leggibile o campo di tipo '{1}' per corrispondere al parametro posizionale '{2}'. - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - l'istruzione foreach non può funzionare con enumeratori di tipo '{0}' in metodi async o iterator perché '{0}' è un ref struct o un parametro di tipo che consente il ref struct. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Non è possibile dichiarare parametri di tipo '{0}' in metodi asincroni o espressioni lambda asincrone. @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Non è possibile usare 'OverloadResolutionPriorityAttribute' per questo membro. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Non è possibile usare 'OverloadResolutionPriorityAttribute' in un membro di override. @@ -507,6 +502,11 @@ Non è possibile inizializzare il tipo '{0}' con un'espressione di raccolta perché il tipo non è costruibile. + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' Il parametro di tipo '{1}' ha il vincolo 'managed'. Non è quindi possibile usare '{1}' come vincolo per '{0}' @@ -632,6 +632,11 @@ Un'istruzione non può iniziare con 'else'. + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Non è possibile aggiungere ai punti di ingresso dell'applicazione l'attributo 'UnmanagedCallersOnly'. @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + La funzionalità '{0}' non è disponibile in C# 13.0. Usare la versione del linguaggio {1} o successiva. @@ -989,7 +994,7 @@ Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct. - Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct. + Impossibile applicare l'attributo 'System.Runtime.CompilerServices.InlineArray' a uno struct di record. @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - La funzionalità sperimentale 'intercettori' non è abilitata in questo spazio dei nomi. Aggiungere '{0}' al progetto. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - '{0}': il tipo usato in un'istruzione using asincrona deve essere convertibile in modo implicito in 'System.IAsyncDisposable' o implementare un metodo 'DisposeAsync' adatto. Si intendeva 'using' invece di 'await using'? + '{0}': il tipo usato in un'istruzione using asincrona deve implementare 'System.IAsyncDisposable' o implementare un metodo 'DisposeAsync' adatto. Si intendeva 'using' invece di 'await using'? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - '{0}': il tipo usato in un'istruzione using deve essere convertibile in modo implicito in 'System.IDisposable'. Si intendeva 'await using' invece di 'using'? + '{0}': il tipo usato in un'istruzione using deve implementare 'System.IDisposable'. Si intendeva 'await using' invece di 'using'? @@ -1659,47 +1664,47 @@ Both partial member declarations must have identical accessibility modifiers. - Both partial member declarations must have identical accessibility modifiers. + I modificatori di accessibilità devono essere identici in entrambe le dichiarazioni di membro parziale. A partial member cannot have the 'abstract' modifier - A partial member cannot have the 'abstract' modifier + Un membro parziale non può contenere il modificatore 'abstract' Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. - Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. + Entrambe le dichiarazioni di membro parziale '{0}' e '{1}' devono usare gli stessi nomi di elementi di tupla. A partial member must be declared within a partial type - A partial member must be declared within a partial type + Un membro parziale deve essere dichiarato in un tipo parziale Both partial member declarations must use a params parameter or neither may use a params parameter - Both partial member declarations must use a params parameter or neither may use a params parameter + Entrambe le dichiarazioni di membro parziale devono usare un parametro params, altrimenti nessuna delle due potrà usarlo Both partial member declarations must be readonly or neither may be readonly - Both partial member declarations must be readonly or neither may be readonly + Entrambe le dichiarazioni di membro parziale devono essere di tipo readonly, altrimenti nessuna delle due potrà esserlo Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. - Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. + Entrambe le dichiarazioni di membro parziale devono contenere combinazioni identiche di modificatori 'virtual', 'override', 'sealed' e 'new'. Partial member declarations must have matching ref return values. - Partial member declarations must have matching ref return values. + Le dichiarazioni di membro parziale devono contenere valori restituiti di riferimento corrispondenti. Both partial member declarations must be unsafe or neither may be unsafe - Both partial member declarations must be unsafe or neither may be unsafe + Entrambe le dichiarazioni di membro parziale devono essere di tipo unsafe, altrimenti nessuna delle due potrà esserlo @@ -1729,47 +1734,52 @@ A partial property may not have multiple defining declarations, and cannot be an auto-property. - A partial property may not have multiple defining declarations, and cannot be an auto-property. + Una proprietà parziale non può avere più dichiarazioni di definizione e non può essere una proprietà automatica. A partial property may not have multiple implementing declarations - A partial property may not have multiple implementing declarations + Una proprietà parziale non può avere più dichiarazioni di implementazione + + + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. Property accessor '{0}' must be '{1}' to match the definition part - Property accessor '{0}' must be '{1}' to match the definition part + La funzione di accesso alle proprietà '{0}' deve essere '{1}' in modo che corrisponda alla parte della definizione Property accessor '{0}' must be implemented because it is declared on the definition part - Property accessor '{0}' must be implemented because it is declared on the definition part + La funzione di accesso alle proprietà '{0}' deve essere implementata perché è dichiarata nella parte della definizione Partial property '{0}' must have a definition part. - Partial property '{0}' must have a definition part. + La proprietà parziale '{0}' deve avere una parte della definizione. Partial property '{0}' must have an implementation part. - Partial property '{0}' must have an implementation part. + La proprietà parziale '{0}' deve avere una parte di implementazione. Both partial property declarations must be required or neither may be required - Both partial property declarations must be required or neither may be required + Entrambe le dichiarazioni di proprietà parziale devono essere richieste, altrimenti nessuna delle due potrà esserlo Both partial property declarations must have the same type. - Both partial property declarations must have the same type. + Il tipo deve essere identico in entrambe le dichiarazioni di proprietà parziale. Property accessor '{0}' does not implement any accessor declared on the definition part - Property accessor '{0}' does not implement any accessor declared on the definition part + La funzione di accesso alle proprietà '{0}' non implementa alcuna funzione di accesso dichiarata nella parte della definizione @@ -2039,7 +2049,7 @@ The 'scoped' modifier of parameter '{0}' doesn't match partial definition. - The 'scoped' modifier of parameter '{0}' doesn't match partial definition. + Il modificatore 'scoped' del parametro '{0}' non corrisponde alla definizione parziale. @@ -2359,7 +2369,7 @@ allows ref struct constraint - allows ref struct constraint + consente il vincolo di struct di riferimento @@ -2397,9 +2407,9 @@ criteri di proprietà estesa - - field and value keywords - field and value keywords + + field keyword + parola chiave campo @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + priorità di risoluzione dell'overload @@ -2637,14 +2647,9 @@ indicatore di misura - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - - Identifier is a contextual keyword, with a specific meaning, in a later language version. - Identifier is a contextual keyword, with a specific meaning, in a later language version. + L'identificatore è una parola chiave contestuale, con un significato specifico, in una versione successiva del linguaggio. @@ -2932,6 +2937,16 @@ L'uso di variabili in questo contesto potrebbe esporre le variabili a cui si fa riferimento al di fuori dell'ambito della dichiarazione + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. L'operatore di conversione della matrice inline non verrà usato per la conversione dell’espressione del tipo dichiarante. @@ -3124,12 +3139,12 @@ Partial property declarations '{0}' and '{1}' have signature differences. - Partial property declarations '{0}' and '{1}' have signature differences. + Le dichiarazioni di proprietà parziale '{0}' e '{1}' presentano differenze di firma. Partial property declarations have signature differences. - Partial property declarations have signature differences. + Le dichiarazioni di proprietà parziale presentano differenze di firma. @@ -5278,6 +5293,16 @@ target:module Compila un modulo che può essere aggiunto ad altro Il membro di iteratore asincrono include uno o più parametri di tipo 'CancellationToken', ma nessuno di essi è decorato con l'attributo 'EnumeratorCancellation', di conseguenza il parametro del token di annullamento restituito dall'elemento 'IAsyncEnumerable<>.GetAsyncEnumerator' generato non verrà utilizzato + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. L'elemento {0} '{1}' non nullable deve contenere un valore non Null all'uscita dal costruttore. Prendere in considerazione l'aggiunta del modificatore 'required' o la dichiarazione di {0} come nullable. @@ -6610,7 +6635,7 @@ target:module Compila un modulo che può essere aggiunto ad altro The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + Il modificatore 'partial' può trovarsi solo immediatamente prima di 'class', 'record', 'struct', 'interface' o del tipo restituito di un metodo o di una proprietà. @@ -7592,11 +7617,6 @@ Se si usa tale classe come classe base e se la classe di derivazione definisce u L'attributo DllImport deve essere specificato in un metodo contrassegnato come 'static' ed 'extern' - - Cannot update '{0}'; attribute '{1}' is missing. - Non è possibile aggiornare '{0}'. Manca l'attributo '{1}'. - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. Non è possibile applicare l'attributo DllImport a un metodo generico o contenuto in un tipo o un metodo generico. @@ -8219,7 +8239,7 @@ Se si usa tale classe come classe base e se la classe di derivazione definisce u A partial member may not explicitly implement an interface member - A partial member may not explicitly implement an interface member + Un membro parziale non può implementare in modo esplicito un membro di interfaccia @@ -8254,7 +8274,7 @@ Se si usa tale classe come classe base e se la classe di derivazione definisce u Both partial member declarations must be static or neither may be static - Both partial member declarations must be static or neither may be static + Entrambe le dichiarazioni di membro parziale devono essere statiche, altrimenti nessuna delle due potrà esserlo @@ -9583,7 +9603,7 @@ Un blocco catch() dopo un blocco catch (System.Exception e) può rilevare eccezi '{0}': type used in a using statement must implement 'System.IDisposable'. - '{0}': il tipo usato in un'istruzione using deve essere convertibile in modo implicito in 'System.IDisposable'. + '{0}': il tipo usato in un'istruzione using deve implementare 'System.IDisposable'. @@ -12160,8 +12180,8 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr - Only auto-implemented properties can have initializers. - Solo le proprietà implementate automaticamente possono avere inizializzatori. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - Non è possibile leggere le informazione di debug del metodo '{0}' (token 0x{1:X8}) dall'assembly '{2}' + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - '{0}': il tipo usato in un'istruzione using asincrona deve essere convertibile in modo implicito in 'System.IAsyncDisposable' o implementare un metodo 'DisposeAsync' adatto. + '{0}': il tipo usato in un'istruzione using asincrona deve implementare 'System.IAsyncDisposable' o implementare un metodo 'DisposeAsync' adatto. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 5e93538852575..147f232e8222d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -287,11 +287,6 @@ レコード メンバー '{0}' は、位置指定パラメーター '{2}' に一致させるための型 '{1}' の読み取り可能なインスタンス プロパティまたはフィールドである必要があります。 - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - '{0}' は ref 構造体または ref 構造体を許容する型パラメーターであるため、非同期または反復子のメソッド内で '{0}' 型の列挙子に対して foreach ステートメントは機能しません。 - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. '{0}' 型のパラメーターは、非同期メソッドまたは非同期ラムダ式で宣言することができません。 @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + このメンバーでは 'OverloadResolutionPriorityAttribute' を使用できません。 Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + オーバーライドするメンバーに 'OverloadResolutionPriorityAttribute' を使用することはできません。 @@ -507,6 +502,11 @@ 型が構築可能でないため、コレクション式で型 '{0}' を初期化できません。 + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' 型パラメーター '{1}' は 'unmanaged' 制約を含むので、'{0}' の制約として '{1}' を使用することはできません @@ -632,6 +632,11 @@ 'else' でステートメントを開始することはできません。 + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. アプリケーションのエントリ ポイントに 'UnmanagedCallersOnly' 属性を設定することはできません。 @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + 機能 '{0}' は C# 13.0 では使用できません。{1} 以上の言語バージョンを使用してください。 @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - 'インターセプター' の実験的な機能は、この名前空間では有効になっていません。プロジェクトに '{0}' を追加します。 + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - '{0}': 非同期 using ステートメントで使用される型は、暗黙的に 'System.IAsyncDisposable' に変換可能であるか、適切な 'DisposeAsync' メソッドを実装する必要があります。'await using' ではなく 'using' ですか? + '{0}': 非同期 using ステートメントで使用される型は、'System.IAsyncDisposable' に実装するか、適切な 'DisposeAsync' メソッドを実装する必要があります。'await using' ではなく 'using' ですか? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - '{0}': using ステートメントで使用される型は、暗黙的に 'System.IDisposable' への変換が可能でなければなりません。'using' ではなく 'await using' ですか? + '{0}': using ステートメントで使用される型は 'System.IDisposable' を実装する必要があります。'using' ではなく 'await using' ですか? @@ -1737,6 +1742,11 @@ 部分プロパティには、複数の実装宣言を含めることができない場合があります + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. + + Property accessor '{0}' must be '{1}' to match the definition part プロパティ アクセサー '{0}' は、定義パーツと一致するように '{1}' である必要があります @@ -2397,9 +2407,9 @@ 拡張プロパティ パターン - - field and value keywords - フィールドと値のキーワード + + field keyword + field キーワード @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + オーバーロード解決の優先順位 @@ -2637,11 +2647,6 @@ ポインター - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - '{0}' は、言語バージョン {1} 以降のプロパティ アクセサーのコンテキスト キーワードです。代わりに '@{0}' を使用してください。 - - Identifier is a contextual keyword, with a specific meaning, in a later language version. 識別子は、後の言語バージョンでは、特定の意味を持つコンテキスト キーワードです。 @@ -2932,6 +2937,16 @@ このコンテキストでの変数の使用は、参照される変数が宣言のスコープ外に公開される可能性があります + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. インライン配列変換演算子は、宣言型の式からの変換には使用されません。 @@ -5278,6 +5293,16 @@ 非同期反復子メンバーには型 'CancellationToken' の 1 つ以上のパラメーターがありますが、'EnumeratorCancellation' 属性で修飾されているパラメーターはありません。そのため、生成された 'IAsyncEnumerable<>.GetAsyncEnumerator' からの取り消しトークン パラメーターは使用されません + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. null 非許容の {0} '{1}' には、コンストラクターの終了時に null 以外の値が入っていなければなりません。'required' 修飾子を追加するか、{0} を Null 許容として宣言することを検討してください。 @@ -7592,11 +7617,6 @@ If such a class is used as a base class and if the deriving class defines a dest static または extern に指定されているメソッドでは、DllImport 属性を指定する必要があります - - Cannot update '{0}'; attribute '{1}' is missing. - '{0}' を更新できません。属性 '{1}' がありません。 - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. DllImport 属性は、ジェネリックであるメソッドに適用することも、ジェネリック メソッドまたは型に含めることもできません。 @@ -9583,7 +9603,7 @@ AssemblyInfo.cs ファイルで RuntimeCompatibilityAttribute が false に設 '{0}': type used in a using statement must implement 'System.IDisposable'. - '{0}': using ステートメントで使用される型は、暗黙的に 'System.IDisposable' への変換が可能でなければなりません。 + '{0}': using ステートメントで使用される型は 'System.IDisposable' を実装する必要があります。 @@ -12160,8 +12180,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only auto-implemented properties can have initializers. - 自動実装プロパティのみが初期化子を持つことができます。 + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - メソッド '{0}' (トークン 0x{1:X8}) のデバッグ情報をアセンブリ '{2}' から読み取ることができません + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - '{0}': 非同期 using ステートメントで使用される型は、暗黙的に 'System.IAsyncDisposable' に変換可能であるか、適切な 'DisposeAsync' メソッドを実装する必要があります。 + '{0}': 非同期 using ステートメントで使用される型は、'System.IAsyncDisposable' に実装するか、適切な 'DisposeAsync' メソッドを実装する必要があります。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index d3231d6674007..201d1a147d35c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -287,11 +287,6 @@ 위치 매개 변수 '{0}'과(와) 일치하려면 레코드 멤버 '{1}'이(가) 유형 '{2}'의 읽을 수 있는 인스턴스 속성 또는 필드여야 합니다. - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - foreach 문은 '{0}'이(가) ref struct 또는 ref struct를 허용하는 형식 매개 변수이므로 비동기 또는 반복기 메서드에서 '{0}' 형식의 열거자에 대해 작동할 수 없습니다. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. '{0}' 형식의 매개 변수는 비동기 메서드나 비동기 람다 식에서 선언할 수 없습니다. @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + 이 멤버에 'OverloadResolutionPriorityAttribute'를 사용할 수 없습니다. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + 재정의 멤버에 'OverloadResolutionPriorityAttribute'를 사용할 수 없습니다. @@ -507,6 +502,11 @@ 형식을 생성할 수 없으므로 컬렉션 식을 사용하여 '{0}' 형식을 초기화할 수 없습니다. + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' 형식 매개 변수 '{1}'에 'unmanaged' 제약 조건이 있으므로 '{1}'은(는) '{0}'에 대한 제약 조건으로 사용할 수 없습니다. @@ -632,6 +632,11 @@ 'else'로 문을 시작할 수 없습니다. + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. 애플리케이션 진입점에는 'UnmanagedCallersOnly' 특성을 지정할 수 없습니다. @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + '{0}' 기능은 C# 13.0에서 사용할 수 없습니다. 언어 버전 {1} 이상을 사용하세요. @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - 이 네임스페이스에서는 '인터셉터' 실험적 기능을 사용할 수 없습니다. 프로젝트에 '{0}'을(를) 추가하세요. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - '{0}': 비동기 using 문에 사용된 형식은 암시적으로 'System.IAsyncDisposable'로 변환할 수 있거나 적합한 'DisposeAsync' 메서드를 구현해야 합니다. 'await using' 대신 'using'을 사용하시겠습니까? + '{0}': 비동기 using 문에 사용되는 형식은 'System.IAsyncDisposable'을 구현하거나 적합한 'DisposeAsync' 메서드를 구현해야 합니다. 'await using'이 아닌 'using'을 의미했나요? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - '{0}': using 문에 사용된 형식은 암시적으로 'System.IDisposable'로 변환할 수 있어야 합니다. 'using' 대신 'await using'을 사용하시겠습니까? + '{0}': using 문에 사용되는 형식은 'System.IDisposable'을 구현해야 합니다. 'using'이 아닌 'await using'을 의미했나요? @@ -1737,6 +1742,11 @@ 부분 속성에는 하나의 구현 선언만 사용할 수 있음 + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. + + Property accessor '{0}' must be '{1}' to match the definition part 속성 접근자 '{0}'은(는) 정의 부분과 일치하려면 '{1}'이어야 합니다. @@ -2397,9 +2407,9 @@ 확장 속성 패턴 - - field and value keywords - 필드 및 값 키워드 + + field keyword + 필드 키워드 @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + 오버로드 해결 우선 순위 @@ -2637,11 +2647,6 @@ 포인터 - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - '{0}'은(는) 언어 버전 {1} 속성 접근자의 컨텍스트 키워드 대신 '@{0}'을(를) 사용하세요. - - Identifier is a contextual keyword, with a specific meaning, in a later language version. 식별자는 이후 언어 버전에서 특정 의미를 가진 컨텍스트 키워드입니다. @@ -2932,6 +2937,16 @@ 이 컨텍스트에서 변수를 사용하면 선언 범위 외부에서 참조된 변수가 노출될 수 있습니다. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. 인라인 배열 변환 연산자는 선언 형식의 식에서 변환하는 데 사용되지 않습니다. @@ -5278,6 +5293,16 @@ 비동기 반복기 멤버에 'CancellationToken' 형식의 매개 변수가 하나 이상 있지만, 이 중 'EnumeratorCancellation' 특성으로 데코레이트된 매개 변수가 없으므로 생성된 'IAsyncEnumerable<>.GetAsyncEnumerator'에서 취소 토큰 매개 변수가 사용되지 않음 + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. null을 허용하지 않는 {0} '{1}'은(는) 생성자를 종료할 때 null이 아닌 값을 포함해야 합니다. 'required' 한정자를 추가하거나 {0}을(를) nullable로 선언하는 것이 좋습니다. @@ -7592,11 +7617,6 @@ If such a class is used as a base class and if the deriving class defines a dest DllImport 특성은 'static' 및 'extern'으로 표시된 메서드에만 지정할 수 있습니다. - - Cannot update '{0}'; attribute '{1}' is missing. - '{0}'을(를) 업데이트할 수 없습니다. 특성 '{1}'이(가) 없습니다. - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. DllImport 특성은 제네릭이거나 제네릭 메서드 또는 형식에 포함된 메서드에 적용할 수 없습니다. @@ -9583,7 +9603,7 @@ catch (System.Exception e) 블록 뒤의 catch() 블록은 RuntimeCompatibilityA '{0}': type used in a using statement must implement 'System.IDisposable'. - '{0}': using 문에 사용된 형식은 암시적으로 'System.IDisposable'로 변환할 수 있어야 합니다. + '{0}': using 문에 사용되는 형식은 'System.IDisposable'을 구현해야 합니다. @@ -12160,8 +12180,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only auto-implemented properties can have initializers. - 자동 구현 속성만 이니셜라이저를 사용할 수 있습니다. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - '{2}' 어셈블리에서 '{0}' 메서드(토큰 0x{1:X8})의 디버그 정보를 읽을 수 없습니다. + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - '{0}': 비동기 using 문에 사용된 형식은 암시적으로 'System.IAsyncDisposable'로 변환할 수 있거나 적합한 'DisposeAsync' 메서드를 구현해야 합니다. + '{0}': 비동기 using 문에 사용되는 형식은 'System.IAsyncDisposable'을 구현하거나 적합한 'DisposeAsync' 메서드를 구현해야 합니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 66781a2121bdb..965fb958255ff 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -287,11 +287,6 @@ Składowa rekordu "{0}" musi być możliwą do odczytu właściwością wystąpienia typu "{1}", aby dopasować parametr pozycyjny "{2}". - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - Instrukcja foreach nie może działać na modułach wyliczeniowych typu „{0}” w metodach asynchronicznych lub iteracyjnych, ponieważ „{0}” jest strukturą ref lub parametrem typu, który zezwala na strukturę ref. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Parametry typu „{0}” nie mogą być deklarowane w metodach asynchronicznych ani asynchronicznych wyrażeniach lambda. @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Nie można użyć atrybutu "OverloadResolutionPriorityAttribute" w tej składowej. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Nie można użyć atrybutu „OverloadResolutionPriorityAttribute” w zastępującej składowej. @@ -507,6 +502,11 @@ Nie można zainicjować typu „{0}” z wyrażeniem kolekcji, ponieważ nie można go skonstruować. + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' Parametr typu „{1}” ma ograniczenie „unmanaged”, dlatego elementu „{1}” nie można użyć jako ograniczenia dla elementu „{0}” @@ -632,6 +632,11 @@ Instrukcja nie może rozpoczynać się od elementu „else”. + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Punkty wejścia aplikacji nie mogą mieć atrybutu „UnmanagedCallersOnly”. @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + Funkcja „{0}” nie jest dostępna w wersji języka C# 13.0. Użyj języka w wersji {1} lub nowszej. @@ -989,7 +994,7 @@ Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct. - Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct. + Atrybut „System.Runtime.CompilerServices.InlineArray” nie może być zastosowany do struktury rekordu. @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - Funkcja eksperymentalna „interceptorów” nie jest włączona w tej przestrzeni nazw. Dodaj „{0}” do swojego projektu. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - „{0}”: Typ użyty w asynchronicznej instrukcji using musi być jawnie konwertowalny na typ „System.IAsyncDisposable” lub musi implementować odpowiednią metodę „DisposeAsync”. Czy chodziło Ci o użycie instrukcji „using”, a nie „await using”? + „{0}”: typ użyty w asynchronicznej instrukcji using musi implementować typ „System.IAsyncDisposable” lub odpowiednią metodę „DisposeAsync”. Czy chodzi Ci o instrukcję „using” zamiast „await using”? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - „{0}”: typ użyty w instrukcji using musi umożliwiać niejawną konwersję na interfejs „System.IDisposable”. Czy chodziło Ci o instrukcję „await using”, a nie „using”? + „{0}”: typ użyty w instrukcji using musi implementować typ „System.IDisposable”. Czy chodzi Ci o instrukcję „await using” zamiast „using”? @@ -1659,47 +1664,47 @@ Both partial member declarations must have identical accessibility modifiers. - Both partial member declarations must have identical accessibility modifiers. + Obie częściowe deklaracje elementów członkowskich muszą mieć identyczne modyfikatory dostępności. A partial member cannot have the 'abstract' modifier - A partial member cannot have the 'abstract' modifier + Częściowy element członkowski nie może mieć modyfikatora „abstract” Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. - Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. + Obie deklaracje częściowych elementów członkowskich, „{0}” i „{1}”, muszą korzystać z tych samych nazw elementów krotki. A partial member must be declared within a partial type - A partial member must be declared within a partial type + Częściowy element członkowski musi być zadeklarowany w ramach częściowego typu Both partial member declarations must use a params parameter or neither may use a params parameter - Both partial member declarations must use a params parameter or neither may use a params parameter + Obie częściowe deklaracje elementów członkowskich muszą używać parametru params lub żadna z nich nie może używać parametru params Both partial member declarations must be readonly or neither may be readonly - Both partial member declarations must be readonly or neither may be readonly + Obie deklaracje częściowych elementów członkowskich muszą być tylko do odczytu lub żadna z nich nie może być tylko do odczytu Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. - Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. + Obie deklaracje częściowych elementów członkowskich muszą mieć identyczne kombinacje modyfikatorów „virtual”, „override”, „sealed” i „new”. Partial member declarations must have matching ref return values. - Partial member declarations must have matching ref return values. + Deklaracje częściowych elementów członkowskich muszą mieć pasujące wartości zwracane ref. Both partial member declarations must be unsafe or neither may be unsafe - Both partial member declarations must be unsafe or neither may be unsafe + Obie częściowe deklaracje elementów członkowskich muszą być niebezpieczne lub żadna z nich nie może być niebezpieczna @@ -1729,47 +1734,52 @@ A partial property may not have multiple defining declarations, and cannot be an auto-property. - A partial property may not have multiple defining declarations, and cannot be an auto-property. + Właściwość częściowa nie może mieć wielu deklaracji definiujących i nie może być właściwością automatyczną. A partial property may not have multiple implementing declarations - A partial property may not have multiple implementing declarations + Właściwość częściowa nie może mieć wielu deklaracji implementujących + + + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. Property accessor '{0}' must be '{1}' to match the definition part - Property accessor '{0}' must be '{1}' to match the definition part + Metoda dostępu właściwości „{0}” musi mieć wartość „{1}”, aby dopasować część definicji Property accessor '{0}' must be implemented because it is declared on the definition part - Property accessor '{0}' must be implemented because it is declared on the definition part + Właściwość accessor „{0}” musi zostać zaimplementowana, ponieważ jest zadeklarowana w części definicji Partial property '{0}' must have a definition part. - Partial property '{0}' must have a definition part. + Właściwość częściowa „{0}” musi mieć część definicji. Partial property '{0}' must have an implementation part. - Partial property '{0}' must have an implementation part. + Właściwość częściowa „{0}” musi mieć część implementacji. Both partial property declarations must be required or neither may be required - Both partial property declarations must be required or neither may be required + Obie deklaracje właściwości częściowych muszą być wymagane lub żadna z nich nie może być wymagana Both partial property declarations must have the same type. - Both partial property declarations must have the same type. + Obie deklaracje właściwości częściowych muszą mieć ten sam typ. Property accessor '{0}' does not implement any accessor declared on the definition part - Property accessor '{0}' does not implement any accessor declared on the definition part + Właściwość accessor „{0}” nie implementuje żadnego accessora zadeklarowanego w części definiującej @@ -2039,7 +2049,7 @@ The 'scoped' modifier of parameter '{0}' doesn't match partial definition. - The 'scoped' modifier of parameter '{0}' doesn't match partial definition. + Modyfikator „scoped” parametru „{0}” nie jest zgodny z częściową definicją. @@ -2359,7 +2369,7 @@ allows ref struct constraint - allows ref struct constraint + zezwala na ograniczenie ref struct @@ -2397,9 +2407,9 @@ wzorce właściwości rozszerzonych - - field and value keywords - field and value keywords + + field keyword + słowo kluczowe pola @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + priorytet rozwiązywania przeciążenia @@ -2637,14 +2647,9 @@ wskaźnik - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - - Identifier is a contextual keyword, with a specific meaning, in a later language version. - Identifier is a contextual keyword, with a specific meaning, in a later language version. + Identyfikator jest kontekstowym słowem kluczowym o określonym znaczeniu w późniejszej wersji językowej. @@ -2932,6 +2937,16 @@ Nie można używać zmiennej w tym kontekście, ponieważ może uwidaczniać odwoływane zmienne poza ich zakresem deklaracji + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. Operator konwersji tablicy wbudowanej nie będzie używany do konwersji z wyrażenia typu deklarującego. @@ -3124,12 +3139,12 @@ Partial property declarations '{0}' and '{1}' have signature differences. - Partial property declarations '{0}' and '{1}' have signature differences. + Deklaracje właściwości częściowych „{0}” i „{1}” mają różnice w sygnaturach. Partial property declarations have signature differences. - Partial property declarations have signature differences. + Deklaracje właściwości częściowych różnią się sygnaturami. @@ -5278,6 +5293,16 @@ Składowa iteratora asynchronicznego ma co najmniej jeden parametr typu „CancellationToken”, ale żaden z nich nie ma atrybutu „EnumeratorCancellation” i dlatego zostanie wykorzystany parametr tokenu anulowania z wygenerowanego elementu „IAsyncEnumerable<>.GetAsyncEnumerator” + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. Niedopuszczający wartości null element {0} „{1}” musi zawierać wartość inną niż null podczas kończenia działania konstruktora. Rozważ dodanie modyfikatora „required” lub zadeklarowanie {0} jako dopuszczającego wartość null. @@ -6610,7 +6635,7 @@ The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + Modyfikator „partial” może pojawić się tylko bezpośrednio przed słowem kluczowym „class”, „record” „struct”, „interface” lub zwracanym typem metody lub właściwości. @@ -7592,11 +7617,6 @@ Jeśli taka klasa zostanie użyta jako klasa bazowa i klasa pochodna definiuje d Dla metody oznaczonej przy użyciu słów kluczowych „static” i „extern” musi zostać określony atrybut DllImport - - Cannot update '{0}'; attribute '{1}' is missing. - Nie można zaktualizować elementu „{0}”. Brak atrybutu „{1}”. - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. Atrybut DllImport nie może być zastosowany do metody, która jest ogólna lub zawarta w metodzie ogólnej lub typie ogólnym. @@ -8219,7 +8239,7 @@ Jeśli taka klasa zostanie użyta jako klasa bazowa i klasa pochodna definiuje d A partial member may not explicitly implement an interface member - A partial member may not explicitly implement an interface member + Częściowy element członkowski nie może wyraźnie implementować elementu członkowskiego interfejsu @@ -8254,7 +8274,7 @@ Jeśli taka klasa zostanie użyta jako klasa bazowa i klasa pochodna definiuje d Both partial member declarations must be static or neither may be static - Both partial member declarations must be static or neither may be static + Obie deklaracje częściowych elementów członkowskich muszą być statyczne lub żadna z nich nie może być statyczna @@ -9583,7 +9603,7 @@ Blok catch() po bloku catch (System.Exception e) może przechwytywać wyjątki n '{0}': type used in a using statement must implement 'System.IDisposable'. - „{0}”: typ użyty w instrukcji using musi umożliwiać niejawną konwersję na interfejs „System.IDisposable”. + „{0}”: typ użyty w instrukcji using musi implementować typ „System.IDisposable”. @@ -12160,8 +12180,8 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w - Only auto-implemented properties can have initializers. - Tylko właściwości zaimplementowane automatycznie mogą mieć inicjatory. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - Nie można odczytać informacji debugowania metody „{0}” (token 0x{1:X8}) z zestawu „{2}” + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - „{0}”: Typ użyty w asynchronicznej instrukcji using musi być jawnie konwertowalny na typ „System.IAsyncDisposable” lub musi implementować odpowiednią metodę „DisposeAsync”. + „{0}”: typ użyty w asynchronicznej instrukcji using musi implementować typ „System.IAsyncDisposable” lub odpowiednią metodę „DisposeAsync”. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 1c933cf3c1572..27c36365bdb90 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -287,11 +287,6 @@ O membro do registro '{0}' precisa ser uma propriedade de instância legível ou campo do tipo '{1}' para corresponder ao parâmetro posicional '{2}'. - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - A instrução foreach não pode operar em enumeradores do tipo "{0}" em métodos assíncronos ou iteradores porque "{0}" é um ref struct ou um parâmetro de tipo que permite o ref struct. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Parâmetros do tipo "{0}" não podem ser declarados em métodos assíncronos ou expressões lambda assíncronas. @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Não é possível usar 'OverloadResolutionPriorityAttribute' neste membro. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Não é possível usar 'OverloadResolutionPriorityAttribute' em um membro que substitui outro. @@ -507,6 +502,11 @@ Não é possível inicializar o tipo '{0}' com uma expressão de coleção porque o tipo não é construível. + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' O parâmetro de tipo '{1}' tem a restrição 'unmanaged' e, por isso, '{1}' não pode ser usado como uma restrição de '{0}' @@ -632,6 +632,11 @@ 'else' não pode iniciar uma instrução. + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Os pontos de entrada do aplicativo não podem ser atribuídos com 'UnmanagedCallersOnly'. @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + O recurso "{0}" não está disponível no C# 13.0. Use a versão da linguagem {1} ou superior. @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - O recurso experimental “interceptadores” não está habilitado neste namespace. Adicione “{0}” ao seu projeto. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - '{0}': o tipo usado em uma instrução using assíncrona deve ser implicitamente conversível em 'System.IAsyncDisposable' ou implementar um método 'DisposeAsync' adequado. Você quis dizer 'using' em vez de 'await using'? + '{0}': o tipo usado em uma instrução using assíncrona deve implementar 'System.IAsyncDisposable' ou implementar um método 'DisposeAsync' adequado. Você quis dizer 'using' em vez de 'await using'? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - '{0}': o tipo usado em uma instrução using deve ser implicitamente conversível em 'System.IDisposable'. Você quis dizer 'await using' em vez de 'using'? + '{0}': o tipo usado em uma instrução 'using' deve implementar 'System.IDisposable'. Você quis dizer 'await using' em vez de 'using'? @@ -1737,6 +1742,11 @@ Uma propriedade parcial não pode ter várias declarações de implementação + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. + + Property accessor '{0}' must be '{1}' to match the definition part O acessador de propriedade "{0}" deve ser "{1}" para corresponder à parte da definição @@ -2397,9 +2407,9 @@ padrões de propriedade estendida - - field and value keywords - palavras-chave de campo e valor + + field keyword + campo palavra-chave @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + prioridade de resolução de sobrecarga @@ -2637,11 +2647,6 @@ ponteiro - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - "{0}" é uma palavra-chave contextual em acessadores de propriedade a partir da versão de linguagem {1}. Em vez disso, use "@{0}". - - Identifier is a contextual keyword, with a specific meaning, in a later language version. Identificador é uma palavra-chave contextual, com um significado específico, em uma versão de linguagem posterior. @@ -2932,6 +2937,16 @@ O uso de variável neste contexto pode expor variáveis referenciadas fora de seu escopo de declaração + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. O operador de conversão de matriz em linha não será usado para a conversão da expressão do tipo declarativo. @@ -5278,6 +5293,16 @@ O membro do iterador assíncrono tem um ou mais parâmetros do tipo 'CancellationToken', mas nenhum deles está decorado com o atributo 'EnumeratorCancellation', portanto, o parâmetro de token de cancelamento do 'IAsyncEnumerable<>.GetAsyncEnumerator' gerado não será consumido + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. O {0} não anulável '{1}' precisa conter um valor não nulo ao sair do construtor. Considere adicionar o modificador "obrigatório" ou declarar o {0} como anulável. @@ -7592,11 +7617,6 @@ Se tal classe for usada como uma classe base e se a classe derivada definir um d O atributo DllImport deve ser especificado em um método marcado como 'static' e 'extern' - - Cannot update '{0}'; attribute '{1}' is missing. - Não é possível atualizar '{0}'; o atributo '{1}' está ausente. - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. O atributo DllImport não pode ser aplicado a um método que seja genérico ou esteja contido em um método ou tipo genérico. @@ -9583,7 +9603,7 @@ Um bloco catch() depois de um bloco catch (System.Exception e) poderá capturar '{0}': type used in a using statement must implement 'System.IDisposable'. - '{0}': o tipo usado em uma instrução using deve ser implicitamente conversível em 'System.IDisposable'. + '{0}': o tipo usado em uma instrução 'using' deve implementar 'System.IDisposable'. @@ -12160,8 +12180,8 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl - Only auto-implemented properties can have initializers. - Somente propriedades implementadas automaticamente podem ter inicializadores. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - Não é possível ler as informações de depuração do método '{0}' (token 0x{1:X8}) do assembly '{2}' + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - '{0}': o tipo usado em uma instrução using assíncrona deve ser implicitamente conversível em 'System.IAsyncDisposable' ou implementar um método 'DisposeAsync' adequado. + '{0}': o tipo usado em uma instrução using assíncrona deve implementar 'System.IAsyncDisposable' ou implementar um método 'DisposeAsync' adequado. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index ce35f318be739..59efdb7e3fb7c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -287,11 +287,6 @@ Элемент записи "{0}" должен быть доступным для чтения свойством экземпляра или полем типа "{1}", чтобы соответствовать позиционному параметру "{2}". - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - Утверждение foreach не может работать с перечислителями типа "{0}" в асинхронных методах или методах итератора, поскольку "{0}" является ссылочной структурой или параметром типа, допускающим структуру ref. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Параметры типа "{0}" не могут быть объявлены в асинхронных методах или асинхронных лямбда-выражениях. @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Невозможно использовать "OverloadResolutionPriorityAttribute" с этим членом. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Невозможно использовать "OverloadResolutionPriorityAttribute" с переопределяемым членом. @@ -507,6 +502,11 @@ Не удается инициализировать тип "{0}" с выражением коллекции, так как тип не является конструируемым. + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' Параметр типа "{1}" имеет ограничение "unmanaged", поэтому "{1}" не может использоваться в качестве ограничения для "{0}". @@ -632,6 +632,11 @@ "else" не может запускать оператор. + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Точки входа приложения не могут иметь атрибут "UnmanagedCallersOnly". @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + Функция "{0}" недоступна в C# 13.0. Используйте язык версии {1} или более поздней. @@ -989,7 +994,7 @@ Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct. - Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct. + Невозможно применить атрибут "System.Runtime.CompilerServices.InlineArray" к структуре записи. @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - Экспериментальная функция "перехватчики" не включена в этом пространстве имен. Добавьте "{0}" в свой проект. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - "{0}": тип, используемый в асинхронном операторе using, должен допускать неявное преобразование в тип "System.IAsyncDisposable" или реализовывать подходящий метод "DisposeAsync". Возможно, вы имели в виду "using", а не "await using"? + "{0}": тип, используемый в асинхронном операторе using, должен допускать реализовывать "System.IAsyncDisposable" или подходящий метод "DisposeAsync". Возможно, вы имели в виду "using", а не "await using"? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - "{0}": тип, использованный в операторе using, должен иметь возможность неявного преобразования в System.IDisposable. Вы хотели использовать "await using" вместо "using"? + "{0}": тип, используемый в операторе using, должен реализовывать "System.IDisposable". Возможно, вы имели в виду "await using", а не "using"? @@ -1659,47 +1664,47 @@ Both partial member declarations must have identical accessibility modifiers. - Both partial member declarations must have identical accessibility modifiers. + У обоих объявлений частичного члена должны быть идентичные модификаторы доступа. A partial member cannot have the 'abstract' modifier - A partial member cannot have the 'abstract' modifier + У частичного члена не может быть модификатора "abstract" Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. - Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. + Оба определения частичного члена "{0}" и "{1}" должны использовать одинаковые имена элементов кортежа. A partial member must be declared within a partial type - A partial member must be declared within a partial type + Частичный член должен быть объявлен из частичного типа Both partial member declarations must use a params parameter or neither may use a params parameter - Both partial member declarations must use a params parameter or neither may use a params parameter + Оба объявления частичного члена должны использовать параметр "params" или оба не должны использовать параметр "params" Both partial member declarations must be readonly or neither may be readonly - Both partial member declarations must be readonly or neither may be readonly + Оба объявления частичного члена должны быть доступными только для чтения или оба не должны быть доступными только для чтения Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. - Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. + У обоих объявлений частичного члена должны быть одинаковые сочетания модификаторов "'virtual", "override", "sealed" и "new". Partial member declarations must have matching ref return values. - Partial member declarations must have matching ref return values. + У объявлений частичного члена должны совпадать возвращаемые значения "ref". Both partial member declarations must be unsafe or neither may be unsafe - Both partial member declarations must be unsafe or neither may be unsafe + Оба объявления частичного члена должны быть небезопасными или оба не должны быть небезопасными @@ -1729,47 +1734,52 @@ A partial property may not have multiple defining declarations, and cannot be an auto-property. - A partial property may not have multiple defining declarations, and cannot be an auto-property. + У частичного свойства не может быть нескольких определяющих определений, оно не может быть автоматическим свойством. A partial property may not have multiple implementing declarations - A partial property may not have multiple implementing declarations + У частичного свойства не может быть нескольких реализующих объявлений + + + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. Property accessor '{0}' must be '{1}' to match the definition part - Property accessor '{0}' must be '{1}' to match the definition part + Метод доступа "{0}" должен быть "{1}", чтобы соответствовать части определения Property accessor '{0}' must be implemented because it is declared on the definition part - Property accessor '{0}' must be implemented because it is declared on the definition part + Метод доступа "{0}" должен быть реализован, поскольку он объявлен в части определения Partial property '{0}' must have a definition part. - Partial property '{0}' must have a definition part. + У частичного свойства "{0}" должна быть часть определения. Partial property '{0}' must have an implementation part. - Partial property '{0}' must have an implementation part. + У частичного свойства "{0}" должна быть часть реализации. Both partial property declarations must be required or neither may be required - Both partial property declarations must be required or neither may be required + Оба объявления частичного члена должны быть обязательными или оба не должны быть обязательными Both partial property declarations must have the same type. - Both partial property declarations must have the same type. + Оба объявления частичного свойства должны быть одинакового типа. Property accessor '{0}' does not implement any accessor declared on the definition part - Property accessor '{0}' does not implement any accessor declared on the definition part + Метод доступа "{0}" не реализует методы доступа, объявленные для части определения @@ -2039,7 +2049,7 @@ The 'scoped' modifier of parameter '{0}' doesn't match partial definition. - The 'scoped' modifier of parameter '{0}' doesn't match partial definition. + Модификатор "scoped" параметра "{0}" не соответствует частичному определению. @@ -2359,7 +2369,7 @@ allows ref struct constraint - allows ref struct constraint + разрешает ограничение структуры "ref" @@ -2397,9 +2407,9 @@ шаблоны расширенных свойств - - field and value keywords - field and value keywords + + field keyword + ключевое слово поля @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + приоритет разрешения перегрузки @@ -2637,14 +2647,9 @@ указатель - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - - Identifier is a contextual keyword, with a specific meaning, in a later language version. - Identifier is a contextual keyword, with a specific meaning, in a later language version. + Идентификатор — это контекстное ключевое слово с определенным значением в более поздней версии языка. @@ -2932,6 +2937,16 @@ Использование переменной в этом контексте может представить ссылочные переменные за пределами области их объявления. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. Оператор преобразования встроенного массива не будет использоваться для преобразования из выражения объявляющего типа. @@ -3124,12 +3139,12 @@ Partial property declarations '{0}' and '{1}' have signature differences. - Partial property declarations '{0}' and '{1}' have signature differences. + У объявлений частичного свойства "{0}" и "{1}" разные сигнатуры. Partial property declarations have signature differences. - Partial property declarations have signature differences. + У объявлений частичного свойств и разные сигнатуры. @@ -5279,6 +5294,16 @@ Элемент асинхронного итератора имеет один или несколько параметров типа "CancellationToken", но ни один из них не снабжен атрибутом "EnumeratorCancellation", поэтому параметр токена отмены из созданного "IAsyncEnumerable<>.GetAsyncEnumerator" не будет использован. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. {0} "{1}", не допускающий значения NULL, должен содержать значение, отличное от NULL, при выходе из конструктора. Рассмотрите возможность добавления модификатора "required" или объявления значения {0}, допускающего значение NULL. @@ -6611,7 +6636,7 @@ The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + Модификатор "partial" может использоваться только перед ключевыми словами "class", "record", "struct" и "interface", а также перед возвращаемым типом метода или свойства. @@ -7593,11 +7618,6 @@ If such a class is used as a base class and if the deriving class defines a dest Атрибут DllImport должен быть указан для метода, который помечен как "static" и "extern". - - Cannot update '{0}'; attribute '{1}' is missing. - Невозможно обновить "{0}"; нет атрибута "{1}". - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. Атрибут DllImport не может применяться для универсального метода или метода, содержащегося в универсальном методе или типе. @@ -8220,7 +8240,7 @@ If such a class is used as a base class and if the deriving class defines a dest A partial member may not explicitly implement an interface member - A partial member may not explicitly implement an interface member + Частичный член не может явным образом реализовать член интерфейса @@ -8255,7 +8275,7 @@ If such a class is used as a base class and if the deriving class defines a dest Both partial member declarations must be static or neither may be static - Both partial member declarations must be static or neither may be static + Оба объявления частичного члена должны быть статическими или оба не должны быть статическими @@ -9584,7 +9604,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep '{0}': type used in a using statement must implement 'System.IDisposable'. - "{0}": тип, использованный в операторе using, должен иметь возможность неявного преобразования в System.IDisposable. + "{0}": тип, используемый в операторе using, должен реализовывать "System.IDisposable". @@ -12161,8 +12181,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only auto-implemented properties can have initializers. - Инициализаторы могут иметь только автоматически реализованные свойства. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12981,8 +13001,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - Не удается считать сведения об отладке метода "{0}" (маркер 0x{1:X8}) из сборки "{2}". + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13112,7 +13132,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - "{0}": тип, используемый в асинхронном операторе using, должен допускать неявное преобразование в тип "System.IAsyncDisposable" или реализовывать подходящий метод "DisposeAsync". + "{0}": тип, используемый в асинхронном операторе using, должен допускать реализовывать "System.IAsyncDisposable" или подходящий метод "DisposeAsync". diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 98182f16253a7..caca114356a2d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -287,11 +287,6 @@ {0} kayıt üyesi, {1} konumsal parametresi ile eşleşmesi için {2} türünde okunabilir bir örnek özelliği veya alan olmalıdır. - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - foreach deyimi, '{0}' bir başvuru yapısı veya başvuru yapısına izin veren bir tür parametresi olduğundan, zaman uyumsuz veya yineleyici metotlarda '{0}' türündeki numaralandırıcılar üzerinde çalışamaz. - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. Zaman uyumsuz yöntemlerde veya zaman uyumsuz lambda ifadelerinde '{0}' türündeki parametreler bildirilemez. @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + Bu üyede 'OverloadResolutionPriorityAttribute' kullanılamaz. Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + Geçersiz kılan bir üyede 'OverloadResolutionPriorityAttribute' kullanılamaz. @@ -507,6 +502,11 @@ Tür, yapılandırılamadığından '{0}' türü bir koleksiyon ifadesiyle başlatılamıyor. + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' '{1}' tür parametresinde 'unmanaged' kısıtlaması olduğundan '{1}', '{0}' için kısıtlama olarak kullanılamaz @@ -632,6 +632,11 @@ 'else' bir deyim başlatamaz. + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. Uygulama giriş noktaları 'UnmanagedCallersOnly' ile ilişkilendirilemez. @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + '{0}' özelliği C# 13.0 sürümünde kullanılamıyor. Lütfen {1} veya daha yüksek dil sürümünü kullanın. @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - 'Engelleyiciler' deneysel özelliği bu ad alanında etkin değil. Projenize '{0}' ekleyin. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - '{0}': Asenkron bir using deyiminde kullanılan tür örtük olarak 'System.IAsyncDisposable' arabirimine dönüştürebilir olmalı veya uygun bir 'DisposeAsync' metodunu uygulamalıdır. 'await using' yerine 'using' mi kullanmak istediniz? + Zaman uyumsuz bir ‘using’ deyiminde kullanılan '{0}' türü 'System.IAsyncDisposable' metodunu uygulamalı veya uygun bir 'DisposeAsync' metodunu uygulamalıdır. 'await using' yerine 'using' mi kullanmak istediniz? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - '{0}': using deyiminde kullanılan tür örtük olarak 'System.IDisposable' arabirimine dönüştürülebilir olmalıdır. 'using' yerine 'await using' mi kullanmak istediniz? + Bir ‘using’ deyiminde kullanılan '{0}' türü 'System.IDisposable' metodunu uygulamalıdır. 'using' yerine 'await using' mi kullanmak istediniz? @@ -1737,6 +1742,11 @@ Bir kısmi özellikte birden fazla uygulama bildirimi olamaz + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. + + Property accessor '{0}' must be '{1}' to match the definition part '{0}' özellik erişimcisi, tanım bölümüyle eşleşmek için '{1}' olmalıdır @@ -2397,9 +2407,9 @@ genişletilmiş özellik desenleri - - field and value keywords - alan ve değer anahtar sözcükleri + + field keyword + alan anahtar sözcüğü @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + aşırı yükleme çözümlemesi önceliği @@ -2637,11 +2647,6 @@ işaretçi - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - '{0}', özellik erişimcilerinde {1} dil sürümünden başlayan bağlamsal bir anahtar sözcüktür. Bunun yerine '@{0}' kullanın. - - Identifier is a contextual keyword, with a specific meaning, in a later language version. Tanımlayıcı, daha sonraki bir dil sürümünde belirli bir anlamı olan bağlamsal bir anahtar sözcüktür. @@ -2932,6 +2937,16 @@ Bu bağlamda değişken kullanımı, başvurulan değişkenleri bildirim kapsamının dışında gösterebilir. + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. Bildirim türündeki ifadeden dönüştürme için satır içi dizi dönüştürme işleci kullanılmaz. @@ -5278,6 +5293,16 @@ Zaman uyumsuz yineleyici üyesinde 'CancellationToken' türünde bir veya daha fazla parametre var ancak bunların hiçbiri 'EnumeratorCancellation' özniteliği ile dekore edilmemiş, bu nedenle oluşturulan 'IAsyncEnumerable<>.GetAsyncEnumerator' öğesindeki iptal belirteci parametresi tüketilmeyecek + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. Null atanamaz {0} '{1}', oluşturucudan çıkış yaparken null olmayan bir değer içermelidir. 'Gerekli' değiştiricisini ekleyin veya {0} değerini null atanabilir olarak bildirmeyi göz önünde bulundurun. @@ -7592,11 +7617,6 @@ Bu sınıf temel sınıf olarak kullanılırsa ve türetilen sınıf bir yıkıc DllImport özniteliği 'static' ve 'extern' olarak işaretlenmiş bir yöntem üzerinde belirtilmelidir - - Cannot update '{0}'; attribute '{1}' is missing. - '{0}' güncelleştirilemiyor; '{1}' özniteliği eksik. - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. DllImport özniteliği, genel olan ya da genel metot veya türde barındırılan bir metoda uygulanamaz. @@ -9583,7 +9603,7 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm '{0}': type used in a using statement must implement 'System.IDisposable'. - '{0}': using deyiminde kullanılan tür örtük olarak 'System.IDisposable' arabirimine dönüştürülebilir olmalıdır. + Bir ‘using’ deyiminde kullanılan '{0}' türü 'System.IDisposable' metodunu uygulamalıdır. @@ -12160,8 +12180,8 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T - Only auto-implemented properties can have initializers. - Yalnızca otomatik uygulanan özelliklerin başlatıcıları olabilir. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - '{2}' bütünleştirilmiş kodundan '{0}' metodunun hata ayıklama bilgileri okunamıyor (belirteç 0x{1:X8}) + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - '{0}': Asenkron bir using deyiminde kullanılan tür örtük olarak 'System.IAsyncDisposable' arabirimine dönüştürebilir olmalı veya uygun bir 'DisposeAsync' metodunu uygulamalıdır. + Zaman uyumsuz bir ‘using’ deyiminde kullanılan '{0}' türü 'System.IAsyncDisposable' metodunu uygulamalı veya uygun bir 'DisposeAsync' metodunu uygulamalıdır. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 0fd9ec856d67e..438e3a64aa8fb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -287,11 +287,6 @@ 记录成员 '{0}' 必须为类型 '{1}' 的可读实例属性或字段,以匹配位置参数 '{2}'。 - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - foreach 语句无法在 "{0}" 类型的枚举器上使用异步或迭代器方法操作,因为 "{0}" 是 ref 结构或允许 ref 结构的类型参数。 - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. 不能在异步方法或异步 lambda 表达式中声明 "{0}" 类型的参数。 @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + 无法对此成员使用 'OverloadResolutionPriorityAttribute'。 Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + 无法对替代成员使用 'OverloadResolutionPriorityAttribute'。 @@ -507,6 +502,11 @@ 无法使用集合表达式初始化类型“{0}”,因为该类型不可构造。 + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' 类型参数“{1}”具有 "unmanaged" 约束,因此“{1}”不能用作“{0}”的约束 @@ -632,6 +632,11 @@ "else" 不能用在语句的开头。 + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. 无法使用 "UnmanagedCallersOnly" 对应用程序入口点进行特性化。 @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + 功能 '{0}' 在 C# 13.0 中不可用。请使用语言版本 {1} 或更高版本。 @@ -989,7 +994,7 @@ Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct. - Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct. + 属性 "System.Runtime.CompilerServices.InlineArray" 无法应用于记录结构。 @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - 此命名空间中未启用“拦截器”实验性功能。请将“{0}”添加到项目。 + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - “{0}”: 异步 using 语句中使用的类型必须可隐式转换为 "System.IAsyncDisposable" 或实现适用的 "DisposeAsync" 方法。是否希望使用 "using" 而非 "await using"? + '{0}': 异步 using 语句中使用的类型必须实现 'System.IAsyncDisposable' 或实现适用的 'DisposeAsync' 方法。是否希望使用 'using' 而非 'await using'? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - “{0}”: using 语句中使用的类型必须可隐式转换为 "System.IDisposable"。是否希望使用 "await using" 而非 "using"? + '{0}': using 语句中使用的类型必须实现 'System.IDisposable'。是否希望使用 'await using' 而非 'using'? @@ -1659,47 +1664,47 @@ Both partial member declarations must have identical accessibility modifiers. - Both partial member declarations must have identical accessibility modifiers. + 这两个分部成员声明必须具有相同的可访问性修饰符。 A partial member cannot have the 'abstract' modifier - A partial member cannot have the 'abstract' modifier + 分部成员不能具有 "abstract" 修饰符 Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. - Both partial member declarations, '{0}' and '{1}', must use the same tuple element names. + 这两个分部成员声明(“{0}”和“{1}”)都必须使用相同的元组元素名称。 A partial member must be declared within a partial type - A partial member must be declared within a partial type + 分部成员必须在分部类型内声明 Both partial member declarations must use a params parameter or neither may use a params parameter - Both partial member declarations must use a params parameter or neither may use a params parameter + 这两个分部成员声明必须都使用或者都不使用 params 参数 Both partial member declarations must be readonly or neither may be readonly - Both partial member declarations must be readonly or neither may be readonly + 这两个分部成员声明必须都是或者都不是只读声明 Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. - Both partial member declarations must have identical combinations of 'virtual', 'override', 'sealed', and 'new' modifiers. + 这两个分部成员声明必须具有 "virtual"、"override"、"sealed" 和 "new" 修饰符的相同组合。 Partial member declarations must have matching ref return values. - Partial member declarations must have matching ref return values. + 分部成员声明必须具有匹配的引用返回值。 Both partial member declarations must be unsafe or neither may be unsafe - Both partial member declarations must be unsafe or neither may be unsafe + 这两个分部成员声明必须都是或者都不是不安全声明 @@ -1729,47 +1734,52 @@ A partial property may not have multiple defining declarations, and cannot be an auto-property. - A partial property may not have multiple defining declarations, and cannot be an auto-property. + 分部属性不能有多个定义声明,并且不能是自动属性。 A partial property may not have multiple implementing declarations - A partial property may not have multiple implementing declarations + 分部属性不能有多个实现声明 + + + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. Property accessor '{0}' must be '{1}' to match the definition part - Property accessor '{0}' must be '{1}' to match the definition part + 属性访问器“{0}”必须为“{1}”才能匹配定义部分 Property accessor '{0}' must be implemented because it is declared on the definition part - Property accessor '{0}' must be implemented because it is declared on the definition part + 必须实现属性访问器“{0}”,因为它是在定义部分上声明的 Partial property '{0}' must have a definition part. - Partial property '{0}' must have a definition part. + 分部属性“{0}”必须具有定义部分。 Partial property '{0}' must have an implementation part. - Partial property '{0}' must have an implementation part. + 分布属性“{0}”必须具有实现部分。 Both partial property declarations must be required or neither may be required - Both partial property declarations must be required or neither may be required + 这两个分部属性声明必须都是或者都不是必需声明 Both partial property declarations must have the same type. - Both partial property declarations must have the same type. + 这两个分部属性声明必须具有相同的类型。 Property accessor '{0}' does not implement any accessor declared on the definition part - Property accessor '{0}' does not implement any accessor declared on the definition part + 属性访问器“{0}”未实现在定义部分上声明的任何访问器 @@ -2039,7 +2049,7 @@ The 'scoped' modifier of parameter '{0}' doesn't match partial definition. - The 'scoped' modifier of parameter '{0}' doesn't match partial definition. + 参数 "{0}" 的 "scoped" 修饰符与分部定义不匹配。 @@ -2359,7 +2369,7 @@ allows ref struct constraint - allows ref struct constraint + 允许 ref struct 约束 @@ -2397,9 +2407,9 @@ 扩展的属性模式 - - field and value keywords - field and value keywords + + field keyword + 字段关键字 @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + 重载解析优先级 @@ -2637,14 +2647,9 @@ 指针 - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - - Identifier is a contextual keyword, with a specific meaning, in a later language version. - Identifier is a contextual keyword, with a specific meaning, in a later language version. + 标识符是更高语言版本中具有特定含义的上下文关键字。 @@ -2932,6 +2937,16 @@ 在此上下文中使用变量可能会在变量声明范围以外公开所引用的变量 + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. 内联数组转换运算符将不会用于从声明类型的表达式进行转换。 @@ -3124,12 +3139,12 @@ Partial property declarations '{0}' and '{1}' have signature differences. - Partial property declarations '{0}' and '{1}' have signature differences. + 分部属性声明“{0}”和“{1}”具有签名差异。 Partial property declarations have signature differences. - Partial property declarations have signature differences. + 分部属性声明具有签名差异。 @@ -5278,6 +5293,16 @@ 异步迭代器成员具有一个或多个类型为 "CancellationToken" 的参数,但它们都未用 "EnumeratorCancellation" 属性修饰,因此将不使用所生成的 "IAsyncEnumerable<>.GetAsyncEnumerator" 中的取消令牌参数 + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. 在退出构造函数时,不可为 null 的 {0} "{1}" 必须包含非 null 值。请考虑添加 "required" 修饰符或将该 {0} 声明为可为 null。 @@ -6610,7 +6635,7 @@ The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. - The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method or property return type. + "partial" 修饰符的后面只能紧跟 "class"、"record"、"struct"、"interface" 或者方法或属性返回类型。 @@ -7592,11 +7617,6 @@ If such a class is used as a base class and if the deriving class defines a dest 必须在标记为 "static" 和 "extern" 的方法上指定 DllImport 特性 - - Cannot update '{0}'; attribute '{1}' is missing. - 无法更新“{0}”;特性“{1}”缺失。 - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. DllImport 特性不能应用于属于泛型类型的方法,或者包含在泛型方法/类型中。 @@ -8219,7 +8239,7 @@ If such a class is used as a base class and if the deriving class defines a dest A partial member may not explicitly implement an interface member - A partial member may not explicitly implement an interface member + 分部成员不能显式实现接口成员 @@ -8254,7 +8274,7 @@ If such a class is used as a base class and if the deriving class defines a dest Both partial member declarations must be static or neither may be static - Both partial member declarations must be static or neither may be static + 这两个分部成员声明必须都是或者都不是静态声明 @@ -9583,7 +9603,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep '{0}': type used in a using statement must implement 'System.IDisposable'. - “{0}”: using 语句中使用的类型必须可隐式转换为“System.IDisposable” + '{0}': using 语句中使用的类型必须实现 'System.IDisposable'。 @@ -12160,8 +12180,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only auto-implemented properties can have initializers. - 只有自动实现的属性才能具有初始值设定项。 + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - 无法从程序集“{2}”读取方法“{0}”(令牌 0x{1:X8})的调试信息 + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - “{0}”: 异步 using 语句中使用的类型必须可隐式转换为 "System.IAsyncDisposable" 或实现适用的 "DisposeAsync" 方法。 + '{0}': 异步 using 语句中使用的类型必须实现 'System.IAsyncDisposable' 或实现适用的 'DisposeAsync' 方法。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 2953af749793e..b417e01791424 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -287,11 +287,6 @@ 記錄成員 '{0}' 必須是類型 '{1}' 的可讀取執行個體屬性或欄位,才能符合位置參數 '{2}'。 - - foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct or a type parameter that allows ref struct. - foreach 陳述式無法對 async 或 iterator 方法中 '{0}' 類型的列舉值運作,因為 '{0}' 是 ref struct 或允許 ref struct 的型別參數。 - - Parameters of type '{0}' cannot be declared in async methods or async lambda expressions. 類型 '{0}' 的參數不得在非同步方法或非同步 Lambda 運算式中宣告。 @@ -334,12 +329,12 @@ Cannot use 'OverloadResolutionPriorityAttribute' on this member. - Cannot use 'OverloadResolutionPriorityAttribute' on this member. + 無法在此成員上使用 'OverloadResolutionPriorityAttribute'。 Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. - Cannot use 'OverloadResolutionPriorityAttribute' on an overriding member. + 無法在覆寫成員上使用 'OverloadResolutionPriorityAttribute'。 @@ -507,6 +502,11 @@ 無法使用集合運算式將類型 '{0}' 初始化,因為該類型為不可建構。 + + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + Collection initializer results in an infinite chain of instantiations of collection '{0}'. + + Type parameter '{1}' has the 'unmanaged' constraint so '{1}' cannot be used as a constraint for '{0}' 類型參數 '{1}' 有 'unmanaged' 條件約束,因此 '{1}' 不可作為 '{0}' 的條件約束 @@ -632,6 +632,11 @@ 'else' 無法開始陳述式。 + + Cannot emit update; {0} '{1}' is missing. + Cannot emit update; {0} '{1}' is missing. + + Application entry points cannot be attributed with 'UnmanagedCallersOnly'. 無法使用 'UnmanagedCallersOnly' 將應用程式進入點屬性化。 @@ -784,7 +789,7 @@ Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. - Feature '{0}' is not available in C# 13.0. Please use language version {1} or greater. + C# 13.0 中無法使用功能 '{0}'。請使用語言版本 {1} 或更高版本。 @@ -1148,8 +1153,8 @@ - The 'interceptors' experimental feature is not enabled in this namespace. Add '{0}' to your project. - 未在此命名空間中啟用「攔截器」實驗功能。將 '{0}' 新增至您的專案。 + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. + The 'interceptors' feature is not enabled in this namespace. Add '{0}' to your project. @@ -1464,12 +1469,12 @@ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. Did you mean 'using' rather than 'await using'? - '{0}': 在非同步 using 陳述式中使用的類型,必須可隱含地轉換為 'System.IAsyncDisposable' 或實作合適的 'DisposeAsync' 方法。您指的是否為 'using',而非 'await using'? + '{0}': 在非同步 using 陳述式中使用的類型,必須可實作 'System.IAsyncDisposable' 或實作合適的 'DisposeAsync' 方法。您是指 'using' 而不是 'await using' 嗎? '{0}': type used in a using statement must implement 'System.IDisposable'. Did you mean 'await using' rather than 'using'? - '{0}': using 陳述式中使用的類型必須可以隱含轉換為 'System.IDisposable'。您指的是 'await using' 而不是 'using' 嗎? + '{0}: 在 using 陳述式中使用的類型必須實作 'System.IDisposable'。您是指 'await using' 而不是 'using' 嗎? @@ -1737,6 +1742,11 @@ 部分屬性不可具有多個實作的宣告 + + A partial property cannot have an initializer on both the definition and implementation. + A partial property cannot have an initializer on both the definition and implementation. + + Property accessor '{0}' must be '{1}' to match the definition part 屬性存取子 '{0}' 必須是 '{1}' 以符合定義部分 @@ -2397,9 +2407,9 @@ 擴充屬性模式 - - field and value keywords - 欄位和值關鍵字 + + field keyword + 欄位關鍵字 @@ -2609,7 +2619,7 @@ overload resolution priority - overload resolution priority + 多載解析優先順序 @@ -2637,11 +2647,6 @@ 指標 - - '{0}' is a contextual keyword in property accessors starting in language version {1}. Use '@{0}' instead. - '{0}' 是從語言版本 {1} 開始之屬性存取子中的內容相關關鍵字。請改用 '@{0}'。 - - Identifier is a contextual keyword, with a specific meaning, in a later language version. 識別碼是在較新語言版本中具有特定意義的內容相關關鍵字。 @@ -2932,6 +2937,16 @@ 在此內容中使用變數,可能會將參考的變數公開在其宣告範圍外 + + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + In language version {0}, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + + + + The 'field' keyword binds to a synthesized backing field for the property. + The 'field' keyword binds to a synthesized backing field for the property. + + Inline array conversion operator will not be used for conversion from expression of the declaring type. 內嵌陣列轉換運算子不會用於從宣告類型的運算式進行轉換。 @@ -5278,6 +5293,16 @@ strument:TestCoverage 產生檢測要收集 非同步迭代器成員有一或多個類型 'CancellationToken' 的參數,但因為沒有任何參數有裝飾 'EnumeratorCancellation' 屬性,所以將不會取用來自已產生 'IAsyncEnumerable<>.GetAsyncEnumerator' 的取消權杖參數 + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the {0} as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Similar diagnostic message as 'WRN_UninitializedNonNullableField' + + + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + Non-nullable property must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + + Non-nullable {0} '{1}' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the {0} as nullable. 退出建構函式時,不可為 Null 的 {0} '{1}' 必須包含非 Null 值。請考慮新增 'required' 修飾元,或將 {0} 宣告為可以為 Null。 @@ -7592,11 +7617,6 @@ If such a class is used as a base class and if the deriving class defines a dest DllImport 屬性必須指定在標記為 'static' 和 'extern' 的方法上 - - Cannot update '{0}'; attribute '{1}' is missing. - 無法更新 '{0}'; 缺少屬性 '{1}'。 - - The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. DllImport 屬性無法套用至泛型方法,或包含在泛型方法或類型中。 @@ -9583,7 +9603,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep '{0}': type used in a using statement must implement 'System.IDisposable'. - '{0}': using 陳述式中使用的類型必須可以隱含轉換為 'System.IDisposable'。 + '{0}: 在 using 陳述式中使用的類型必須實作 'System.IDisposable'。 @@ -12160,8 +12180,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Only auto-implemented properties can have initializers. - 只有自動實作的屬性可以有初始設定式。 + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. @@ -12980,8 +13000,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - 無法從組件 '{2}' 讀取方法 '{0}' 的偵錯資訊 (權杖 0x{1:X8}) + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} @@ -13111,7 +13131,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ '{0}': type used in an asynchronous using statement must implement 'System.IAsyncDisposable' or implement a suitable 'DisposeAsync' method. - '{0}': 在非同步 using 陳述式中使用的類型,必須可隱含地轉換為 'System.IAsyncDisposable' 或實作合適的 'DisposeAsync' 方法。 + '{0}': 在非同步 using 陳述式中使用的類型,必須可實作 'System.IAsyncDisposable' 或實作合適的 'DisposeAsync' 方法。 diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTestBase.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTestBase.cs index e6ddad5f5b487..878e1acd5b792 100644 --- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTestBase.cs +++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTestBase.cs @@ -16,7 +16,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.CommandLine.UnitTests { diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs index beb952e6d23e3..1cef8beaea68f 100644 --- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs +++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs @@ -26,7 +26,6 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Test.Resources.Proprietary; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.DiaSymReader; @@ -39,13 +38,12 @@ using Basic.Reference.Assemblies; using static Microsoft.CodeAnalysis.CommonDiagnosticAnalyzers; using static Roslyn.Test.Utilities.SharedResourceHelpers; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.CommandLine.UnitTests { public class CommandLineTests : CommandLineTestBase { -#if NETCOREAPP +#if NET private static readonly string s_CSharpCompilerExecutable; private static readonly string s_DotnetCscRun; #else @@ -60,7 +58,7 @@ public class CommandLineTests : CommandLineTestBase static CommandLineTests() { -#if NETCOREAPP +#if NET var cscDllPath = Path.Combine( Path.GetDirectoryName(typeof(CommandLineTests).GetTypeInfo().Assembly.Location), Path.Combine("dependency", "csc.dll")); @@ -4340,8 +4338,8 @@ public void AppConfigBasic() "); - var silverlight = Temp.CreateFile().WriteAllBytes(ProprietaryTestResources.silverlight_v5_0_5_0.System_v5_0_5_0_silverlight).Path; - var net4_0dll = Temp.CreateFile().WriteAllBytes(ResourcesNet451.System).Path; + var silverlight = Temp.CreateFile().WriteAllBytes(Silverlight.System).Path; + var net4_0dll = Temp.CreateFile().WriteAllBytes(Net461.Resources.System).Path; // Test linking two appconfig dlls with simple src var outWriter = new StringWriter(CultureInfo.InvariantCulture); @@ -6310,7 +6308,7 @@ public class CS1698_a {} [ConditionalFact(typeof(ClrOnly), Reason = "https://github.com/dotnet/roslyn/issues/30926")] public void BinaryFileErrorTest() { - var binaryPath = Temp.CreateFile().WriteAllBytes(ResourcesNet451.mscorlib).Path; + var binaryPath = Temp.CreateFile().WriteAllBytes(Net461.Resources.mscorlib).Path; var csc = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/nologo", "/preferreduilang:en", binaryPath }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); int exitCode = csc.Run(outWriter); @@ -10463,6 +10461,44 @@ class C void RunWithCache() => VerifyOutput(dir, src, includeCurrentAssemblyAsAnalyzerReference: false, additionalFlags: new[] { "/langversion:preview", "/features:enable-generator-cache" }, generators: new[] { generator.AsSourceGenerator() }, driverCache: cache, analyzers: null); } + [Fact] + public void Compiler_DoesNot_RunHostOutputs() + { + var dir = Temp.CreateDirectory(); + var src = dir.CreateFile("temp.cs").WriteAllText(@" +class C +{ +}"); + bool hostOutputRan = false; + bool sourceOutputRan = false; + + var generator = new PipelineCallbackGenerator((ctx) => + { +#pragma warning disable RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + ctx.RegisterHostOutput(ctx.CompilationProvider, (hostCtx, value) => + { + hostOutputRan = true; + hostCtx.AddOutput("output", "value"); + }); +#pragma warning restore RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + ctx.RegisterSourceOutput(ctx.CompilationProvider, (spc, po) => + { + sourceOutputRan = true; + spc.AddSource("output.cs", "//value"); + }); + }); + + VerifyOutput(dir, src, includeCurrentAssemblyAsAnalyzerReference: false, additionalFlags: new[] { "/langversion:preview" }, generators: new[] { generator.AsSourceGenerator() }, analyzers: null); + + Assert.False(hostOutputRan); + Assert.True(sourceOutputRan); + + // Clean up temp files + CleanupAllGeneratedFiles(src.Path); + Directory.Delete(dir.Path, true); + } + private static int OccurrenceCount(string source, string word) { var n = 0; @@ -12250,9 +12286,9 @@ public void StrongNameProviderWithCustomTempPath() } [Theory] - [InlineData(@"/features:InterceptorsPreviewNamespaces=NS1.NS2;NS3.NS4")] - [InlineData(@"/features:""InterceptorsPreviewNamespaces=NS1.NS2;NS3.NS4""")] - public void FeaturesInterceptorsPreviewNamespaces_OptionParsing(string features) + [InlineData(@"/features:InterceptorsNamespaces=NS1.NS2;NS3.NS4")] + [InlineData(@"/features:""InterceptorsNamespaces=NS1.NS2;NS3.NS4""")] + public void FeaturesInterceptorsNamespaces_OptionParsing(string features) { var tempDir = Temp.CreateDirectory(); var workingDir = Temp.CreateDirectory(); @@ -12263,33 +12299,54 @@ public void FeaturesInterceptorsPreviewNamespaces_OptionParsing(string features) var comp = (CSharpCompilation)csc.CreateCompilation(new StringWriter(), new TouchedFileLogger(), errorLogger: null); var options = comp.SyntaxTrees[0].Options; Assert.Equal(1, options.Features.Count); - Assert.Equal("NS1.NS2;NS3.NS4", options.Features["InterceptorsPreviewNamespaces"]); + Assert.Equal("NS1.NS2;NS3.NS4", options.Features["InterceptorsNamespaces"]); - var previewNamespaces = ((CSharpParseOptions)options).InterceptorsPreviewNamespaces; + var previewNamespaces = ((CSharpParseOptions)options).InterceptorsNamespaces; Assert.Equal(2, previewNamespaces.Length); Assert.Equal(new[] { "NS1", "NS2" }, previewNamespaces[0]); Assert.Equal(new[] { "NS3", "NS4" }, previewNamespaces[1]); } [Fact] - public void FeaturesInterceptorsPreviewNamespaces_Duplicate() + public void FeaturesInterceptorsNamespaces_Duplicate() { var tempDir = Temp.CreateDirectory(); var workingDir = Temp.CreateDirectory(); workingDir.CreateFile("a.cs"); var buildPaths = new BuildPaths(clientDir: "", workingDir: workingDir.Path, sdkDir: null, tempDir: tempDir.Path); - var csc = new MockCSharpCompiler(null, buildPaths, args: new[] { @"/features:InterceptorsPreviewNamespaces=NS1.NS2", @"/features:InterceptorsPreviewNamespaces=NS3.NS4", "a.cs" }); + var csc = new MockCSharpCompiler(null, buildPaths, args: new[] { @"/features:InterceptorsNamespaces=NS1.NS2", @"/features:InterceptorsNamespaces=NS3.NS4", "a.cs" }); var comp = (CSharpCompilation)csc.CreateCompilation(new StringWriter(), new TouchedFileLogger(), errorLogger: null); var options = comp.SyntaxTrees[0].Options; Assert.Equal(1, options.Features.Count); - Assert.Equal("NS3.NS4", options.Features["InterceptorsPreviewNamespaces"]); + Assert.Equal("NS3.NS4", options.Features["InterceptorsNamespaces"]); - var previewNamespaces = ((CSharpParseOptions)options).InterceptorsPreviewNamespaces; + var previewNamespaces = ((CSharpParseOptions)options).InterceptorsNamespaces; Assert.Equal(1, previewNamespaces.Length); Assert.Equal(new[] { "NS3", "NS4" }, previewNamespaces[0]); } + [Fact] + public void FeaturesInterceptorsPreviewNamespaces_NotRecognizedInCommandLine() + { + // '' is recognized in the build task and passed through as a '/features:InterceptorsNamespaces=...' argument. + // '/features:InterceptorsPreviewNamespaces=...' is included in the Features dictionary but does not enable the interceptors feature. + var tempDir = Temp.CreateDirectory(); + var workingDir = Temp.CreateDirectory(); + workingDir.CreateFile("a.cs"); + + var buildPaths = new BuildPaths(clientDir: "", workingDir: workingDir.Path, sdkDir: null, tempDir: tempDir.Path); + var csc = new MockCSharpCompiler(null, buildPaths, args: new[] { @"/features:InterceptorsPreviewNamespaces=NS1.NS2", "a.cs" }); + var comp = (CSharpCompilation)csc.CreateCompilation(new StringWriter(), new TouchedFileLogger(), errorLogger: null); + var options = comp.SyntaxTrees[0].Options; + + Assert.Equal(1, options.Features.Count); + Assert.Equal("NS1.NS2", options.Features["InterceptorsPreviewNamespaces"]); + + Assert.False(options.Features.ContainsKey("InterceptorsNamespaces")); + Assert.Empty(((CSharpParseOptions)options).InterceptorsNamespaces); + } + public class QuotedArgumentTests : CommandLineTestBase { private static readonly string s_rootPath = ExecutionConditionUtil.IsWindows @@ -14373,7 +14430,7 @@ public InterceptsLocationAttribute(string filePath, int line, int character) """; var generator = new SingleFileTestGenerator(generatedSource, "Generated.cs"); - VerifyOutput(dir, src, includeCurrentAssemblyAsAnalyzerReference: false, additionalFlags: ["/langversion:preview", "/out:embed.exe", "/features:InterceptorsPreviewNamespaces=Generated"], generators: [generator], analyzers: null); + VerifyOutput(dir, src, includeCurrentAssemblyAsAnalyzerReference: false, additionalFlags: ["/langversion:preview", "/out:embed.exe", "/features:InterceptorsNamespaces=Generated"], generators: [generator], analyzers: null); ValidateWrittenSources([]); // Clean up temp files @@ -14432,7 +14489,7 @@ public InterceptsLocationAttribute(string filePath, int line, int character) var generator = new SingleFileTestGenerator(generatedSource, "Generated.cs"); var objDir = dir.CreateDirectory("obj"); - VerifyOutput(dir, src, includeCurrentAssemblyAsAnalyzerReference: false, additionalFlags: ["/langversion:preview", $"/out:{objDir.Path}/embed.exe", "/features:InterceptorsPreviewNamespaces=Generated"], generators: [generator], analyzers: null); + VerifyOutput(dir, src, includeCurrentAssemblyAsAnalyzerReference: false, additionalFlags: ["/langversion:preview", $"/out:{objDir.Path}/embed.exe", "/features:InterceptorsNamespaces=Generated"], generators: [generator], analyzers: null); ValidateWrittenSources([]); // Clean up temp files @@ -14502,7 +14559,7 @@ public InterceptsLocationAttribute(string filePath, int line, int character) "/generatedfilesout:" + objDir.Path, "/langversion:preview", "/out:embed.exe", - "/features:InterceptorsPreviewNamespaces=Generated", + "/features:InterceptorsNamespaces=Generated", .. string.IsNullOrEmpty(pathMapArgument) ? default(Span) : [pathMapArgument] ], generators: [generator], diff --git a/src/Compilers/CSharp/Test/CommandLine/TouchedFileLoggingTests.cs b/src/Compilers/CSharp/Test/CommandLine/TouchedFileLoggingTests.cs index fdf9cb0b5c099..0a1b0c7c3b4fc 100644 --- a/src/Compilers/CSharp/Test/CommandLine/TouchedFileLoggingTests.cs +++ b/src/Compilers/CSharp/Test/CommandLine/TouchedFileLoggingTests.cs @@ -10,13 +10,12 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; -using Microsoft.CodeAnalysis.Test.Resources.Proprietary; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; using static Roslyn.Test.Utilities.SharedResourceHelpers; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.CommandLine.UnitTests { @@ -77,8 +76,8 @@ public void AppConfigCsc() ").Path; - var silverlight = Temp.CreateFile().WriteAllBytes(ProprietaryTestResources.silverlight_v5_0_5_0.System_v5_0_5_0_silverlight).Path; - var net4_0dll = Temp.CreateFile().WriteAllBytes(ResourcesNet451.System).Path; + var silverlight = Temp.CreateFile().WriteAllBytes(Silverlight.System).Path; + var net4_0dll = Temp.CreateFile().WriteAllBytes(Net461.Resources.System).Path; var outWriter = new StringWriter(CultureInfo.InvariantCulture); var cmd = CreateCSharpCompiler( diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index 7f2ea11dadc4b..c8b79ddce9d23 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -9,9 +9,9 @@ using System.Reflection.PortableExecutable; using System.Runtime.CompilerServices; using System.Text; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; -using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -31,6 +31,11 @@ internal enum Instruction [CompilerTrait(CompilerFeature.AsyncStreams)] public class CodeGenAsyncIteratorTests : EmitMetadataTestBase { + internal static string ExpectedOutput(string output) + { + return ExecutionConditionUtil.IsMonoOrCoreClr ? output : null; + } + /// /// Enumerates `C.M()` a given number of iterations. /// @@ -6475,7 +6480,7 @@ async System.Collections.Generic.IAsyncEnumerable M() [Fact] public void TestWellKnownMembers() { - var comp = CreateCompilation(AsyncStreamsTypes, references: new[] { TestMetadata.SystemThreadingTasksExtensions.NetStandard20Lib }, targetFramework: TargetFramework.NetStandard20); + var comp = CreateCompilation(AsyncStreamsTypes, references: new[] { NetStandard20.ExtraReferences.SystemThreadingTasksExtensions }, targetFramework: TargetFramework.NetStandard20); comp.VerifyDiagnostics(); verifyType(WellKnownType.System_Threading_Tasks_Sources_ManualResetValueTaskSourceCore_T, @@ -8458,5 +8463,208 @@ public async IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellati var comp = CreateCompilationWithAsyncIterator(source); CompileAndVerify(comp, expectedOutput: "RAN RAN RAN CLEARED"); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74362")] + public void AwaitForeachInLocalFunctionInAccessor() + { + var src = """ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +foreach (var x in X.ValuesViaLocalFunction) +{ + Console.WriteLine(x); +} + +public class X +{ + public static async IAsyncEnumerable GetValues() + { + await Task.Yield(); + yield return 42; + } + + public static IEnumerable ValuesViaLocalFunction + { + get + { + foreach (var b in Do().ToBlockingEnumerable()) + { + yield return b; + } + + async IAsyncEnumerable Do() + { + await foreach (var v in GetValues()) + { + yield return v; + } + } + } + } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("42"), verify: Verification.FailsPEVerify); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74362")] + public void AwaitForeachInMethod() + { + var src = """ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +await foreach (var x in X.Do()) +{ + Console.WriteLine(x); +} + +public class X +{ + public static async IAsyncEnumerable GetValues() + { + await Task.Yield(); + yield return 42; + } + + public static async IAsyncEnumerable Do() + { + await foreach (var v in GetValues()) + { + yield return v; + } + } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("42"), verify: Verification.FailsPEVerify); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74362")] + public void AwaitInForeachInLocalFunctionInAccessor() + { + var src = """ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +public class C +{ + public static void Main() + { + Console.Write(Property); + } + + public static int Property + { + get + { + return Do().GetAwaiter().GetResult(); + + async Task Do() + { + IEnumerable a = [42]; + foreach (var v in a) + { + await Task.Yield(); + return v; + } + + return 0; + } + } + } +} +"""; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: ExpectedOutput("42"), verify: Verification.FailsPEVerify); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73563")] + public void IsMetadataVirtual_01() + { + var src1 = @" +using System.Collections.Generic; +using System.Threading; + +public struct S : IAsyncEnumerable +{ + public IAsyncEnumerator GetAsyncEnumerator(CancellationToken token = default) => throw null; + + void M() + { + GetAsyncEnumerator(); + } +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: TargetFramework.Net80); + + var src2 = @" +using System.Threading.Tasks; + +class C +{ + static async Task Main() + { + await foreach (var i in new S()) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: TargetFramework.Net80); + comp2.VerifyEmitDiagnostics(); // Indirectly calling IsMetadataVirtual on S.GetAsyncEnumerator (a read which causes the lock to be set) + comp1.VerifyEmitDiagnostics(); // Would call EnsureMetadataVirtual on S.GetAsyncEnumerator and would therefore assert if S was not already ForceCompleted + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73563")] + public void IsMetadataVirtual_02() + { + var src1 = @" +using System; +using System.Threading.Tasks; + +public struct S2 : IAsyncDisposable +{ + public ValueTask DisposeAsync() + { + return ValueTask.CompletedTask; + } + + void M() + { + DisposeAsync(); + } +} +"; + + var comp1 = CreateCompilation(src1, targetFramework: TargetFramework.Net80); + + var src2 = @" +class C +{ + static async System.Threading.Tasks.Task Main() + { + await using (new S2()) + { + } + + await using (var s = new S2()) + { + } + } +} +"; + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: TargetFramework.Net80); + comp2.VerifyEmitDiagnostics(); // Indirectly calling IsMetadataVirtual on S.DisposeAsync (a read which causes the lock to be set) + comp1.VerifyEmitDiagnostics(); // Would call EnsureMetadataVirtual on S.DisposeAsync and would therefore assert if S was not already ForceCompleted + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncLocalsTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncLocalsTests.cs index 9f35f02b9440e..caaf685ab21be 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncLocalsTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncLocalsTests.cs @@ -958,8 +958,8 @@ public static void Main() Run(); } }"; - var reference = CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { SystemRef_v4_0_30319_17929 }).EmitToImageReference(); - var comp = CreateCompilationWithMscorlib45("", new[] { reference }, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal)); + var reference = CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { SystemRef_v4_0_30319_17929 }).EmitToImageReference(); + var comp = CreateCompilationWithMscorlib461("", new[] { reference }, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal)); var testClass = comp.GlobalNamespace.GetMember("Test"); var stateMachineClass = (NamedTypeSymbol)testClass.GetMembers().Single(s => s.Name.StartsWith("", StringComparison.Ordinal)); IEnumerable> spillFieldsByType = stateMachineClass.GetMembers().Where(m => m.Kind == SymbolKind.Field && m.Name.StartsWith("<>7__wrap", StringComparison.Ordinal)).Cast().GroupBy(x => x.Type); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs index 9352974a34fb8..a822b9665647e 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs @@ -366,7 +366,7 @@ public struct Int32{} namespace System.Threading.Tasks { public class Task{} }"; - var taskCompilation = CreateCompilationWithMscorlib45(taskAssembly, options: TestOptions.DebugDll); + var taskCompilation = CreateCompilationWithMscorlib461(taskAssembly, options: TestOptions.DebugDll); taskCompilation.VerifyDiagnostics(); var source = @" @@ -406,7 +406,7 @@ public class Object {} namespace System.Threading.Tasks { public class Task{} }"; - var taskCompilation = CreateCompilationWithMscorlib45(taskAssembly, options: TestOptions.DebugDll); + var taskCompilation = CreateCompilationWithMscorlib461(taskAssembly, options: TestOptions.DebugDll); taskCompilation.VerifyDiagnostics(); var source = @" @@ -446,7 +446,7 @@ static async Task Main() { Console.Write(""async main""); } }"; - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 0); } @@ -464,7 +464,7 @@ static async Task Main() { Console.WriteLine(""async main""); } }"; - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); c.VerifyEmitDiagnostics( // (6,28): error CS0161: 'Program.Main()': not all code paths return a value // static async Task Main() { @@ -486,7 +486,7 @@ static async Task Main(string[] args) { return 10; } }"; - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 10); } @@ -505,7 +505,7 @@ static async Task Main(params string[] args) { return 10; } }"; - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 10); } @@ -523,7 +523,7 @@ static async Task Main(string[] args) { Console.Write(""async main""); } }"; - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 0); } @@ -541,7 +541,7 @@ static async Task Main(string[] args) { Console.WriteLine(""async main""); } }"; - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); c.VerifyEmitDiagnostics( // (6,28): error CS0161: 'Program.Main()': not all code paths return a value // static async Task Main() { @@ -563,7 +563,7 @@ static async Task Main(string[] args) { return 10; } }"; - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 10, args: new string[] { "async main" }); } @@ -581,7 +581,7 @@ static async Task Main(string[] args) { Console.Write(args[0]); } }"; - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); var verifier = CompileAndVerify(c, expectedOutput: "hello async main", expectedReturnCode: 0, args: new string[] { "async main" }); } @@ -598,7 +598,7 @@ async static Task Main(string[] args) await Task.Factory.StartNew(() => { }); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics(); var entry = compilation.GetEntryPoint(CancellationToken.None); Assert.NotNull(entry); @@ -620,7 +620,7 @@ static Task Main(string[] args) return Task.Factory.StartNew(() => { }); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics(); var entry = compilation.GetEntryPoint(CancellationToken.None); Assert.NotNull(entry); @@ -642,7 +642,7 @@ static ref Task Main(string[] args) throw new System.Exception(); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics( // (6,21): warning CS0028: 'A.Main(string[])' has the wrong signature to be an entry point // static ref Task Main(string[] args) @@ -664,7 +664,7 @@ async static Task Main(string[] args) await Task.Factory.StartNew(() => { }); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); compilation.VerifyDiagnostics( // (6,18): error CS8107: Feature 'async main' is not available in C# 7.0. Please use language version 7.1 or greater. // async static Task Main(string[] args) @@ -687,7 +687,7 @@ static Task Main(string[] args) return Task.Factory.StartNew(() => { }); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); compilation.VerifyDiagnostics( // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. // async static Task Main(string[] args) @@ -709,7 +709,7 @@ async static Task Main() await Task.Factory.StartNew(() => { }); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics(); var entry = compilation.GetEntryPoint(CancellationToken.None); Assert.NotNull(entry); @@ -786,7 +786,7 @@ static Task Main() return Task.Factory.StartNew(() => { }); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics(); var entry = compilation.GetEntryPoint(CancellationToken.None); Assert.NotNull(entry); @@ -806,7 +806,7 @@ async static void Main() await Task.Factory.StartNew(() => { }); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); compilation.VerifyDiagnostics( // (6,23): error CS8413: Async Main methods must return Task or Task // async static void Main() @@ -828,7 +828,7 @@ async static int Main() return await Task.Factory.StartNew(() => 5); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics( // (6,22): error CS1983: The return type of an async method must be void, Task or Task // async static int Main() @@ -855,7 +855,7 @@ async static int Main() return await Task.Factory.StartNew(() => 5); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); compilation.VerifyDiagnostics( // (6,22): error CS1983: The return type of an async method must be void, Task or Task // async static int Main() @@ -880,7 +880,7 @@ async static Task Main(string[] args) return await Task.Factory.StartNew(() => 5); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics(); var entry = compilation.GetEntryPoint(CancellationToken.None); Assert.NotNull(entry); @@ -900,7 +900,7 @@ static Task Main(string[] args) return Task.Factory.StartNew(() => 5); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics(); var entry = compilation.GetEntryPoint(CancellationToken.None); Assert.NotNull(entry); @@ -920,7 +920,7 @@ async static Task Main(string[] args) return await Task.Factory.StartNew(() => 5); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); compilation.VerifyDiagnostics( // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. // async static Task Main(string[] args) @@ -942,7 +942,7 @@ static Task Main(string[] args) return Task.Factory.StartNew(() => 5); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); compilation.VerifyDiagnostics( // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. // async static Task Main(string[] args) @@ -964,7 +964,7 @@ async static Task Main() return await Task.Factory.StartNew(() => 5); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics(); var entry = compilation.GetEntryPoint(CancellationToken.None); Assert.NotNull(entry); @@ -984,7 +984,7 @@ static Task Main() return Task.Factory.StartNew(() => 5); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics(); var entry = compilation.GetEntryPoint(CancellationToken.None); Assert.NotNull(entry); @@ -1004,7 +1004,7 @@ async static Task Main() return await Task.Factory.StartNew(() => 5); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); compilation.VerifyDiagnostics( // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. // async static Task Main() @@ -1026,7 +1026,7 @@ static Task Main() return Task.Factory.StartNew(() => 5); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); compilation.VerifyDiagnostics( // (6,18): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. // async static Task Main() @@ -1049,7 +1049,7 @@ async static Task Main() return 0; } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)); compilation.VerifyDiagnostics( // (6,30): warning CS0028: 'A.Main()' has the wrong signature to be an entry point // async static Task Main() @@ -1071,7 +1071,7 @@ async static void Main() await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics( // (6,23): warning CS0402: 'A.Main()': an entry point cannot be generic or in a generic type // async static void Main() Diagnostic(ErrorCode.WRN_MainCantBeGeneric, "Main").WithArguments("A.Main()").WithLocation(6, 23), @@ -1092,7 +1092,7 @@ async static void Main(bool truth) await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (6,23): warning CS0028: 'A.Main(bool)' has the wrong signature to be an entry point // async static void Main(bool truth) Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(bool)").WithLocation(6, 23), @@ -1113,7 +1113,7 @@ async static void Main(bool truth) await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (6,23): warning CS0028: 'A.Main(bool)' has the wrong signature to be an entry point // async static void Main(bool truth) Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(bool)").WithLocation(6, 23), @@ -1139,7 +1139,7 @@ async static Task Main(string[] args) System.Console.WriteLine(""Task Main""); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)).VerifyDiagnostics(); CompileAndVerify(compilation, expectedOutput: "Non Task Main", expectedReturnCode: 0); } @@ -1161,7 +1161,7 @@ async static Task Main(string[] args) System.Console.WriteLine(""Task Main""); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics( + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics( // (10,23): warning CS8892: Method 'A.Main(string[])' will not be used as an entry point because a synchronous entry point 'A.Main()' was found. // async static Task Main(string[] args) Diagnostic(ErrorCode.WRN_SyncAndAsyncEntryPoints, "Main").WithArguments("A.Main(string[])", "A.Main()").WithLocation(10, 23) @@ -1189,7 +1189,7 @@ async static int Main() return 1; } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (11,22): error CS1983: The return type of an async method must be void, Task or Task // async static int Main() Diagnostic(ErrorCode.ERR_BadAsyncReturn, "Main").WithLocation(11, 22), @@ -1217,7 +1217,7 @@ static async void Main(string[] args) System.Console.WriteLine(""Async Void Main""); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics( + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics( // (6,23): error CS4009: A void or int returning entry point cannot be async // static async void Main(string[] args) Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithLocation(6, 23), @@ -1243,7 +1243,7 @@ async static Task Main(string[] args) System.Console.WriteLine(""Task Main""); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithMainTypeName("A")).VerifyDiagnostics( + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithMainTypeName("A")).VerifyDiagnostics( // (10,23): warning CS8892: Method 'A.Main(string[])' will not be used as an entry point because a synchronous entry point 'A.Main()' was found. // async static Task Main(string[] args) Diagnostic(ErrorCode.WRN_SyncAndAsyncEntryPoints, "Main").WithArguments("A.Main(string[])", "A.Main()").WithLocation(10, 23)); @@ -1270,7 +1270,7 @@ async static Task Main(string[] args) return 0.0F; } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseDebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)).VerifyDiagnostics( + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseDebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)).VerifyDiagnostics( // (6,28): warning 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. // async static Task Main() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Main").WithLocation(6, 28), @@ -1307,7 +1307,7 @@ static Task Main(string[] args) return Task.FromResult(0.0F); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseDebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)).VerifyDiagnostics( + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseDebugExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)).VerifyDiagnostics( // (6,12): error CS8107: Feature 'async main' is not available in C# 7. Please use language version 7.1 or greater. // static Task Main() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "Task").WithArguments("async main", "7.1").WithLocation(6, 12), @@ -1338,7 +1338,7 @@ async static Task Main(string[] args) return 0.0f; } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (10,30): warning CS0028: 'A.Main(string[])' has the wrong signature to be an entry point // async static Task Main(string[] args) Diagnostic(ErrorCode.WRN_InvalidMainSig, "Main").WithArguments("A.Main(string[])").WithLocation(11, 30)); @@ -1365,7 +1365,7 @@ async static Task Main(string[] args) return 0.0f; } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithMainTypeName("A")).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithMainTypeName("A")).VerifyDiagnostics(); CompileAndVerify(compilation, expectedOutput: "Non Task Main", expectedReturnCode: 0); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs index 6c4a94e3e62c7..fc204d27f2eb2 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMethodBuilderOverrideTests.cs @@ -113,7 +113,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (11,25): error CS8773: Feature 'async method builder override' is not available in C# 9.0. Please use language version 10.0 or greater. // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -126,7 +126,7 @@ class C Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "M").WithArguments("async method builder override", "10.0").WithLocation(17, 37) ); - compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular10); + compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular10); var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3"); verifier.VerifyDiagnostics(); var testData = verifier.TestData; @@ -223,7 +223,7 @@ public static async MyTask M() {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular10); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular10); compilation.VerifyDiagnostics( // (14,16): warning CS8603: Possible null reference return. // return default(T); // 1 @@ -274,7 +274,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (9,51): error CS1997: Since 'C.F()' is an async method that returns 'MyTask', a return keyword must not be followed by an object expression // static async MyTask F() { await Task.Yield(); return 1; } // 1 @@ -328,7 +328,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics(); } @@ -366,7 +366,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics(); } @@ -404,7 +404,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics(); } @@ -444,7 +444,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics(); } @@ -482,7 +482,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics(); } @@ -519,7 +519,7 @@ public void BuilderOnMethod_DummyBuilderOnType_OnLocalFunction(string dummyBuild {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (9,21): error CS8773: Feature 'async method builder override' is not available in C# 9.0. Please use language version 10.0 or greater. // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -532,7 +532,7 @@ public void BuilderOnMethod_DummyBuilderOnType_OnLocalFunction(string dummyBuild Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "M").WithArguments("async method builder override", "10.0").WithLocation(15, 26) ); - compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular10); + compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular10); var verifier = CompileAndVerify(compilation, expectedOutput: "M F G 3"); verifier.VerifyDiagnostics(); } @@ -568,7 +568,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,32): error CS0246: The type or namespace name 'Error' could not be found (are you missing a using directive or an assembly reference?) // [AsyncMethodBuilder(typeof(Error))] @@ -614,7 +614,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (9,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -693,7 +693,7 @@ class C {asyncBuilderFactoryCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (11,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Create' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -763,7 +763,7 @@ public void BuilderOnMethod_OnLambda() {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular9); compilation.VerifyEmitDiagnostics( // (6,18): error CS8773: Feature 'lambda attributes' is not available in C# 9.0. Please use language version 10.0 or greater. // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; @@ -784,7 +784,7 @@ public void BuilderOnMethod_OnLambda() // Func> m = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] async () => { System.Console.Write("M "); await f(); return 3; }; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "=>").WithArguments("async method builder override", "10.0").WithLocation(8, 84) ); - compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular10); + compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular10); compilation.VerifyEmitDiagnostics( // (6,84): error CS8933: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("F "); await Task.Delay(0); }; @@ -817,7 +817,7 @@ public void BuilderOnMethod_OnLambda_WithExplicitType() {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular9); compilation.VerifyEmitDiagnostics( // (6,18): error CS8773: Feature 'lambda attributes' is not available in C# 9.0. Please use language version 10.0 or greater. // Func f = [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async MyTask () => { System.Console.Write("F "); await Task.Delay(0); }; @@ -839,7 +839,7 @@ public void BuilderOnMethod_OnLambda_WithExplicitType() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "=>").WithArguments("async method builder override", "10.0").WithLocation(8, 96) ); - compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular10); + compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular10); var verifier = CompileAndVerify(compilation, expectedOutput: "M F 3"); verifier.VerifyDiagnostics(); } @@ -880,7 +880,7 @@ public class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (7,71): error CS8935: The AsyncMethodBuilder attribute is disallowed on anonymous methods without an explicit return type. // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] static async () => { System.Console.Write("Lambda1 "); await Task.Delay(0); } // 1 @@ -938,7 +938,7 @@ public class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T", isStruct: true)} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); var verifier = CompileAndVerify(compilation, expectedOutput: "Overload1 Lambda1 Overload2 Lambda2"); verifier.VerifyDiagnostics(); @@ -980,7 +980,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task", "public object Task")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics(); compilation.VerifyEmitDiagnostics( // (8,29): error CS8204: For type 'MyTaskMethodBuilder' to be used as an AsyncMethodBuilder for type 'MyTask', its Task property should return type 'MyTask' instead of type 'object'. @@ -1024,7 +1024,7 @@ class C .Replace("public static MyTaskMethodBuilder Create() => new MyTaskMethodBuilder(new MyTask());", "")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics(); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' @@ -1067,7 +1067,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", accessibility + " static MyTaskMethodBuilder Create()")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1107,7 +1107,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public MyTaskMethodBuilder Create()")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics(); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' @@ -1148,7 +1148,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create(int i)")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics(); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' @@ -1189,7 +1189,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "public static MyTaskMethodBuilder Create()")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics(); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' @@ -1238,7 +1238,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyDiagnostics(); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' @@ -1282,7 +1282,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public class MyTaskMethodBuilder", "internal class MyTaskMethodBuilder")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); CompileAndVerify(compilation, expectedOutput: "M F G 3"); } @@ -1316,7 +1316,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); CompileAndVerify(compilation, expectedOutput: "M F G 3"); } @@ -1346,7 +1346,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public static MyTaskMethodBuilder Create()", "internal static MyTaskMethodBuilder Create()")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1398,7 +1398,7 @@ class AsyncMethodBuilderAttribute : System.Attribute {{ public AsyncMethodBuilde }} "; // The first attribute is used - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics(); CompileAndVerify(compilation, expectedOutput: "M F G 3"); } @@ -1439,7 +1439,7 @@ class AsyncMethodBuilderAttribute : System.Attribute {{ public AsyncMethodBuilde }} "; // The first attribute is used - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (10,29): error CS1983: The return type of an async method must be void, Task, Task, a task-like type, IAsyncEnumerable, or IAsyncEnumerator // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1473,7 +1473,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,25): error CS0416: 'MyTaskMethodBuilder': an attribute argument cannot use type parameters // [AsyncMethodBuilder(typeof(MyTaskMethodBuilder))] @@ -1501,7 +1501,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyEmitDiagnostics( // (9,34): error CS8940: A generic task-like return type was expected, but the type 'MyTaskMethodBuilder' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. // static async MyTask M() { await Task.Delay(0); throw null; } @@ -1535,7 +1535,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task =>", "internal MyTask Task =>")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1575,7 +1575,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public static MyTask Task => throw null;")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1615,7 +1615,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public MyTask Task => _task;", "public MyTask Task = null;")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1655,7 +1655,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException", "internal void SetException")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1699,7 +1699,7 @@ class C {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1739,7 +1739,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetException(System.Exception e)", "public void SetException()")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetException' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1779,7 +1779,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetResult", "internal void SetResult")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetResult' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1819,7 +1819,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitOnCompleted", "internal void AwaitOnCompleted")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.AwaitOnCompleted' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1859,7 +1859,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void AwaitUnsafeOnCompleted", "internal void AwaitUnsafeOnCompleted")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.AwaitUnsafeOnCompleted' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1899,7 +1899,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void Start", "internal void Start")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Start' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } @@ -1939,7 +1939,7 @@ class C {AsyncBuilderCode("MyTaskMethodBuilder", "MyTask", "T").Replace("public void SetStateMachine", "internal void SetStateMachine")} {AsyncMethodBuilderAttribute} "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.RegularPreview); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.RegularPreview); compilation.VerifyEmitDiagnostics( // (8,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetStateMachine' // static async MyTask F() { System.Console.Write("F "); await Task.Delay(0); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs index fa39f561f1e8b..5906b205ab039 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncTests.cs @@ -13,7 +13,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { @@ -23,10 +23,10 @@ private static CSharpCompilation CreateCompilation(string source, IEnumerable asyncRefs = new[] { Net451.System, Net451.SystemCore, Net451.MicrosoftCSharp }; + IEnumerable asyncRefs = new[] { NetFramework.System, NetFramework.SystemCore, NetFramework.MicrosoftCSharp }; references = (references != null) ? references.Concat(asyncRefs) : asyncRefs; - return CreateCompilationWithMscorlib45(source, options: options, references: references); + return CreateCompilationWithMscorlib461(source, options: options, references: references); } private CompilationVerifier CompileAndVerify(string source, string expectedOutput, IEnumerable references = null, CSharpCompilationOptions options = null, Verification verify = default) @@ -54,7 +54,7 @@ public static void Main() F(123).Wait(); } }"; - var c = CreateCompilationWithMscorlib45(source); + var c = CreateCompilationWithMscorlib461(source); CompilationOptions options; @@ -3304,7 +3304,7 @@ async void M() {} } "; - var comp = CSharpTestBase.CreateEmptyCompilation(source, new[] { Net40.mscorlib }, TestOptions.ReleaseDll); // NOTE: 4.0, not 4.5, so it's missing the async helpers. + var comp = CSharpTestBase.CreateEmptyCompilation(source, new[] { Net40.References.mscorlib }, TestOptions.ReleaseDll); // NOTE: 4.0, not 4.5, so it's missing the async helpers. // CONSIDER: It would be nice if we didn't squiggle the whole method body, but this is a corner case. comp.VerifyEmitDiagnostics( @@ -3334,7 +3334,7 @@ class C { async Task M() {} }"; - var comp = CSharpTestBase.CreateEmptyCompilation(source, new[] { Net40.mscorlib }, TestOptions.ReleaseDll); // NOTE: 4.0, not 4.5, so it's missing the async helpers. + var comp = CSharpTestBase.CreateEmptyCompilation(source, new[] { Net40.References.mscorlib }, TestOptions.ReleaseDll); // NOTE: 4.0, not 4.5, so it's missing the async helpers. comp.VerifyEmitDiagnostics( // (4,16): warning 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. // async Task M() {} @@ -3365,7 +3365,7 @@ class C { async Task F() => 3; }"; - var comp = CSharpTestBase.CreateEmptyCompilation(source, new[] { Net40.mscorlib }, TestOptions.ReleaseDll); // NOTE: 4.0, not 4.5, so it's missing the async helpers. + var comp = CSharpTestBase.CreateEmptyCompilation(source, new[] { Net40.References.mscorlib }, TestOptions.ReleaseDll); // NOTE: 4.0, not 4.5, so it's missing the async helpers. comp.VerifyEmitDiagnostics( // (4,21): warning 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. // async Task F() => 3; @@ -3703,7 +3703,7 @@ public void AsyncTasklikeMissingBuilderType() { // Builder var libB = @"public class B { }"; - var cB = CreateCompilationWithMscorlib45(libB); + var cB = CreateCompilationWithMscorlib461(libB); var rB = cB.EmitToImageReference(); // Tasklike @@ -3714,7 +3714,7 @@ public void AsyncTasklikeMissingBuilderType() namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var cT = CreateCompilationWithMscorlib45(libT, references: new[] { rB }); + var cT = CreateCompilationWithMscorlib461(libT, references: new[] { rB }); var rT = cT.EmitToImageReference(); // Consumer, fails to reference builder @@ -3726,7 +3726,7 @@ static void Main() { } async T f() => await Task.Delay(1); } "; - var c = CreateCompilationWithMscorlib45(source, references: new[] { rT }); + var c = CreateCompilationWithMscorlib461(source, references: new[] { rT }); c.VerifyEmitDiagnostics( // (6,17): error CS1983: The return type of an async method must be void, Task or Task // async T f() => await Task.Delay(1); @@ -4023,7 +4023,7 @@ class Mismatch2MethodBuilder } namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyEmitDiagnostics( // (5,30): error CS8940: A generic task-like return type was expected, but the type 'Mismatch1MethodBuilder' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. // async Mismatch1 f() { await (Task)null; return 1; } @@ -4501,7 +4501,7 @@ public void AwaitInScriptExpression() { var source = @"System.Console.WriteLine(await System.Threading.Tasks.Task.FromResult(1));"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); compilation.VerifyDiagnostics(); } @@ -4510,7 +4510,7 @@ public void AwaitInScriptGlobalStatement() { var source = @"await System.Threading.Tasks.Task.FromResult(4);"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); compilation.VerifyDiagnostics(); } @@ -4520,7 +4520,7 @@ public void AwaitInScriptDeclaration() var source = @"int x = await System.Threading.Tasks.Task.Run(() => 2); System.Console.WriteLine(x);"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); compilation.VerifyDiagnostics(); } @@ -4564,7 +4564,7 @@ public void AwaitInScriptStaticInitializer() await System.Threading.Tasks.Task.FromResult(1); int y = x + await System.Threading.Tasks.Task.FromResult(2);"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); compilation.VerifyDiagnostics( // (2,5): error CS8100: The 'await' operator cannot be used in a static script variable initializer. // await System.Threading.Tasks.Task.FromResult(1); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs index 940ebc0837026..f0827cb755292 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAwaitForeachTests.cs @@ -2061,10 +2061,12 @@ public S(int i) CompileAndVerify(comp, expectedOutput: "1 2 Done"); } - [Fact] - public void TestWithPattern_RefStructEnumerator_Async() + [Theory] + [InlineData("")] + [InlineData("await Task.Yield();")] + public void TestWithPattern_RefStructEnumerator_Async(string body) { - var source = """ + var source = $$""" using System.Threading.Tasks; public class C { @@ -2072,6 +2074,7 @@ public static async Task Main() { await foreach (var s in new C()) { + {{body}} } } public Enumerator GetAsyncEnumerator() => new Enumerator(); @@ -2083,22 +2086,34 @@ public ref struct Enumerator } """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // await foreach (var s in new C()) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 15)); + var expectedDiagnostics = new[] { - // (6,15): error CS8344: foreach statement cannot operate on enumerators of type 'C.Enumerator' in async or iterator methods because 'C.Enumerator' is a ref struct. + // (6,9): error CS4007: Instance of type 'C.Enumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var s in new C()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C.Enumerator").WithLocation(6, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var s in new C()) + { + " + body + @" + }").WithArguments("C.Enumerator").WithLocation(6, 9) }; - CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); } - [Fact] - public void TestWithPattern_RefStructEnumerator_AsyncIterator() + [Theory] + [InlineData("")] + [InlineData("await Task.Yield();")] + [InlineData("yield return x;")] + [InlineData("yield return x; await Task.Yield();")] + [InlineData("await Task.Yield(); yield return x;")] + public void TestWithPattern_RefStructEnumerator_AsyncIterator(string body) { - var source = """ + var source = $$""" using System.Collections.Generic; using System.Threading.Tasks; public class C @@ -2107,8 +2122,9 @@ public static async IAsyncEnumerable M() { await foreach (var x in new C()) { - yield return x; + {{body}} } + yield return -1; } public Enumerator GetAsyncEnumerator() => new Enumerator(); public ref struct Enumerator @@ -2117,18 +2133,25 @@ public ref struct Enumerator public Task MoveNextAsync() => throw null; } } - """ + s_IAsyncEnumerable; + """ + AsyncStreamsTypes; + + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (7,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // await foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(7, 15)); var expectedDiagnostics = new[] { - // (7,15): error CS8344: foreach statement cannot operate on enumerators of type 'C.Enumerator' in async or iterator methods because 'C.Enumerator' is a ref struct. + // (7,9): error CS4007: Instance of type 'C.Enumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var x in new C()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C.Enumerator").WithLocation(7, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var x in new C()) + { + " + body + @" + }").WithArguments("C.Enumerator").WithLocation(7, 9) }; - CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); - CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); - CreateCompilationWithTasksExtensions(source).VerifyDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithTasksExtensions(source).VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] @@ -2154,16 +2177,23 @@ public ref struct Enumerator } """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // foreach (var x in new C()) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 9)); + var expectedDiagnostics = new[] { - // (6,9): error CS8344: foreach statement cannot operate on enumerators of type 'C.Enumerator' in async or iterator methods because 'C.Enumerator' is a ref struct. + // (6,9): error CS4007: Instance of type 'C.Enumerator' cannot be preserved across 'await' or 'yield' boundary. // foreach (var x in new C()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C.Enumerator").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"foreach (var x in new C()) + { + yield return x; + }").WithArguments("C.Enumerator").WithLocation(6, 9) }; - CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); - CreateCompilation(source).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConversionTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConversionTests.cs index e78e792a938e4..77fb49bd220d4 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConversionTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConversionTests.cs @@ -1067,7 +1067,7 @@ public interface IAaa "; - var compilation = CreateCompilationWithMscorlib45AndCSharp(source, options: TestOptions.ReleaseExe.WithAllowUnsafe(true)); + var compilation = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseExe.WithAllowUnsafe(true)); CompileAndVerify(compilation); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs index 32bd50f9a7b3e..c9cb6628f66d0 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs @@ -5043,7 +5043,7 @@ public void SimpleDeconstructionInScript() Assert.Equal("alias=System.Int32", model.GetAliasInfo(yType).ToTestDisplayString()); }; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "hello 42", sourceSymbolValidator: validator); @@ -5116,7 +5116,7 @@ public void GlobalDeconstructionOutsideScript() System.Console.Write(x); System.Console.Write(y); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular9, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular9, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); @@ -5134,7 +5134,7 @@ public void NestedDeconstructionInScript() (string x, (int y, int z)) = (""hello"", (42, 43)); System.Console.Write($""{x} {y} {z}""); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "hello 42 43"); @@ -5148,7 +5148,7 @@ public void VarDeconstructionInScript() (var x, var y) = (""hello"", 42); System.Console.Write($""{x} {y}""); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "hello 42"); @@ -5194,7 +5194,7 @@ public void NestedVarDeconstructionInScript() Assert.Equal("(System.Int32 x2, System.Int32 x3)", model.GetSymbolInfo(x23Var.Type).Symbol.ToTestDisplayString()); }; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "hello 42 43", sourceSymbolValidator: validator); @@ -5209,7 +5209,7 @@ public void EvaluationOrderForDeconstructionInScript() var (x2, x3) = M(out var x1); System.Console.Write($""{x1} {x2} {x3}""); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "1 2 3"); @@ -5318,7 +5318,7 @@ public void DeconstructionForEachInScript() Assert.Equal(SymbolKind.Local, x2Symbol.Kind); }; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "hello 42 world", sourceSymbolValidator: validator); @@ -5354,7 +5354,7 @@ public void DeconstructionInForLoopInScript() Assert.Equal(SymbolKind.Local, x2Symbol.Kind); }; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "hello 42 world", sourceSymbolValidator: validator); @@ -5368,7 +5368,7 @@ public void DeconstructionInCSharp6Script() var (x, y) = (1, 2); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp6), options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp6), options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics( // (2,5): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7.0 or greater. @@ -5388,7 +5388,7 @@ public void InvalidDeconstructionInScript() int (x, y) = (1, 2); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics( // (2,5): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. // int (x, y) = (1, 2); @@ -5421,7 +5421,7 @@ public void InvalidDeconstructionInScript_2() (int (x, y), int z) = ((1, 2), 3); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics( // (2,6): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. // (int (x, y), int z) = ((1, 2), 3); @@ -5456,7 +5456,7 @@ public void NameConflictInDeconstructionInScript() System.Console.Write(x1); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics( // (3,6): error CS0102: The type 'Script' already contains a definition for 'x1' // var (x1, x2) = (1, 2); @@ -5491,7 +5491,7 @@ public void NameConflictInDeconstructionInScript2() var (z, y) = (1, 2); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics( // (3,9): error CS0102: The type 'Script' already contains a definition for 'y' // var (z, y) = (1, 2); @@ -5522,7 +5522,7 @@ public void NameConflictInDeconstructionInScript3() var (x, (y, x)) = (1, (2, ""hello"")); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics( // (2,13): error CS0102: The type 'Script' already contains a definition for 'x' // var (x, (y, x)) = (1, (2, "hello")); @@ -5554,7 +5554,7 @@ public void UnassignedUsedInDeconstructionInScript() var (x, y) = (1, 2); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0"); @@ -5579,7 +5579,7 @@ public void FailedInferenceInDeconstructionInScript() var (x, y) = (1, null); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.GetDeclarationDiagnostics().Verify( // (2,6): error CS8130: Cannot infer the type of implicitly-typed deconstruction variable 'x'. // var (x, y) = (1, null); @@ -5627,7 +5627,7 @@ public void FailedCircularInferenceInDeconstructionInScript() var (x1, x2) = (x2, x1); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.GetDeclarationDiagnostics().Verify( // (2,10): error CS7019: Type of 'x2' cannot be inferred since its initializer directly or indirectly refers to the definition. // var (x1, x2) = (x2, x1); @@ -5668,7 +5668,7 @@ public void FailedCircularInferenceInDeconstructionInScript2() var (y1, y2) = (x1, x2); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.GetDeclarationDiagnostics().Verify( // (3,6): error CS7019: Type of 'y1' cannot be inferred since its initializer directly or indirectly refers to the definition. // var (y1, y2) = (x1, x2); @@ -5713,7 +5713,7 @@ public void VarAliasInVarDeconstructionInScript() System.Console.Write($""{x1} {x2} {x3}""); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics( // (3,5): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. // var (x1, (x2, x3)) = (1, (2, 3)); @@ -5755,7 +5755,7 @@ class @var System.Console.Write($""{x1} {x2} {x3}""); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics( // (6,5): error CS8136: Deconstruction 'var (...)' form disallows a specific type for 'var'. // var (x1, (x2, x3)) = (1, (2, 3)); @@ -5794,7 +5794,7 @@ public void VarAliasInTypedDeconstructionInScript() System.Console.Write($""{x1} {x2} {x3}""); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "1 2 3"); @@ -5844,7 +5844,7 @@ class @var System.Console.Write($""{x1} {x2} {x3}""); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "var var var"); @@ -6677,7 +6677,7 @@ async void M() } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (6,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // System.Threading.Tasks.Task.Delay(new System.TimeSpan(0)); @@ -6874,7 +6874,7 @@ public void SimpleDiscardDeconstructInScript() Assert.Equal("(System.String, System.Int32)", model.GetTypeInfo(tuple).Type.ToTestDisplayString()); }; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); CompileAndVerify(comp, sourceSymbolValidator: validator); @@ -6893,7 +6893,7 @@ public class C (string _, string _) = new C(); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "ctor"); @@ -6908,7 +6908,7 @@ public void SingleDiscardInAssignmentInScript() _ = M(); "; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "M"); } @@ -6943,7 +6943,7 @@ public void NestedVarDiscardDeconstructionInScript() Assert.Null(model.GetSymbolInfo(tuple).Symbol); }; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe, references: s_valueTupleRefs); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "43", sourceSymbolValidator: validator); @@ -8204,7 +8204,7 @@ static async Task M() } "; - var comp = CreateCompilationWithMscorlib45(source, references: s_valueTupleRefs, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib461(source, references: s_valueTupleRefs, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); var verifier = CompileAndVerify(comp, expectedOutput: "3"); } @@ -8225,7 +8225,7 @@ void M() } "; - var comp = CreateCompilationWithMscorlib45(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (8,11): warning CS1717: Assignment made to same variable; did you mean to assign something else? // ((x, x), this.x, C.y) = ((x, (1, 2)), x, y); @@ -8256,7 +8256,7 @@ void M() } "; - var comp = CreateCompilationWithMscorlib45(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (9,10): warning CS1717: Assignment made to same variable; did you mean to assign something else? // (x, (y, z)) = (x, (y, z)); @@ -8291,7 +8291,7 @@ class D } "; - var comp = CreateCompilationWithMscorlib45(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (8,10): warning CS1717: Assignment made to same variable; did you mean to assign something else? // (x, y) = (x, (C)(D)y); @@ -8321,7 +8321,7 @@ void M() } "; - var comp = CreateCompilationWithMscorlib45(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (14,14): warning CS1717: Assignment made to same variable; did you mean to assign something else? // (_, (x, y)) = (1, (x, b)); @@ -8350,7 +8350,7 @@ void M() } "; - var comp = CreateCompilationWithMscorlib45(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); comp.VerifyDiagnostics( ); @@ -8406,7 +8406,7 @@ public static void Deconstruct(this object input, out object output1, out object } }"; - var comp = CreateCompilationWithMscorlib45(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(source, references: s_valueTupleRefs, options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (9,10): warning CS1717: Assignment made to same variable; did you mean to assign something else? // (x, (y, z)) = (x, y); @@ -8429,7 +8429,7 @@ Error M() } }"; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); // no ValueTuple reference + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); // no ValueTuple reference comp.VerifyDiagnostics( // (4,5): error CS0246: The type or namespace name 'Error' could not be found (are you missing a using directive or an assembly reference?) // Error M() @@ -8441,10 +8441,10 @@ Error M() public void TestDeconstructOnErrorTypeFromImageReference() { var missing_cs = "public class Missing { }"; - var missing = CreateCompilationWithMscorlib45(missing_cs, options: TestOptions.DebugDll, assemblyName: "missing"); + var missing = CreateCompilationWithMscorlib461(missing_cs, options: TestOptions.DebugDll, assemblyName: "missing"); var lib_cs = "public class C { public Missing M() { throw null; } }"; - var lib = CreateCompilationWithMscorlib45(lib_cs, references: new[] { missing.EmitToImageReference() }, options: TestOptions.DebugDll); + var lib = CreateCompilationWithMscorlib461(lib_cs, references: new[] { missing.EmitToImageReference() }, options: TestOptions.DebugDll); var source = @" @@ -8458,7 +8458,7 @@ void M() } }"; - var comp = CreateCompilationWithMscorlib45(source, references: new[] { lib.EmitToImageReference() }, options: TestOptions.DebugDll); // no ValueTuple reference + var comp = CreateCompilationWithMscorlib461(source, references: new[] { lib.EmitToImageReference() }, options: TestOptions.DebugDll); // no ValueTuple reference comp.VerifyDiagnostics( // (7,18): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (x, y) = new C().M(); @@ -8470,10 +8470,10 @@ void M() public void TestDeconstructOnErrorTypeFromCompilationReference() { var missing_cs = "public class Missing { }"; - var missing = CreateCompilationWithMscorlib45(missing_cs, options: TestOptions.DebugDll, assemblyName: "missing"); + var missing = CreateCompilationWithMscorlib461(missing_cs, options: TestOptions.DebugDll, assemblyName: "missing"); var lib_cs = "public class C { public Missing M() { throw null; } }"; - var lib = CreateCompilationWithMscorlib45(lib_cs, references: new[] { missing.ToMetadataReference() }, options: TestOptions.DebugDll); + var lib = CreateCompilationWithMscorlib461(lib_cs, references: new[] { missing.ToMetadataReference() }, options: TestOptions.DebugDll); var source = @" @@ -8487,7 +8487,7 @@ void M() } }"; - var comp = CreateCompilationWithMscorlib45(source, references: new[] { lib.ToMetadataReference() }, options: TestOptions.DebugDll); // no ValueTuple reference + var comp = CreateCompilationWithMscorlib461(source, references: new[] { lib.ToMetadataReference() }, options: TestOptions.DebugDll); // no ValueTuple reference comp.VerifyDiagnostics( // (7,18): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // (x, y) = new C().M(); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs index f6560bb991044..2331a9abfa16a 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDynamicTests.cs @@ -38,8 +38,8 @@ private CompilationVerifier CompileAndVerifyIL( references = references ?? new[] { SystemCoreRef, CSharpRef }; // verify that we emit correct optimized and unoptimized IL: - var unoptimizedCompilation = CreateCompilationWithMscorlib45(source, references, parseOptions: parseOptions, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All).WithAllowUnsafe(allowUnsafe)); - var optimizedCompilation = CreateCompilationWithMscorlib45(source, references, parseOptions: parseOptions, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All).WithAllowUnsafe(allowUnsafe)); + var unoptimizedCompilation = CreateCompilationWithMscorlib461(source, references, parseOptions: parseOptions, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All).WithAllowUnsafe(allowUnsafe)); + var optimizedCompilation = CreateCompilationWithMscorlib461(source, references, parseOptions: parseOptions, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All).WithAllowUnsafe(allowUnsafe)); var unoptimizedVerifier = CompileAndVerify(unoptimizedCompilation, verify: verify); var optimizedVerifier = CompileAndVerify(optimizedCompilation, verify: verify); @@ -7489,7 +7489,7 @@ public class Color Color Color; dynamic x = Color.F((dynamic)1); "; - var script = CreateCompilationWithMscorlib45( + var script = CreateCompilationWithMscorlib461( new[] { Parse(sourceScript, options: TestOptions.Script) }, new[] { new CSharpCompilationReference(lib), SystemCoreRef, CSharpRef }); @@ -7587,7 +7587,7 @@ void Goo() dynamic x = Color.F((dynamic)1); } "; - var script = CreateCompilationWithMscorlib45( + var script = CreateCompilationWithMscorlib461( new[] { Parse(sourceScript, options: TestOptions.Script) }, new[] { new CSharpCompilationReference(lib), SystemCoreRef, CSharpRef }, TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)); @@ -15787,7 +15787,7 @@ static void F(dynamic d) d.F(); } }"; - var comp = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( new[] { DynamicAttributeSource, source }, references: new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929 }); comp.VerifyEmitDiagnostics( @@ -15809,7 +15809,7 @@ static async Task F(dynamic d) await d; } }"; - var comp = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( new[] { DynamicAttributeSource, source }, references: new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929 }); comp.VerifyEmitDiagnostics( diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs index 91bf7680c94dd..965b59ad53d23 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenExprLambdaTests.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { @@ -2460,14 +2461,15 @@ .maxstack 7 } "); - var comp45 = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( new[] { text, ExpressionTestLibrary }, new[] { ExpressionAssemblyRef }, options: TestOptions.ReleaseExe); + comp.MakeMemberMissing(SpecialMember.System_Array__Empty); // no use Array.Empty here since it is not available CompileAndVerify( - comp45, + comp, expectedOutput: expectedOutput). VerifyIL("Test.Main", @" @@ -3511,7 +3513,7 @@ static void Main(string[] args) var comp = CreateEmptyCompilation( new[] { source, ExpressionTestLibrary }, - new[] { TestMetadata.Net40.mscorlib, TestMetadata.Net40.SystemCore }, + new[] { Net40.References.mscorlib, Net40.References.SystemCore }, TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: expectedOutput); @@ -3519,7 +3521,7 @@ static void Main(string[] args) //NOTE: different shape of delegate creation in 45+ is bydesign and matches behavior of the with old compiler. string expectedOutput45 = @"Convert(Call(Constant(Int32 Func1(System.String) Type:System.Reflection.MethodInfo).[System.Delegate CreateDelegate(System.Type, System.Object)](Constant(Del Type:System.Type), Parameter(tc1 Type:TestClass1)) Type:System.Delegate) Type:Del)"; - var comp45 = CreateCompilationWithMscorlib45( + var comp45 = CreateCompilationWithMscorlib461( new[] { source, ExpressionTestLibrary }, new[] { ExpressionAssemblyRef }, TestOptions.ReleaseExe); @@ -5939,7 +5941,7 @@ protected static void Lambda(Expression e, ParameterExpression[] args) { } public class Expression { } public class ParameterExpression : Expression { } }"; - var compilation1 = CreateCompilationWithMscorlib45(source1); + var compilation1 = CreateCompilationWithMscorlib461(source1); compilation1.VerifyDiagnostics(); var reference1 = compilation1.EmitToImageReference(); @@ -5950,7 +5952,7 @@ class C { static Expression E = () => 1; }"; - var compilation2 = CreateCompilationWithMscorlib45(source2, references: new[] { reference1 }); + var compilation2 = CreateCompilationWithMscorlib461(source2, references: new[] { reference1 }); compilation2.VerifyDiagnostics(); using (var stream = new MemoryStream()) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFieldInitTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFieldInitTests.cs index e3dac2d9e0c0b..b421dd2588486 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFieldInitTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFieldInitTests.cs @@ -655,7 +655,7 @@ public void Ordering() expectedOutput.AppendLine(i.ToString()); } - var compilation = CreateCompilationWithMscorlib45(trees, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(trees, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expectedOutput.ToString()); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs index 73f912f5b7d23..f12568ed2c313 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs @@ -11604,7 +11604,6 @@ public enum E { } unsafe class C { } """; - // https://github.com/dotnet/roslyn/issues/66187 tracks enabling runtime reflection support for this scenario. CreateCompilation(source, options: TestOptions.UnsafeDebugDll).VerifyEmitDiagnostics( // (3,16): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // public A(B[]>.E e) { } @@ -11616,7 +11615,14 @@ unsafe class C { } public void Attribute_TypedDefault_Enum_Implicit_ConstructorArgument_WithUnsafeContext([CombinatorialValues("class", "struct")] string kind) { var source = $$""" - class A : System.Attribute + using System; + using System.Linq; + + var attr = typeof(C).CustomAttributes.Single(d => d.AttributeType == typeof(A)); + var arg = attr.ConstructorArguments.Single(); + Console.WriteLine((int)arg.Value == 0); + + class A : Attribute { public unsafe A(B[]>.E e) { } } @@ -11630,8 +11636,7 @@ public enum E { } unsafe class C { } """; - // https://github.com/dotnet/roslyn/issues/66187 tracks enabling runtime reflection support for this scenario. - var verifier = CompileAndVerify(source, options: TestOptions.UnsafeDebugDll, symbolValidator: static module => + var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "True" : null, options: TestOptions.UnsafeDebugExe, symbolValidator: static module => { var c = module.GlobalNamespace.GetTypeMember("C"); var attr = c.GetAttributes().Single(d => d.AttributeClass?.Name == "A"); @@ -11673,7 +11678,14 @@ class C { } public void Attribute_GenericTypedDefault_Enum_Implicit_ConstructorArgument([CombinatorialValues("class", "struct")] string kind) { var source = $$""" - class A : System.Attribute + using System; + using System.Linq; + + var attr = typeof(C).CustomAttributes.Single(d => d.AttributeType.GetGenericTypeDefinition() == typeof(A<>)); + var arg = attr.ConstructorArguments.Single(); + Console.WriteLine((int)arg.Value == 0); + + class A : Attribute { public A(T t) { } } @@ -11687,8 +11699,7 @@ public enum E { } unsafe class C { } """; - // https://github.com/dotnet/roslyn/issues/66187 tracks enabling runtime reflection support for this scenario. - var verifier = CompileAndVerify(source, options: TestOptions.UnsafeDebugDll, symbolValidator: static module => + var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "True" : null, options: TestOptions.UnsafeDebugExe, symbolValidator: static module => { var c = module.GlobalNamespace.GetTypeMember("C"); var attr = c.GetAttributes().Single(d => d.AttributeClass?.Name == "A"); @@ -11730,7 +11741,14 @@ class C { } public void Attribute_TypedDefault_Enum_Explicit_ConstructorArgument([CombinatorialValues("class", "struct")] string kind) { var source = $$""" - class A : System.Attribute + using System; + using System.Linq; + + var attr = typeof(C).CustomAttributes.Single(d => d.AttributeType == typeof(A)); + var arg = attr.ConstructorArguments.Single(); + Console.WriteLine((int)arg.Value == 0); + + class A : Attribute { public unsafe A(B[]>.E e) { } } @@ -11744,8 +11762,7 @@ public enum E { } unsafe class C { } """; - // https://github.com/dotnet/roslyn/issues/66187 tracks enabling runtime reflection support for this scenario. - var verifier = CompileAndVerify(source, options: TestOptions.UnsafeDebugDll, symbolValidator: static module => + var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "True" : null, options: TestOptions.UnsafeDebugExe, symbolValidator: static module => { var c = module.GlobalNamespace.GetTypeMember("C"); var attr = c.GetAttributes().Single(d => d.AttributeClass?.Name == "A"); @@ -12057,7 +12074,14 @@ unsafe class C { } public void Attribute_GenericTypedConstant_Enum_ConstructorArgument([CombinatorialValues("class", "struct")] string kind) { var source = $$""" - class A : System.Attribute + using System; + using System.Linq; + + var attr = typeof(C).CustomAttributes.Single(d => d.AttributeType.GetGenericTypeDefinition() == typeof(A<>)); + var arg = attr.ConstructorArguments.Single(); + Console.WriteLine((int)arg.Value == 33); + + class A : Attribute { public A(T t) { } } @@ -12072,8 +12096,7 @@ public enum E { } unsafe class C { } """; - // https://github.com/dotnet/roslyn/issues/66187 tracks enabling runtime reflection support for this scenario. - var verifier = CompileAndVerify(source, options: TestOptions.UnsafeDebugDll, symbolValidator: static module => + var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "True" : null, options: TestOptions.UnsafeDebugExe, symbolValidator: static module => { var c = module.GlobalNamespace.GetTypeMember("C"); var attr = c.GetAttributes().Single(d => d.AttributeClass?.Name == "A"); @@ -12194,7 +12217,14 @@ unsafe class C { } public void Attribute_TypedConstant_Enum_ConstructorArgument([CombinatorialValues("class", "struct")] string kind) { var source = $$""" - class A : System.Attribute + using System; + using System.Linq; + + var attr = typeof(C).CustomAttributes.Single(d => d.AttributeType == typeof(A)); + var arg = attr.ConstructorArguments.Single(); + Console.WriteLine((int)arg.Value == 33); + + class A : Attribute { public unsafe A(B[]>.E o) { } } @@ -12209,8 +12239,7 @@ public enum E { } unsafe class C { } """; - // https://github.com/dotnet/roslyn/issues/66187 tracks enabling runtime reflection support for this scenario. - var verifier = CompileAndVerify(source, options: TestOptions.UnsafeDebugDll, symbolValidator: static module => + var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "True" : null, options: TestOptions.UnsafeDebugExe, symbolValidator: static module => { var c = module.GlobalNamespace.GetTypeMember("C"); var attr = c.GetAttributes().Single(d => d.AttributeClass?.Name == "A"); @@ -12227,7 +12256,15 @@ unsafe class C { } public void Attribute_TypedConstant_EnumArray_ConstructorArgument([CombinatorialValues("class", "struct")] string kind) { var source = $$""" - class A : System.Attribute + using System; + using System.Collections; + using System.Linq; + + var attr = typeof(C).CustomAttributes.Single(d => d.AttributeType == typeof(A)); + var arg = attr.ConstructorArguments.Single(); + Console.WriteLine(!((IEnumerable)arg.Value).Cast().Any()); + + class A : Attribute { public unsafe A(B[]>.E[] a) { } } @@ -12241,8 +12278,7 @@ public enum E { } unsafe class C { } """; - // https://github.com/dotnet/roslyn/issues/66187 tracks enabling runtime reflection support for this scenario. - var verifier = CompileAndVerify(source, options: TestOptions.UnsafeDebugDll, symbolValidator: static module => + var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "True" : null, options: TestOptions.UnsafeDebugExe, symbolValidator: static module => { var c = module.GlobalNamespace.GetTypeMember("C"); var attr = c.GetAttributes().Single(d => d.AttributeClass?.Name == "A"); @@ -12261,7 +12297,16 @@ public void Attribute_TypedParamsConstant_EnumArray_ConstructorArgument( [CombinatorialValues("[]{}", "()")] string initializer) { var source = $$""" - class A : System.Attribute + using System; + using System.Collections; + using System.Linq; + using System.Reflection; + + var attr = typeof(C).CustomAttributes.Single(d => d.AttributeType == typeof(A)); + var arg = attr.ConstructorArguments.Single(); + Console.WriteLine(((IEnumerable)arg.Value).Cast().SingleOrDefault().Value ?? "null"); + + class A : Attribute { public unsafe A(params B[]>.E[] a) { } } @@ -12275,8 +12320,9 @@ public enum E { } unsafe class C { } """; - // https://github.com/dotnet/roslyn/issues/66187 tracks enabling runtime reflection support for this scenario. - var verifier = CompileAndVerify(source, options: TestOptions.UnsafeDebugDll, symbolValidator: module => + var expectedOutput = ExecutionConditionUtil.IsMonoOrCoreClr ? (initializer == "()" ? "0" : "null") : null; + + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput, options: TestOptions.UnsafeDebugExe, symbolValidator: module => { var c = module.GlobalNamespace.GetTypeMember("C"); var attr = c.GetAttributes().Single(d => d.AttributeClass?.Name == "A"); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenImplicitlyTypeArraysTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenImplicitlyTypeArraysTests.cs index a2bf867ce0594..fd4c0b1f8a24d 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenImplicitlyTypeArraysTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenImplicitlyTypeArraysTests.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { @@ -280,7 +281,7 @@ public static void Main() } } "; - var mscorlib17626 = MetadataReference.CreateFromImage(TestMetadata.ResourcesNet451.mscorlib); + var mscorlib17626 = MetadataReference.CreateFromImage(Net461.Resources.mscorlib); CompileAndVerify(testSrc, new MetadataReference[] { mscorlib17626 }, expectedOutput: "1", targetFramework: TargetFramework.Empty); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs index dc493a696634e..1f87e26e45231 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs @@ -1154,7 +1154,7 @@ static void M(in int arg1, in (int Alice, int Bob) arg2) } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,9): error CS8331: Cannot assign to variable 'arg1' or use it as the right hand side of a ref assignment because it is a readonly variable // arg1 = 1; @@ -1206,7 +1206,7 @@ static ref int M2(in int arg1, in (int Alice, int Bob) arg2) } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (18,20): error CS8333: Cannot return variable 'arg1' by writable reference because it is a readonly variable // return ref arg1; @@ -1231,7 +1231,7 @@ static void M(in int arg1, in (int Alice, int Bob) arg2) } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,25): error CS8329: Cannot use variable 'arg1' as a ref or out value because it is a readonly variable // ref var y = ref arg1; @@ -1264,7 +1264,7 @@ unsafe static void M(in int arg1, in (int Alice, int Bob) arg2) } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.UnsafeReleaseDll); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.UnsafeReleaseDll); comp.VerifyDiagnostics( // (6,18): error CS0212: You can only take the address of an unfixed expression inside of a fixed statement initializer // int* a = & arg1; @@ -1297,7 +1297,7 @@ static ref int M(in int arg1, in (int Alice, int Bob) arg2) } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (10,24): error CS8333: Cannot return variable 'arg1' by writable reference because it is a readonly variable // return ref arg1; @@ -1416,7 +1416,7 @@ ref int M1(in int arg11, in (int Alice, int Bob) arg21) } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (12,28): error CS8333: Cannot return variable 'arg11' by writable reference because it is a readonly variable // return ref arg11; diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs index ce35d78cc0a5e..3f29bbdb28868 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs @@ -1936,7 +1936,7 @@ public static IEnumerable Goo() "; //EDMAURER ensure that we use System.Environment.CurrentManagedThreadId when compiling against 4.5 var parsed = new[] { Parse(source) }; - var comp = CreateCompilationWithMscorlib45(parsed); + var comp = CreateCompilationWithMscorlib461(parsed); var verifier = this.CompileAndVerify(comp); var il = verifier.VisualizeIL("Program.d__0.System.Collections.Generic.IEnumerable.GetEnumerator()"); Assert.Contains("System.Environment.CurrentManagedThreadId.get", il, StringComparison.Ordinal); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs index e8e3913525cbb..a8dcc43ef9c49 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs @@ -2082,7 +2082,7 @@ void LocalFunc(int a = 2) { } } } "; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedSignatures: new SignatureDescription[] { Signature("C", "Main", ".method public hidebysig static System.Void Main() cil managed"), @@ -6300,13 +6300,13 @@ static void Local1() internal CompilationVerifier VerifyOutput(string source, string output, CSharpCompilationOptions options, Verification verify = default) { - var comp = CreateCompilationWithMscorlib45AndCSharp(source, options: options); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: options); return CompileAndVerify(comp, expectedOutput: output, verify: verify).VerifyDiagnostics(); // no diagnostics } internal CompilationVerifier VerifyOutput(string source, string output) { - var comp = CreateCompilationWithMscorlib45AndCSharp(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseExe); return CompileAndVerify(comp, expectedOutput: output).VerifyDiagnostics(); // no diagnostics } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs index f873d1ef0c65b..297da1b78bb9c 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLockTests.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { @@ -1741,7 +1742,7 @@ .locals init (object V_0) private static CSharpCompilation CreateCompilationWithCorlib20(string text) { - return CreateEmptyCompilation(new string[] { text }, new[] { TestMetadata.Net20.mscorlib }); + return CreateEmptyCompilation(new string[] { text }, new[] { Net20.References.mscorlib }); } #endregion Pre-4.0 codegen diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs index 60ca1c1996c02..eb8319ef8c917 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { @@ -525,7 +526,7 @@ static async Task One() } }"; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (16,10): error CS8325: 'await' cannot be used in an expression containing a ref conditional operator @@ -570,7 +571,7 @@ static async Task One() } }"; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (16,10): error CS8325: 'await' cannot be used in an expression containing a ref conditional operator @@ -597,7 +598,7 @@ static void Main() static int val2 = 44; } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (8,43): error CS8326: Both conditional operator values must be ref values or neither may be a ref value @@ -628,7 +629,7 @@ static void Main() static int val1 = 33; } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (8,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference @@ -662,7 +663,7 @@ void Test() } } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular7_1); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular7_1); comp.VerifyEmitDiagnostics( // (15,25): error CS8302: Feature 'ref conditional expression' is not available in C# 7.1. Please use language version 7.2 or greater. @@ -692,7 +693,7 @@ ref int Test() } } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (15,27): error CS8168: Cannot return local 'local1' by reference because it is not a ref local @@ -723,7 +724,7 @@ ref int Test() static int val1 = 33; } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (14,37): error CS8168: Cannot return local 'local2' by reference because it is not a ref local @@ -759,7 +760,7 @@ struct S1 } } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (14,38): error CS8168: Cannot return local 'local2' by reference because it is not a ref local @@ -796,7 +797,7 @@ struct S1 } } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (15,20): error CS8157: Cannot return 'temp' by reference because it was initialized to a value that cannot be returned by reference @@ -943,7 +944,7 @@ static void Main() static short val2 = 44; } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (8,47): error CS8327: The expression must be of type 'int' to match the alternative ref value @@ -968,7 +969,7 @@ static void Main() static System.Func val1 = null; } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (8,47): error CS8156: An expression cannot be used in this context because it may not be returned by reference @@ -1061,7 +1062,7 @@ public static void RoExtension(in this S1 self) "; // PEVerify: Cannot change initonly field outside its .ctor. - var comp = CompileAndVerifyWithMscorlib40(source, references: new[] { TestMetadata.Net40.System, ValueTupleRef, TestMetadata.Net40.SystemCore }, expectedOutput: "00", verify: Verification.FailsPEVerify); + var comp = CompileAndVerifyWithMscorlib40(source, references: new[] { Net40.References.System, ValueTupleRef, Net40.References.SystemCore }, expectedOutput: "00", verify: Verification.FailsPEVerify); comp.VerifyDiagnostics(); comp.VerifyIL("Program.Main", @" @@ -1194,7 +1195,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib45(source, references: new[] { SystemRuntimeFacadeRef, ValueTupleRef }, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, references: new[] { SystemRuntimeFacadeRef, ValueTupleRef }, options: TestOptions.ReleaseExe); comp.VerifyEmitDiagnostics( // (9,32): error CS1061: '(int Alice, int)' does not contain a definition for 'Bob' and no extension method 'Bob' accepting a first argument of type '(int Alice, int)' could be found (are you missing a using directive or an assembly reference?) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs index 23cf311d431af..5e6809f136b60 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs @@ -1643,8 +1643,8 @@ static void Main() 2"); } - [Fact] - public void RefAssignArrayAccess() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")] + public void RefAssignArrayAccess_Struct() { var text = @" class Program @@ -1669,6 +1669,405 @@ .locals init (int& V_0) //rl IL_000d: stloc.0 IL_000e: ret }"); + + CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M()", @" +{ + // Code size 10 (0xa) + .maxstack 2 + IL_0000: ldc.i4.1 + IL_0001: newarr ""int"" + IL_0006: ldc.i4.0 + IL_0007: ldelem.i4 + IL_0008: pop + IL_0009: ret +}"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")] + public void RefAssignArrayAccess_Struct_Readonly() + { + var text = @" +class Program +{ + static void M(int[] a) + { + ref readonly int rl = ref a[0]; + } +} +"; + + CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @" +{ + // Code size 10 (0xa) + .maxstack 2 + .locals init (int& V_0) //rl + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: ldelema ""int"" + IL_0008: stloc.0 + IL_0009: ret +}"); + + CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @" +{ + // Code size 5 (0x5) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: ldelem.i4 + IL_0003: pop + IL_0004: ret +}"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")] + public void RefAssignArrayAccess_Class() + { + var text = @" +class Program +{ + static void M(object[] a) + { + ref object rl = ref a[0]; + } +} +"; + + CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @" +{ + // Code size 10 (0xa) + .maxstack 2 + .locals init (object& V_0) //rl + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: ldelema ""object"" + IL_0008: stloc.0 + IL_0009: ret +}"); + + CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @" +{ + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: ldelema ""object"" + IL_0007: pop + IL_0008: ret +}"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")] + public void RefAssignArrayAccess_Class_Readonly() + { + var text = @" +class Program +{ + static void M(object[] a) + { + ref readonly object rl = ref a[0]; + } +} +"; + + CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails).VerifyIL("Program.M", @" +{ + // Code size 12 (0xc) + .maxstack 2 + .locals init (object& V_0) //rl + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: readonly. + IL_0005: ldelema ""object"" + IL_000a: stloc.0 + IL_000b: ret +}"); + + CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @" +{ + // Code size 5 (0x5) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: ldelem.ref + IL_0003: pop + IL_0004: ret +}"); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/73215")] + public void RefAssignArrayAccess_Generic( + [CombinatorialValues("", "where T : class")] string constraints) + { + var text = $$""" +class Program +{ + static void M(T[] a) {{constraints}} + { + ref T rl = ref a[0]; + } +} +"""; + + CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @" +{ + // Code size 10 (0xa) + .maxstack 2 + .locals init (T& V_0) //rl + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: ldelema ""T"" + IL_0008: stloc.0 + IL_0009: ret +}"); + + CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @" +{ + // Code size 9 (0x9) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: ldelema ""T"" + IL_0007: pop + IL_0008: ret +}"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")] + public void RefAssignArrayAccess_Generic_Struct() + { + var text = """ +class Program +{ + static void M(T[] a) where T : struct + { + ref T rl = ref a[0]; + } +} +"""; + + CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @" +{ + // Code size 10 (0xa) + .maxstack 2 + .locals init (T& V_0) //rl + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: ldelema ""T"" + IL_0008: stloc.0 + IL_0009: ret +}"); + + CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @" +{ + // Code size 11 (0xb) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: readonly. + IL_0004: ldelema ""T"" + IL_0009: pop + IL_000a: ret +}"); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/73215")] + public void RefAssignArrayAccess_Generic_Readonly( + [CombinatorialValues("", "where T : class")] string constraints) + { + var text = $$""" +class Program +{ + static void M(T[] a) {{constraints}} + { + ref readonly T rl = ref a[0]; + } +} +"""; + + CompileAndVerify(text, options: TestOptions.DebugDll, verify: Verification.Fails).VerifyIL("Program.M", @" +{ + // Code size 12 (0xc) + .maxstack 2 + .locals init (T& V_0) //rl + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: readonly. + IL_0005: ldelema ""T"" + IL_000a: stloc.0 + IL_000b: ret +}"); + + CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @" +{ + // Code size 11 (0xb) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: readonly. + IL_0004: ldelema ""T"" + IL_0009: pop + IL_000a: ret +}"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73215")] + public void RefAssignArrayAccess_Generic_Readonly_Struct() + { + var text = @" +class Program +{ + static void M(T[] a) where T : struct + { + ref readonly T rl = ref a[0]; + } +} +"; + + CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @" +{ + // Code size 10 (0xa) + .maxstack 2 + .locals init (T& V_0) //rl + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: ldelema ""T"" + IL_0008: stloc.0 + IL_0009: ret +}"); + + CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @" +{ + // Code size 11 (0xb) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: readonly. + IL_0004: ldelema ""T"" + IL_0009: pop + IL_000a: ret +}"); + } + + [Fact] + public void RefAssignArrayAccess_Discard_Struct() + { + var text = @" +class Program +{ + static void M(int[] a) + { + _ = ref a[0]; + } +} +"; + + CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @" +{ + // Code size 6 (0x6) + .maxstack 2 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: ldelem.i4 + IL_0004: pop + IL_0005: ret +}"); + + CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @" +{ + // Code size 5 (0x5) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: ldelem.i4 + IL_0003: pop + IL_0004: ret +}"); + } + + [Fact] + public void RefAssignArrayAccess_Discard_Class() + { + var text = @" +class Program +{ + static void M(object[] a) + { + _ = ref a[0]; + } +} +"; + + CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @" +{ + // Code size 6 (0x6) + .maxstack 2 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: ldelem.ref + IL_0004: pop + IL_0005: ret +}"); + + CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @" +{ + // Code size 5 (0x5) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: ldelem.ref + IL_0003: pop + IL_0004: ret +}"); + } + + [Theory, CombinatorialData] + public void RefAssignArrayAccess_Discard_Generic( + [CombinatorialValues("", "where T : class", "where T : struct")] string constraints) + { + var text = $$""" +class Program +{ + static void M(T[] a) {{constraints}} + { + _ = ref a[0]; + } +} +"""; + + CompileAndVerify(text, options: TestOptions.DebugDll).VerifyIL("Program.M", @" +{ + // Code size 12 (0xc) + .maxstack 2 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: readonly. + IL_0005: ldelema ""T"" + IL_000a: pop + IL_000b: ret +}"); + + CompileAndVerify(text, options: TestOptions.ReleaseDll).VerifyIL("Program.M", @" +{ + // Code size 11 (0xb) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: readonly. + IL_0004: ldelema ""T"" + IL_0009: pop + IL_000a: ret +}"); } [Fact] @@ -1761,7 +2160,7 @@ public void RefAssignStaticProperty() class Program { static int field = 0; - static ref int P { get { return ref field; } } + static ref int P { get { return ref @field; } } static void M() { @@ -1789,7 +2188,7 @@ public void RefAssignClassInstanceProperty() class Program { int field = 0; - ref int P { get { return ref field; } } + ref int P { get { return ref @field; } } void M() { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs index 5cf694c120e30..f8bd426515e5b 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs @@ -499,7 +499,7 @@ static readonly int M1(int x) } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,25): error CS1031: Type expected // static ref readonly ref int M(int x) @@ -539,7 +539,7 @@ static void Test() } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,9): error CS8331: Cannot assign to method 'M' or use it as the right hand side of a ref assignment because it is a readonly variable // M() = 1; @@ -585,7 +585,7 @@ static void Test() } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,9): error CS8331: Cannot assign to property 'P' or use it as the right hand side of a ref assignment because it is a readonly variable // P = 1; @@ -629,7 +629,7 @@ static void Test() } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,25): error CS8329: Cannot use method 'M' as a ref or out value because it is a readonly variable // ref var y = ref M(); @@ -685,7 +685,7 @@ unsafe static void Test() } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.UnsafeReleaseDll); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.UnsafeReleaseDll); comp.VerifyDiagnostics( // (6,18): error CS0212: You can only take the address of an unfixed expression inside of a fixed statement initializer // int* a = & M(); @@ -743,7 +743,7 @@ static ref int Test() } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (12,28): error CS8333: Cannot return method 'M' by writable reference because it is a readonly variable // return ref M(); @@ -970,7 +970,7 @@ ref readonly int Test() "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular10); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (11,30): error CS8168: Cannot return local 'local' by reference because it is not a ref local // return ref M(ref local); @@ -986,7 +986,7 @@ ref readonly int Test() Diagnostic(ErrorCode.ERR_EscapeCall2, "M1(out local)").WithArguments("Program.M1(out int)", "x").WithLocation(15, 24) ); - comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (11,30): error CS8168: Cannot return local 'local' by reference because it is not a ref local // return ref M(ref local); @@ -1014,7 +1014,7 @@ ref readonly int Test() "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (8,25): error CS8168: Cannot return local 'local' by reference because it is not a ref local // return ref this[local]; @@ -1041,7 +1041,7 @@ ref readonly int Test() "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,25): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref this[42]; @@ -1071,7 +1071,7 @@ ref readonly S1 Test() "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (8,20): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref this; @@ -1097,7 +1097,7 @@ ref readonly int Test() "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref 42; @@ -1121,7 +1121,7 @@ ref readonly int Test() "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,22): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref M(42); @@ -1148,7 +1148,7 @@ ref readonly int Test() "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (6,20): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // return ref M(); @@ -1176,7 +1176,7 @@ ref readonly int Test() "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (7,22): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref M(b); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs index 728fafdf945a1..0802bf3696837 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReturnTests.cs @@ -174,7 +174,7 @@ public void RefReturnStaticProperty() class Program { static int field = 0; - static ref int P { get { return ref field; } } + static ref int P { get { return ref @field; } } static ref int M() { @@ -229,7 +229,7 @@ public void RefReturnClassInstanceProperty() class Program { int field = 0; - ref int P { get { return ref field; } } + ref int P { get { return ref @field; } } ref int M() { @@ -1258,7 +1258,7 @@ class Program { int field = 0; - ref int P { get { return ref field; } } + ref int P { get { return ref @field; } } ref int this[int i] { get { return ref field; } } @@ -1455,7 +1455,7 @@ class Program { int field = 0; - ref int P { get { return ref field; } } + ref int P { get { return ref @field; } } ref int this[int i] { get { return ref field; } } @@ -2924,7 +2924,7 @@ public static void F1(ref dynamic d) "; - CreateCompilationWithMscorlib45AndCSharp(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics( // (18,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref d.Length; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "d.Length").WithLocation(18, 20) @@ -2964,7 +2964,7 @@ public static ref dynamic F1(ref dynamic d) "; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseExe); var v = CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: "2"); @@ -3077,7 +3077,7 @@ public static ref dynamic Test(ref dynamic arg1, ref dynamic arg2) } "; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseExe); var v = CompileAndVerify(comp, verify: Verification.Fails, expectedOutput: "2"); } @@ -3113,7 +3113,7 @@ public static void F1(ref dynamic d) "; - CreateCompilationWithMscorlib45AndCSharp(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics( // (17,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref d[0]; Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "d[0]").WithLocation(17, 20) @@ -3149,7 +3149,7 @@ public static ref dynamic G(ref dynamic d) "; - CreateCompilationWithMscorlib45AndCSharp(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics( // (14,26): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref G(ref d.Length); Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "d.Length").WithLocation(14, 26), @@ -3179,7 +3179,7 @@ public void RefReturnVarianceDelegate() "; - CreateCompilationWithMscorlib45AndCSharp(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics( // (6,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc3.Invoke()'. 'T' is covariant. // delegate ref T RefFunc3(); Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("RefFunc3.Invoke()", "T", "covariant", "invariantly").WithLocation(6, 10), @@ -3222,7 +3222,7 @@ interface IM3f { ref Func RefMethod(); } "; - CreateCompilationWithMscorlib45AndCSharp(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics( // (6,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM3.RefMethod()'. 'T' is covariant. // interface IM3 { ref T RefMethod(); } Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IM3.RefMethod()", "T", "covariant", "invariantly").WithLocation(6, 24), @@ -3265,7 +3265,7 @@ interface IP3f { ref Func RefProp{get;} } "; - CreateCompilationWithMscorlib45AndCSharp(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics( // (5,23): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP2.RefProp'. 'T' is contravariant. // interface IP2 { ref T RefProp{get;} } Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IP2.RefProp", "T", "contravariant", "invariantly").WithLocation(5, 23), @@ -3308,7 +3308,7 @@ interface IP3f { ref Func this[int i]{get;} } "; - CreateCompilationWithMscorlib45AndCSharp(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics( // (6,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP3.this[int]'. 'T' is covariant. // interface IP3 { ref T this[int i]{get;} } Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IP3.this[int]", "T", "covariant", "invariantly").WithLocation(6, 24), @@ -3355,7 +3355,7 @@ static void Main() "; - CreateCompilationWithMscorlib45AndCSharp(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics( // (10,30): error CS0407: 'string Program.M1()' has the wrong return type // RefFunc1 f = M1; Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string"), @@ -3363,7 +3363,7 @@ static void Main() // f = new RefFunc1(M1); Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string").WithLocation(13, 34) ); - CreateCompilationWithMscorlib45AndCSharp(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics( // (10,30): error CS0407: 'string Program.M1()' has the wrong return type // RefFunc1 f = M1; Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string").WithLocation(10, 30), @@ -3407,12 +3407,12 @@ static void Main() "; - CreateCompilationWithMscorlib45AndCSharp(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics( // (22,38): error CS0407: 'Derived1 Program.M1(Derived1)' has the wrong return type // RefFunc1 f = M1; Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1(Derived1)", "Derived1").WithLocation(22, 38) ); - CreateCompilationWithMscorlib45AndCSharp(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics( ); } @@ -3495,7 +3495,7 @@ static void Main() "; - CreateCompilationWithMscorlib45AndCSharp(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyEmitDiagnostics( // (25,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Test(Program.RefFunc1)' and 'Program.Test(Program.RefFunc1)' // Test(M1); Diagnostic(ErrorCode.ERR_AmbigCall, "Test").WithArguments("Program.Test(Program.RefFunc1)", "Program.Test(Program.RefFunc1)").WithLocation(25, 9), @@ -3503,7 +3503,7 @@ static void Main() // Test(M3); Diagnostic(ErrorCode.ERR_AmbigCall, "Test").WithArguments("Program.Test(Program.RefFunc1)", "Program.Test(Program.RefFunc1)").WithLocation(26, 9) ); - CreateCompilationWithMscorlib45AndCSharp(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyEmitDiagnostics( ); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenScriptTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenScriptTests.cs index 27a58c250f995..fc56403fc300d 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenScriptTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenScriptTests.cs @@ -25,7 +25,7 @@ public void AnonymousTypes_TopLevelVar() var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script); CompileAndVerify( - CreateCompilationWithMscorlib45( + CreateCompilationWithMscorlib461( new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), references: new[] { SystemCoreRef }), @@ -44,7 +44,7 @@ public void AnonymousTypes_TopLevel_Object() var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script); CompileAndVerify( - CreateCompilationWithMscorlib45( + CreateCompilationWithMscorlib461( new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), references: new[] { SystemCoreRef }), @@ -62,7 +62,7 @@ public void AnonymousTypes_TopLevel_NoLocal() var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script); CompileAndVerify( - CreateCompilationWithMscorlib45( + CreateCompilationWithMscorlib461( new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), references: new[] { SystemCoreRef }), @@ -88,7 +88,7 @@ public void M() var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script); CompileAndVerify( - CreateCompilationWithMscorlib45( + CreateCompilationWithMscorlib461( new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), references: new[] { SystemCoreRef }), @@ -112,7 +112,7 @@ class CLS "; var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script); - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); @@ -137,7 +137,7 @@ public void AnonymousTypes_TopLevel_MethodParamDefValue() "; var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script); - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); @@ -168,7 +168,7 @@ public void M() "; var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script); - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); @@ -196,7 +196,7 @@ class CLS "; var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script); - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); @@ -493,7 +493,7 @@ public void ScriptEntryPoint() await System.Threading.Tasks.Task.Delay(100); System.Console.Write(""complete""); }"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); var verifier = CompileAndVerify(compilation, expectedOutput: @"complete"); var methodData = verifier.TestData.GetMethodData(""); Assert.Equal("System.Threading.Tasks.Task", ((MethodSymbol)methodData.Method).ReturnType.ToDisplayString()); @@ -635,7 +635,7 @@ void I1.M() {} "; var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script); - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs index 063c9eaf72adb..f3538e88440e6 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenShortCircuitOperatorTests.cs @@ -2752,7 +2752,7 @@ static async Task Test(T[] x, T[] y) where T : IDisposable1 return 1; } }"; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"False True False @@ -2821,7 +2821,7 @@ static async Task Test(T x, T y) where T : IDisposable1 } } "; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"False True False @@ -2902,7 +2902,7 @@ static async Task Test(T x, T y) where T : IDisposable1 } } "; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"False True False @@ -2972,7 +2972,7 @@ static async Task Test(T[] x, T[] y) where T : IDisposable1 return 1; } }"; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"False True False @@ -3055,7 +3055,7 @@ static async Task Test(T[] x, T[] y) where T : IDisposable1 return 1; } }"; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"False True False @@ -3138,7 +3138,7 @@ static async Task Test(T[] x, T[] y) where T : IDisposable1 return 1; } }"; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"False True False @@ -3370,7 +3370,7 @@ interface I1 "; - var comp = CreateCompilationWithMscorlib45(source, references: new[] { CSharpRef }); + var comp = CreateCompilationWithMscorlib461(source, references: new[] { CSharpRef }); base.CompileAndVerify(comp); } @@ -3419,7 +3419,7 @@ interface I1 int CallAsync(int x); } "; - var comp = CreateCompilationWithMscorlib45(source, references: new[] { CSharpRef }, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, references: new[] { CSharpRef }, options: TestOptions.ReleaseExe); base.CompileAndVerify(comp, expectedOutput: "420"); } @@ -4774,7 +4774,7 @@ static string Test3(ref WeakReference slot) } } "; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: ""). VerifyIL("Program.Test0(ref System.WeakReference)", @" { @@ -5859,7 +5859,7 @@ public static void Main() new Goo().M4(); } }"; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( source, references: new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, options: TestOptions.DebugExe); CompileAndVerify(compilation, expectedOutput: "12456"); } @@ -6188,7 +6188,7 @@ static async Task Bar() "; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"FalseTrueTrue"); } @@ -6225,7 +6225,7 @@ static async Task Bar() "; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"FalseTrueTrue"); } @@ -6268,7 +6268,7 @@ static async Task Bar(int arg) "; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"FalseTrueTrue"); } @@ -6304,7 +6304,7 @@ static async Task Bar() } } "; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"# False# FalseqBarBar# @@ -6347,7 +6347,7 @@ static async Task Bar(string arg) } } "; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"False True"); } @@ -6382,7 +6382,7 @@ static async Task Bar(string arg) return arg; } }"; - var c = CreateCompilationWithMscorlib45(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); + var c = CreateCompilationWithMscorlib461(source, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, TestOptions.ReleaseExe); var comp = CompileAndVerify(c, expectedOutput: @"False True"); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs index e49acbe498357..21e197949387c 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs @@ -947,13 +947,14 @@ static void Write(Span span) } } """; - var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsCoreClr ? "123" : null, + var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "123" : null; + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput, verify: Verification.Fails, targetFramework: TargetFramework.Net70); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.Main", """ { // Code size 44 (0x2c) - .maxstack 5 + .maxstack 4 .locals init (System.ReadOnlySpan V_0) IL_0000: ldc.i4.s 12 IL_0002: conv.u @@ -974,6 +975,10 @@ .locals init (System.ReadOnlySpan V_0) IL_002b: ret } """); + + CompileAndVerify(source, expectedOutput: expectedOutput, + verify: Verification.Fails, targetFramework: TargetFramework.Net70, + options: TestOptions.DebugExe).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69325")] @@ -1098,13 +1103,14 @@ static void Write(ReadOnlySpan span) } } """; - var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsCoreClr ? "123" : null, + var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "123" : null; + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput, verify: Verification.Fails, targetFramework: TargetFramework.Net70); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.Main", """ { // Code size 49 (0x31) - .maxstack 5 + .maxstack 4 .locals init (System.ReadOnlySpan V_0) IL_0000: ldc.i4.s 12 IL_0002: conv.u @@ -1126,6 +1132,10 @@ .locals init (System.ReadOnlySpan V_0) IL_0030: ret } """); + + CompileAndVerify(source, expectedOutput: expectedOutput, + verify: Verification.Fails, targetFramework: TargetFramework.Net70, + options: TestOptions.DebugExe).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69325")] @@ -1192,13 +1202,14 @@ static void Write(ReadOnlySpan span) } } """; - var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsCoreClr ? "123" : null, + var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "123" : null; + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput, verify: Verification.Fails, targetFramework: TargetFramework.Net70); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.Main", """ { // Code size 47 (0x2f) - .maxstack 5 + .maxstack 4 .locals init (System.ReadOnlySpan V_0) IL_0000: ldc.i4.6 IL_0001: conv.u @@ -1220,6 +1231,10 @@ .locals init (System.ReadOnlySpan V_0) IL_002e: ret } """); + + CompileAndVerify(source, expectedOutput: expectedOutput, + verify: Verification.Fails, targetFramework: TargetFramework.Net70, + options: TestOptions.DebugExe).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69325")] @@ -1244,13 +1259,14 @@ static void Write(ReadOnlySpan span) } } """; - var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsCoreClr ? "1 2.9 3.8" : null, + var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "1 2.9 3.8" : null; + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput, verify: Verification.Fails, targetFramework: TargetFramework.Net70); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.Main", """ { // Code size 46 (0x2e) - .maxstack 5 + .maxstack 4 .locals init (System.ReadOnlySpan V_0) IL_0000: ldc.i4.s 24 IL_0002: conv.u @@ -1271,6 +1287,10 @@ .locals init (System.ReadOnlySpan V_0) IL_002d: ret } """); + + CompileAndVerify(source, expectedOutput: expectedOutput, + verify: Verification.Fails, targetFramework: TargetFramework.Net70, + options: TestOptions.DebugExe).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69325")] @@ -1294,13 +1314,14 @@ static void Write(ReadOnlySpan span) } } """; - var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsCoreClr ? "XYZ" : null, + var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "XYZ" : null; + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput, verify: Verification.Fails, targetFramework: TargetFramework.Net70); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.Main", """ { // Code size 46 (0x2e) - .maxstack 5 + .maxstack 4 .locals init (System.ReadOnlySpan V_0) IL_0000: ldc.i4.s 24 IL_0002: conv.u @@ -1321,6 +1342,10 @@ .locals init (System.ReadOnlySpan V_0) IL_002d: ret } """); + + CompileAndVerify(source, expectedOutput: expectedOutput, + verify: Verification.Fails, targetFramework: TargetFramework.Net70, + options: TestOptions.DebugExe).VerifyDiagnostics(); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69325")] @@ -1475,7 +1500,7 @@ static void Write(int* span) verifier.VerifyIL("C.Main", """ { // Code size 38 (0x26) - .maxstack 5 + .maxstack 4 .locals init (System.ReadOnlySpan V_0) IL_0000: ldc.i4.s 12 IL_0002: conv.u @@ -1495,6 +1520,9 @@ .locals init (System.ReadOnlySpan V_0) } """); + CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsCoreClr ? output : null, + verify: Verification.Fails, options: TestOptions.UnsafeDebugExe, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); + var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseExe, targetFramework: TargetFramework.Net70); comp.MakeMemberMissing((WellKnownMember)missingMember); verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsCoreClr ? output : null, verify: Verification.Fails); @@ -1604,13 +1632,14 @@ static void Write(ReadOnlySpan span) } } """; - var verifier = CompileAndVerify(source, expectedOutput: ExecutionConditionUtil.IsCoreClr ? "1234" : null, + var expectedOutput = ExecutionConditionUtil.IsCoreClr ? "1234" : null; + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput, verify: Verification.Fails, targetFramework: TargetFramework.Net70); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.M", """ { // Code size 57 (0x39) - .maxstack 5 + .maxstack 4 .locals init (System.ReadOnlySpan V_0) IL_0000: ldc.i4.s 16 IL_0002: conv.u @@ -1640,6 +1669,10 @@ .locals init (System.ReadOnlySpan V_0) IL_0038: ret } """); + + CompileAndVerify(source, expectedOutput: expectedOutput, + verify: Verification.Fails, targetFramework: TargetFramework.Net70, + options: TestOptions.DebugExe).VerifyDiagnostics(); } private static string GetSource(string pointerType) => $@" diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs index 190e152c175b4..3ae7ccf2a7ec9 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTests.cs @@ -8,11 +8,11 @@ using System.IO; using System.Linq; using System.Threading; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; -using Microsoft.CodeAnalysis.Test.Resources.Proprietary; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -473,7 +473,8 @@ public static void Main(string[] args) } }"; var tree = Parse(source); - var compilation = CreateEmptyCompilation(tree, new[] { MscorlibRefSilverlight }, TestOptions.ReleaseExe, assemblyName: "Test"); + var compilation = CreateEmptyCompilation(tree, [Net461.References.mscorlib], TestOptions.ReleaseExe, assemblyName: "Test"); + compilation.MakeMemberMissing(SpecialMember.System_Array__LongLength); CompileAndVerify(compilation, expectedOutput: "k"); } @@ -530,7 +531,7 @@ static void A() } } "; - var compilation = CreateCompilationWithILAndMscorlib40(source, il, TargetFramework.Mscorlib45, options: TestOptions.ReleaseDll); + var compilation = CreateCompilationWithILAndMscorlib40(source, il, TargetFramework.Mscorlib461, options: TestOptions.ReleaseDll); var result = CompileAndVerify(compilation); result.VerifyIL("C.A", @" @@ -604,7 +605,7 @@ static void A() } } "; - var compilation = CreateCompilationWithILAndMscorlib40(source, il, TargetFramework.Mscorlib45, options: TestOptions.DebugDll); + var compilation = CreateCompilationWithILAndMscorlib40(source, il, TargetFramework.Mscorlib461, options: TestOptions.DebugDll); var result = CompileAndVerify(compilation); result.VerifyIL("C.A", @@ -863,7 +864,7 @@ public static void Main(string[] args) } } "; - var compilation = CreateCompilationWithILAndMscorlib40(source, il, TargetFramework.Mscorlib45, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithILAndMscorlib40(source, il, TargetFramework.Mscorlib461, options: TestOptions.ReleaseExe); var result = CompileAndVerify(compilation, expectedOutput: "Struct1 Struct2 "); result.VerifyIL("Clazz.Main", @" @@ -7005,7 +7006,7 @@ public static void Main() DBNull "; - var compilation = CreateCompilationWithMscorlib45(source: source, options: TestOptions.ReleaseExe.WithModuleName("MODULE")); + var compilation = CreateCompilationWithMscorlib461(source: source, options: TestOptions.ReleaseExe.WithModuleName("MODULE")); var verifier = CompileAndVerify(compilation, expectedOutput: expectedOutput); //NOTE: @@ -15130,7 +15131,7 @@ static void Main() } }"; - var testReference = AssemblyMetadata.CreateFromImage(ProprietaryTestResources.Repros.BadDefaultParameterValue).GetReference(); + var testReference = AssemblyMetadata.CreateFromImage(TestResources.SymbolsTests.Metadata.BadDefaultParameterValue).GetReference(); var compilation = CompileAndVerify(source, references: new[] { testReference }); compilation.VerifyIL("Program.Main", @" { @@ -15695,7 +15696,7 @@ static void Main() "; // BREAKING CHANGE: The native compiler allowed this (and generated code that will always throw at runtime) - CreateCompilationWithMscorlib45AndCSharp(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyDiagnostics( // (6,16): error CS0236: A field initializer cannot reference the non-static field, method, or property 'M.Test(object)' // object a = Test((dynamic)2); Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "Test").WithArguments("M.Test(object)").WithLocation(6, 16) @@ -15832,7 +15833,7 @@ static void Main() "; // BREAKING CHANGE: The native compiler allowed this (and generated code that will always throw at runtime) - CreateCompilationWithMscorlib45AndCSharp(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyDiagnostics( // (16,31): error CS0120: An object reference is required for the non-static field, method, or property 'M.Test(object)' // public M() : base((object)Test((dynamic)2)) Diagnostic(ErrorCode.ERR_ObjectRequired, "Test").WithArguments("M.Test(object)").WithLocation(16, 31) @@ -15865,7 +15866,7 @@ static void Main() "; // BREAKING CHANGE: The native compiler allowed this (and generated code that will always throw at runtime) - CreateCompilationWithMscorlib45AndCSharp(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyDiagnostics( // (8,31): error CS0120: An object reference is required for the non-static field, method, or property 'M.Test(object)' // Console.Write((object)Test((dynamic)2)); Diagnostic(ErrorCode.ERR_ObjectRequired, "Test").WithArguments("M.Test(object)").WithLocation(8, 31) @@ -15893,7 +15894,7 @@ static void Main() "; // BREAKING CHANGE: The native compiler allowed this (and generated code that will always throw at runtime) - CreateCompilationWithMscorlib45AndCSharp(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyDiagnostics( // (4,31): error CS0236: A field initializer cannot reference the non-static field, method, or property 'M.Test(object)' // static object o = (object)Test((dynamic)2); Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "Test").WithArguments("M.Test(object)").WithLocation(4, 31) @@ -15952,7 +15953,7 @@ static void Main() "; // BREAKING CHANGE: The native compiler allowed this (and generated code that will always throw at runtime) - CreateCompilationWithMscorlib45AndCSharp(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyDiagnostics( // (16,29): error CS0236: A field initializer cannot reference the non-static field, method, or property 'C.InstanceMethod(int)' // static int field = (int)InstanceMethod((dynamic)2); Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(16, 29), @@ -16031,7 +16032,7 @@ static void Main() "; // BREAKING CHANGE: The native compiler allowed this (and generated code that will always throw at runtime) - CreateCompilationWithMscorlib45AndCSharp(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source).VerifyDiagnostics( // (16,29): error CS0120: An object reference is required for the non-static field, method, or property 'C.InstanceMethod(int)' // static int field = (int)C.InstanceMethod((dynamic)2); Diagnostic(ErrorCode.ERR_ObjectRequired, "C.InstanceMethod").WithArguments("C.InstanceMethod(int)").WithLocation(16, 29), @@ -16232,8 +16233,7 @@ public static void Main(string[] args) } } "; - CompileAndVerifyWithMscorlib40(source, references: new[] { SystemRef, SystemCoreRef }, - expectedOutput: "0"); + CompileAndVerify(source, targetFramework: TargetFramework.NetFramework, expectedOutput: "0"); } [Fact, WorkItem(9703, "https://github.com/dotnet/roslyn/issues/9703")] diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs index fae220e9f5929..37e621fc00955 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs @@ -21,7 +21,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; using static TestResources.NetFX.ValueTuple; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen @@ -775,7 +775,7 @@ .assembly extern mscorlib { } .assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) - .ver 4:0:1:0 + .ver 4:0:3:0 } .class public auto ansi C @@ -871,7 +871,7 @@ .assembly extern mscorlib { } .assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) - .ver 4:0:1:0 + .ver 4:0:3:0 } .class public auto ansi C @@ -969,7 +969,7 @@ .assembly extern mscorlib { } .assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) - .ver 4:0:1:0 + .ver 4:0:3:0 } .class public auto ansi beforefieldinit Base`1 @@ -3550,8 +3550,7 @@ static void Main() "; CompileAndVerify(source, - targetFramework: TargetFramework.Mscorlib45, - references: new[] { Net451.System, Net451.SystemCore, Net451.SystemRuntime, ValueTupleRef }, + targetFramework: TargetFramework.NetFramework, expectedOutput: @"42 Alice"); } @@ -3856,7 +3855,7 @@ public static class Extensions public static string a(this (int, int) self) { return ""hello""; } } "; - var comp = CreateCompilationWithMscorlib45(source, references: new[] { Net451.System, Net451.SystemCore, Net451.SystemRuntime, ValueTupleRef }, parseOptions: TestOptions.Regular7); + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetFramework, parseOptions: TestOptions.Regular7); comp.VerifyDiagnostics( // (8,32): error CS8305: Tuple element name 'a' is inferred. Please use language version 7.1 or greater to access an element by its inferred name. // System.Console.Write(t.a); @@ -3918,7 +3917,7 @@ int P set { var t = (M(), value); - System.Console.Write(t.@value); + System.Console.Write(t.value); } } } @@ -10360,7 +10359,7 @@ static void Main((int, int) p) (int, int) t1 = t0; } }"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source); + var comp = CreateCompilationWithMscorlib461AndCSharp(source); comp.VerifyDiagnostics( // (14,33): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // static void Main((int, int) p) @@ -10390,7 +10389,7 @@ unsafe void M((int, int*) p, ValueTuple q) ValueTuple t3 = t2; } }"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, references: s_valueTupleRefs, + var comp = CreateCompilationWithMscorlib461AndCSharp(source, references: s_valueTupleRefs, options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (5,31): error CS0306: The type 'int*' may not be used as a type argument @@ -10441,7 +10440,7 @@ class C return default((U, U)); } }"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source); + var comp = CreateCompilationWithMscorlib461AndCSharp(source); comp.VerifyDiagnostics( // (15,12): error CS0452: The type 'U' must be a reference type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // (U, U) M(U x) @@ -10482,7 +10481,7 @@ class C where T : class return default((U, U)); } }"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source); + var comp = CreateCompilationWithMscorlib461AndCSharp(source); comp.VerifyDiagnostics( // (17,24): error CS0452: The type 'int' must be a reference type in order to use it as parameter 'T' in the generic type or method 'C' // var t0 = new C(); @@ -10520,7 +10519,7 @@ class C where T : class return default((U, U)); } }"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source); + var comp = CreateCompilationWithMscorlib461AndCSharp(source); comp.VerifyDiagnostics( // (15,12): error CS0453: The type 'U' must be a non-nullable value type in order to use it as parameter 'T2' in the generic type or method '(T1, T2)' // (U, U) M(U x) where U : class @@ -10593,7 +10592,7 @@ void M((int, int, int, int, int, int, int, int) p) (int, int, int, int, int, int, int, int) t1 = t0; } }"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source); + var comp = CreateCompilationWithMscorlib461AndCSharp(source); comp.VerifyDiagnostics( // (42,53): error CS0452: The type 'ValueTuple' must be a reference type in order to use it as parameter 'TRest' in the generic type or method 'ValueTuple' // void M((int, int, int, int, int, int, int, int) p) @@ -10639,7 +10638,7 @@ unsafe void M1((int, int, int, int, int, int, int, int, int, int, int, int, int, var v2 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, (int*)null); } }"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, references: s_valueTupleRefs, + var comp = CreateCompilationWithMscorlib461AndCSharp(source, references: s_valueTupleRefs, options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (15,102): error CS0306: The type 'int*' may not be used as a type argument @@ -13914,7 +13913,7 @@ public static ValueTuple options: TestOptions.ReleaseDll); var comp2CompilationRef = comp2.ToMetadataReference(); - var comp3 = CreateCompilationWithMscorlib45(source1, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, comp2CompilationRef }, + var comp3 = CreateCompilationWithMscorlib461(source1, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef, comp2CompilationRef }, options: TestOptions.ReleaseExe); Assert.NotSame(comp2.Assembly, (AssemblySymbol)comp3.GetAssemblyOrModuleSymbol(comp2CompilationRef)); // We are interested in retargeting scenario @@ -14079,7 +14078,7 @@ public class Test options: TestOptions.ReleaseDll); var comp2CompilationRef = comp2.ToMetadataReference(); - var comp3 = CreateCompilationWithMscorlib45(source1, references: (new[] { comp2CompilationRef }).Concat(s_valueTupleRefs), + var comp3 = CreateCompilationWithMscorlib461(source1, references: (new[] { comp2CompilationRef }).Concat(s_valueTupleRefs), options: TestOptions.ReleaseExe); Assert.NotSame(comp2.Assembly, (AssemblySymbol)comp3.GetAssemblyOrModuleSymbol(comp2CompilationRef)); // We are interested in retargeting scenario @@ -19057,7 +19056,7 @@ public C() var tupleComp1 = CreateCompilationWithMscorlib40(trivial2uple + trivial3uple + trivialRemainingTuples); var tree = Parse(text); - var comp = (Compilation)CSharpCompilation.Create("test", syntaxTrees: new[] { tree }, references: new[] { (MetadataReference)Net40.mscorlib, tupleComp1.ToMetadataReference() }); + var comp = (Compilation)CSharpCompilation.Create("test", syntaxTrees: new[] { tree }, references: new[] { (MetadataReference)Net40.References.mscorlib, tupleComp1.ToMetadataReference() }); var model = comp.GetSemanticModel(tree); var exprs = GetBindingNodes(comp); @@ -19096,7 +19095,7 @@ public C() var tupleComp1 = CreateCompilationWithMscorlib40(trivial2uple + trivial3uple + trivialRemainingTuples); var tree = Parse(text); - var comp = (Compilation)CSharpCompilation.Create("test", syntaxTrees: new[] { tree }, references: new[] { (MetadataReference)Net40.mscorlib, tupleComp1.ToMetadataReference() }); + var comp = (Compilation)CSharpCompilation.Create("test", syntaxTrees: new[] { tree }, references: new[] { (MetadataReference)Net40.References.mscorlib, tupleComp1.ToMetadataReference() }); var model = comp.GetSemanticModel(tree); var exprs = GetBindingNodes(comp); @@ -19766,7 +19765,7 @@ public override void M(T x) var comp1 = CreateCompilation(source1 + trivial2uple + source2); comp1.VerifyDiagnostics(); - var comp2 = CreateCompilationWithMscorlib45(source1 + trivial2uple); + var comp2 = CreateCompilationWithMscorlib461(source1 + trivial2uple); comp2.VerifyDiagnostics(); // Retargeting (different version of mscorlib) @@ -19774,7 +19773,7 @@ public override void M(T x) comp3.VerifyDiagnostics(); // Metadata - var comp4 = CreateCompilationWithMscorlib45(source2, references: new[] { comp2.EmitToImageReference() }); + var comp4 = CreateCompilationWithMscorlib461(source2, references: new[] { comp2.EmitToImageReference() }); comp4.VerifyDiagnostics(); } @@ -21206,7 +21205,7 @@ .assembly extern mscorlib { } .assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) - .ver 4:0:1:0 + .ver 4:0:3:0 } .class public auto ansi beforefieldinit Base @@ -22274,9 +22273,9 @@ public class B var comp = CreateCompilationWithMscorlib40(source, references: new[] { lib.ToMetadataReference() }); comp.VerifyDiagnostics( - // (4,24): error CS0012: The type '(, )' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. + // (4,24): error CS0012: The type '(, )' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. // void M2() { return A.M(); } - Diagnostic(ErrorCode.ERR_NoTypeDef, "A.M").WithArguments("(, )", "System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51").WithLocation(4, 24) + Diagnostic(ErrorCode.ERR_NoTypeDef, "A.M").WithArguments("(, )", "System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51").WithLocation(4, 24) ); var methodM = comp.GetMember("A.M"); @@ -22314,9 +22313,9 @@ public class B var comp = CreateCompilationWithMscorlib40(source, references: new[] { lib.ToMetadataReference() }); comp.VerifyDiagnostics( - // (4,24): error CS0012: The type '(, )' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. + // (4,24): error CS0012: The type '(, )' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. // void M2() { return A.M(); } - Diagnostic(ErrorCode.ERR_NoTypeDef, "A.M").WithArguments("(, )", "System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51").WithLocation(4, 24) + Diagnostic(ErrorCode.ERR_NoTypeDef, "A.M").WithArguments("(, )", "System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51").WithLocation(4, 24) ); var methodM = comp.GetMember("A.M"); @@ -23146,7 +23145,7 @@ public void ValueTupleBaseError_NoSystemRuntime() { ((int, int), (int, int)) F(); }"; - var comp = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleRef }); + var comp = CreateCompilationWithMscorlib40(source, references: [ValueTupleLegacyRef]); comp.VerifyEmitDiagnostics( // (3,6): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. // ((int, int), (int, int)) F(); @@ -23417,7 +23416,7 @@ public virtual ref (int, dynamic) Goo(int arg) } } "; - var libComp = CreateCompilationWithMscorlib45AndCSharp(lib, references: s_valueTupleRefs, options: TestOptions.DebugDll); + var libComp = CreateCompilationWithMscorlib461AndCSharp(lib, references: s_valueTupleRefs, options: TestOptions.DebugDll); libComp.VerifyDiagnostics(); var source = @" @@ -23471,7 +23470,7 @@ public virtual ref (int, dynamic) Goo(int arg) } } "; - var libComp = CreateCompilationWithMscorlib45AndCSharp(lib, options: TestOptions.DebugDll, references: s_valueTupleRefs); + var libComp = CreateCompilationWithMscorlib461AndCSharp(lib, options: TestOptions.DebugDll, references: s_valueTupleRefs); libComp.VerifyDiagnostics(); var source = @" @@ -23767,7 +23766,7 @@ .assembly extern System.Core .assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) // .{...-.Q - .ver 4:0:1:0 + .ver 4:0:3:0 } // =============== CLASS MEMBERS DECLARATION =================== @@ -23844,7 +23843,7 @@ public override ref (int, dynamic) Goo(int arg) } "; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, references: (new[] { libCompRef }).Concat(s_valueTupleRefs).ToArray(), options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, references: (new[] { libCompRef }).Concat(s_valueTupleRefs).ToArray(), options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "42qq", verify: Verification.Fails); @@ -23873,7 +23872,7 @@ public class C1 } } "; - var libComp = CreateCompilationWithMscorlib45AndCSharp(lib, references: s_valueTupleRefs, options: TestOptions.DebugDll); + var libComp = CreateCompilationWithMscorlib461AndCSharp(lib, references: s_valueTupleRefs, options: TestOptions.DebugDll); libComp.VerifyDiagnostics(); var source = @" @@ -23924,16 +23923,14 @@ static void M() } "; - var compilation = CreateCompilationWithMscorlib40(source, - references: new[] { ValueTupleRef }); + var compilation = CreateCompilationWithMscorlib40(source, references: [ValueTupleLegacyRef]); Assert.Equal(TypeKind.Class, compilation.GetWellKnownType(WellKnownType.System_ValueTuple_T2).TypeKind); compilation.VerifyDiagnostics( - // (6,17): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. - // var o = (1, 2); - Diagnostic(ErrorCode.ERR_NoTypeDef, "(1, 2)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(6, 17) - ); + // (6,17): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. + // var o = (1, 2); + Diagnostic(ErrorCode.ERR_NoTypeDef, "(1, 2)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(6, 17)); } [Fact] @@ -23970,7 +23967,6 @@ static void Main(string[] args) public void Iterator_02() { var source = @" -using System; using System.Collections.Generic; public class C @@ -23982,17 +23978,14 @@ public class C } "; - var compilation = CreateCompilationWithMscorlib40(source, - references: new[] { ValueTupleRef }); - + var compilation = CreateCompilationWithMscorlib40(source, references: new[] { ValueTupleLegacyRef }); compilation.VerifyEmitDiagnostics( - // (7,24): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. + // (6,24): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. // public IEnumerable<(int, int)> entries() - Diagnostic(ErrorCode.ERR_NoTypeDef, "(int, int)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(7, 24), - // (9,22): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. + Diagnostic(ErrorCode.ERR_NoTypeDef, "(int, int)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(6, 24), + // (8,22): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. // yield return (1, 2); - Diagnostic(ErrorCode.ERR_NoTypeDef, "(1, 2)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(9, 22) - ); + Diagnostic(ErrorCode.ERR_NoTypeDef, "(1, 2)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(8, 22)); } [Fact] @@ -24079,7 +24072,7 @@ public static implicit operator C((int, int) t) } public struct S { } "; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, references: s_valueTupleRefs, options: TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, references: s_valueTupleRefs, options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (13,18): error CS0306: The type 'int*' may not be used as a type argument // (int*, int*) t1 = (p, p); // converted tuple literal with a pointer type @@ -27620,7 +27613,7 @@ public static string GetFromExternal() } } "; - var compilation = CreateCompilationWithMscorlib45(source, null, TestOptions.UnsafeDebugExe); + var compilation = CreateCompilationWithMscorlib461(source, null, TestOptions.UnsafeDebugExe); CompileAndVerify(compilation, expectedOutput: "MessageType x MessageType").VerifyDiagnostics(); } @@ -27925,7 +27918,7 @@ public ValueTuple(T1 item1) } } }"; - var comp = CreateCompilation(source, targetFramework: TargetFramework.Mscorlib45); + var comp = CreateCompilation(source, targetFramework: TargetFramework.Mscorlib461); var type = (SourceNamedTypeSymbol)comp.GetMember("System.ValueTuple"); var field = (SourceMemberFieldSymbolFromDeclarator)type.GetMember("Item1"); var underlyingField = field.TupleUnderlyingField; @@ -28553,7 +28546,7 @@ public struct ValueTuple public T1 Rest; } }"; - var comp = CreateCompilation(source, targetFramework: TargetFramework.Mscorlib45); + var comp = CreateCompilation(source, targetFramework: TargetFramework.Mscorlib461); comp.VerifyDiagnostics(); CompileAndVerify(comp, symbolValidator: verifyModule, sourceSymbolValidator: verifyModule); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs index bd68eefaa1e3e..546e068951632 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/GotoTest.cs @@ -929,7 +929,7 @@ public void OutOfScriptBlock() string expectedOutput = @"True False"; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: Verification.Passes); } @@ -944,7 +944,7 @@ public void IntoScriptBlock() { L1: ; }"; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); compilation.VerifyDiagnostics( // (1,6): error CS0159: No such label 'L0' within the scope of the goto statement // goto L0; @@ -980,7 +980,7 @@ static int G(string s) @"2: P 3: F 4: Q"; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: Verification.Fails); } @@ -1016,7 +1016,7 @@ public void OutOfScriptMethod() } L: F(true);"; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (5,1): warning CS0164: This label has not been referenced // L: @@ -1036,7 +1036,7 @@ public void IntoScriptMethod() return; } goto L;"; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,6): error CS0159: No such label 'L' within the scope of the goto statement // goto L; @@ -1063,7 +1063,7 @@ public void InScriptSwitch() }"; string expectedOutput = @"3"; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); CompileAndVerify(compilation, expectedOutput: expectedOutput, verify: Verification.Passes); } @@ -1083,7 +1083,7 @@ public void DuplicateLabelInScript() if (b) goto L; L: ; }"; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); compilation.VerifyDiagnostics( // (11,1): error CS0158: The label 'L' shadows another label by the same name in a contained scope // L: ; @@ -1126,7 +1126,7 @@ public void LoadedFile() B: goto A;"; var resolver = TestSourceReferenceResolver.Create(KeyValuePairUtil.Create("a.csx", sourceA)); var options = TestOptions.DebugDll.WithSourceReferenceResolver(resolver); - var compilation = CreateCompilationWithMscorlib45(sourceB, options: options, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(sourceB, options: options, parseOptions: TestOptions.Script); compilation.GetDiagnostics().Verify( // a.csx(2,9): error CS0159: No such label 'B' within the scope of the goto statement // A: goto B; @@ -1144,7 +1144,7 @@ public void Label_GetDeclaredSymbol_Script() static void F() { } L1: goto L0;"; var tree = Parse(source, options: TestOptions.Script); - var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false); + var model = CreateCompilationWithMscorlib461(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false); var label = (LabeledStatementSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.LabeledStatement); var symbol = model.GetDeclaredSymbol(label); Assert.Equal("L0", symbol.Name); @@ -1157,7 +1157,7 @@ public void Label_GetDeclaredSymbol_Error_Script() C: \a\b\ "; var tree = Parse(source, options: TestOptions.Script); - var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false); + var model = CreateCompilationWithMscorlib461(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false); var label = (LabeledStatementSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.LabeledStatement); var symbol = model.GetDeclaredSymbol(label); Assert.Equal("C", symbol.Name); @@ -1170,7 +1170,7 @@ public void TrailingExpression() goto EOF; EOF:"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script); compilation.GetDiagnostics().Verify( // (3,5): error CS1733: Expected expression // EOF: @@ -1185,7 +1185,7 @@ public void TrailingExpression() source = @" goto EOF; EOF: 42"; - compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script); + compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script); compilation.GetDiagnostics().Verify( // (3,8): error CS1002: ; expected // EOF: 42 @@ -1198,7 +1198,7 @@ public void TrailingExpression() L2: EOF: obj.ToString()"; - compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script); + compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script); compilation.GetDiagnostics().Verify( // (6,20): error CS1002: ; expected // EOF: obj.ToString() diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/IndexerTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/IndexerTests.cs index 962aad44400e0..6b01995d2246c 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/IndexerTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/IndexerTests.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.CSharp.UnitTests.Emit; +using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; @@ -1185,5 +1186,80 @@ static void Main() } #endregion Lowering + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75032")] + public void MissingDefaultMemberAttribute_01() + { + var text1 = @" +public interface I1 +{ + public I1 this[I1 args] { get; } +} +"; + var comp1 = CreateCompilation(text1); + comp1.MakeMemberMissing(WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor); + + comp1.VerifyDiagnostics( + // (4,15): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor' + // public I1 this[I1 args] { get; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(4, 15) + ); + + comp1 = CreateCompilation(text1); + comp1.MakeTypeMissing(WellKnownType.System_Reflection_DefaultMemberAttribute); + + comp1.VerifyDiagnostics( + // (4,15): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor' + // public I1 this[I1 args] { get; } + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(4, 15) + ); + + comp1 = CreateCompilation(text1); + comp1.VerifyEmitDiagnostics(); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75032")] + public void MissingDefaultMemberAttribute_02() + { + var text1 = @" +public interface I1 +{ + public I1 this[I1 args] { get; } +} +"; + var comp1 = CreateCompilation(text1); + + var text2 = @" +class C : I1 +{ + I1 I1.this[I1 args] => throw null; +} +"; + var comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()]); + comp2.MakeMemberMissing(WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor); + comp2.VerifyEmitDiagnostics(); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75032")] + public void MissingDefaultMemberAttribute_03() + { + var text1 = @" +using System.Collections.Generic; + +class Program +{ + static IEnumerable Test() + { + return [123]; + } +} +"; + var comp1 = CreateCompilation(text1); + comp1.MakeMemberMissing(WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor); + CompileAndVerify(comp1).VerifyDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/ObjectAndCollectionInitializerTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/ObjectAndCollectionInitializerTests.cs index bc400616f839b..45532c13e7a1b 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/ObjectAndCollectionInitializerTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/ObjectAndCollectionInitializerTests.cs @@ -1383,7 +1383,7 @@ private static async Task F(int x) - 5"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: expectedOutput); } @@ -1480,7 +1480,7 @@ static void Main() - 5"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: expectedOutput); } @@ -1817,7 +1817,7 @@ private static async Task F(int x) get 3"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, options: TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: expectedOutput); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs index 90fb9ab5de6eb..d36e398902681 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/UnsafeTests.cs @@ -5410,7 +5410,7 @@ public Fixable(int arg){} public void CustomFixedStructVariousErr06_UseSite() { var missing_cs = "public struct Missing { }"; - var missing = CreateCompilationWithMscorlib45(missing_cs, options: TestOptions.DebugDll, assemblyName: "missing"); + var missing = CreateCompilationWithMscorlib461(missing_cs, options: TestOptions.DebugDll, assemblyName: "missing"); var lib_cs = @" public struct Fixable @@ -5421,7 +5421,7 @@ public Fixable(int arg){} } "; - var lib = CreateCompilationWithMscorlib45(lib_cs, references: new[] { missing.EmitToImageReference() }, options: TestOptions.DebugDll); + var lib = CreateCompilationWithMscorlib461(lib_cs, references: new[] { missing.EmitToImageReference() }, options: TestOptions.DebugDll); var source = @" @@ -5436,7 +5436,7 @@ public static void Main() } "; - var comp = CreateCompilationWithMscorlib45(source, references: new[] { lib.EmitToImageReference() }, options: TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlib461(source, references: new[] { lib.EmitToImageReference() }, options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (6,26): error CS0012: The type 'Missing' is defined in an assembly that is not referenced. You must add a reference to assembly 'missing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // fixed (void* p = new Fixable(1)) diff --git a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs index f72cc8ec0077b..5058dc3912928 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs @@ -24,7 +24,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Emit { @@ -3462,7 +3462,7 @@ public static void Main() var compilation = CSharpCompilation.Create( "v2Fx.exe", new[] { Parse(source) }, - new[] { Net20.mscorlib }); + new[] { Net20.References.mscorlib }); //EDMAURER this is built with a 2.0 mscorlib. The runtimeMetadataVersion should be the same as the runtimeMetadataVersion stored in the assembly //that contains System.Object. @@ -4041,7 +4041,12 @@ public void EmitModuleWithDifferentName() var extension = ".netmodule"; var outputName = "b"; - var compilation = CreateCompilation("class A { }", options: TestOptions.ReleaseModule.WithModuleName(name + extension), assemblyName: null); + var compilation = CSharpCompilation.Create( + assemblyName: null, + syntaxTrees: [SyntaxFactory.ParseSyntaxTree("class A { }")], + references: TargetFrameworkUtil.GetReferences(TargetFramework.Standard), + options: TestOptions.ReleaseModule.WithModuleName(name + extension)); + compilation.VerifyDiagnostics(); var assembly = compilation.Assembly; diff --git a/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.cs index 026652a9acfc7..dc9347a1974da 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.cs @@ -3095,6 +3095,78 @@ static void Test() " + checker.ExpectedOutput; var verifier = CompileAndVerify(source, expectedOutput, options: TestOptions.ReleaseExe); + verifier.VerifyIL("Class1.Method1", +@" +{ + // Code size 138 (0x8a) + .maxstack 5 + .locals init (bool[] V_0) + IL_0000: ldsfld ""bool[][] .PayloadRoot0"" + IL_0005: ldtoken ""void Class1.Method1(int)"" + IL_000a: ldelem.ref + IL_000b: stloc.0 + IL_000c: ldloc.0 + IL_000d: brtrue.s IL_0034 + IL_000f: ldsfld ""System.Guid .MVID"" + IL_0014: ldtoken ""void Class1.Method1(int)"" + IL_0019: ldtoken Source Document 0 + IL_001e: ldsfld ""bool[][] .PayloadRoot0"" + IL_0023: ldtoken ""void Class1.Method1(int)"" + IL_0028: ldelema ""bool[]"" + IL_002d: ldc.i4.7 + IL_002e: call ""bool[] Microsoft.CodeAnalysis.Runtime.Instrumentation.CreatePayload(System.Guid, int, int, ref bool[], int)"" + IL_0033: stloc.0 + IL_0034: ldloc.0 + IL_0035: ldc.i4.0 + IL_0036: ldc.i4.1 + IL_0037: stelem.i1 + IL_0038: ldloc.0 + IL_0039: ldc.i4.1 + IL_003a: ldc.i4.1 + IL_003b: stelem.i1 + IL_003c: ldstr ""Method1: x = {0}"" + IL_0041: ldarg.1 + IL_0042: box ""int"" + IL_0047: call ""string string.Format(string, object)"" + IL_004c: call ""void System.Console.WriteLine(string)"" + IL_0051: ldloc.0 + IL_0052: ldc.i4.6 + IL_0053: ldc.i4.1 + IL_0054: stelem.i1 + IL_0055: ldarg.1 + IL_0056: ldc.i4.0 + IL_0057: ble.s IL_0073 + IL_0059: ldloc.0 + IL_005a: ldc.i4.2 + IL_005b: ldc.i4.1 + IL_005c: stelem.i1 + IL_005d: ldstr ""Method1: x > 0"" + IL_0062: call ""void System.Console.WriteLine(string)"" + IL_0067: ldloc.0 + IL_0068: ldc.i4.3 + IL_0069: ldc.i4.1 + IL_006a: stelem.i1 + IL_006b: ldarg.0 + IL_006c: ldc.i4.0 + IL_006d: call ""void Class1.Method1(int)"" + IL_0072: ret + IL_0073: ldloc.0 + IL_0074: ldc.i4.5 + IL_0075: ldc.i4.1 + IL_0076: stelem.i1 + IL_0077: ldarg.1 + IL_0078: ldc.i4.0 + IL_0079: bge.s IL_0089 + IL_007b: ldloc.0 + IL_007c: ldc.i4.4 + IL_007d: ldc.i4.1 + IL_007e: stelem.i1 + IL_007f: ldstr ""Method1: x < 0"" + IL_0084: call ""void System.Console.WriteLine(string)"" + IL_0089: ret +} +"); + checker.CompleteCheck(verifier.Compilation, source); verifier.VerifyDiagnostics(); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EmitCustomModifiers.cs b/src/Compilers/CSharp/Test/Emit/Emit/EmitCustomModifiers.cs index a005d98afe66b..3c75e4be0b1f5 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EmitCustomModifiers.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EmitCustomModifiers.cs @@ -12,6 +12,7 @@ using Roslyn.Test.Utilities; using Xunit; using System.Linq; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Emit { @@ -20,7 +21,7 @@ public class EmitCustomModifiers : EmitMetadataTestBase [Fact] public void Test1() { - var mscorlibRef = TestMetadata.Net40.mscorlib; + var mscorlibRef = Net40.References.mscorlib; string source = @" public class A { diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs index 7b919c1221b08..738a07c592c94 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs @@ -891,7 +891,7 @@ private int P5 { set { } } [Fact] public void SetGetOnlyAutopropsInConstructors() { - var comp = CreateCompilationWithMscorlib45(@"using System; + var comp = CreateCompilationWithMscorlib461(@"using System; class C { public int P1 { get; } @@ -1294,7 +1294,7 @@ private static void VerifyAutoProperty(PropertySymbol property, bool isFromSourc { if (property is SourcePropertySymbol sourceProperty) { - Assert.True(sourceProperty.IsAutoPropertyWithGetAccessor); + Assert.True(sourceProperty.IsAutoProperty); } } else diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EntryPointTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EntryPointTests.cs index d64793bb83c99..02501a577845b 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EntryPointTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EntryPointTests.cs @@ -277,7 +277,7 @@ public class C } "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { Parse(csx, options: TestOptions.Script), @@ -368,7 +368,7 @@ public void ScriptNonMethodMain() System.Console.WriteLine(Main); "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(csx, options: TestOptions.Script), @@ -389,7 +389,7 @@ public void ScriptInstanceMethodMain() System.Console.WriteLine(Main()); "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(csx, options: TestOptions.Script), @@ -722,7 +722,7 @@ public void Script() System.Console.WriteLine(1); "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.Script) }, options: TestOptions.ReleaseExe); @@ -743,7 +743,7 @@ public class C } "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(csx, options: TestOptions.Script), @@ -777,7 +777,7 @@ public class D } "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(csx, options: TestOptions.Script), @@ -924,7 +924,7 @@ class C } "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(csx, options: TestOptions.Script), diff --git a/src/Compilers/CSharp/Test/Emit/Emit/InAttributeModifierTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/InAttributeModifierTests.cs index 903de0150cf12..85dab8e75c6d1 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/InAttributeModifierTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/InAttributeModifierTests.cs @@ -1565,6 +1565,9 @@ class Test }"; CreateEmptyCompilation(code).VerifyDiagnostics( + // (9,27): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor' + // public virtual object this[in object p] => null; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(9, 27), // (9,32): error CS0518: Predefined type 'System.Runtime.InteropServices.InAttribute' is not defined or imported // public virtual object this[in object p] => null; Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "in object p").WithArguments("System.Runtime.InteropServices.InAttribute").WithLocation(9, 32)); @@ -1588,7 +1591,11 @@ class Test CreateEmptyCompilation(code).VerifyDiagnostics( // (10,20): error CS0518: Predefined type 'System.Runtime.InteropServices.InAttribute' is not defined or imported // public virtual ref readonly object this[object p] => ref value; - Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "ref readonly object").WithArguments("System.Runtime.InteropServices.InAttribute").WithLocation(10, 20)); + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "ref readonly object").WithArguments("System.Runtime.InteropServices.InAttribute").WithLocation(10, 20), + // (10,40): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor' + // public virtual ref readonly object this[object p] => ref value; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(10, 40) + ); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit/Emit/OptionalArgumentsTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/OptionalArgumentsTests.cs index f3d4fced5990f..cc001016cb53b 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/OptionalArgumentsTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/OptionalArgumentsTests.cs @@ -105,7 +105,7 @@ static void Report(object o) System.Console.WriteLine(""{0}: {1}"", o.GetType(), value); } }"; - var compilation = CreateCompilationWithILAndMscorlib40(csharpSource, ilSource, TargetFramework.Mscorlib45, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithILAndMscorlib40(csharpSource, ilSource, TargetFramework.Mscorlib461, options: TestOptions.DebugExe); compilation.VerifyDiagnostics(); CompileAndVerify(compilation, expectedOutput: @"System.Reflection.Missing: System.Reflection.Missing diff --git a/src/Compilers/CSharp/Test/Emit/Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj b/src/Compilers/CSharp/Test/Emit/Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj index 3276fae69d6c0..aa297ca0ff6be 100644 --- a/src/Compilers/CSharp/Test/Emit/Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj +++ b/src/Compilers/CSharp/Test/Emit/Microsoft.CodeAnalysis.CSharp.Emit.UnitTests.csproj @@ -4,7 +4,7 @@ Library Microsoft.CodeAnalysis.CSharp.UnitTests - $(NetRoslyn);net472 + $(NetRoslynNext);net472 true diff --git a/src/Compilers/CSharp/Test/Emit/PrivateProtected.cs b/src/Compilers/CSharp/Test/Emit/PrivateProtected.cs index 9f1745a691031..4598488bf0faa 100644 --- a/src/Compilers/CSharp/Test/Emit/PrivateProtected.cs +++ b/src/Compilers/CSharp/Test/Emit/PrivateProtected.cs @@ -783,7 +783,7 @@ public static void M(string s) } } "; - CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular7_2) + CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular7_2) .VerifyDiagnostics( // (4,35): error CS1057: 'Extensions.SomeExtension(string)': static classes cannot contain protected members // static private protected void SomeExtension(this string s) { } // error: no pp in static class diff --git a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs index ea003bba0b2f6..26e0d88f23509 100644 --- a/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; -using Microsoft.CodeAnalysis.Test.Resources.Proprietary; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueClosureTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueClosureTests.cs index ccba392f338d1..5618ffc8b3428 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueClosureTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueClosureTests.cs @@ -146,7 +146,8 @@ static void F() } """) .AddGeneration( - """ + // 1 + source: """ using System; class C { @@ -168,7 +169,8 @@ static void F() "C.<>c__DisplayClass0#1_0#1: {x, b__0#1}"); }) .AddGeneration( - """ + // 2 + source: """ using System; class C { @@ -185,11 +187,13 @@ static void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__DisplayClass0#1_0#1}", "C.<>c__DisplayClass0#1_0#1: {x, b__0#1}"); }) .AddGeneration( - """ + // 3 + source: """ using System; class C { @@ -207,6 +211,7 @@ static void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__DisplayClass0#1_0#3, <>c__DisplayClass0#1_0#1}", "C.<>c__DisplayClass0#1_0#3: {x, b__0#3}", "C.<>c__DisplayClass0#1_0#1: {x, b__0#1}"); @@ -844,15 +849,12 @@ public void F(string? x) ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); diff1.VerifySynthesizedMembers( - "Microsoft.CodeAnalysis: {EmbeddedAttribute}", - "Microsoft: {CodeAnalysis}", - "System.Runtime: {CompilerServices, CompilerServices}", - ": {Microsoft, System, System}", + "Microsoft.CodeAnalysis.EmbeddedAttribute", + "System.Runtime.CompilerServices.NullableAttribute", + "System.Runtime.CompilerServices.NullableContextAttribute", "C: {<>c__DisplayClass2_0}", - "System: {Runtime, Runtime}", "C.<>c__DisplayClass2_0: {x, y1, y2, b__0, b__1}", "<>f__AnonymousType1<j__TPar>: {Equals, GetHashCode, ToString}", - "System.Runtime.CompilerServices: {NullableAttribute, NullableContextAttribute}", "<>f__AnonymousType0<j__TPar>: {Equals, GetHashCode, ToString}"); diff1.VerifyIL("C.<>c__DisplayClass2_0.b__1()", @" @@ -2458,7 +2460,7 @@ public int F() } }"; - var compilation0 = CreateCompilationWithMscorlib45(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); + var compilation0 = CreateCompilationWithMscorlib461(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); var compilation1 = compilation0.WithSource(source1); var compilation2 = compilation1.WithSource(source2); @@ -2575,7 +2577,7 @@ public int F() } }"; - var compilation0 = CreateCompilationWithMscorlib45(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); + var compilation0 = CreateCompilationWithMscorlib461(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); var compilation1 = compilation0.WithSource(source1); var compilation2 = compilation1.WithSource(source2); @@ -2708,7 +2710,7 @@ public int F() } }"; - var compilation0 = CreateCompilationWithMscorlib45(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); + var compilation0 = CreateCompilationWithMscorlib461(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); var compilation1 = compilation0.WithSource(source1); var compilation2 = compilation1.WithSource(source2); var compilation3 = compilation2.WithSource(source3); @@ -3333,119 +3335,114 @@ .locals init (System.Collections.Generic.IEnumerable V_0) //result [Fact] public void Queries_Select_Reduced2() { - var source0 = MarkedSource(@" -using System; -using System.Linq; -using System.Collections.Generic; - -class C -{ - void F() - { - var result = from a in array - where a > 0 - select a + 1; - } - - int[] array = null; -} -"); - var source1 = MarkedSource(@" -using System; -using System.Linq; -using System.Collections.Generic; - -class C -{ - void F() - { - var result = from a in array - where a > 0 - select a; - } - - int[] array = null; -} -"); - var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll); - var compilation1 = compilation0.WithSource(source1.Tree); - var v0 = CompileAndVerify(compilation0); - var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - - var f0 = compilation0.GetMember("C.F"); - var f1 = compilation1.GetMember("C.F"); - - var generation0 = CreateInitialBaseline(compilation0, md0, v0.CreateSymReader().GetEncMethodDebugInfo); - - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); - - var md1 = diff1.GetMetadata(); - var reader1 = md1.Reader; - - // lambda for Select(a => a + 1) is gone - diff1.VerifySynthesizedMembers( - "C: {<>c}", - "C.<>c: {<>9__0_0, b__0_0}"); + using var _ = new EditAndContinueTest(references: [CSharpRef]) + .AddBaseline( + source: """ + using System; + using System.Linq; + using System.Collections.Generic; + + class C + { + void F() + { + var result = from a in array + where a > 0 + select a + 1; + } + + int[] array = null; + } + """, + validator: v => + { + v.VerifyIL("C.F", """ + { + // Code size 81 (0x51) + .maxstack 3 + .locals init (System.Collections.Generic.IEnumerable V_0) //result + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldfld "int[] C.array" + IL_0007: ldsfld "System.Func C.<>c.<>9__0_0" + IL_000c: dup + IL_000d: brtrue.s IL_0026 + IL_000f: pop + IL_0010: ldsfld "C.<>c C.<>c.<>9" + IL_0015: ldftn "bool C.<>c.b__0_0(int)" + IL_001b: newobj "System.Func..ctor(object, System.IntPtr)" + IL_0020: dup + IL_0021: stsfld "System.Func C.<>c.<>9__0_0" + IL_0026: call "System.Collections.Generic.IEnumerable System.Linq.Enumerable.Where(System.Collections.Generic.IEnumerable, System.Func)" + IL_002b: ldsfld "System.Func C.<>c.<>9__0_1" + IL_0030: dup + IL_0031: brtrue.s IL_004a + IL_0033: pop + IL_0034: ldsfld "C.<>c C.<>c.<>9" + IL_0039: ldftn "int C.<>c.b__0_1(int)" + IL_003f: newobj "System.Func..ctor(object, System.IntPtr)" + IL_0044: dup + IL_0045: stsfld "System.Func C.<>c.<>9__0_1" + IL_004a: call "System.Collections.Generic.IEnumerable System.Linq.Enumerable.Select(System.Collections.Generic.IEnumerable, System.Func)" + IL_004f: stloc.0 + IL_0050: ret + } + """); + }) + .AddGeneration( + source: """ + using System; + using System.Linq; + using System.Collections.Generic; + + class C + { + void F() + { + var result = from a in array + where a > 0 + select a; + } + + int[] array = null; + } + """, + edits: + [ + Edit(SemanticEditKind.Update, c => c.GetMember("C.F"), preserveLocalVariables: true) + ], + validator: v => + { + // lambda for Select(a => a + 1) is gone + v.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", + "C: {<>c}", + "C.<>c: {<>9__0_0, b__0_0}"); - // old query: - v0.VerifyIL("C.F", @" -{ - // Code size 81 (0x51) - .maxstack 3 - .locals init (System.Collections.Generic.IEnumerable V_0) //result - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldfld ""int[] C.array"" - IL_0007: ldsfld ""System.Func C.<>c.<>9__0_0"" - IL_000c: dup - IL_000d: brtrue.s IL_0026 - IL_000f: pop - IL_0010: ldsfld ""C.<>c C.<>c.<>9"" - IL_0015: ldftn ""bool C.<>c.b__0_0(int)"" - IL_001b: newobj ""System.Func..ctor(object, System.IntPtr)"" - IL_0020: dup - IL_0021: stsfld ""System.Func C.<>c.<>9__0_0"" - IL_0026: call ""System.Collections.Generic.IEnumerable System.Linq.Enumerable.Where(System.Collections.Generic.IEnumerable, System.Func)"" - IL_002b: ldsfld ""System.Func C.<>c.<>9__0_1"" - IL_0030: dup - IL_0031: brtrue.s IL_004a - IL_0033: pop - IL_0034: ldsfld ""C.<>c C.<>c.<>9"" - IL_0039: ldftn ""int C.<>c.b__0_1(int)"" - IL_003f: newobj ""System.Func..ctor(object, System.IntPtr)"" - IL_0044: dup - IL_0045: stsfld ""System.Func C.<>c.<>9__0_1"" - IL_004a: call ""System.Collections.Generic.IEnumerable System.Linq.Enumerable.Select(System.Collections.Generic.IEnumerable, System.Func)"" - IL_004f: stloc.0 - IL_0050: ret -} -"); - // new query: - diff1.VerifyIL("C.F", @" -{ - // Code size 45 (0x2d) - .maxstack 3 - .locals init (System.Collections.Generic.IEnumerable V_0) //result - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldfld ""int[] C.array"" - IL_0007: ldsfld ""System.Func C.<>c.<>9__0_0"" - IL_000c: dup - IL_000d: brtrue.s IL_0026 - IL_000f: pop - IL_0010: ldsfld ""C.<>c C.<>c.<>9"" - IL_0015: ldftn ""bool C.<>c.b__0_0(int)"" - IL_001b: newobj ""System.Func..ctor(object, System.IntPtr)"" - IL_0020: dup - IL_0021: stsfld ""System.Func C.<>c.<>9__0_0"" - IL_0026: call ""System.Collections.Generic.IEnumerable System.Linq.Enumerable.Where(System.Collections.Generic.IEnumerable, System.Func)"" - IL_002b: stloc.0 - IL_002c: ret -} -"); + v.VerifyIL("C.F", """ + { + // Code size 45 (0x2d) + .maxstack 3 + .locals init (System.Collections.Generic.IEnumerable V_0) //result + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldfld "int[] C.array" + IL_0007: ldsfld "System.Func C.<>c.<>9__0_0" + IL_000c: dup + IL_000d: brtrue.s IL_0026 + IL_000f: pop + IL_0010: ldsfld "C.<>c C.<>c.<>9" + IL_0015: ldftn "bool C.<>c.b__0_0(int)" + IL_001b: newobj "System.Func..ctor(object, System.IntPtr)" + IL_0020: dup + IL_0021: stsfld "System.Func C.<>c.<>9__0_0" + IL_0026: call "System.Collections.Generic.IEnumerable System.Linq.Enumerable.Where(System.Collections.Generic.IEnumerable, System.Func)" + IL_002b: stloc.0 + IL_002c: ret + } + """); + }) + .Verify(); } [Fact] @@ -3575,171 +3572,167 @@ .locals init (System.Collections.Generic.IEnumerableresult = from a in array + group a + 1 by a; + } + + int[] array = null; + } + """, + validator: v => + { + v.VerifyIL("C.F", """ + { + // Code size 76 (0x4c) + .maxstack 4 + .locals init (System.Collections.Generic.IEnumerable> V_0) //result + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldfld "int[] C.array" + IL_0007: ldsfld "System.Func C.<>c.<>9__0_0" + IL_000c: dup + IL_000d: brtrue.s IL_0026 + IL_000f: pop + IL_0010: ldsfld "C.<>c C.<>c.<>9" + IL_0015: ldftn "int C.<>c.b__0_0(int)" + IL_001b: newobj "System.Func..ctor(object, System.IntPtr)" + IL_0020: dup + IL_0021: stsfld "System.Func C.<>c.<>9__0_0" + IL_0026: ldsfld "System.Func C.<>c.<>9__0_1" + IL_002b: dup + IL_002c: brtrue.s IL_0045 + IL_002e: pop + IL_002f: ldsfld "C.<>c C.<>c.<>9" + IL_0034: ldftn "int C.<>c.b__0_1(int)" + IL_003a: newobj "System.Func..ctor(object, System.IntPtr)" + IL_003f: dup + IL_0040: stsfld "System.Func C.<>c.<>9__0_1" + IL_0045: call "System.Collections.Generic.IEnumerable> System.Linq.Enumerable.GroupBy(System.Collections.Generic.IEnumerable, System.Func, System.Func)" + IL_004a: stloc.0 + IL_004b: ret + } + """); + }) + .AddGeneration( + // 1 + source: """ + using System; + using System.Linq; + using System.Collections.Generic; + + class C + { + void F() + { + var result = from a in array + group a by a; + } + + int[] array = null; + } + """, + edits: + [ + Edit(SemanticEditKind.Update, c => c.GetMember("C.F"), preserveLocalVariables: true) + ], + validator: v => + { + // lambda for GroupBy(..., a => a + 1) is gone + v.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", + "C: {<>c}", + "C.<>c: {<>9__0_0, b__0_0}"); + + v.VerifyIL("C.F", """ + { + // Code size 45 (0x2d) + .maxstack 3 + .locals init (System.Collections.Generic.IEnumerable> V_0) //result + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldfld "int[] C.array" + IL_0007: ldsfld "System.Func C.<>c.<>9__0_0" + IL_000c: dup + IL_000d: brtrue.s IL_0026 + IL_000f: pop + IL_0010: ldsfld "C.<>c C.<>c.<>9" + IL_0015: ldftn "int C.<>c.b__0_0(int)" + IL_001b: newobj "System.Func..ctor(object, System.IntPtr)" + IL_0020: dup + IL_0021: stsfld "System.Func C.<>c.<>9__0_0" + IL_0026: call "System.Collections.Generic.IEnumerable> System.Linq.Enumerable.GroupBy(System.Collections.Generic.IEnumerable, System.Func)" + IL_002b: stloc.0 + IL_002c: ret + } + """); + }) + .Verify(); + } + + [Fact, WorkItem(1170899, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1170899")] + public void CapturedAnonymousTypes1() { var source0 = MarkedSource(@" using System; -using System.Linq; -using System.Collections.Generic; class C { - void F() - { - var result = from a in array - group a + 1 by a; - } - - int[] array = null; + static void F() + { + var x = new { A = 1 }; + var y = new Func(() => x.A); + Console.WriteLine(1); + } } "); var source1 = MarkedSource(@" using System; -using System.Linq; -using System.Collections.Generic; class C { - void F() - { - var result = from a in array - group a by a; - } + static void F() + { + var x = new { A = 1 }; + var y = new Func(() => x.A); + Console.WriteLine(2); + } +} +"); + var source2 = MarkedSource(@" +using System; - int[] array = null; +class C +{ + static void F() + { + var x = new { A = 1 }; + var y = new Func(() => x.A); + Console.WriteLine(3); + } } "); var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); + var compilation2 = compilation1.WithSource(source2.Tree); + var v0 = CompileAndVerify(compilation0); var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); var f0 = compilation0.GetMember("C.F"); var f1 = compilation1.GetMember("C.F"); - - var generation0 = CreateInitialBaseline(compilation0, md0, v0.CreateSymReader().GetEncMethodDebugInfo); - - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); - - var md1 = diff1.GetMetadata(); - var reader1 = md1.Reader; - - // lambda for GroupBy(..., a => a + 1) is gone - diff1.VerifySynthesizedMembers( - "C: {<>c}", - "C.<>c: {<>9__0_0, b__0_0}"); - - // old query: - v0.VerifyIL("C.F", @" -{ - // Code size 76 (0x4c) - .maxstack 4 - .locals init (System.Collections.Generic.IEnumerable> V_0) //result - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldfld ""int[] C.array"" - IL_0007: ldsfld ""System.Func C.<>c.<>9__0_0"" - IL_000c: dup - IL_000d: brtrue.s IL_0026 - IL_000f: pop - IL_0010: ldsfld ""C.<>c C.<>c.<>9"" - IL_0015: ldftn ""int C.<>c.b__0_0(int)"" - IL_001b: newobj ""System.Func..ctor(object, System.IntPtr)"" - IL_0020: dup - IL_0021: stsfld ""System.Func C.<>c.<>9__0_0"" - IL_0026: ldsfld ""System.Func C.<>c.<>9__0_1"" - IL_002b: dup - IL_002c: brtrue.s IL_0045 - IL_002e: pop - IL_002f: ldsfld ""C.<>c C.<>c.<>9"" - IL_0034: ldftn ""int C.<>c.b__0_1(int)"" - IL_003a: newobj ""System.Func..ctor(object, System.IntPtr)"" - IL_003f: dup - IL_0040: stsfld ""System.Func C.<>c.<>9__0_1"" - IL_0045: call ""System.Collections.Generic.IEnumerable> System.Linq.Enumerable.GroupBy(System.Collections.Generic.IEnumerable, System.Func, System.Func)"" - IL_004a: stloc.0 - IL_004b: ret -} -"); - // new query: - diff1.VerifyIL("C.F", @" -{ - // Code size 45 (0x2d) - .maxstack 3 - .locals init (System.Collections.Generic.IEnumerable> V_0) //result - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldfld ""int[] C.array"" - IL_0007: ldsfld ""System.Func C.<>c.<>9__0_0"" - IL_000c: dup - IL_000d: brtrue.s IL_0026 - IL_000f: pop - IL_0010: ldsfld ""C.<>c C.<>c.<>9"" - IL_0015: ldftn ""int C.<>c.b__0_0(int)"" - IL_001b: newobj ""System.Func..ctor(object, System.IntPtr)"" - IL_0020: dup - IL_0021: stsfld ""System.Func C.<>c.<>9__0_0"" - IL_0026: call ""System.Collections.Generic.IEnumerable> System.Linq.Enumerable.GroupBy(System.Collections.Generic.IEnumerable, System.Func)"" - IL_002b: stloc.0 - IL_002c: ret -} -"); - } - - [Fact, WorkItem(1170899, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1170899")] - public void CapturedAnonymousTypes1() - { - var source0 = MarkedSource(@" -using System; - -class C -{ - static void F() - { - var x = new { A = 1 }; - var y = new Func(() => x.A); - Console.WriteLine(1); - } -} -"); - var source1 = MarkedSource(@" -using System; - -class C -{ - static void F() - { - var x = new { A = 1 }; - var y = new Func(() => x.A); - Console.WriteLine(2); - } -} -"); - var source2 = MarkedSource(@" -using System; - -class C -{ - static void F() - { - var x = new { A = 1 }; - var y = new Func(() => x.A); - Console.WriteLine(3); - } -} -"); - var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll); - var compilation1 = compilation0.WithSource(source1.Tree); - var compilation2 = compilation1.WithSource(source2.Tree); - - var v0 = CompileAndVerify(compilation0); - var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - - var f0 = compilation0.GetMember("C.F"); - var f1 = compilation1.GetMember("C.F"); - var f2 = compilation2.GetMember("C.F"); + var f2 = compilation2.GetMember("C.F"); var generation0 = CreateInitialBaseline(compilation0, md0, v0.CreateSymReader().GetEncMethodDebugInfo); @@ -4844,23 +4837,24 @@ public void F() // Static lambda is reused. // A new display class and method is generated for lambda that captures x. g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c, <>c__DisplayClass0_0#1}", "C.<>c: {<>9__0_1, b__0_1}", "C.<>c__DisplayClass0_0#1: {x, b__0#1}"); - g.VerifyMethodDefNames("F", "b__0_0", "b__0_1", ".ctor", "b__0#1"); + g.VerifyMethodDefNames("F", "b__0_0", "b__0_1", ".ctor", ".ctor", "b__0#1"); g.VerifyIL( """ { // Code size 44 (0x2c) .maxstack 2 - IL_0000: newobj 0x06000007 + IL_0000: newobj 0x06000008 IL_0005: stloc.1 IL_0006: nop IL_0007: ldloc.1 IL_0008: ldc.i4.1 - IL_0009: stfld 0x04000004 + IL_0009: stfld 0x04000005 IL_000e: nop IL_000f: ldsfld 0x04000003 IL_0014: brtrue.s IL_002b @@ -4871,20 +4865,33 @@ .maxstack 2 IL_002b: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000007 + IL_000c: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.2 - IL_0001: call 0x0A00000B + IL_0001: call 0x0A00000A IL_0006: nop IL_0007: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000004 + IL_000f: ret + } { // Code size 8 (0x8) .maxstack 8 @@ -4897,8 +4904,8 @@ .maxstack 8 // Code size 13 (0xd) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000004 - IL_0006: call 0x0A00000B + IL_0001: ldfld 0x04000005 + IL_0006: call 0x0A00000A IL_000b: nop IL_000c: ret } @@ -4971,10 +4978,11 @@ public void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L1|0_0#1, g__L2|0_1, <>c__DisplayClass0_0#1}", "C.<>c__DisplayClass0_0#1: {x}"); - g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L1|0_0#1"); + g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L1|0_0#1", ".ctor"); g.VerifyIL( """ @@ -4984,23 +4992,24 @@ .maxstack 2 IL_0000: nop IL_0001: ldloca.s V_1 IL_0003: ldc.i4.1 - IL_0004: stfld 0x04000001 + IL_0004: stfld 0x04000002 IL_0009: nop IL_000a: nop IL_000b: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000006 + IL_000c: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.2 - IL_0001: call 0x0A000009 + IL_0001: call 0x0A000008 IL_0006: nop IL_0007: ret } @@ -5008,11 +5017,23 @@ .maxstack 8 // Code size 13 (0xd) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000001 - IL_0006: call 0x0A000009 + IL_0001: ldfld 0x04000002 + IL_0006: call 0x0A000008 IL_000b: nop IL_000c: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret + } """); }) .Verify(); @@ -5059,22 +5080,23 @@ public void F(int x) // Static lambda is reused. // A new display class and method is generated for lambda that captures x. g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c, <>c__DisplayClass0_0#1}", "C.<>c: {<>9__0_1, b__0_1}", "C.<>c__DisplayClass0_0#1: {x, b__0#1}"); - g.VerifyMethodDefNames("F", "b__0_0", "b__0_1", ".ctor", "b__0#1"); + g.VerifyMethodDefNames("F", "b__0_0", "b__0_1", ".ctor", ".ctor", "b__0#1"); g.VerifyIL( """ { // Code size 44 (0x2c) .maxstack 2 - IL_0000: newobj 0x06000007 + IL_0000: newobj 0x06000008 IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldarg.1 - IL_0008: stfld 0x04000004 + IL_0008: stfld 0x04000005 IL_000d: nop IL_000e: nop IL_000f: ldsfld 0x04000003 @@ -5086,20 +5108,33 @@ .maxstack 2 IL_002b: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000007 + IL_000c: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.2 - IL_0001: call 0x0A00000B + IL_0001: call 0x0A00000A IL_0006: nop IL_0007: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000004 + IL_000f: ret + } { // Code size 8 (0x8) .maxstack 8 @@ -5112,8 +5147,8 @@ .maxstack 8 // Code size 13 (0xd) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000004 - IL_0006: call 0x0A00000B + IL_0001: ldfld 0x04000005 + IL_0006: call 0x0A00000A IL_000b: nop IL_000c: ret } @@ -5184,36 +5219,37 @@ public void F(int x) validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L1|0_0#1, g__L2|0_1, <>c__DisplayClass0_0#1}", "C.<>c__DisplayClass0_0#1: {x}"); - g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L1|0_0#1"); + g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L1|0_0#1", ".ctor"); - g.VerifyIL( - """ + g.VerifyIL(""" { // Code size 12 (0xc) .maxstack 2 IL_0000: ldloca.s V_0 IL_0002: ldarg.1 - IL_0003: stfld 0x04000001 + IL_0003: stfld 0x04000002 IL_0008: nop IL_0009: nop IL_000a: nop IL_000b: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000006 + IL_000c: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.2 - IL_0001: call 0x0A000009 + IL_0001: call 0x0A000008 IL_0006: nop IL_0007: ret } @@ -5221,11 +5257,23 @@ .maxstack 8 // Code size 13 (0xd) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000001 - IL_0006: call 0x0A000009 + IL_0001: ldfld 0x04000002 + IL_0006: call 0x0A000008 IL_000b: nop IL_000c: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret + } """); }) .Verify(); @@ -5274,11 +5322,12 @@ static void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c, <>c__DisplayClass1_0#1}", "C.<>c: {<>9__1_0, b__1_0}", "C.<>c__DisplayClass1_0#1: {x, b__1#1}"); - g.VerifyMethodDefNames("F", "b__1_0", "b__1_1", ".ctor", "b__1#1"); + g.VerifyMethodDefNames("F", "b__1_0", "b__1_1", ".ctor", ".ctor", "b__1#1"); g.VerifyIL( """ @@ -5301,23 +5350,36 @@ .maxstack 2 { // Code size 31 (0x1f) .maxstack 2 - IL_0000: newobj 0x06000008 + IL_0000: newobj 0x06000009 IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldarg.1 - IL_0008: stfld 0x04000004 + IL_0008: stfld 0x04000005 IL_000d: ldloc.0 - IL_000e: ldftn 0x06000009 + IL_000e: ldftn 0x0600000A IL_0014: newobj 0x0A00000A IL_0019: call 0x06000001 IL_001e: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000B - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000008 + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000004 + IL_000f: ret } { // Code size 8 (0x8) @@ -5331,7 +5393,7 @@ .maxstack 8 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000004 + IL_0001: ldfld 0x04000005 IL_0006: ret } """); @@ -5382,28 +5444,29 @@ class C : B validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__DisplayClass0_0#1}", "C.<>c__DisplayClass0_0#1: {x, y, <.ctor>b__0#1, <.ctor>b__1#1}"); g.VerifyMethodDefNames( - ".ctor", "<.ctor>b__0_0", "<.ctor>b__0_1", ".ctor", "<.ctor>b__0#1", "<.ctor>b__1#1"); + ".ctor", "<.ctor>b__0_0", "<.ctor>b__0_1", ".ctor", ".ctor", "<.ctor>b__0#1", "<.ctor>b__1#1"); g.VerifyIL( """ { // Code size 42 (0x2a) .maxstack 3 - IL_0000: newobj 0x06000007 + IL_0000: newobj 0x06000008 IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldarg.1 - IL_0008: stfld 0x04000004 + IL_0008: stfld 0x04000005 IL_000d: ldloc.0 IL_000e: ldarg.2 - IL_000f: stfld 0x04000005 + IL_000f: stfld 0x04000006 IL_0014: ldarg.0 IL_0015: ldloc.0 - IL_0016: ldftn 0x06000008 + IL_0016: ldftn 0x06000009 IL_001c: newobj 0x0A00000A IL_0021: call 0x06000001 IL_0026: nop @@ -5412,18 +5475,32 @@ .maxstack 3 IL_0029: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000B - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000007 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x700001F4 - IL_0005: newobj 0x0A00000B - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000007 + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000004 + IL_000f: ret } { // Code size 8 (0x8) @@ -5437,14 +5514,14 @@ .maxstack 8 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000004 + IL_0001: ldfld 0x04000005 IL_0006: ret } { // Code size 13 (0xd) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000005 + IL_0001: ldfld 0x04000006 IL_0006: call 0x0A00000D IL_000b: nop IL_000c: ret @@ -5483,36 +5560,50 @@ class B(Func f); validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__DisplayClass0_0#1}", "C.<>c__DisplayClass0_0#1: {x, <.ctor>b__0#1}"); g.VerifyMethodDefNames( - ".ctor", "<.ctor>b__0_0", ".ctor", "<.ctor>b__0#1"); + ".ctor", "<.ctor>b__0_0", ".ctor", ".ctor", "<.ctor>b__0#1"); g.VerifyIL( """ { // Code size 33 (0x21) .maxstack 3 - IL_0000: newobj 0x06000006 + IL_0000: newobj 0x06000007 IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldarg.1 - IL_0008: stfld 0x04000003 + IL_0008: stfld 0x04000004 IL_000d: ldarg.0 IL_000e: ldloc.0 - IL_000f: ldftn 0x06000007 + IL_000f: ldftn 0x06000008 IL_0015: newobj 0x0A000008 IL_001a: call 0x06000001 IL_001f: nop IL_0020: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000006 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret } { // Code size 8 (0x8) @@ -5526,7 +5617,7 @@ .maxstack 8 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000003 + IL_0001: ldfld 0x04000004 IL_0006: ret } """); @@ -5563,34 +5654,48 @@ public void Capture_TopLevelArgs() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "Program: {<>c__DisplayClass0_0#1}", "Program.<>c__DisplayClass0_0#1: {args, <
$>b__0#1}"); g.VerifyMethodDefNames( - "
$", "<
$>b__0_0", ".ctor", "<
$>b__0#1"); + "
$", "<
$>b__0_0", ".ctor", ".ctor", "<
$>b__0#1"); g.VerifyIL( """ { // Code size 27 (0x1b) .maxstack 2 - IL_0000: newobj 0x06000006 + IL_0000: newobj 0x06000007 IL_0005: stloc.1 IL_0006: ldloc.1 IL_0007: ldarg.0 - IL_0008: stfld 0x04000003 + IL_0008: stfld 0x04000004 IL_000d: ldloc.1 - IL_000e: ldftn 0x06000007 + IL_000e: ldftn 0x06000008 IL_0014: newobj 0x0A000008 IL_0019: stloc.2 IL_001a: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000006 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret } { // Code size 8 (0x8) @@ -5604,7 +5709,7 @@ .maxstack 8 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000003 + IL_0001: ldfld 0x04000004 IL_0006: ret } """); @@ -5680,10 +5785,11 @@ public void F() // Static lambda is reused. // A new display class and method is generated for lambda that captures x. g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {b__1_0#1, <>c}", "C.<>c: {<>9__1_1, b__1_1}"); - g.VerifyMethodDefNames("F", "b__1_0", "b__1_1", "b__1_0#1"); + g.VerifyMethodDefNames("F", "b__1_0", "b__1_1", "b__1_0#1", ".ctor"); g.VerifyIL( """ @@ -5701,17 +5807,18 @@ .maxstack 8 IL_001e: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000008 + IL_000c: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.1 - IL_0001: call 0x0A00000B + IL_0001: call 0x0A00000A IL_0006: nop IL_0007: ret } @@ -5720,10 +5827,22 @@ .maxstack 8 .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld 0x04000001 - IL_0006: call 0x0A00000B + IL_0006: call 0x0A00000A IL_000b: nop IL_000c: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000005 + IL_000f: ret + } """); }) .Verify(); @@ -5796,9 +5915,10 @@ public void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L1|1_0#1, g__L2|1_1}"); - g.VerifyMethodDefNames("F", "g__L1|1_0", "g__L2|1_1", "g__L1|1_0#1"); + g.VerifyMethodDefNames("F", "g__L1|1_0", "g__L2|1_1", "g__L1|1_0#1", ".ctor"); g.VerifyIL( """ @@ -5811,17 +5931,18 @@ .maxstack 8 IL_0003: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000006 + IL_000c: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.1 - IL_0001: call 0x0A000009 + IL_0001: call 0x0A000008 IL_0006: nop IL_0007: ret } @@ -5830,10 +5951,22 @@ .maxstack 8 .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld 0x04000001 - IL_0006: call 0x0A000009 + IL_0006: call 0x0A000008 IL_000b: nop IL_000c: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret + } """); }) .Verify(); @@ -5880,10 +6013,11 @@ public void F() // Static lambda is reused. // A new display class and method is generated for lambda that captures x. g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {b__1_0#1, <>c}", "C.<>c: {<>9__1_1, b__1_1}"); - g.VerifyMethodDefNames("F", "b__1_0", "b__1_1", "b__1_0#1"); + g.VerifyMethodDefNames("F", "b__1_0", "b__1_1", "b__1_0#1", ".ctor"); g.VerifyIL( """ @@ -5901,17 +6035,18 @@ .maxstack 8 IL_001e: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000B - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000008 + IL_000c: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.2 - IL_0001: call 0x0A00000C + IL_0001: call 0x0A00000B IL_0006: nop IL_0007: ret } @@ -5920,10 +6055,22 @@ .maxstack 8 .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld 0x04000004 - IL_0006: call 0x0A00000C + IL_0006: call 0x0A00000B IL_000b: nop IL_000c: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000C + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000005 + IL_000f: ret + } """); }) .Verify(); @@ -5968,9 +6115,10 @@ public void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L1|1_0#1, g__L2|1_1}"); - g.VerifyMethodDefNames("F", "g__L1|1_0", "g__L2|1_1", "g__L1|1_0#1"); + g.VerifyMethodDefNames("F", "g__L1|1_0", "g__L2|1_1", "g__L1|1_0#1", ".ctor"); g.VerifyIL( """ @@ -5983,17 +6131,18 @@ .maxstack 8 IL_0003: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000006 + IL_000c: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.1 - IL_0001: call 0x0A00000A + IL_0001: call 0x0A000009 IL_0006: nop IL_0007: ret } @@ -6002,10 +6151,22 @@ .maxstack 8 .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld 0x04000001 - IL_0006: call 0x0A00000A + IL_0006: call 0x0A000009 IL_000b: nop IL_000c: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000A + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret + } """); }) .Verify(); @@ -6239,6 +6400,7 @@ public void F() { }) .AddGeneration( + // 1 source: """ using System; class C @@ -6257,10 +6419,11 @@ public void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c}", "C.<>c: {<>9__0_0#1, b__0_0#1}"); - g.VerifyMethodDefNames("F", "b__0", ".cctor", ".ctor", "b__0_0#1"); + g.VerifyMethodDefNames("F", "b__0", ".ctor", ".cctor", ".ctor", "b__0_0#1"); g.VerifyIL( """ @@ -6270,26 +6433,39 @@ .maxstack 2 IL_0000: nop IL_0001: ldc.i4.1 IL_0002: stloc.1 - IL_0003: ldsfld 0x04000003 + IL_0003: ldsfld 0x04000004 IL_0008: brtrue.s IL_001f - IL_000a: ldsfld 0x04000002 - IL_000f: ldftn 0x06000007 + IL_000a: ldsfld 0x04000003 + IL_000f: ldftn 0x06000008 IL_0015: newobj 0x0A000008 - IL_001a: stsfld 0x04000003 + IL_001a: stsfld 0x04000004 IL_001f: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000005 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret } { // Code size 11 (0xb) .maxstack 8 - IL_0000: newobj 0x06000006 - IL_0005: stsfld 0x04000002 + IL_0000: newobj 0x06000007 + IL_0005: stsfld 0x04000003 IL_000a: ret } { @@ -6310,7 +6486,8 @@ .maxstack 8 } """); }) - .AddGeneration( // resume capture + .AddGeneration( + // 2: resume capture source: """ using System; class C @@ -6329,10 +6506,14 @@ public void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__DisplayClass0_0#2, <>c}", "C.<>c: {<>9__0_0#1, b__0_0#1}", "C.<>c__DisplayClass0_0#2: {x, b__0#2}"); + // was emitted in previous generation and TypeRef is emitted to the current one: + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Console"); + g.VerifyMethodDefNames("F", "b__0_0#1", ".ctor", "b__0#2"); g.VerifyIL( @@ -6340,27 +6521,28 @@ public void F() { // Code size 16 (0x10) .maxstack 2 - IL_0000: newobj 0x06000008 + IL_0000: newobj 0x06000009 IL_0005: stloc.2 IL_0006: nop IL_0007: ldloc.2 IL_0008: ldc.i4.1 - IL_0009: stfld 0x04000004 + IL_0009: stfld 0x04000005 IL_000e: nop IL_000f: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x700001F5 - IL_0005: newobj 0x0A00000D - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000005 + IL_000b: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldarg.0 - IL_0001: call 0x0A00000E + IL_0001: call 0x0A00000D IL_0006: nop IL_0007: ret } @@ -6368,10 +6550,10 @@ .maxstack 8 // Code size 15 (0xf) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000004 + IL_0001: ldfld 0x04000005 IL_0006: ldc.i4.3 IL_0007: add - IL_0008: call 0x0A00000F + IL_0008: call 0x0A00000E IL_000d: nop IL_000e: ret } @@ -6454,9 +6636,10 @@ public void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L|0_0#1, g__L|0_1#1}"); - g.VerifyMethodDefNames("F", "g__L|0_0", "g__L|0_1", "g__L|0_0#1", "g__L|0_1#1"); + g.VerifyMethodDefNames("F", "g__L|0_0", "g__L|0_1", "g__L|0_0#1", "g__L|0_1#1", ".ctor"); g.VerifyIL( """ @@ -6479,24 +6662,26 @@ .maxstack 1 IL_000d: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000007 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x700001F4 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000007 + IL_000b: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.1 - IL_0001: call 0x0A000009 + IL_0001: call 0x0A000008 IL_0006: nop IL_0007: ret } @@ -6504,10 +6689,22 @@ .maxstack 8 // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.2 - IL_0001: call 0x0A000009 + IL_0001: call 0x0A000008 IL_0006: nop IL_0007: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret + } """); }) .Verify(); @@ -6579,6 +6776,7 @@ .maxstack 1 }) .AddGeneration( + // 1 source: """ using System; class C @@ -6601,10 +6799,11 @@ public void F() // Static lambda is reused. // A new display class and method is generated for lambda that captured x. g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c}", "C.<>c: {<>9__1_0#1, <>9__1_1, b__1_0#1, b__1_1}"); - g.VerifyMethodDefNames("F", "b__1_0", "b__1_1", "b__1_0#1"); + g.VerifyMethodDefNames("F", "b__1_0", "b__1_1", ".ctor", "b__1_0#1"); g.VerifyIL( """ @@ -6612,12 +6811,12 @@ public void F() // Code size 58 (0x3a) .maxstack 8 IL_0000: nop - IL_0001: ldsfld 0x04000004 + IL_0001: ldsfld 0x04000005 IL_0006: brtrue.s IL_001d IL_0008: ldsfld 0x04000002 - IL_000d: ldftn 0x06000007 + IL_000d: ldftn 0x06000008 IL_0013: newobj 0x0A000009 - IL_0018: stsfld 0x04000004 + IL_0018: stsfld 0x04000005 IL_001d: ldsfld 0x04000003 IL_0022: brtrue.s IL_0039 IL_0024: ldsfld 0x04000002 @@ -6627,25 +6826,38 @@ .maxstack 8 IL_0039: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000007 + IL_000c: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.1 - IL_0001: call 0x0A00000B + IL_0001: call 0x0A00000A IL_0006: nop IL_0007: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000004 + IL_000f: ret + } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.0 - IL_0001: call 0x0A00000B + IL_0001: call 0x0A00000A IL_0006: nop IL_0007: ret } @@ -6740,9 +6952,10 @@ public void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L1|1_0#1, g__L2|1_1}"); - g.VerifyMethodDefNames("F", "g__L1|1_0", "g__L2|1_1", "g__L1|1_0#1"); + g.VerifyMethodDefNames("F", "g__L1|1_0", "g__L2|1_1", "g__L1|1_0#1", ".ctor"); g.VerifyIL( """ @@ -6755,17 +6968,18 @@ .maxstack 8 IL_0003: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000006 + IL_000c: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.1 - IL_0001: call 0x0A000009 + IL_0001: call 0x0A000008 IL_0006: nop IL_0007: ret } @@ -6773,10 +6987,22 @@ .maxstack 8 // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.0 - IL_0001: call 0x0A000009 + IL_0001: call 0x0A000008 IL_0006: nop IL_0007: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret + } """); }) .Verify(); @@ -6801,6 +7027,7 @@ public void F() { }) .AddGeneration( + // 1 source: """ using System; class C @@ -6825,6 +7052,8 @@ public void F() g.VerifyMethodDefNames("F", ".ctor", "b__0#1"); + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Console"); + g.VerifyIL( """ { @@ -6858,7 +7087,8 @@ .maxstack 8 } """); }) - .AddGeneration( // remove closure + .AddGeneration( + // 2: remove closure source: """ using System; class C @@ -6876,10 +7106,14 @@ public void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__DisplayClass0#1_0#1}", "C.<>c__DisplayClass0#1_0#1: {x, b__0#1}"); - g.VerifyMethodDefNames("F", "b__0#1"); + // is emitted as a definition in this generation + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Exception"); + + g.VerifyMethodDefNames("F", "b__0#1", ".ctor"); g.VerifyIL(""" { @@ -6891,11 +7125,24 @@ .maxstack 1 IL_0003: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000009 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000005 + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret } """); }) @@ -6921,6 +7168,7 @@ public void F() { }) .AddGeneration( + // 1 source: """ using System; class C @@ -6968,7 +7216,8 @@ .maxstack 8 } """); }) - .AddGeneration( // remove closure + .AddGeneration( + // 2: remove closure source: """ using System; class C @@ -6986,10 +7235,11 @@ public void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L|0#1_0#1, <>c__DisplayClass0#1_0#1}", "C.<>c__DisplayClass0#1_0#1: {x}"); - g.VerifyMethodDefNames("F", "g__L|0#1_0#1"); + g.VerifyMethodDefNames("F", "g__L|0#1_0#1", ".ctor"); g.VerifyIL(""" { @@ -7001,11 +7251,24 @@ .maxstack 1 IL_0003: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000009 - IL_0005: newobj 0x0A000007 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000004 + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret } """); }) @@ -7088,11 +7351,12 @@ void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__DisplayClass1_0, <>c__DisplayClass1_1#1}", "C.<>c__DisplayClass1_1#1: {x1, CS$<>8__locals1, b__1#1}", "C.<>c__DisplayClass1_0: {x0, b__0}"); - g.VerifyMethodDefNames("F", "b__0", "b__1", ".ctor", "b__1#1"); + g.VerifyMethodDefNames("F", "b__0", "b__1", ".ctor", ".ctor", "b__1#1"); g.VerifyIL( """ @@ -7106,25 +7370,25 @@ .maxstack 3 IL_0008: ldloc.0 IL_0009: ldc.i4.0 IL_000a: stfld 0x04000001 - IL_000f: newobj 0x06000008 + IL_000f: newobj 0x06000009 IL_0014: stloc.2 IL_0015: ldloc.2 IL_0016: ldloc.0 - IL_0017: stfld 0x04000004 + IL_0017: stfld 0x04000005 IL_001c: nop IL_001d: ldloc.2 IL_001e: ldc.i4.0 - IL_001f: stfld 0x04000003 + IL_001f: stfld 0x04000004 IL_0024: ldarg.0 IL_0025: ldloc.2 - IL_0026: ldfld 0x04000004 + IL_0026: ldfld 0x04000005 IL_002b: ldftn 0x06000005 IL_0031: newobj 0x0A000008 IL_0036: call 0x06000001 IL_003b: nop IL_003c: ldarg.0 IL_003d: ldloc.2 - IL_003e: ldftn 0x06000009 + IL_003e: ldftn 0x0600000A IL_0044: newobj 0x0A000008 IL_0049: call 0x06000001 IL_004e: nop @@ -7140,11 +7404,24 @@ .maxstack 8 IL_0006: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000008 + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret } { // Code size 8 (0x8) @@ -7158,10 +7435,10 @@ .maxstack 8 // Code size 19 (0x13) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000004 + IL_0001: ldfld 0x04000005 IL_0006: ldfld 0x04000001 IL_000b: ldarg.0 - IL_000c: ldfld 0x04000003 + IL_000c: ldfld 0x04000004 IL_0011: add IL_0012: ret } @@ -7266,11 +7543,12 @@ void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L1|0_0, g__L2|0_1#1, <>c__DisplayClass0_0, <>c__DisplayClass0_1}", "C.<>c__DisplayClass0_0: {x0}", "C.<>c__DisplayClass0_1: {x1}"); - g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L2|0_1#1"); + g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L2|0_1#1", ".ctor"); g.VerifyIL( """ @@ -7300,11 +7578,12 @@ .maxstack 8 IL_0006: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000007 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000006 + IL_000b: throw } { // Code size 14 (0xe) @@ -7316,6 +7595,18 @@ .maxstack 8 IL_000c: add IL_000d: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000007 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret + } """); }) .Verify(); @@ -7398,11 +7689,12 @@ void F() { // closure #0 is preserved, a new closure #1 is created as it has a different parent now: g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__DisplayClass1_0, <>c__DisplayClass1_1#1}", "C.<>c__DisplayClass1_0: {x0, b__0}", "C.<>c__DisplayClass1_1#1: {x1, b__1#1}"); - g.VerifyMethodDefNames("F", "b__0", "b__1", ".ctor", "b__1#1"); + g.VerifyMethodDefNames("F", "b__0", "b__1", ".ctor", ".ctor", "b__1#1"); g.VerifyIL( """ @@ -7416,19 +7708,19 @@ .maxstack 2 IL_0008: ldloc.0 IL_0009: ldc.i4.0 IL_000a: stfld 0x04000001 - IL_000f: newobj 0x06000008 + IL_000f: newobj 0x06000009 IL_0014: stloc.2 IL_0015: nop IL_0016: ldloc.2 IL_0017: ldc.i4.0 - IL_0018: stfld 0x04000004 + IL_0018: stfld 0x04000005 IL_001d: ldloc.0 IL_001e: ldftn 0x06000005 IL_0024: newobj 0x0A000008 IL_0029: call 0x06000001 IL_002e: nop IL_002f: ldloc.2 - IL_0030: ldftn 0x06000009 + IL_0030: ldftn 0x0600000A IL_0036: newobj 0x0A000008 IL_003b: call 0x06000001 IL_0040: nop @@ -7444,11 +7736,24 @@ .maxstack 8 IL_0006: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000008 + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000004 + IL_000f: ret } { // Code size 8 (0x8) @@ -7462,7 +7767,7 @@ .maxstack 8 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000004 + IL_0001: ldfld 0x04000005 IL_0006: ret } """); @@ -7569,11 +7874,12 @@ void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L1|0_0, g__L2|0_1#1, <>c__DisplayClass0_0, <>c__DisplayClass0_1}", "C.<>c__DisplayClass0_1: {x1}", "C.<>c__DisplayClass0_0: {x0}"); - g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L2|0_1#1"); + g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L2|0_1#1", ".ctor"); g.VerifyIL( """ @@ -7603,11 +7909,12 @@ .maxstack 8 IL_0006: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000007 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000006 + IL_000b: throw } { // Code size 7 (0x7) @@ -7616,6 +7923,18 @@ .maxstack 8 IL_0001: ldfld 0x04000002 IL_0006: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000007 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret + } """); }) .Verify(); @@ -7683,6 +8002,7 @@ void F() { // closure #0 is preserved, new closures #1 and #2 are created: g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__DisplayClass1_0, <>c__DisplayClass1_1#1, <>c__DisplayClass1_2#1}", "C.<>c__DisplayClass1_0: {x, b__0}", "C.<>c__DisplayClass1_1#1: {y, CS$<>8__locals1}", @@ -7694,6 +8014,7 @@ void F() "b__1", ".ctor", ".ctor", + ".ctor", "b__1#1", "b__2#1"); @@ -7708,38 +8029,38 @@ .maxstack 2 IL_0008: ldloc.0 IL_0009: ldc.i4.1 IL_000a: stfld 0x04000001 - IL_000f: newobj 0x06000008 + IL_000f: newobj 0x06000009 IL_0014: stloc.3 IL_0015: ldloc.3 IL_0016: ldloc.0 - IL_0017: stfld 0x04000005 + IL_0017: stfld 0x04000006 IL_001c: nop IL_001d: ldloc.3 IL_001e: ldc.i4.2 - IL_001f: stfld 0x04000004 - IL_0024: newobj 0x06000009 + IL_001f: stfld 0x04000005 + IL_0024: newobj 0x0600000A IL_0029: stloc.s V_4 IL_002b: ldloc.s V_4 IL_002d: ldloc.3 - IL_002e: stfld 0x04000007 + IL_002e: stfld 0x04000008 IL_0033: nop IL_0034: ldloc.s V_4 IL_0036: ldc.i4.3 - IL_0037: stfld 0x04000006 + IL_0037: stfld 0x04000007 IL_003c: ldloc.s V_4 - IL_003e: ldfld 0x04000007 - IL_0043: ldfld 0x04000005 + IL_003e: ldfld 0x04000008 + IL_0043: ldfld 0x04000006 IL_0048: ldftn 0x06000005 IL_004e: newobj 0x0A000008 IL_0053: call 0x06000001 IL_0058: nop IL_0059: ldloc.s V_4 - IL_005b: ldftn 0x0600000A + IL_005b: ldftn 0x0600000B IL_0061: newobj 0x0A000008 IL_0066: call 0x06000001 IL_006b: nop IL_006c: ldloc.s V_4 - IL_006e: ldftn 0x0600000B + IL_006e: ldftn 0x0600000C IL_0074: newobj 0x0A000008 IL_0079: call 0x06000001 IL_007e: nop @@ -7756,11 +8077,24 @@ .maxstack 8 IL_0006: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000008 + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000004 + IL_000f: ret } { // Code size 8 (0x8) @@ -7774,10 +8108,10 @@ .maxstack 8 // Code size 24 (0x18) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000006 + IL_0001: ldfld 0x04000007 IL_0006: ldarg.0 - IL_0007: ldfld 0x04000007 - IL_000c: ldfld 0x04000005 + IL_0007: ldfld 0x04000008 + IL_000c: ldfld 0x04000006 IL_0011: ldfld 0x04000001 IL_0016: add IL_0017: ret @@ -7786,15 +8120,15 @@ .maxstack 8 // Code size 36 (0x24) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000006 + IL_0001: ldfld 0x04000007 IL_0006: ldarg.0 - IL_0007: ldfld 0x04000007 - IL_000c: ldfld 0x04000005 + IL_0007: ldfld 0x04000008 + IL_000c: ldfld 0x04000006 IL_0011: ldfld 0x04000001 IL_0016: add IL_0017: ldarg.0 - IL_0018: ldfld 0x04000007 - IL_001d: ldfld 0x04000004 + IL_0018: ldfld 0x04000008 + IL_001d: ldfld 0x04000005 IL_0022: add IL_0023: ret } @@ -8084,11 +8418,12 @@ public void F() { // Lambda moved from closure 0 to 1: g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__DisplayClass1_0, <>c__DisplayClass1_1}", "C.<>c__DisplayClass1_0: {x, b__0}", "C.<>c__DisplayClass1_1: {y, b__1, b__2#1}"); - g.VerifyMethodDefNames("F", "b__0", "b__2", "b__1", "b__2#1"); + g.VerifyMethodDefNames("F", "b__0", "b__2", "b__1", ".ctor", "b__2#1"); g.VerifyIL( """ @@ -8118,7 +8453,7 @@ .maxstack 2 IL_003a: call 0x06000001 IL_003f: nop IL_0040: ldloc.1 - IL_0041: ldftn 0x06000009 + IL_0041: ldftn 0x0600000A IL_0047: newobj 0x0A000008 IL_004c: call 0x06000001 IL_0051: nop @@ -8133,11 +8468,12 @@ .maxstack 8 IL_0006: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000009 + IL_000b: throw } { // Code size 7 (0x7) @@ -8146,6 +8482,18 @@ .maxstack 8 IL_0001: ldfld 0x04000002 IL_0006: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret + } { // Code size 9 (0x9) .maxstack 8 @@ -8268,11 +8616,12 @@ public void F() { // Lambda moved from closure 0 to 1: g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L1|0_0, g__L2|0_1, g__L3|0_2#1, <>c__DisplayClass0_0, <>c__DisplayClass0_1}", "C.<>c__DisplayClass0_0: {x}", "C.<>c__DisplayClass0_1: {y}"); - g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L3|0_2", "g__L3|0_2#1"); + g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L3|0_2", "g__L3|0_2#1", ".ctor"); g.VerifyIL( """ @@ -8308,11 +8657,12 @@ .maxstack 8 IL_0006: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000007 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000007 + IL_000b: throw } { // Code size 9 (0x9) @@ -8323,6 +8673,18 @@ .maxstack 8 IL_0007: add IL_0008: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000007 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret + } """); }) .Verify(); @@ -8418,11 +8780,12 @@ public void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L1|1_0#1, <>c__DisplayClass1_0#1, <>c__DisplayClass1_1}", "C.<>c__DisplayClass1_0#1: {x}", "C.<>c__DisplayClass1_1: {y, b__1, b__2#1}"); - g.VerifyMethodDefNames("F", "g__L1|0", "b__2", "b__1", "g__L1|1_0#1", "b__2#1"); + g.VerifyMethodDefNames("F", "g__L1|0", "b__2", "b__1", "g__L1|1_0#1", ".ctor", "b__2#1"); g.VerifyIL( """ @@ -8432,7 +8795,7 @@ .maxstack 2 IL_0000: nop IL_0001: ldloca.s V_2 IL_0003: ldc.i4.1 - IL_0004: stfld 0x04000003 + IL_0004: stfld 0x04000004 IL_0009: newobj 0x06000007 IL_000e: stloc.1 IL_000f: nop @@ -8446,7 +8809,7 @@ .maxstack 2 IL_0024: call 0x06000001 IL_0029: nop IL_002a: ldloc.1 - IL_002b: ldftn 0x0600000A + IL_002b: ldftn 0x0600000B IL_0031: newobj 0x0A000008 IL_0036: call 0x06000001 IL_003b: nop @@ -8454,18 +8817,20 @@ .maxstack 2 IL_003d: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x0600000A + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x700001F4 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x0600000A + IL_000b: throw } { // Code size 7 (0x7) @@ -8478,9 +8843,21 @@ .maxstack 8 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000003 + IL_0001: ldfld 0x04000004 IL_0006: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret + } { // Code size 9 (0x9) .maxstack 8 @@ -8605,14 +8982,14 @@ public void F() { // Lambda moved from closure 0 to 1: g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L1|1_0, <>c__DisplayClass1_0, <>c__DisplayClass1_1}", "C.<>c__DisplayClass1_0: {x}", "C.<>c__DisplayClass1_1: {y, b__1, g__L3|2#1}"); - g.VerifyMethodDefNames("F", "g__L1|1_0", "g__L3|1_2", "b__1", "g__L3|2#1"); + g.VerifyMethodDefNames("F", "g__L1|1_0", "g__L3|1_2", "b__1", ".ctor", "g__L3|2#1"); - g.VerifyIL( - """ + g.VerifyIL(""" { // Code size 45 (0x2d) .maxstack 2 @@ -8644,11 +9021,12 @@ .maxstack 8 IL_0006: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000008 + IL_000b: throw } { // Code size 7 (0x7) @@ -8657,6 +9035,18 @@ .maxstack 8 IL_0001: ldfld 0x04000002 IL_0006: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret + } { // Code size 9 (0x9) .maxstack 8 @@ -8827,10 +9217,11 @@ public void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L|0_0#1, <>c__DisplayClass0_0#1}", "C.<>c__DisplayClass0_0#1: {x, y}"); - g.VerifyMethodDefNames("F", "g__L|0_0", "g__L|0_0#1"); + g.VerifyMethodDefNames("F", "g__L|0_0", "g__L|0_0#1", ".ctor"); g.VerifyIL(""" { @@ -8839,30 +9230,43 @@ .maxstack 2 IL_0000: nop IL_0001: ldloca.s V_2 IL_0003: ldc.i4.1 - IL_0004: stfld 0x04000002 + IL_0004: stfld 0x04000003 IL_0009: ldloca.s V_2 IL_000b: ldc.i4.2 - IL_000c: stfld 0x04000003 + IL_000c: stfld 0x04000004 IL_0011: nop IL_0012: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000007 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000005 + IL_000c: throw } { // Code size 14 (0xe) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000002 + IL_0001: ldfld 0x04000003 IL_0006: ldarg.0 - IL_0007: ldfld 0x04000003 + IL_0007: ldfld 0x04000004 IL_000c: add IL_000d: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000007 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret + } """); }) .Verify(); @@ -9029,11 +9433,12 @@ public void F() { g.VerifySynthesizedMembers(displayTypeKind: true, [ + "System.Runtime.CompilerServices.HotReloadException", "struct C.<>c__DisplayClass1_0#1: {x}", "class C: {g__L|1_0#1, <>c__DisplayClass1_0#1}" ]); - g.VerifyMethodDefNames("F", "g__L|0", "b__1", "g__L|1_0#1"); + g.VerifyMethodDefNames("F", "g__L|0", "b__1", "g__L|1_0#1", ".ctor"); g.VerifyIL( """ @@ -9043,46 +9448,66 @@ .maxstack 2 IL_0000: nop IL_0001: ldloca.s V_1 IL_0003: ldc.i4.1 - IL_0004: stfld 0x04000002 + IL_0004: stfld 0x04000003 IL_0009: nop IL_000a: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000008 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x700001F4 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000008 + IL_000b: throw } { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000002 + IL_0001: ldfld 0x04000003 IL_0006: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret + } """); g.VerifyEncLogDefinitions( [ Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddField), Row(2, TableIndex.Field, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(2, TableIndex.NestedClass, EditAndContinueOperation.Default) ]); }) @@ -9139,11 +9564,12 @@ public void F() { g.VerifySynthesizedMembers(displayTypeKind: true, [ + "System.Runtime.CompilerServices.HotReloadException", "struct C.<>c__DisplayClass1_0#1: {x}", "class C: {g__L|1_0#1, <>c__DisplayClass1_0#1}" ]); - g.VerifyMethodDefNames("F", "g__L|0", "g__L|1_0#1"); + g.VerifyMethodDefNames("F", "g__L|0", "g__L|1_0#1", ".ctor"); g.VerifyIL( """ @@ -9153,24 +9579,37 @@ .maxstack 2 IL_0000: nop IL_0001: ldloca.s V_1 IL_0003: ldc.i4.1 - IL_0004: stfld 0x04000002 + IL_0004: stfld 0x04000003 IL_0009: nop IL_000a: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000007 + IL_000c: throw } { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000002 + IL_0001: ldfld 0x04000003 IL_0006: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret + } """); }) .Verify(); @@ -9204,6 +9643,7 @@ public void F() }) .AddGeneration( + // 1 source: """ using System; class C @@ -9226,37 +9666,52 @@ public void F() { g.VerifySynthesizedMembers(displayTypeKind: true, [ + "System.Runtime.CompilerServices.HotReloadException", "class C: {<>c__DisplayClass1_0#1}", "class C.<>c__DisplayClass1_0#1: {x, g__L|0#1, b__1#1}" ]); - g.VerifyMethodDefNames("F", "g__L|1_0", ".ctor", "g__L|0#1", "b__1#1"); + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Exception", "Func`1"); - g.VerifyIL( - """ + g.VerifyMethodDefNames("F", "g__L|1_0", ".ctor", ".ctor", "g__L|0#1", "b__1#1"); + + g.VerifyIL(""" { // Code size 34 (0x22) .maxstack 2 - IL_0000: newobj 0x06000005 + IL_0000: newobj 0x06000006 IL_0005: stloc.1 IL_0006: nop IL_0007: ldloc.1 IL_0008: ldc.i4.1 - IL_0009: stfld 0x04000002 + IL_0009: stfld 0x04000003 IL_000e: nop IL_000f: ldloc.1 - IL_0010: ldftn 0x06000007 + IL_0010: ldftn 0x06000008 IL_0016: newobj 0x0A000007 IL_001b: call 0x06000001 IL_0020: nop IL_0021: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000005 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret } { // Code size 8 (0x8) @@ -9270,7 +9725,7 @@ .maxstack 8 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000002 + IL_0001: ldfld 0x04000003 IL_0006: ret } """); @@ -9328,37 +9783,53 @@ public void F() { g.VerifySynthesizedMembers(displayTypeKind: true, [ + "System.Runtime.CompilerServices.HotReloadException", "class C: {<>c__DisplayClass1_0#1}", "class C.<>c__DisplayClass1_0#1: {x, g__L|0#1}" ]); - g.VerifyMethodDefNames("F", "g__L|1_0", ".ctor", "g__L|0#1"); + g.VerifyMethodDefNames("F", "g__L|1_0", ".ctor", ".ctor", "g__L|0#1"); + + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Exception", "Func`1"); g.VerifyIL( """ - { + { // Code size 34 (0x22) .maxstack 2 - IL_0000: newobj 0x06000005 + IL_0000: newobj 0x06000006 IL_0005: stloc.1 IL_0006: nop IL_0007: ldloc.1 IL_0008: ldc.i4.1 - IL_0009: stfld 0x04000002 + IL_0009: stfld 0x04000003 IL_000e: nop IL_000f: ldloc.1 - IL_0010: ldftn 0x06000006 + IL_0010: ldftn 0x06000007 IL_0016: newobj 0x0A000007 IL_001b: call 0x06000001 IL_0020: nop IL_0021: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.s -5 + IL_0007: newobj 0x06000005 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret } { // Code size 8 (0x8) @@ -9372,7 +9843,7 @@ .maxstack 8 // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000002 + IL_0001: ldfld 0x04000003 IL_0006: ret } """); diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinuePdbTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinuePdbTests.cs index 4ab420ddd6beb..134c4c0ec6da4 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinuePdbTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinuePdbTests.cs @@ -274,6 +274,7 @@ void G() SemanticEdit.Create(SemanticEditKind.Insert, null, b2))); diff2.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c}", "C.<>c: {<>9__3_3#1, <>9__3_1, b__3_1, b__3_3#1, <>9__3_0, <>9__3_2, b__3_0, b__3_2}"); @@ -282,6 +283,9 @@ void G() CheckEncLogDefinitions(reader2, Row(5, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(6, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(6, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), @@ -290,7 +294,10 @@ void G() Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(11, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default)); + Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(13, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); if (format == DebugInformationFormat.PortablePdb) { @@ -304,7 +311,8 @@ void G() Handle(9, TableIndex.MethodDebugInformation), Handle(10, TableIndex.MethodDebugInformation), Handle(11, TableIndex.MethodDebugInformation), - Handle(12, TableIndex.MethodDebugInformation)); + Handle(12, TableIndex.MethodDebugInformation), + Handle(13, TableIndex.MethodDebugInformation)); } diff2.VerifyPdb(Enumerable.Range(0x06000001, 20), @" diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs index 028ff1e8ff7d4..be32d75c9af80 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs @@ -4,11 +4,10 @@ #nullable disable -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.CSharp.UnitTests; @@ -16,12 +15,14 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests { - public class EditAndContinueStateMachineTests : EditAndContinueTestBase + public class EditAndContinueStateMachineTests(ITestOutputHelper logger) : EditAndContinueTestBase { + private readonly ITestOutputHelper _logger = logger; + [Fact] [WorkItem(1068894, "DevDiv"), WorkItem(1137300, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1137300")] public void AddIteratorMethod() @@ -224,7 +225,7 @@ static async Task F() return 20; } }"; - var compilation0 = CreateCompilationWithMscorlib45(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); var compilation1 = compilation0.WithSource(source1); var v0 = CompileAndVerify(compilation0, emitOptions: EmitOptions.Default.WithDebugInformationFormat(format)); @@ -341,7 +342,7 @@ static IEnumerable F() yield return 2; } }"; - var compilation0 = CreateCompilationWithMscorlib45(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); var compilation1 = compilation0.WithSource(source1); var v0 = CompileAndVerify(compilation0); @@ -443,7 +444,7 @@ static async Task F() return await Task.FromResult(1); } }"; - var compilation0 = CreateCompilationWithMscorlib45(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); var compilation1 = compilation0.WithSource(source1); var v0 = CompileAndVerify(compilation0); @@ -516,7 +517,7 @@ static IEnumerable F() return new int[] { 1, 2, 3 }; } }"; - var compilation0 = CreateCompilationWithMscorlib45(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); var compilation1 = compilation0.WithSource(source1); var v0 = CompileAndVerify(compilation0); @@ -567,7 +568,7 @@ static Task F() return Task.FromResult(1); } }"; - var compilation0 = CreateCompilationWithMscorlib45(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); var compilation1 = compilation0.WithSource(source1); var v0 = CompileAndVerify(compilation0); @@ -1115,7 +1116,7 @@ static async Task F() End(); } }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -1540,7 +1541,7 @@ static void End() {} End(); }); }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -1834,93 +1835,94 @@ .locals init (int V_0, }"); diff1.VerifyIL("C.<>c.<<-ctor>b__7_1>d.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" -{ - // Code size 176 (0xb0) - .maxstack 3 - .locals init (int V_0, - System.Runtime.CompilerServices.TaskAwaiter V_1, - C.<>c.<<-ctor>b__7_1>d V_2, - System.Exception V_3) - IL_0000: ldarg.0 - IL_0001: ldfld ""int C.<>c.<<-ctor>b__7_1>d.<>1__state"" - IL_0006: stloc.0 - .try - { - IL_0007: ldloc.0 - IL_0008: ldc.i4.1 - IL_0009: beq.s IL_000d - IL_000b: br.s IL_000f - IL_000d: br.s IL_0057 - IL_000f: ldloc.0 - IL_0010: ldc.i4.0 - IL_0011: blt.s IL_001e - IL_0013: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" - IL_0018: newobj ""System.InvalidOperationException..ctor(string)"" - IL_001d: throw - IL_001e: nop - IL_001f: call ""System.Threading.Tasks.Task C.M2()"" - IL_0024: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0029: stloc.1 - IL_002a: ldloca.s V_1 - IL_002c: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0031: brtrue.s IL_0073 - IL_0033: ldarg.0 - IL_0034: ldc.i4.1 - IL_0035: dup - IL_0036: stloc.0 - IL_0037: stfld ""int C.<>c.<<-ctor>b__7_1>d.<>1__state"" - IL_003c: ldarg.0 - IL_003d: ldloc.1 - IL_003e: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.<>c.<<-ctor>b__7_1>d.<>u__1"" - IL_0043: ldarg.0 - IL_0044: stloc.2 - IL_0045: ldarg.0 - IL_0046: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<>c.<<-ctor>b__7_1>d.<>t__builder"" - IL_004b: ldloca.s V_1 - IL_004d: ldloca.s V_2 - IL_004f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedc.<<-ctor>b__7_1>d>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.<>c.<<-ctor>b__7_1>d)"" - IL_0054: nop - IL_0055: leave.s IL_00af - IL_0057: ldarg.0 - IL_0058: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.<>c.<<-ctor>b__7_1>d.<>u__1"" - IL_005d: stloc.1 - IL_005e: ldarg.0 - IL_005f: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.<>c.<<-ctor>b__7_1>d.<>u__1"" - IL_0064: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_006a: ldarg.0 - IL_006b: ldc.i4.m1 - IL_006c: dup - IL_006d: stloc.0 - IL_006e: stfld ""int C.<>c.<<-ctor>b__7_1>d.<>1__state"" - IL_0073: ldloca.s V_1 - IL_0075: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_007a: nop - IL_007b: call ""void C.End()"" - IL_0080: nop - IL_0081: leave.s IL_009b - } - catch System.Exception - { - IL_0083: stloc.3 - IL_0084: ldarg.0 - IL_0085: ldc.i4.s -2 - IL_0087: stfld ""int C.<>c.<<-ctor>b__7_1>d.<>1__state"" - IL_008c: ldarg.0 - IL_008d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<>c.<<-ctor>b__7_1>d.<>t__builder"" - IL_0092: ldloc.3 - IL_0093: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0098: nop - IL_0099: leave.s IL_00af - } - IL_009b: ldarg.0 - IL_009c: ldc.i4.s -2 - IL_009e: stfld ""int C.<>c.<<-ctor>b__7_1>d.<>1__state"" - IL_00a3: ldarg.0 - IL_00a4: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<>c.<<-ctor>b__7_1>d.<>t__builder"" - IL_00a9: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_00ae: nop - IL_00af: ret -} + { + // Code size 178 (0xb2) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.<>c.<<-ctor>b__7_1>d V_2, + System.Exception V_3) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.<>c.<<-ctor>b__7_1>d.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: beq.s IL_000d + IL_000b: br.s IL_000f + IL_000d: br.s IL_0059 + IL_000f: ldloc.0 + IL_0010: ldc.i4.0 + IL_0011: blt.s IL_0020 + IL_0013: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" + IL_0018: ldc.i4.s -4 + IL_001a: newobj ""System.Runtime.CompilerServices.HotReloadException..ctor(string, int)"" + IL_001f: throw + IL_0020: nop + IL_0021: call ""System.Threading.Tasks.Task C.M2()"" + IL_0026: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_002b: stloc.1 + IL_002c: ldloca.s V_1 + IL_002e: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0033: brtrue.s IL_0075 + IL_0035: ldarg.0 + IL_0036: ldc.i4.1 + IL_0037: dup + IL_0038: stloc.0 + IL_0039: stfld ""int C.<>c.<<-ctor>b__7_1>d.<>1__state"" + IL_003e: ldarg.0 + IL_003f: ldloc.1 + IL_0040: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.<>c.<<-ctor>b__7_1>d.<>u__1"" + IL_0045: ldarg.0 + IL_0046: stloc.2 + IL_0047: ldarg.0 + IL_0048: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<>c.<<-ctor>b__7_1>d.<>t__builder"" + IL_004d: ldloca.s V_1 + IL_004f: ldloca.s V_2 + IL_0051: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedc.<<-ctor>b__7_1>d>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.<>c.<<-ctor>b__7_1>d)"" + IL_0056: nop + IL_0057: leave.s IL_00b1 + IL_0059: ldarg.0 + IL_005a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.<>c.<<-ctor>b__7_1>d.<>u__1"" + IL_005f: stloc.1 + IL_0060: ldarg.0 + IL_0061: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.<>c.<<-ctor>b__7_1>d.<>u__1"" + IL_0066: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_006c: ldarg.0 + IL_006d: ldc.i4.m1 + IL_006e: dup + IL_006f: stloc.0 + IL_0070: stfld ""int C.<>c.<<-ctor>b__7_1>d.<>1__state"" + IL_0075: ldloca.s V_1 + IL_0077: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_007c: nop + IL_007d: call ""void C.End()"" + IL_0082: nop + IL_0083: leave.s IL_009d + } + catch System.Exception + { + IL_0085: stloc.3 + IL_0086: ldarg.0 + IL_0087: ldc.i4.s -2 + IL_0089: stfld ""int C.<>c.<<-ctor>b__7_1>d.<>1__state"" + IL_008e: ldarg.0 + IL_008f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<>c.<<-ctor>b__7_1>d.<>t__builder"" + IL_0094: ldloc.3 + IL_0095: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_009a: nop + IL_009b: leave.s IL_00b1 + } + IL_009d: ldarg.0 + IL_009e: ldc.i4.s -2 + IL_00a0: stfld ""int C.<>c.<<-ctor>b__7_1>d.<>1__state"" + IL_00a5: ldarg.0 + IL_00a6: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.<>c.<<-ctor>b__7_1>d.<>t__builder"" + IL_00ab: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_00b0: nop + IL_00b1: ret + } "); } @@ -1979,7 +1981,7 @@ static async Task F() End(); } }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation0.WithSource(source2.Tree); @@ -2227,7 +2229,7 @@ .locals init (int V_0, diff1.VerifyIL("C.d__4.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 283 (0x11b) + // Code size 285 (0x11d) .maxstack 3 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -2246,290 +2248,279 @@ .locals init (int V_0, IL_000d: ldc.i4.2 IL_000e: beq.s IL_0014 IL_0010: br.s IL_0019 - IL_0012: br.s IL_0064 - IL_0014: br IL_00c0 + IL_0012: br.s IL_0066 + IL_0014: br IL_00c2 IL_0019: ldloc.0 IL_001a: ldc.i4.0 - IL_001b: blt.s IL_0028 + IL_001b: blt.s IL_002a IL_001d: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" - IL_0022: newobj ""System.InvalidOperationException..ctor(string)"" - IL_0027: throw - - IL_0028: nop - IL_0029: call ""System.Threading.Tasks.Task C.M1()"" - IL_002e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0033: stloc.1 - IL_0034: ldloca.s V_1 - IL_0036: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_003b: brtrue.s IL_0080 - - IL_003d: ldarg.0 - IL_003e: ldc.i4.0 - IL_003f: dup - IL_0040: stloc.0 - IL_0041: stfld ""int C.d__4.<>1__state"" - IL_0046: ldarg.0 - IL_0047: ldloc.1 - IL_0048: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_004d: ldarg.0 - IL_004e: stloc.2 + IL_0022: ldc.i4.s -4 + IL_0024: newobj ""System.Runtime.CompilerServices.HotReloadException..ctor(string, int)"" + IL_0029: throw + IL_002a: nop + IL_002b: call ""System.Threading.Tasks.Task C.M1()"" + IL_0030: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0035: stloc.1 + IL_0036: ldloca.s V_1 + IL_0038: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_003d: brtrue.s IL_0082 + IL_003f: ldarg.0 + IL_0040: ldc.i4.0 + IL_0041: dup + IL_0042: stloc.0 + IL_0043: stfld ""int C.d__4.<>1__state"" + IL_0048: ldarg.0 + IL_0049: ldloc.1 + IL_004a: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" IL_004f: ldarg.0 - IL_0050: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" - IL_0055: ldloca.s V_1 - IL_0057: ldloca.s V_2 - IL_0059: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" - IL_005e: nop - IL_005f: leave IL_011a - - IL_0064: ldarg.0 - IL_0065: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_006a: stloc.1 - IL_006b: ldarg.0 - IL_006c: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_0071: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0077: ldarg.0 - IL_0078: ldc.i4.m1 - IL_0079: dup - IL_007a: stloc.0 - IL_007b: stfld ""int C.d__4.<>1__state"" - IL_0080: ldloca.s V_1 - IL_0082: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_0087: nop - IL_0088: call ""System.Threading.Tasks.Task C.M2()"" - IL_008d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0092: stloc.3 - IL_0093: ldloca.s V_3 - IL_0095: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_009a: brtrue.s IL_00dc - - IL_009c: ldarg.0 - IL_009d: ldc.i4.2 - IL_009e: dup - IL_009f: stloc.0 - IL_00a0: stfld ""int C.d__4.<>1__state"" - IL_00a5: ldarg.0 - IL_00a6: ldloc.3 - IL_00a7: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_00ac: ldarg.0 - IL_00ad: stloc.2 + IL_0050: stloc.2 + IL_0051: ldarg.0 + IL_0052: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0057: ldloca.s V_1 + IL_0059: ldloca.s V_2 + IL_005b: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_0060: nop + IL_0061: leave IL_011c + IL_0066: ldarg.0 + IL_0067: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_006c: stloc.1 + IL_006d: ldarg.0 + IL_006e: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0073: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0079: ldarg.0 + IL_007a: ldc.i4.m1 + IL_007b: dup + IL_007c: stloc.0 + IL_007d: stfld ""int C.d__4.<>1__state"" + IL_0082: ldloca.s V_1 + IL_0084: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0089: nop + IL_008a: call ""System.Threading.Tasks.Task C.M2()"" + IL_008f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0094: stloc.3 + IL_0095: ldloca.s V_3 + IL_0097: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_009c: brtrue.s IL_00de + IL_009e: ldarg.0 + IL_009f: ldc.i4.2 + IL_00a0: dup + IL_00a1: stloc.0 + IL_00a2: stfld ""int C.d__4.<>1__state"" + IL_00a7: ldarg.0 + IL_00a8: ldloc.3 + IL_00a9: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" IL_00ae: ldarg.0 - IL_00af: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" - IL_00b4: ldloca.s V_3 - IL_00b6: ldloca.s V_2 - IL_00b8: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" - IL_00bd: nop - IL_00be: leave.s IL_011a - - IL_00c0: ldarg.0 - IL_00c1: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_00c6: stloc.3 - IL_00c7: ldarg.0 - IL_00c8: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_00cd: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00d3: ldarg.0 - IL_00d4: ldc.i4.m1 - IL_00d5: dup - IL_00d6: stloc.0 - IL_00d7: stfld ""int C.d__4.<>1__state"" - - IL_00dc: ldloca.s V_3 - IL_00de: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00e3: nop - IL_00e4: call ""void C.End()"" - IL_00e9: nop - IL_00ea: leave.s IL_0106 + IL_00af: stloc.2 + IL_00b0: ldarg.0 + IL_00b1: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00b6: ldloca.s V_3 + IL_00b8: ldloca.s V_2 + IL_00ba: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_00bf: nop + IL_00c0: leave.s IL_011c + IL_00c2: ldarg.0 + IL_00c3: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00c8: stloc.3 + IL_00c9: ldarg.0 + IL_00ca: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>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 C.d__4.<>1__state"" + IL_00de: ldloca.s V_3 + IL_00e0: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00e5: nop + IL_00e6: call ""void C.End()"" + IL_00eb: nop + IL_00ec: leave.s IL_0108 } catch System.Exception { - IL_00ec: stloc.s V_4 - IL_00ee: ldarg.0 - IL_00ef: ldc.i4.s -2 - IL_00f1: stfld ""int C.d__4.<>1__state"" - IL_00f6: ldarg.0 - IL_00f7: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" - IL_00fc: ldloc.s V_4 - IL_00fe: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0103: nop - IL_0104: leave.s IL_011a + IL_00ee: stloc.s V_4 + IL_00f0: ldarg.0 + IL_00f1: ldc.i4.s -2 + IL_00f3: stfld ""int C.d__4.<>1__state"" + IL_00f8: ldarg.0 + IL_00f9: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00fe: ldloc.s V_4 + IL_0100: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0105: nop + IL_0106: leave.s IL_011c } - IL_0106: ldarg.0 - IL_0107: ldc.i4.s -2 - IL_0109: stfld ""int C.d__4.<>1__state"" - IL_010e: ldarg.0 - IL_010f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" - IL_0114: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_0119: nop - IL_011a: ret + IL_0108: ldarg.0 + IL_0109: ldc.i4.s -2 + IL_010b: stfld ""int C.d__4.<>1__state"" + IL_0110: ldarg.0 + IL_0111: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0116: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_011b: nop + IL_011c: ret } "); // note that CDI is not emitted to the delta since we already have the information captured in changed symbols: diff1.VerifyPdb(Enumerable.Range(1, 20).Select(MetadataTokens.MethodDefinitionHandle), @" - - - - + + + + - - + + - + "); - diff2.VerifyIL("C.d__4.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" -{ - // Code size 283 (0x11b) - .maxstack 3 - .locals init (int V_0, - System.Runtime.CompilerServices.TaskAwaiter V_1, - C.d__4 V_2, - System.Runtime.CompilerServices.TaskAwaiter V_3, - System.Exception V_4) - IL_0000: ldarg.0 - IL_0001: ldfld ""int C.d__4.<>1__state"" - IL_0006: stloc.0 - .try - { - IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0012 - IL_000a: br.s IL_000c - IL_000c: ldloc.0 - IL_000d: ldc.i4.3 - IL_000e: beq.s IL_0017 - IL_0010: br.s IL_0019 - IL_0012: br IL_00c0 - IL_0017: br.s IL_0064 - IL_0019: ldloc.0 - IL_001a: ldc.i4.0 - IL_001b: blt.s IL_0028 - IL_001d: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" - IL_0022: newobj ""System.InvalidOperationException..ctor(string)"" - IL_0027: throw - - IL_0028: nop - IL_0029: call ""System.Threading.Tasks.Task C.M3()"" - IL_002e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0033: stloc.1 - IL_0034: ldloca.s V_1 - IL_0036: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_003b: brtrue.s IL_0080 - - IL_003d: ldarg.0 - IL_003e: ldc.i4.3 - IL_003f: dup - IL_0040: stloc.0 - IL_0041: stfld ""int C.d__4.<>1__state"" - IL_0046: ldarg.0 - IL_0047: ldloc.1 - IL_0048: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_004d: ldarg.0 - IL_004e: stloc.2 - IL_004f: ldarg.0 - IL_0050: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" - IL_0055: ldloca.s V_1 - IL_0057: ldloca.s V_2 - IL_0059: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" - IL_005e: nop - IL_005f: leave IL_011a - - IL_0064: ldarg.0 - IL_0065: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_006a: stloc.1 - IL_006b: ldarg.0 - IL_006c: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_0071: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0077: ldarg.0 - IL_0078: ldc.i4.m1 - IL_0079: dup - IL_007a: stloc.0 - IL_007b: stfld ""int C.d__4.<>1__state"" - - IL_0080: ldloca.s V_1 - IL_0082: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_0087: nop - IL_0088: call ""System.Threading.Tasks.Task C.M1()"" - IL_008d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0092: stloc.3 - IL_0093: ldloca.s V_3 - IL_0095: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_009a: brtrue.s IL_00dc - - IL_009c: ldarg.0 - IL_009d: ldc.i4.0 - IL_009e: dup - IL_009f: stloc.0 - IL_00a0: stfld ""int C.d__4.<>1__state"" - IL_00a5: ldarg.0 - IL_00a6: ldloc.3 - IL_00a7: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_00ac: ldarg.0 - IL_00ad: stloc.2 - IL_00ae: ldarg.0 - IL_00af: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" - IL_00b4: ldloca.s V_3 - IL_00b6: ldloca.s V_2 - IL_00b8: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" - IL_00bd: nop - IL_00be: leave.s IL_011a - - IL_00c0: ldarg.0 - IL_00c1: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_00c6: stloc.3 - IL_00c7: ldarg.0 - IL_00c8: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_00cd: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00d3: ldarg.0 - IL_00d4: ldc.i4.m1 - IL_00d5: dup - IL_00d6: stloc.0 - IL_00d7: stfld ""int C.d__4.<>1__state"" - - IL_00dc: ldloca.s V_3 - IL_00de: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00e3: nop - IL_00e4: call ""void C.End()"" - IL_00e9: nop - IL_00ea: leave.s IL_0106 - } - catch System.Exception - { - IL_00ec: stloc.s V_4 - IL_00ee: ldarg.0 - IL_00ef: ldc.i4.s -2 - IL_00f1: stfld ""int C.d__4.<>1__state"" - IL_00f6: ldarg.0 - IL_00f7: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" - IL_00fc: ldloc.s V_4 - IL_00fe: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0103: nop - IL_0104: leave.s IL_011a - } - IL_0106: ldarg.0 - IL_0107: ldc.i4.s -2 - IL_0109: stfld ""int C.d__4.<>1__state"" - IL_010e: ldarg.0 - IL_010f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" - IL_0114: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_0119: nop - IL_011a: ret -} -"); + diff2.VerifyIL("C.d__4.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", $$""" + { + // Code size 285 (0x11d) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__4 V_2, + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld "int C.d__4.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.3 + IL_000e: beq.s IL_0017 + IL_0010: br.s IL_0019 + IL_0012: br IL_00c2 + IL_0017: br.s IL_0066 + IL_0019: ldloc.0 + IL_001a: ldc.i4.0 + IL_001b: blt.s IL_002a + IL_001d: ldstr "{{CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod}}" + IL_0022: ldc.i4.s -4 + IL_0024: newobj "System.Runtime.CompilerServices.HotReloadException..ctor(string, int)" + IL_0029: throw + IL_002a: nop + IL_002b: call "System.Threading.Tasks.Task C.M3()" + IL_0030: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_0035: stloc.1 + IL_0036: ldloca.s V_1 + IL_0038: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_003d: brtrue.s IL_0082 + IL_003f: ldarg.0 + IL_0040: ldc.i4.3 + IL_0041: dup + IL_0042: stloc.0 + IL_0043: stfld "int C.d__4.<>1__state" + IL_0048: ldarg.0 + IL_0049: ldloc.1 + IL_004a: stfld "System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1" + IL_004f: ldarg.0 + IL_0050: stloc.2 + IL_0051: ldarg.0 + IL_0052: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder" + IL_0057: ldloca.s V_1 + IL_0059: ldloca.s V_2 + IL_005b: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)" + IL_0060: nop + IL_0061: leave IL_011c + IL_0066: ldarg.0 + IL_0067: ldfld "System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1" + IL_006c: stloc.1 + IL_006d: ldarg.0 + IL_006e: ldflda "System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1" + IL_0073: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_0079: ldarg.0 + IL_007a: ldc.i4.m1 + IL_007b: dup + IL_007c: stloc.0 + IL_007d: stfld "int C.d__4.<>1__state" + IL_0082: ldloca.s V_1 + IL_0084: call "void System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_0089: nop + IL_008a: call "System.Threading.Tasks.Task C.M1()" + IL_008f: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_0094: stloc.3 + IL_0095: ldloca.s V_3 + IL_0097: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_009c: brtrue.s IL_00de + IL_009e: ldarg.0 + IL_009f: ldc.i4.0 + IL_00a0: dup + IL_00a1: stloc.0 + IL_00a2: stfld "int C.d__4.<>1__state" + IL_00a7: ldarg.0 + IL_00a8: ldloc.3 + IL_00a9: stfld "System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1" + IL_00ae: ldarg.0 + IL_00af: stloc.2 + IL_00b0: ldarg.0 + IL_00b1: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder" + IL_00b6: ldloca.s V_3 + IL_00b8: ldloca.s V_2 + IL_00ba: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)" + IL_00bf: nop + IL_00c0: leave.s IL_011c + IL_00c2: ldarg.0 + IL_00c3: ldfld "System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1" + IL_00c8: stloc.3 + IL_00c9: ldarg.0 + IL_00ca: ldflda "System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>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 C.d__4.<>1__state" + IL_00de: ldloca.s V_3 + IL_00e0: call "void System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_00e5: nop + IL_00e6: call "void C.End()" + IL_00eb: nop + IL_00ec: leave.s IL_0108 + } + catch System.Exception + { + IL_00ee: stloc.s V_4 + IL_00f0: ldarg.0 + IL_00f1: ldc.i4.s -2 + IL_00f3: stfld "int C.d__4.<>1__state" + IL_00f8: ldarg.0 + IL_00f9: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder" + IL_00fe: ldloc.s V_4 + IL_0100: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_0105: nop + IL_0106: leave.s IL_011c + } + IL_0108: ldarg.0 + IL_0109: ldc.i4.s -2 + IL_010b: stfld "int C.d__4.<>1__state" + IL_0110: ldarg.0 + IL_0111: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder" + IL_0116: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_011b: nop + IL_011c: ret + } + """); } [Fact] @@ -2569,7 +2560,7 @@ static async Task F() End(); } }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -2588,7 +2579,7 @@ static async Task F() diff1.VerifyIL("C.d__4.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 176 (0xb0) + // Code size 178 (0xb2) .maxstack 3 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -2603,80 +2594,77 @@ .locals init (int V_0, IL_0008: ldc.i4.1 IL_0009: beq.s IL_000d IL_000b: br.s IL_000f - IL_000d: br.s IL_0057 + IL_000d: br.s IL_0059 IL_000f: ldloc.0 IL_0010: ldc.i4.0 - IL_0011: blt.s IL_001e + IL_0011: blt.s IL_0020 IL_0013: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" - IL_0018: newobj ""System.InvalidOperationException..ctor(string)"" - IL_001d: throw - - IL_001e: nop - IL_001f: call ""System.Threading.Tasks.Task C.M2()"" - IL_0024: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0029: stloc.1 - IL_002a: ldloca.s V_1 - IL_002c: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0031: brtrue.s IL_0073 - - IL_0033: ldarg.0 - IL_0034: ldc.i4.1 - IL_0035: dup - IL_0036: stloc.0 - IL_0037: stfld ""int C.d__4.<>1__state"" - IL_003c: ldarg.0 - IL_003d: ldloc.1 - IL_003e: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_0043: ldarg.0 - IL_0044: stloc.2 + IL_0018: ldc.i4.s -4 + IL_001a: newobj ""System.Runtime.CompilerServices.HotReloadException..ctor(string, int)"" + IL_001f: throw + IL_0020: nop + IL_0021: call ""System.Threading.Tasks.Task C.M2()"" + IL_0026: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_002b: stloc.1 + IL_002c: ldloca.s V_1 + IL_002e: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0033: brtrue.s IL_0075 + IL_0035: ldarg.0 + IL_0036: ldc.i4.1 + IL_0037: dup + IL_0038: stloc.0 + IL_0039: stfld ""int C.d__4.<>1__state"" + IL_003e: ldarg.0 + IL_003f: ldloc.1 + IL_0040: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" IL_0045: ldarg.0 - IL_0046: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" - IL_004b: ldloca.s V_1 - IL_004d: ldloca.s V_2 - IL_004f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" - IL_0054: nop - IL_0055: leave.s IL_00af - - IL_0057: ldarg.0 - IL_0058: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_005d: stloc.1 - IL_005e: ldarg.0 - IL_005f: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" - IL_0064: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_006a: ldarg.0 - IL_006b: ldc.i4.m1 - IL_006c: dup - IL_006d: stloc.0 - IL_006e: stfld ""int C.d__4.<>1__state"" - - IL_0073: ldloca.s V_1 - IL_0075: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_007a: nop - IL_007b: call ""void C.End()"" - IL_0080: nop - IL_0081: leave.s IL_009b + IL_0046: stloc.2 + IL_0047: ldarg.0 + IL_0048: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_004d: ldloca.s V_1 + IL_004f: ldloca.s V_2 + IL_0051: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_0056: nop + IL_0057: leave.s IL_00b1 + IL_0059: ldarg.0 + IL_005a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_005f: stloc.1 + IL_0060: ldarg.0 + IL_0061: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0066: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_006c: ldarg.0 + IL_006d: ldc.i4.m1 + IL_006e: dup + IL_006f: stloc.0 + IL_0070: stfld ""int C.d__4.<>1__state"" + IL_0075: ldloca.s V_1 + IL_0077: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_007c: nop + IL_007d: call ""void C.End()"" + IL_0082: nop + IL_0083: leave.s IL_009d } catch System.Exception { - IL_0083: stloc.3 - IL_0084: ldarg.0 - IL_0085: ldc.i4.s -2 - IL_0087: stfld ""int C.d__4.<>1__state"" - IL_008c: ldarg.0 - IL_008d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" - IL_0092: ldloc.3 - IL_0093: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_0098: nop - IL_0099: leave.s IL_00af + IL_0085: stloc.3 + IL_0086: ldarg.0 + IL_0087: ldc.i4.s -2 + IL_0089: stfld ""int C.d__4.<>1__state"" + IL_008e: ldarg.0 + IL_008f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0094: ldloc.3 + IL_0095: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_009a: nop + IL_009b: leave.s IL_00b1 } - IL_009b: ldarg.0 - IL_009c: ldc.i4.s -2 - IL_009e: stfld ""int C.d__4.<>1__state"" - IL_00a3: ldarg.0 - IL_00a4: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" - IL_00a9: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_00ae: nop - IL_00af: ret + IL_009d: ldarg.0 + IL_009e: ldc.i4.s -2 + IL_00a0: stfld ""int C.d__4.<>1__state"" + IL_00a5: ldarg.0 + IL_00a6: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00ab: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_00b0: nop + IL_00b1: ret } "); } @@ -2741,7 +2729,7 @@ static async Task F() End(); } }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -3069,191 +3057,182 @@ .locals init (int V_0, } "); - diff1.VerifyIL("C.d__7.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" -{ - // Code size 356 (0x164) - .maxstack 3 - .locals init (int V_0, - System.Runtime.CompilerServices.TaskAwaiter V_1, - C.d__7 V_2, - object V_3, - int V_4, - System.Runtime.CompilerServices.TaskAwaiter V_5, - System.Exception V_6) - IL_0000: ldarg.0 - IL_0001: ldfld ""int C.d__7.<>1__state"" - IL_0006: stloc.0 - .try - { - IL_0007: ldloc.0 - IL_0008: ldc.i4.1 - IL_0009: beq.s IL_0013 - IL_000b: br.s IL_000d - IL_000d: ldloc.0 - IL_000e: ldc.i4.2 - IL_000f: beq.s IL_0015 - IL_0011: br.s IL_001a - IL_0013: br.s IL_0037 - IL_0015: br IL_00fe - IL_001a: ldloc.0 - IL_001b: ldc.i4.0 - IL_001c: blt.s IL_0029 - IL_001e: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" - IL_0023: newobj ""System.InvalidOperationException..ctor(string)"" - IL_0028: throw - - IL_0029: nop - IL_002a: call ""void C.Start()"" - IL_002f: nop - IL_0030: ldarg.0 - IL_0031: ldc.i4.0 - IL_0032: stfld ""int C.d__7.<>s__4"" - - IL_0037: nop - .try - { - IL_0038: ldloc.0 - IL_0039: ldc.i4.1 - IL_003a: beq.s IL_003e - IL_003c: br.s IL_0040 - IL_003e: br.s IL_007c - - IL_0040: nop - IL_0041: call ""System.Threading.Tasks.Task C.M2()"" - IL_0046: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_004b: stloc.1 - IL_004c: ldloca.s V_1 - IL_004e: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0053: brtrue.s IL_0098 - - IL_0055: ldarg.0 - IL_0056: ldc.i4.1 - IL_0057: dup - IL_0058: stloc.0 - IL_0059: stfld ""int C.d__7.<>1__state"" - IL_005e: ldarg.0 - IL_005f: ldloc.1 - IL_0060: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" - IL_0065: ldarg.0 - IL_0066: stloc.2 - IL_0067: ldarg.0 - IL_0068: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" - IL_006d: ldloca.s V_1 - IL_006f: ldloca.s V_2 - IL_0071: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__7>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__7)"" - IL_0076: nop - IL_0077: leave IL_0163 - - IL_007c: ldarg.0 - IL_007d: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" - IL_0082: stloc.1 - IL_0083: ldarg.0 - IL_0084: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" - IL_0089: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_008f: ldarg.0 - IL_0090: ldc.i4.m1 - IL_0091: dup - IL_0092: stloc.0 - IL_0093: stfld ""int C.d__7.<>1__state"" - IL_0098: ldloca.s V_1 - IL_009a: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_009f: nop - IL_00a0: nop - IL_00a1: leave.s IL_00b4 - } - catch object - { - IL_00a3: stloc.3 - IL_00a4: ldarg.0 - IL_00a5: ldloc.3 - IL_00a6: stfld ""object C.d__7.<>s__3"" - IL_00ab: ldarg.0 - IL_00ac: ldc.i4.1 - IL_00ad: stfld ""int C.d__7.<>s__4"" - IL_00b2: leave.s IL_00b4 - } - IL_00b4: ldarg.0 - IL_00b5: ldfld ""int C.d__7.<>s__4"" - IL_00ba: stloc.s V_4 - IL_00bc: ldloc.s V_4 - IL_00be: ldc.i4.1 - IL_00bf: beq.s IL_00c3 - IL_00c1: br.s IL_0126 - - IL_00c3: nop - IL_00c4: call ""System.Threading.Tasks.Task C.M4()"" - IL_00c9: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00ce: stloc.s V_5 - IL_00d0: ldloca.s V_5 - IL_00d2: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_00d7: brtrue.s IL_011b - - IL_00d9: ldarg.0 - IL_00da: ldc.i4.2 - IL_00db: dup - IL_00dc: stloc.0 - IL_00dd: stfld ""int C.d__7.<>1__state"" - IL_00e2: ldarg.0 - IL_00e3: ldloc.s V_5 - IL_00e5: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" - IL_00ea: ldarg.0 - IL_00eb: stloc.2 - IL_00ec: ldarg.0 - IL_00ed: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" - IL_00f2: ldloca.s V_5 - IL_00f4: ldloca.s V_2 - IL_00f6: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__7>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__7)"" - IL_00fb: nop - IL_00fc: leave.s IL_0163 - - IL_00fe: ldarg.0 - IL_00ff: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" - IL_0104: stloc.s V_5 - IL_0106: ldarg.0 - IL_0107: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" - IL_010c: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0112: ldarg.0 - IL_0113: ldc.i4.m1 - IL_0114: dup - IL_0115: stloc.0 - IL_0116: stfld ""int C.d__7.<>1__state"" - - IL_011b: ldloca.s V_5 - IL_011d: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_0122: nop - IL_0123: nop - IL_0124: br.s IL_0126 - - IL_0126: ldarg.0 - IL_0127: ldnull - IL_0128: stfld ""object C.d__7.<>s__3"" - IL_012d: call ""void C.End()"" - IL_0132: nop - IL_0133: leave.s IL_014f - } - catch System.Exception - { - IL_0135: stloc.s V_6 - IL_0137: ldarg.0 - IL_0138: ldc.i4.s -2 - IL_013a: stfld ""int C.d__7.<>1__state"" - IL_013f: ldarg.0 - IL_0140: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" - IL_0145: ldloc.s V_6 - IL_0147: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_014c: nop - IL_014d: leave.s IL_0163 - } - IL_014f: ldarg.0 - IL_0150: ldc.i4.s -2 - IL_0152: stfld ""int C.d__7.<>1__state"" - IL_0157: ldarg.0 - IL_0158: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" - IL_015d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_0162: nop - IL_0163: ret -} -"); + diff1.VerifyIL("C.d__7.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", """ + { + // Code size 358 (0x166) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__7 V_2, + object V_3, + int V_4, + System.Runtime.CompilerServices.TaskAwaiter V_5, + System.Exception V_6) + IL_0000: ldarg.0 + IL_0001: ldfld "int C.d__7.<>1__state" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: beq.s IL_0013 + IL_000b: br.s IL_000d + IL_000d: ldloc.0 + IL_000e: ldc.i4.2 + IL_000f: beq.s IL_0015 + IL_0011: br.s IL_001a + IL_0013: br.s IL_0039 + IL_0015: br IL_0100 + IL_001a: ldloc.0 + IL_001b: ldc.i4.0 + IL_001c: blt.s IL_002b + IL_001e: ldstr "Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted" + IL_0023: ldc.i4.s -4 + IL_0025: newobj "System.Runtime.CompilerServices.HotReloadException..ctor(string, int)" + IL_002a: throw + IL_002b: nop + IL_002c: call "void C.Start()" + IL_0031: nop + IL_0032: ldarg.0 + IL_0033: ldc.i4.0 + IL_0034: stfld "int C.d__7.<>s__4" + IL_0039: nop + .try + { + IL_003a: ldloc.0 + IL_003b: ldc.i4.1 + IL_003c: beq.s IL_0040 + IL_003e: br.s IL_0042 + IL_0040: br.s IL_007e + IL_0042: nop + IL_0043: call "System.Threading.Tasks.Task C.M2()" + IL_0048: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_004d: stloc.1 + IL_004e: ldloca.s V_1 + IL_0050: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_0055: brtrue.s IL_009a + IL_0057: ldarg.0 + IL_0058: ldc.i4.1 + IL_0059: dup + IL_005a: stloc.0 + IL_005b: stfld "int C.d__7.<>1__state" + IL_0060: ldarg.0 + IL_0061: ldloc.1 + IL_0062: stfld "System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1" + IL_0067: ldarg.0 + IL_0068: stloc.2 + IL_0069: ldarg.0 + IL_006a: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder" + IL_006f: ldloca.s V_1 + IL_0071: ldloca.s V_2 + IL_0073: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__7>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__7)" + IL_0078: nop + IL_0079: leave IL_0165 + IL_007e: ldarg.0 + IL_007f: ldfld "System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1" + IL_0084: stloc.1 + IL_0085: ldarg.0 + IL_0086: ldflda "System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1" + IL_008b: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_0091: ldarg.0 + IL_0092: ldc.i4.m1 + IL_0093: dup + IL_0094: stloc.0 + IL_0095: stfld "int C.d__7.<>1__state" + IL_009a: ldloca.s V_1 + IL_009c: call "void System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_00a1: nop + IL_00a2: nop + IL_00a3: leave.s IL_00b6 + } + catch object + { + IL_00a5: stloc.3 + IL_00a6: ldarg.0 + IL_00a7: ldloc.3 + IL_00a8: stfld "object C.d__7.<>s__3" + IL_00ad: ldarg.0 + IL_00ae: ldc.i4.1 + IL_00af: stfld "int C.d__7.<>s__4" + IL_00b4: leave.s IL_00b6 + } + IL_00b6: ldarg.0 + IL_00b7: ldfld "int C.d__7.<>s__4" + IL_00bc: stloc.s V_4 + IL_00be: ldloc.s V_4 + IL_00c0: ldc.i4.1 + IL_00c1: beq.s IL_00c5 + IL_00c3: br.s IL_0128 + IL_00c5: nop + IL_00c6: call "System.Threading.Tasks.Task C.M4()" + IL_00cb: callvirt "System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()" + IL_00d0: stloc.s V_5 + IL_00d2: ldloca.s V_5 + IL_00d4: call "bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get" + IL_00d9: brtrue.s IL_011d + IL_00db: ldarg.0 + IL_00dc: ldc.i4.2 + IL_00dd: dup + IL_00de: stloc.0 + IL_00df: stfld "int C.d__7.<>1__state" + IL_00e4: ldarg.0 + IL_00e5: ldloc.s V_5 + IL_00e7: stfld "System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1" + IL_00ec: ldarg.0 + IL_00ed: stloc.2 + IL_00ee: ldarg.0 + IL_00ef: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder" + IL_00f4: ldloca.s V_5 + IL_00f6: ldloca.s V_2 + IL_00f8: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__7>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__7)" + IL_00fd: nop + IL_00fe: leave.s IL_0165 + IL_0100: ldarg.0 + IL_0101: ldfld "System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1" + IL_0106: stloc.s V_5 + IL_0108: ldarg.0 + IL_0109: ldflda "System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1" + IL_010e: initobj "System.Runtime.CompilerServices.TaskAwaiter" + IL_0114: ldarg.0 + IL_0115: ldc.i4.m1 + IL_0116: dup + IL_0117: stloc.0 + IL_0118: stfld "int C.d__7.<>1__state" + IL_011d: ldloca.s V_5 + IL_011f: call "void System.Runtime.CompilerServices.TaskAwaiter.GetResult()" + IL_0124: nop + IL_0125: nop + IL_0126: br.s IL_0128 + IL_0128: ldarg.0 + IL_0129: ldnull + IL_012a: stfld "object C.d__7.<>s__3" + IL_012f: call "void C.End()" + IL_0134: nop + IL_0135: leave.s IL_0151 + } + catch System.Exception + { + IL_0137: stloc.s V_6 + IL_0139: ldarg.0 + IL_013a: ldc.i4.s -2 + IL_013c: stfld "int C.d__7.<>1__state" + IL_0141: ldarg.0 + IL_0142: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder" + IL_0147: ldloc.s V_6 + IL_0149: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)" + IL_014e: nop + IL_014f: leave.s IL_0165 + } + IL_0151: ldarg.0 + IL_0152: ldc.i4.s -2 + IL_0154: stfld "int C.d__7.<>1__state" + IL_0159: ldarg.0 + IL_015a: ldflda "System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder" + IL_015f: call "void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()" + IL_0164: nop + IL_0165: ret + } + """); } [Fact] @@ -3684,7 +3663,7 @@ static IEnumerable F(int p) yield return 2; } }"); - var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source0.Tree, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -3789,7 +3768,7 @@ static IEnumerable F(int p) Console.WriteLine(x); } }"); - var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source0.Tree, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -3898,7 +3877,7 @@ static IEnumerable F(int p) Console.WriteLine(p); } }"); - var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source0.Tree, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -4004,7 +3983,7 @@ static IEnumerable F() Console.WriteLine(x); } }"); - var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source0.Tree, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -4106,7 +4085,7 @@ static IEnumerable F() }"); // Rude edit but the compiler should handle it. - var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation0 = CreateCompilationWithMscorlib461(source0.Tree, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0, symbolValidator: module => @@ -4269,7 +4248,7 @@ static IEnumerable F() End(); } }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -4503,7 +4482,7 @@ static IEnumerable F() End(); } }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -4522,7 +4501,7 @@ static IEnumerable F() diff1.VerifyIL("C.d__5.System.Collections.IEnumerator.MoveNext", @" { - // Code size 124 (0x7c) + // Code size 126 (0x7e) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 @@ -4535,51 +4514,48 @@ .locals init (int V_0) IL_0021, IL_0023) IL_001d: br.s IL_0025 - IL_001f: br.s IL_0036 - IL_0021: br.s IL_0052 - IL_0023: br.s IL_006d + IL_001f: br.s IL_0038 + IL_0021: br.s IL_0054 + IL_0023: br.s IL_006f IL_0025: ldloc.0 IL_0026: ldc.i4.1 - IL_0027: blt.s IL_0034 + IL_0027: blt.s IL_0036 IL_0029: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod + @""" - IL_002e: newobj ""System.InvalidOperationException..ctor(string)"" - IL_0033: throw - - IL_0034: ldc.i4.0 - IL_0035: ret - - IL_0036: ldarg.0 - IL_0037: ldc.i4.m1 - IL_0038: stfld ""int C.d__5.<>1__state"" - IL_003d: nop - IL_003e: ldarg.0 - IL_003f: call ""int C.M2()"" - IL_0044: stfld ""int C.d__5.<>2__current"" - IL_0049: ldarg.0 - IL_004a: ldc.i4.2 - IL_004b: stfld ""int C.d__5.<>1__state"" - IL_0050: ldc.i4.1 - IL_0051: ret - - IL_0052: ldarg.0 - IL_0053: ldc.i4.m1 - IL_0054: stfld ""int C.d__5.<>1__state"" - IL_0059: ldarg.0 - IL_005a: call ""int C.M3()"" - IL_005f: stfld ""int C.d__5.<>2__current"" - IL_0064: ldarg.0 - IL_0065: ldc.i4.3 - IL_0066: stfld ""int C.d__5.<>1__state"" - IL_006b: ldc.i4.1 - IL_006c: ret - - IL_006d: ldarg.0 - IL_006e: ldc.i4.m1 - IL_006f: stfld ""int C.d__5.<>1__state"" - IL_0074: call ""void C.End()"" - IL_0079: nop - IL_007a: ldc.i4.0 - IL_007b: ret + IL_002e: ldc.i4.s -3 + IL_0030: newobj ""System.Runtime.CompilerServices.HotReloadException..ctor(string, int)"" + IL_0035: throw + IL_0036: ldc.i4.0 + IL_0037: ret + IL_0038: ldarg.0 + IL_0039: ldc.i4.m1 + IL_003a: stfld ""int C.d__5.<>1__state"" + IL_003f: nop + IL_0040: ldarg.0 + IL_0041: call ""int C.M2()"" + IL_0046: stfld ""int C.d__5.<>2__current"" + IL_004b: ldarg.0 + IL_004c: ldc.i4.2 + IL_004d: stfld ""int C.d__5.<>1__state"" + IL_0052: ldc.i4.1 + IL_0053: ret + IL_0054: ldarg.0 + IL_0055: ldc.i4.m1 + IL_0056: stfld ""int C.d__5.<>1__state"" + IL_005b: ldarg.0 + IL_005c: call ""int C.M3()"" + IL_0061: stfld ""int C.d__5.<>2__current"" + IL_0066: ldarg.0 + IL_0067: ldc.i4.3 + IL_0068: stfld ""int C.d__5.<>1__state"" + IL_006d: ldc.i4.1 + IL_006e: ret + IL_006f: ldarg.0 + IL_0070: ldc.i4.m1 + IL_0071: stfld ""int C.d__5.<>1__state"" + IL_0076: call ""void C.End()"" + IL_007b: nop + IL_007c: ldc.i4.0 + IL_007d: ret } "); } @@ -4666,7 +4642,7 @@ static void Finally1(int gen) {} static void Finally2(int gen) {} static void Finally3(int gen) {} }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -5123,7 +5099,7 @@ static IEnumerable F() static int M3() => 0; static void End() {} }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -5459,7 +5435,7 @@ static IEnumerable F() static IDisposable D() => null; static IEnumerable<(int, int)> E() => null; }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemRuntimeFacadeRef, ValueTupleRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemRuntimeFacadeRef, ValueTupleRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); @@ -6051,7 +6027,7 @@ .locals init (int V_0, diff2.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 447 (0x1bf) + // Code size 449 (0x1c1) .maxstack 3 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -6075,170 +6051,171 @@ .locals init (int V_0, IL_0032, IL_0037) IL_002c: br.s IL_003c - IL_002e: br.s IL_007d - IL_0030: br.s IL_004c - IL_0032: br IL_012f - IL_0037: br IL_00cf + IL_002e: br.s IL_007f + IL_0030: br.s IL_004e + IL_0032: br IL_0131 + IL_0037: br IL_00d1 IL_003c: ldloc.0 IL_003d: ldc.i4.s -4 - IL_003f: bgt.s IL_004c + IL_003f: bgt.s IL_004e IL_0041: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod + @""" - IL_0046: newobj ""System.InvalidOperationException..ctor(string)"" - IL_004b: throw - IL_004c: ldarg.0 - IL_004d: ldfld ""bool C.d__0.<>w__disposeMode"" - IL_0052: brfalse.s IL_0059 - IL_0054: leave IL_0188 - IL_0059: ldarg.0 - IL_005a: ldc.i4.m1 - IL_005b: dup - IL_005c: stloc.0 - IL_005d: stfld ""int C.d__0.<>1__state"" - IL_0062: nop - IL_0063: ldarg.0 - IL_0064: call ""int C.F2()"" - IL_0069: stfld ""int C.d__0.<>2__current"" - IL_006e: ldarg.0 - IL_006f: ldc.i4.s -5 - IL_0071: dup - IL_0072: stloc.0 - IL_0073: stfld ""int C.d__0.<>1__state"" - IL_0078: leave IL_01b1 - IL_007d: ldarg.0 - IL_007e: ldc.i4.m1 - IL_007f: dup - IL_0080: stloc.0 - IL_0081: stfld ""int C.d__0.<>1__state"" - IL_0086: ldarg.0 - IL_0087: ldfld ""bool C.d__0.<>w__disposeMode"" - IL_008c: brfalse.s IL_0093 - IL_008e: leave IL_0188 - IL_0093: ldc.i4.2 - IL_0094: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)"" - IL_0099: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_009e: stloc.1 - IL_009f: ldloca.s V_1 - IL_00a1: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_00a6: brtrue.s IL_00eb - IL_00a8: ldarg.0 - IL_00a9: ldc.i4.1 - IL_00aa: dup - IL_00ab: stloc.0 - IL_00ac: stfld ""int C.d__0.<>1__state"" - IL_00b1: ldarg.0 - IL_00b2: ldloc.1 - IL_00b3: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_00b8: ldarg.0 - IL_00b9: stloc.2 + IL_0046: ldc.i4.s -3 + IL_0048: newobj ""System.Runtime.CompilerServices.HotReloadException..ctor(string, int)"" + IL_004d: throw + IL_004e: ldarg.0 + IL_004f: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_0054: brfalse.s IL_005b + IL_0056: leave IL_018a + IL_005b: ldarg.0 + IL_005c: ldc.i4.m1 + IL_005d: dup + IL_005e: stloc.0 + IL_005f: stfld ""int C.d__0.<>1__state"" + IL_0064: nop + IL_0065: ldarg.0 + IL_0066: call ""int C.F2()"" + IL_006b: stfld ""int C.d__0.<>2__current"" + IL_0070: ldarg.0 + IL_0071: ldc.i4.s -5 + IL_0073: dup + IL_0074: stloc.0 + IL_0075: stfld ""int C.d__0.<>1__state"" + IL_007a: leave IL_01b3 + IL_007f: ldarg.0 + IL_0080: ldc.i4.m1 + IL_0081: dup + IL_0082: stloc.0 + IL_0083: stfld ""int C.d__0.<>1__state"" + IL_0088: ldarg.0 + IL_0089: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_008e: brfalse.s IL_0095 + IL_0090: leave IL_018a + IL_0095: ldc.i4.2 + IL_0096: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)"" + IL_009b: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_00a0: stloc.1 + IL_00a1: ldloca.s V_1 + IL_00a3: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_00a8: brtrue.s IL_00ed + IL_00aa: ldarg.0 + IL_00ab: ldc.i4.1 + IL_00ac: dup + IL_00ad: stloc.0 + IL_00ae: stfld ""int C.d__0.<>1__state"" + IL_00b3: ldarg.0 + IL_00b4: ldloc.1 + IL_00b5: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" IL_00ba: ldarg.0 - IL_00bb: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_00c0: ldloca.s V_1 - IL_00c2: ldloca.s V_2 - IL_00c4: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted, C.d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" - IL_00c9: nop - IL_00ca: leave IL_01be - IL_00cf: ldarg.0 - IL_00d0: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_00d5: stloc.1 - IL_00d6: ldarg.0 - IL_00d7: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_00dc: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00e2: ldarg.0 - IL_00e3: ldc.i4.m1 - IL_00e4: dup - IL_00e5: stloc.0 - IL_00e6: stfld ""int C.d__0.<>1__state"" - IL_00eb: ldloca.s V_1 - IL_00ed: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00f2: pop - IL_00f3: ldc.i4.1 - IL_00f4: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)"" - IL_00f9: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_00fe: stloc.3 - IL_00ff: ldloca.s V_3 - IL_0101: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_0106: brtrue.s IL_014b - IL_0108: ldarg.0 - IL_0109: ldc.i4.0 - IL_010a: dup - IL_010b: stloc.0 - IL_010c: stfld ""int C.d__0.<>1__state"" - IL_0111: ldarg.0 - IL_0112: ldloc.3 - IL_0113: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_0118: ldarg.0 - IL_0119: stloc.2 + IL_00bb: stloc.2 + IL_00bc: ldarg.0 + IL_00bd: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_00c2: ldloca.s V_1 + IL_00c4: ldloca.s V_2 + IL_00c6: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted, C.d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_00cb: nop + IL_00cc: leave IL_01c0 + IL_00d1: ldarg.0 + IL_00d2: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00d7: stloc.1 + IL_00d8: ldarg.0 + IL_00d9: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00de: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00e4: ldarg.0 + IL_00e5: ldc.i4.m1 + IL_00e6: dup + IL_00e7: stloc.0 + IL_00e8: stfld ""int C.d__0.<>1__state"" + IL_00ed: ldloca.s V_1 + IL_00ef: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00f4: pop + IL_00f5: ldc.i4.1 + IL_00f6: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)"" + IL_00fb: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0100: stloc.3 + IL_0101: ldloca.s V_3 + IL_0103: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0108: brtrue.s IL_014d + IL_010a: ldarg.0 + IL_010b: ldc.i4.0 + IL_010c: dup + IL_010d: stloc.0 + IL_010e: stfld ""int C.d__0.<>1__state"" + IL_0113: ldarg.0 + IL_0114: ldloc.3 + IL_0115: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" IL_011a: ldarg.0 - IL_011b: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_0120: ldloca.s V_3 - IL_0122: ldloca.s V_2 - IL_0124: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted, C.d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" - IL_0129: nop - IL_012a: leave IL_01be - IL_012f: ldarg.0 - IL_0130: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_0135: stloc.3 - IL_0136: ldarg.0 - IL_0137: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_013c: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0142: ldarg.0 - IL_0143: ldc.i4.m1 - IL_0144: dup - IL_0145: stloc.0 - IL_0146: stfld ""int C.d__0.<>1__state"" - IL_014b: ldloca.s V_3 - IL_014d: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_0152: pop - IL_0153: call ""void C.End()"" - IL_0158: nop - IL_0159: leave.s IL_0188 + IL_011b: stloc.2 + IL_011c: ldarg.0 + IL_011d: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0122: ldloca.s V_3 + IL_0124: ldloca.s V_2 + IL_0126: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted, C.d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_012b: nop + IL_012c: leave IL_01c0 + IL_0131: ldarg.0 + IL_0132: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0137: stloc.3 + IL_0138: ldarg.0 + IL_0139: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_013e: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0144: ldarg.0 + IL_0145: ldc.i4.m1 + IL_0146: dup + IL_0147: stloc.0 + IL_0148: stfld ""int C.d__0.<>1__state"" + IL_014d: ldloca.s V_3 + IL_014f: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0154: pop + IL_0155: call ""void C.End()"" + IL_015a: nop + IL_015b: leave.s IL_018a } catch System.Exception { - IL_015b: stloc.s V_4 - IL_015d: ldarg.0 - IL_015e: ldc.i4.s -2 - IL_0160: stfld ""int C.d__0.<>1__state"" - IL_0165: ldarg.0 - IL_0166: ldc.i4.0 - IL_0167: stfld ""int C.d__0.<>2__current"" - IL_016c: ldarg.0 - IL_016d: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_0172: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_0177: nop - IL_0178: ldarg.0 - IL_0179: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_017e: ldloc.s V_4 - IL_0180: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" - IL_0185: nop - IL_0186: leave.s IL_01be + IL_015d: stloc.s V_4 + IL_015f: ldarg.0 + IL_0160: ldc.i4.s -2 + IL_0162: stfld ""int C.d__0.<>1__state"" + IL_0167: ldarg.0 + IL_0168: ldc.i4.0 + IL_0169: stfld ""int C.d__0.<>2__current"" + IL_016e: ldarg.0 + IL_016f: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0174: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_0179: nop + IL_017a: ldarg.0 + IL_017b: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0180: ldloc.s V_4 + IL_0182: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_0187: nop + IL_0188: leave.s IL_01c0 } - IL_0188: ldarg.0 - IL_0189: ldc.i4.s -2 - IL_018b: stfld ""int C.d__0.<>1__state"" - IL_0190: ldarg.0 - IL_0191: ldc.i4.0 - IL_0192: stfld ""int C.d__0.<>2__current"" - IL_0197: ldarg.0 - IL_0198: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_019d: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_01a2: nop - IL_01a3: ldarg.0 - IL_01a4: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_01a9: ldc.i4.0 - IL_01aa: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_01af: nop - IL_01b0: ret - IL_01b1: ldarg.0 - IL_01b2: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_01b7: ldc.i4.1 - IL_01b8: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_01bd: nop - IL_01be: ret + IL_018a: ldarg.0 + IL_018b: ldc.i4.s -2 + IL_018d: stfld ""int C.d__0.<>1__state"" + IL_0192: ldarg.0 + IL_0193: ldc.i4.0 + IL_0194: stfld ""int C.d__0.<>2__current"" + IL_0199: ldarg.0 + IL_019a: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_019f: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_01a4: nop + IL_01a5: ldarg.0 + IL_01a6: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_01ab: ldc.i4.0 + IL_01ac: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_01b1: nop + IL_01b2: ret + IL_01b3: ldarg.0 + IL_01b4: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_01b9: ldc.i4.1 + IL_01ba: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_01bf: nop + IL_01c0: ret }"); diff3.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" -{ - // Code size 339 (0x153) + { + // Code size 343 (0x157) .maxstack 3 .locals init (int V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -6260,143 +6237,135 @@ .locals init (int V_0, IL_0015: ldloc.0 IL_0016: brfalse.s IL_001e IL_0018: br.s IL_0023 - IL_001a: br.s IL_0073 - IL_001c: br.s IL_0042 - IL_001e: br IL_00c5 - + IL_001a: br.s IL_0077 + IL_001c: br.s IL_0046 + IL_001e: br IL_00c9 IL_0023: ldloc.0 IL_0024: ldc.i4.0 - IL_0025: blt.s IL_0032 + IL_0025: blt.s IL_0034 IL_0027: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" - IL_002c: newobj ""System.InvalidOperationException..ctor(string)"" - IL_0031: throw - - IL_0032: ldloc.0 - IL_0033: ldc.i4.s -4 - IL_0035: bgt.s IL_0042 - IL_0037: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod + @""" - IL_003c: newobj ""System.InvalidOperationException..ctor(string)"" - IL_0041: throw - - IL_0042: ldarg.0 - IL_0043: ldfld ""bool C.d__0.<>w__disposeMode"" - IL_0048: brfalse.s IL_004f - IL_004a: leave IL_011c - - IL_004f: ldarg.0 - IL_0050: ldc.i4.m1 - IL_0051: dup - IL_0052: stloc.0 - IL_0053: stfld ""int C.d__0.<>1__state"" - IL_0058: nop - IL_0059: ldarg.0 - IL_005a: call ""int C.F2()"" - IL_005f: stfld ""int C.d__0.<>2__current"" - IL_0064: ldarg.0 - IL_0065: ldc.i4.s -5 - IL_0067: dup - IL_0068: stloc.0 - IL_0069: stfld ""int C.d__0.<>1__state"" - IL_006e: leave IL_0145 - - IL_0073: ldarg.0 - IL_0074: ldc.i4.m1 - IL_0075: dup - IL_0076: stloc.0 - IL_0077: stfld ""int C.d__0.<>1__state"" - IL_007c: ldarg.0 - IL_007d: ldfld ""bool C.d__0.<>w__disposeMode"" - IL_0082: brfalse.s IL_0089 - IL_0084: leave IL_011c - - IL_0089: ldc.i4.1 - IL_008a: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)"" - IL_008f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" - IL_0094: stloc.1 - IL_0095: ldloca.s V_1 - IL_0097: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" - IL_009c: brtrue.s IL_00e1 - - IL_009e: ldarg.0 - IL_009f: ldc.i4.0 - IL_00a0: dup - IL_00a1: stloc.0 - IL_00a2: stfld ""int C.d__0.<>1__state"" - IL_00a7: ldarg.0 - IL_00a8: ldloc.1 - IL_00a9: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_00ae: ldarg.0 - IL_00af: stloc.2 - IL_00b0: ldarg.0 - IL_00b1: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_00b6: ldloca.s V_1 - IL_00b8: ldloca.s V_2 - IL_00ba: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted, C.d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" - IL_00bf: nop - IL_00c0: leave IL_0152 - - IL_00c5: ldarg.0 - IL_00c6: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_00cb: stloc.1 - IL_00cc: ldarg.0 - IL_00cd: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" - IL_00d2: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00d8: ldarg.0 - IL_00d9: ldc.i4.m1 - IL_00da: dup - IL_00db: stloc.0 - IL_00dc: stfld ""int C.d__0.<>1__state"" - - IL_00e1: ldloca.s V_1 - IL_00e3: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00e8: pop - IL_00e9: call ""void C.End()"" - IL_00ee: nop - IL_00ef: leave.s IL_011c + IL_002c: ldc.i4.s -4 + IL_002e: newobj ""System.Runtime.CompilerServices.HotReloadException..ctor(string, int)"" + IL_0033: throw + IL_0034: ldloc.0 + IL_0035: ldc.i4.s -4 + IL_0037: bgt.s IL_0046 + IL_0039: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod + @""" + IL_003e: ldc.i4.s -3 + IL_0040: newobj ""System.Runtime.CompilerServices.HotReloadException..ctor(string, int)"" + IL_0045: throw + IL_0046: ldarg.0 + IL_0047: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_004c: brfalse.s IL_0053 + IL_004e: leave IL_0120 + IL_0053: ldarg.0 + IL_0054: ldc.i4.m1 + IL_0055: dup + IL_0056: stloc.0 + IL_0057: stfld ""int C.d__0.<>1__state"" + IL_005c: nop + IL_005d: ldarg.0 + IL_005e: call ""int C.F2()"" + IL_0063: stfld ""int C.d__0.<>2__current"" + IL_0068: ldarg.0 + IL_0069: ldc.i4.s -5 + IL_006b: dup + IL_006c: stloc.0 + IL_006d: stfld ""int C.d__0.<>1__state"" + IL_0072: leave IL_0149 + IL_0077: ldarg.0 + IL_0078: ldc.i4.m1 + IL_0079: dup + IL_007a: stloc.0 + IL_007b: stfld ""int C.d__0.<>1__state"" + IL_0080: ldarg.0 + IL_0081: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_0086: brfalse.s IL_008d + IL_0088: leave IL_0120 + IL_008d: ldc.i4.1 + IL_008e: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)"" + IL_0093: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0098: stloc.1 + IL_0099: ldloca.s V_1 + IL_009b: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_00a0: brtrue.s IL_00e5 + IL_00a2: ldarg.0 + IL_00a3: ldc.i4.0 + IL_00a4: dup + IL_00a5: stloc.0 + IL_00a6: stfld ""int C.d__0.<>1__state"" + IL_00ab: ldarg.0 + IL_00ac: ldloc.1 + IL_00ad: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00b2: ldarg.0 + IL_00b3: stloc.2 + IL_00b4: ldarg.0 + IL_00b5: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_00ba: ldloca.s V_1 + IL_00bc: ldloca.s V_2 + IL_00be: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted, C.d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_00c3: nop + IL_00c4: leave IL_0156 + IL_00c9: ldarg.0 + IL_00ca: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00cf: stloc.1 + IL_00d0: ldarg.0 + IL_00d1: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00d6: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00dc: ldarg.0 + IL_00dd: ldc.i4.m1 + IL_00de: dup + IL_00df: stloc.0 + IL_00e0: stfld ""int C.d__0.<>1__state"" + IL_00e5: ldloca.s V_1 + IL_00e7: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00ec: pop + IL_00ed: call ""void C.End()"" + IL_00f2: nop + IL_00f3: leave.s IL_0120 } catch System.Exception { - IL_00f1: stloc.3 - IL_00f2: ldarg.0 - IL_00f3: ldc.i4.s -2 - IL_00f5: stfld ""int C.d__0.<>1__state"" - IL_00fa: ldarg.0 - IL_00fb: ldc.i4.0 - IL_00fc: stfld ""int C.d__0.<>2__current"" - IL_0101: ldarg.0 - IL_0102: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_0107: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_010c: nop - IL_010d: ldarg.0 - IL_010e: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_0113: ldloc.3 - IL_0114: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" - IL_0119: nop - IL_011a: leave.s IL_0152 + IL_00f5: stloc.3 + IL_00f6: ldarg.0 + IL_00f7: ldc.i4.s -2 + IL_00f9: stfld ""int C.d__0.<>1__state"" + IL_00fe: ldarg.0 + IL_00ff: ldc.i4.0 + IL_0100: stfld ""int C.d__0.<>2__current"" + IL_0105: ldarg.0 + IL_0106: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_010b: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_0110: nop + IL_0111: ldarg.0 + IL_0112: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0117: ldloc.3 + IL_0118: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_011d: nop + IL_011e: leave.s IL_0156 } - IL_011c: ldarg.0 - IL_011d: ldc.i4.s -2 - IL_011f: stfld ""int C.d__0.<>1__state"" - IL_0124: ldarg.0 - IL_0125: ldc.i4.0 - IL_0126: stfld ""int C.d__0.<>2__current"" - IL_012b: ldarg.0 - IL_012c: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" - IL_0131: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" - IL_0136: nop - IL_0137: ldarg.0 - IL_0138: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_013d: ldc.i4.0 - IL_013e: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_0143: nop - IL_0144: ret - - IL_0145: ldarg.0 - IL_0146: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" - IL_014b: ldc.i4.1 - IL_014c: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" - IL_0151: nop - IL_0152: ret + IL_0120: ldarg.0 + IL_0121: ldc.i4.s -2 + IL_0123: stfld ""int C.d__0.<>1__state"" + IL_0128: ldarg.0 + IL_0129: ldc.i4.0 + IL_012a: stfld ""int C.d__0.<>2__current"" + IL_012f: ldarg.0 + IL_0130: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0135: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_013a: nop + IL_013b: ldarg.0 + IL_013c: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0141: ldc.i4.0 + IL_0142: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0147: nop + IL_0148: ret + IL_0149: ldarg.0 + IL_014a: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_014f: ldc.i4.1 + IL_0150: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0155: nop + IL_0156: ret }"); } @@ -7413,7 +7382,7 @@ static async Task H() // updated // Rude edit but the compiler should handle it. - var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation0 = CreateCompilationWithMscorlib461(source0.Tree, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation1.WithSource(source2.Tree); var compilation3 = compilation2.WithSource(source3.Tree); @@ -7751,7 +7720,7 @@ public IEnumerable F() var source1 = MarkedSource(template.Replace("<>", "1")); var source2 = MarkedSource(template.Replace("<>", "2")); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation1.WithSource(source2.Tree); @@ -7919,82 +7888,80 @@ .locals init (int V_0) [Fact] public void HoistedVariables_Dynamic2() { - var source0 = MarkedSource(@" -using System; -using System.Collections.Generic; - -class C -{ - private static IEnumerable F() - { - dynamic d = ""x""; - yield return d; - Console.WriteLine(0); - } -} -"); - var source1 = MarkedSource(@" -using System; -using System.Collections.Generic; - -class C -{ - private static IEnumerable F() - { - dynamic d = ""x""; - yield return d.ToString(); - Console.WriteLine(1); - } -} -"); - var source2 = MarkedSource(@" -using System; -using System.Collections.Generic; - -class C -{ - private static IEnumerable F() - { - dynamic d = ""x""; - yield return d; - Console.WriteLine(2); - } -} -"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); - var compilation1 = compilation0.WithSource(source1.Tree); - var compilation2 = compilation0.WithSource(source2.Tree); - - var v0 = CompileAndVerify(compilation0); - v0.VerifyDiagnostics(); - var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - - var f0 = compilation0.GetMember("C.F"); - var f1 = compilation1.GetMember("C.F"); - var f2 = compilation2.GetMember("C.F"); - - var generation0 = CreateInitialBaseline(compilation0, md0, v0.CreateSymReader().GetEncMethodDebugInfo); - - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); - - diff1.VerifySynthesizedMembers( - "C: {<>o__0#1, d__0}", - "C.<>o__0#1: {<>p__0, <>p__1}", - "C.d__0: {<>1__state, <>2__current, <>l__initialThreadId, 5__1, System.IDisposable.Dispose, MoveNext, System.Collections.Generic.IEnumerator.get_Current, System.Collections.IEnumerator.Reset, System.Collections.IEnumerator.get_Current, System.Collections.Generic.IEnumerable.GetEnumerator, System.Collections.IEnumerable.GetEnumerator, System.Collections.Generic.IEnumerator.Current, System.Collections.IEnumerator.Current}"); + using var _ = new EditAndContinueTest(_logger, references: [CSharpRef]) + .AddBaseline( + source: """ + using System; + using System.Collections.Generic; - var diff2 = compilation2.EmitDifference( - diff1.NextGeneration, - ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, f1, f2, GetSyntaxMapFromMarkers(source1, source2)))); + class C + { + private static IEnumerable F() + { + dynamic d = "x"; + yield return d; + Console.WriteLine(0); + } + } + """) + .AddGeneration( + // 1 + source: """ + using System; + using System.Collections.Generic; - diff2.VerifySynthesizedMembers( - "C: {<>o__0#2, d__0, <>o__0#1}", - "C.<>o__0#1: {<>p__0, <>p__1}", - "C.<>o__0#2: {<>p__0}", - "C.d__0: {<>1__state, <>2__current, <>l__initialThreadId, 5__1, System.IDisposable.Dispose, MoveNext, System.Collections.Generic.IEnumerator.get_Current, System.Collections.IEnumerator.Reset, System.Collections.IEnumerator.get_Current, System.Collections.Generic.IEnumerable.GetEnumerator, System.Collections.IEnumerable.GetEnumerator, System.Collections.Generic.IEnumerator.Current, System.Collections.IEnumerator.Current}"); + class C + { + private static IEnumerable F() + { + dynamic d = "x"; + yield return d.ToString(); + Console.WriteLine(1); + } + } + """, + edits: + [ + Edit(SemanticEditKind.Update, c => c.GetMember("C.F"), preserveLocalVariables: true) + ], + validator: v => + { + v.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", + "C: {<>o__0#1, d__0}", + "C.<>o__0#1: {<>p__0, <>p__1}", + "C.d__0: {<>1__state, <>2__current, <>l__initialThreadId, 5__1, System.IDisposable.Dispose, MoveNext, System.Collections.Generic.IEnumerator.get_Current, System.Collections.IEnumerator.Reset, System.Collections.IEnumerator.get_Current, System.Collections.Generic.IEnumerable.GetEnumerator, System.Collections.IEnumerable.GetEnumerator, System.Collections.Generic.IEnumerator.Current, System.Collections.IEnumerator.Current}"); + }) + .AddGeneration( + // 2 + source: """ + using System; + using System.Collections.Generic; + + class C + { + private static IEnumerable F() + { + dynamic d = "x"; + yield return d; + Console.WriteLine(2); + } + } + """, + edits: + [ + Edit(SemanticEditKind.Update, c => c.GetMember("C.F"), preserveLocalVariables: true) + ], + validator: v => + { + v.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", + "C: {<>o__0#2, d__0, <>o__0#1}", + "C.<>o__0#1: {<>p__0, <>p__1}", + "C.<>o__0#2: {<>p__0}", + "C.d__0: {<>1__state, <>2__current, <>l__initialThreadId, 5__1, System.IDisposable.Dispose, MoveNext, System.Collections.Generic.IEnumerator.get_Current, System.Collections.IEnumerator.Reset, System.Collections.IEnumerator.get_Current, System.Collections.Generic.IEnumerable.GetEnumerator, System.Collections.IEnumerable.GetEnumerator, System.Collections.Generic.IEnumerator.Current, System.Collections.IEnumerator.Current}"); + }) + .Verify(); } [Fact] @@ -8023,7 +7990,7 @@ static async Task G() return 1; } }"; - var compilation0 = CreateCompilationWithMscorlib45(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation0 = CreateCompilationWithMscorlib461(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); CompileAndVerify(compilation0, symbolValidator: module => { @@ -8164,7 +8131,7 @@ static async Task H() // updated // Rude edit but the compiler should handle it. - var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); + var compilation0 = CreateCompilationWithMscorlib461(source0.Tree, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation1.WithSource(source2.Tree); var compilation3 = compilation2.WithSource(source3.Tree); @@ -8242,7 +8209,7 @@ static async Task H() // updated diff1.VerifyPdb(new[] { MetadataTokens.MethodDefinitionHandle(9) }, @" - + @@ -8715,7 +8682,7 @@ public static IEnumerable H() // Rude edit but the compiler should handle it. - var compilation0 = CreateCompilationWithMscorlib45(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); + var compilation0 = CreateCompilationWithMscorlib461(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); var compilation1 = compilation0.WithSource(source1); var compilation2 = compilation1.WithSource(source2); var compilation3 = compilation2.WithSource(source3); @@ -8798,7 +8765,7 @@ public class C public static IEnumerable F() { yield return 1; } }"; - var compilation0 = CreateCompilationWithMscorlib45(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); + var compilation0 = CreateCompilationWithMscorlib461(source0, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); var compilation1 = compilation0.WithSource(source1); var compilation2 = compilation1.WithSource(source2); @@ -8890,7 +8857,7 @@ static void F() static Task A3() => null; }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation1.WithSource(source2.Tree); @@ -9043,7 +9010,7 @@ static async Task M() int F() => num; } }"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var m0 = compilation0.GetMember("C.M"); @@ -9166,7 +9133,7 @@ public IEnumerable F() } } "); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation1.WithSource(source2.Tree); @@ -9315,7 +9282,7 @@ public IEnumerable F() } } "); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation1.WithSource(source2.Tree); @@ -9475,7 +9442,7 @@ public IEnumerable F() } } "); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation1.WithSource(source2.Tree); @@ -9587,7 +9554,7 @@ public IEnumerable F() var source1 = MarkedSource(template.Replace("<>", "1")); var source2 = MarkedSource(template.Replace("<>", "2")); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation1.WithSource(source2.Tree); @@ -9760,7 +9727,7 @@ static async Task F() var source4 = source0; var source5 = source1; - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation0.WithSource(source2.Tree); var compilation3 = compilation0.WithSource(source3.Tree); @@ -9997,7 +9964,7 @@ from a in result } } "); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation1.WithSource(source2.Tree); @@ -10664,8 +10631,8 @@ public IEnumerable F() SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); diff1.EmitResult.Diagnostics.Verify( - // (7,29): error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' is missing. - Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("C.F()", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(7, 29)); + // (7,29): error CS7043: Cannot emit update; attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' is missing. + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingSymbol, "F").WithArguments(CodeAnalysisResources.Attribute, "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(7, 29)); } [Fact, WorkItem(9119, "https://github.com/dotnet/roslyn/issues/9119")] @@ -10731,9 +10698,9 @@ public IEnumerable F() SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); diff1.EmitResult.Diagnostics.Verify( - // (12,29): error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' is missing. + // (12,29): error CS7043: Cannot emit update; attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' is missing. // public IEnumerable F() - Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("C.F()", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(12, 29)); + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingSymbol, "F").WithArguments(CodeAnalysisResources.Attribute, "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(12, 29)); } [Fact] @@ -10917,8 +10884,11 @@ public async Task F() SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); diff1.EmitResult.Diagnostics.Verify( - // (6,28): error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.AsyncStateMachineAttribute' is missing. - Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("C.F()", "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(6, 28)); + // error CS7043: Cannot emit update; constructor 'System.Exception..ctor(string)' is missing. + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingSymbol).WithArguments("constructor", "System.Exception..ctor(string)").WithLocation(1, 1), + // (6,28): error CS7043: Cannot emit update; attribute 'System.Runtime.CompilerServices.AsyncStateMachineAttribute' is missing. + // public async Task F() + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingSymbol, "F").WithArguments("attribute", "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(6, 28)); } [Fact] @@ -10978,7 +10948,9 @@ public async Task F() SemanticEdit.Create(SemanticEditKind.Insert, null, asm1), SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); - diff1.EmitResult.Diagnostics.Verify(); + diff1.EmitResult.Diagnostics.Verify( + // error CS7043: Cannot emit update; constructor 'System.Exception..ctor(string)' is missing. + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingSymbol).WithArguments("constructor", "System.Exception..ctor(string)")); } [Fact] @@ -11028,6 +11000,7 @@ public async Task F() var v0 = CompileAndVerify(compilation0, verify: Verification.FailsPEVerify); v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); var f0 = compilation0.GetMember("C.F"); @@ -11040,7 +11013,9 @@ public async Task F() ImmutableArray.Create( SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); - diff1.EmitResult.Diagnostics.Verify(); + diff1.EmitResult.Diagnostics.Verify( + // error CS7043: Cannot emit update; constructor 'System.Exception..ctor(string)' is missing. + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingSymbol).WithArguments(CodeAnalysisResources.Constructor, "System.Exception..ctor(string)")); } [Fact, WorkItem(10190, "https://github.com/dotnet/roslyn/issues/10190")] @@ -11071,7 +11046,7 @@ public async Task F() } "); - var compilation0 = CreateEmptyCompilation(new[] { source0.Tree }, new[] { Net451.mscorlib }, options: ComSafeDebugDll); + var compilation0 = CreateEmptyCompilation(new[] { source0.Tree }, new[] { NetFramework.mscorlib }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); @@ -11141,8 +11116,11 @@ public async Task F() SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); diff1.EmitResult.Diagnostics.Verify( - // (6,28): error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.AsyncStateMachineAttribute' is missing. - Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("C.F()", "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(6, 28)); + // error CS7043: Cannot emit update; constructor 'System.Exception..ctor(string)' is missing. + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingSymbol).WithArguments("constructor", "System.Exception..ctor(string)").WithLocation(1, 1), + // (6,28): error CS7043: Cannot emit update; attribute 'System.Runtime.CompilerServices.AsyncStateMachineAttribute' is missing. + // public async Task F() + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingSymbol, "F").WithArguments("attribute", "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(6, 28)); } [Fact] @@ -11173,7 +11151,7 @@ public IEnumerable F() } "); - var compilation0 = CreateEmptyCompilation(new[] { source0.Tree }, new[] { Net20.mscorlib }, options: ComSafeDebugDll); + var compilation0 = CreateEmptyCompilation(new[] { source0.Tree }, new[] { Net20.References.mscorlib }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor)); @@ -11192,8 +11170,8 @@ public IEnumerable F() SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); diff1.EmitResult.Diagnostics.Verify( - // (6,29): error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' is missing. - Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("C.F()", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(6, 29)); + // (6,29): error CS7043: Cannot emit update; attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' is missing. + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingSymbol, "F").WithArguments(CodeAnalysisResources.Attribute, "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(6, 29)); } [Fact] @@ -11234,7 +11212,7 @@ public IEnumerable F() } "); - var compilation0 = CreateEmptyCompilation(new[] { source0.Tree }, new[] { Net20.mscorlib }, options: ComSafeDebugDll); + var compilation0 = CreateEmptyCompilation(new[] { source0.Tree }, new[] { Net20.References.mscorlib }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor)); @@ -11289,7 +11267,7 @@ public object F() } "); - var compilation0 = CreateEmptyCompilation(new[] { source0.Tree }, new[] { Net451.mscorlib }, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation0 = CreateEmptyCompilation(new[] { source0.Tree }, new[] { NetFramework.mscorlib }, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); var compilation1 = compilation0.WithSource(source1.Tree); Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); @@ -11356,7 +11334,7 @@ public async void F(string? x) } ", options: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9)); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); @@ -11377,15 +11355,12 @@ public async void F(string? x) diff1.EmitResult.Diagnostics.Verify(); diff1.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.NullableContextAttribute", + "Microsoft.CodeAnalysis.EmbeddedAttribute", + "System.Runtime.CompilerServices.NullableAttribute", "C.<>c__DisplayClass3_0: {x, y, b__1, b__0}", "<>f__AnonymousType0<j__TPar>: {Equals, GetHashCode, ToString}", - "System.Runtime.CompilerServices: {NullableAttribute, NullableContextAttribute}", - "Microsoft.CodeAnalysis: {EmbeddedAttribute}", - "Microsoft: {CodeAnalysis}", - "System.Runtime: {CompilerServices, CompilerServices}", "C: {<>c__DisplayClass3_0, d__3}", - ": {Microsoft, System, System}", - "System: {Runtime, Runtime}", "C.d__3: {<>1__state, <>t__builder, x, <>4__this, <>8__1, 5__2, <>s__3, <>u__1, MoveNext, SetStateMachine}"); diff1.VerifyIL("C.<>c__DisplayClass3_0.b__1()", @" diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTest.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTest.cs index 5161c2720c398..8305bb104d938 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTest.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTest.cs @@ -9,25 +9,29 @@ using Microsoft.CodeAnalysis.EditAndContinue.UnitTests; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; +using Xunit.Abstractions; using Public = Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel; namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests; internal sealed class EditAndContinueTest( + ITestOutputHelper? output = null, CSharpCompilationOptions? options = null, CSharpParseOptions? parseOptions = null, TargetFramework targetFramework = TargetFramework.Standard, IEnumerable? references = null, + string assemblyName = "", Verification? verification = null) - : EditAndContinueTest(verification) + : EditAndContinueTest(output, verification) { private readonly CSharpCompilationOptions _compilationOptions = (options ?? TestOptions.DebugDll).WithConcurrentBuild(false); private readonly CSharpParseOptions _parseOptions = parseOptions ?? TestOptions.Regular.WithNoRefSafetyRulesAttribute(); private readonly TargetFramework _targetFramework = targetFramework; private readonly IEnumerable? _references = references; + private readonly string? _assemblyName = assemblyName; protected override Compilation CreateCompilation(SyntaxTree tree) - => CSharpTestBase.CreateCompilation(tree, _references, options: _compilationOptions, targetFramework: _targetFramework); + => CSharpTestBase.CreateCompilation(tree, _references, options: _compilationOptions, assemblyName: _assemblyName, targetFramework: _targetFramework); protected override SourceWithMarkedNodes CreateSourceWithMarkedNodes(string source) => EditAndContinueTestBase.MarkedSource(source, options: _parseOptions); diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index 41ff3e1fd848c..ce58d22354c8a 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -74,28 +74,52 @@ public C() }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames(".ctor"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames(".ctor", ".ctor"); - g.VerifyTypeRefNames("Object", "MissingMethodException"); - g.VerifyMemberRefNames(".ctor"); + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Exception"); + g.VerifyMemberRefNames(".ctor", ".ctor"); g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); + g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(2, TableIndex.MethodDef), + Handle(3, TableIndex.MethodDef), + Handle(4, TableIndex.CustomAttribute) }); var expectedIL = """ { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000003 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000006 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret } """; @@ -136,28 +160,39 @@ class C validator: g => { // The default constructor is added and the deleted constructor is updated to throw: - g.VerifyMethodDefNames(".ctor", ".ctor"); - g.VerifyTypeRefNames("Object", "MissingMethodException"); + g.VerifyMethodDefNames(".ctor", ".ctor", ".ctor"); + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Exception"); g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef), + Handle(3, TableIndex.MethodDef), + Handle(4, TableIndex.CustomAttribute) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000003 + IL_000c: throw } { // Code size 8 (0x8) @@ -167,6 +202,18 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000007 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret + } """); }) .Verify(); @@ -291,7 +338,7 @@ public void Delta_AssemblyDefTable() var source0 = @"public class C { public static void F() { System.Console.WriteLine(1); } }"; var source1 = @"public class C { public static void F() { System.Console.WriteLine(2); } }"; - var compilation0 = CreateCompilationWithMscorlib45(source0, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source0, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1); var f0 = compilation0.GetMember("C.F"); @@ -2186,13 +2233,9 @@ static unsafe void F() where U : unmanaged CheckNames(readers, reader1.GetMethodDefNames(), "F", "b__0_0", ".ctor", "Invoke", "b__0_1#1"); diff1.VerifySynthesizedMembers( - "Microsoft.CodeAnalysis: {EmbeddedAttribute}", - "Microsoft: {CodeAnalysis}", - "System.Runtime: {CompilerServices}", + "Microsoft.CodeAnalysis.EmbeddedAttribute", + "System.Runtime.CompilerServices.IsUnmanagedAttribute", "C: {<>c__0}", - ": {Microsoft, System}", - "System: {Runtime}", - "System.Runtime.CompilerServices: {IsUnmanagedAttribute}", "C.<>c__0: {<>9__0_0, <>9__0_1#1, b__0_0, b__0_1#1}"); var diff2 = compilation2.EmitDifference( @@ -2209,13 +2252,9 @@ static unsafe void F() where U : unmanaged CheckNames(readers, reader2.GetMethodDefNames(), "F", "b__0_0", "b__0_1#1"); diff2.VerifySynthesizedMembers( - "Microsoft.CodeAnalysis: {EmbeddedAttribute}", - "System: {Runtime}", - ": {Microsoft, System}", + "Microsoft.CodeAnalysis.EmbeddedAttribute", + "System.Runtime.CompilerServices.IsUnmanagedAttribute", "C: {<>c__0}", - "System.Runtime.CompilerServices: {IsUnmanagedAttribute}", - "System.Runtime: {CompilerServices}", - "Microsoft: {CodeAnalysis}", "C.<>c__0: {<>9__0_0, <>9__0_1#1, b__0_0, b__0_1#1}"); } @@ -2314,24 +2353,35 @@ void F() validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c}", "C.<>c: {<>9__0_1, b__0_1}"); - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("F", "b__0_0", "b__0_1"); - g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Action", "MissingMethodException", "Console"); - g.VerifyMemberRefNames(".ctor", ".ctor", ".ctor", "WriteLine"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("F", "b__0_0", "b__0_1", ".ctor"); + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Exception", "Action", "Console"); + g.VerifyMemberRefNames(".ctor", ".ctor", "WriteLine", ".ctor"); g.VerifyEncLogDefinitions(new[] { + Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(4, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(4, TableIndex.TypeDef), + Handle(4, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(5, TableIndex.MethodDef), - Handle(6, TableIndex.MethodDef) + Handle(6, TableIndex.MethodDef), + Handle(7, TableIndex.MethodDef), + Handle(5, TableIndex.CustomAttribute) }); g.VerifyIL(""" @@ -2348,20 +2398,33 @@ .maxstack 8 IL_001d: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000007 + IL_000b: throw } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.2 - IL_0001: call 0x0A00000B + IL_0001: call 0x0A00000A IL_0006: nop IL_0007: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000004 + IL_000f: ret + } """); }) .Verify(); @@ -2567,56 +2630,52 @@ .locals init ([unchanged] V_0, [Fact] public void PartialMethod() { - var source = -@"partial class C -{ - static partial void M1(); - static partial void M2(); - static partial void M3(); - static partial void M1() { } - static partial void M2() { } -}"; - var compilation0 = CreateCompilation(source, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); - var compilation1 = compilation0.WithSource(source); - - var bytes0 = compilation0.EmitToArray(); - using var md0 = ModuleMetadata.CreateFromImage(bytes0); - var reader0 = md0.MetadataReader; - - CheckNames(reader0, reader0.GetMethodDefNames(), "M1", "M2", ".ctor"); - - var method0 = compilation0.GetMember("C.M2").PartialImplementationPart; - var method1 = compilation1.GetMember("C.M2").PartialImplementationPart; - - var generation0 = CreateInitialBaseline(compilation0, - md0, - EmptyLocalsProvider); - - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1))); - - var methods = diff1.TestData.GetMethodsByName(); - Assert.Equal(1, methods.Count); - Assert.True(methods.ContainsKey("C.M2()")); - - using var md1 = diff1.GetMetadata(); - var reader1 = md1.Reader; - var readers = new[] { reader0, reader1 }; - - EncValidation.VerifyModuleMvid(1, reader0, reader1); - - CheckNames(readers, reader1.GetMethodDefNames(), "M2"); + using var _ = new EditAndContinueTest(options: TestOptions.DebugDll) + .AddBaseline( + source: """ + partial class C + { + static partial void M1(); + static partial void M2(); + static partial void M3(); + static partial void M1() { } + static partial void M2() { } + } + """, + validator: v => + { + v.VerifyMethodDefNames("M1", "M2", ".ctor"); + }) + .AddGeneration( + source: """ + partial class C + { + static partial void M1(); + static partial void M2(); + static partial void M3(); + static partial void M1() { } + static partial void M2() { } + } + """, + edits: + [ + Edit(SemanticEditKind.Update, c => c.GetMember("C.M2").PartialImplementationPart), + ], + validator: v => + { + v.VerifyMethodDefNames("M2"); - CheckEncLog(reader1, - Row(2, TableIndex.AssemblyRef, EditAndContinueOperation.Default), - Row(6, TableIndex.TypeRef, EditAndContinueOperation.Default), - Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default)); + v.VerifyEncLogDefinitions( + [ + Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default) + ]); - CheckEncMap(reader1, - Handle(6, TableIndex.TypeRef), - Handle(2, TableIndex.MethodDef), - Handle(2, TableIndex.AssemblyRef)); + v.VerifyEncMapDefinitions( + [ + Handle(2, TableIndex.MethodDef) + ]); + }) + .Verify(); } [WorkItem(60804, "https://github.com/dotnet/roslyn/issues/60804")] @@ -2663,30 +2722,43 @@ partial void M() }, validator: g => { - g.VerifyMethodDefNames("M", "b__0", ".ctor", "b__0#1"); + g.VerifyMethodDefNames("M", "b__0", ".ctor", ".ctor", "b__0#1"); g.VerifyIL(""" - { + { // Code size 28 (0x1c) .maxstack 2 - IL_0000: newobj 0x06000005 + IL_0000: newobj 0x06000006 IL_0005: stloc.0 IL_0006: nop IL_0007: ldloc.0 IL_0008: ldc.i4.5 - IL_0009: stfld 0x04000002 + IL_0009: stfld 0x04000003 IL_000e: ldloc.0 - IL_000f: ldftn 0x06000006 + IL_000f: ldftn 0x06000007 IL_0015: newobj 0x0A000008 IL_001a: stloc.1 IL_001b: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000005 + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret } { // Code size 8 (0x8) @@ -2700,7 +2772,7 @@ .maxstack 8 // Code size 9 (0x9) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000002 + IL_0001: ldfld 0x04000003 IL_0006: ldc.i4.4 IL_0007: add IL_0008: ret @@ -2711,6 +2783,100 @@ .maxstack 8 .Verify(); } + [Fact] + public void PartialProperty() + { + using var _ = new EditAndContinueTest(options: TestOptions.DebugDll) + .AddBaseline( + source: """ + partial class C + { + partial int P { get; } + partial int P => 1; + } + """, + validator: v => + { + v.VerifyMethodDefNames("get_P", ".ctor"); + }) + .AddGeneration( + source: """ + partial class C + { + [System.Obsolete]partial int P { get; } + partial int P => 1; + } + """, + edits: + [ + Edit(SemanticEditKind.Update, c => c.GetMember("C.P").PartialImplementationPart), + ], + validator: v => + { + v.VerifyMethodDefNames(); + + v.VerifyEncLogDefinitions( + [ + Row(1, TableIndex.Property, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodSemantics, EditAndContinueOperation.Default) + ]); + + v.VerifyEncMapDefinitions( + [ + Handle(4, TableIndex.CustomAttribute), + Handle(1, TableIndex.Property), + Handle(2, TableIndex.MethodSemantics) + ]); + }) + .Verify(); + } + + [Fact] + public void PartialProperty_Accessor() + { + using var _ = new EditAndContinueTest(options: TestOptions.DebugDll) + .AddBaseline( + source: """ + partial class C + { + partial int P { get; } + partial int P => 1; + } + """, + validator: v => + { + v.VerifyMethodDefNames("get_P", ".ctor"); + }) + .AddGeneration( + source: """ + partial class C + { + partial int P { get; } + partial int P => 2; + } + """, + edits: + [ + Edit(SemanticEditKind.Update, c => c.GetMember("C.get_P").PartialImplementationPart), + ], + validator: v => + { + v.VerifyMethodDefNames("get_P"); + + v.VerifyEncLogDefinitions( + [ + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default) + ]); + + v.VerifyEncMapDefinitions( + [ + Handle(1, TableIndex.MethodDef) + ]); + }) + .Verify(); + } + [Fact] public void Method_WithAttributes_Add() { @@ -3434,10 +3600,8 @@ static void H(string? s) {} SemanticEdit.Create(SemanticEditKind.Insert, null, g1))); diff1.VerifySynthesizedMembers( - ": {Microsoft}", - "Microsoft: {CodeAnalysis}", - "Microsoft.CodeAnalysis: {EmbeddedAttribute}", - "System.Runtime.CompilerServices: {IsReadOnlyAttribute}"); + "Microsoft.CodeAnalysis.EmbeddedAttribute", + "System.Runtime.CompilerServices.IsReadOnlyAttribute"); diff1.VerifyIL("N.C.Main", @" { @@ -3526,10 +3690,10 @@ .maxstack 4 // synthesized member for nullable annotations added: diff2.VerifySynthesizedMembers( - ": {Microsoft}", - "Microsoft: {CodeAnalysis}", - "Microsoft.CodeAnalysis: {EmbeddedAttribute}", - "System.Runtime.CompilerServices: {IsReadOnlyAttribute, NullableAttribute, NullableContextAttribute}"); + "System.Runtime.CompilerServices.IsReadOnlyAttribute", + "System.Runtime.CompilerServices.NullableAttribute", + "System.Runtime.CompilerServices.NullableContextAttribute", + "Microsoft.CodeAnalysis.EmbeddedAttribute"); // Verify delta metadata contains expected rows. using var md2 = diff2.GetMetadata(); @@ -3621,10 +3785,10 @@ .maxstack 4 // no change in synthesized members: diff3.VerifySynthesizedMembers( - ": {Microsoft}", - "Microsoft: {CodeAnalysis}", - "Microsoft.CodeAnalysis: {EmbeddedAttribute}", - "System.Runtime.CompilerServices: {IsReadOnlyAttribute, NullableAttribute, NullableContextAttribute}"); + "System.Runtime.CompilerServices.IsReadOnlyAttribute", + "System.Runtime.CompilerServices.NullableAttribute", + "System.Runtime.CompilerServices.NullableContextAttribute", + "Microsoft.CodeAnalysis.EmbeddedAttribute"); // Verify delta metadata contains expected rows. using var md3 = diff3.GetMetadata(); @@ -3924,30 +4088,53 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("get_P", "set_P"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("get_P", "set_P", ".ctor"); // Set the property name to "_deleted" // TODO: https://github.com/dotnet/roslyn/issues/69834 g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(2, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(8, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(2, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(8, TableIndex.CustomAttribute) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000007 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret } """); }) @@ -4043,29 +4230,53 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("get_P", "set_P"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("get_P", "set_P", ".ctor"); // Set the property name to "_deleted" // TODO: https://github.com/dotnet/roslyn/issues/69834 - g.VerifyEncLogDefinitions(new[] - { + g.VerifyEncLogDefinitions( + [ + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), - }); - g.VerifyEncMapDefinitions(new[] - { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) + ]); + + g.VerifyEncMapDefinitions( + [ + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef), - }); + Handle(4, TableIndex.MethodDef), + Handle(4, TableIndex.CustomAttribute) + ]); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000009 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000006 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret } """); }) @@ -4087,28 +4298,28 @@ class C g.VerifyEncLogDefinitions(new[] { Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(1, TableIndex.Field, EditAndContinueOperation.Default), + Row(2, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(1, TableIndex.Property, EditAndContinueOperation.Default), Row(1, TableIndex.Param, EditAndContinueOperation.Default), - Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(8, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(3, TableIndex.MethodSemantics, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodSemantics, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodSemantics, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { - Handle(1, TableIndex.Field), + Handle(2, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef), Handle(1, TableIndex.Param), - Handle(4, TableIndex.CustomAttribute), Handle(5, TableIndex.CustomAttribute), Handle(6, TableIndex.CustomAttribute), Handle(7, TableIndex.CustomAttribute), + Handle(8, TableIndex.CustomAttribute), Handle(1, TableIndex.Property), Handle(3, TableIndex.MethodSemantics), Handle(4, TableIndex.MethodSemantics) @@ -4119,7 +4330,7 @@ class C // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x04000001 + IL_0001: ldfld 0x04000002 IL_0006: ret } { @@ -4127,7 +4338,7 @@ .maxstack 8 .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 - IL_0002: stfld 0x04000001 + IL_0002: stfld 0x04000002 IL_0007: ret } """; @@ -4168,29 +4379,52 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("get_P", "set_P"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("get_P", "set_P", ".ctor"); // Set the property name to "_deleted" // TODO: https://github.com/dotnet/roslyn/issues/69834 g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(4, TableIndex.CustomAttribute) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000009 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000006 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret } """); }) @@ -4285,25 +4519,48 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("set_P"); - g.VerifyMemberRefNames(/* MissingMethodException */ ".ctor"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("set_P", ".ctor"); + g.VerifyMemberRefNames(/* Exception */ ".ctor", /* CompilerGeneratedAttribute */ ".ctor"); g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(2, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(4, TableIndex.CustomAttribute) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000009 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000006 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret } """); }) @@ -4384,6 +4641,7 @@ class C g.VerifyMethodDefNames("get_P", "set_P", ".ctor"); }) .AddGeneration( + // 1 source: $$""" class C { @@ -4401,20 +4659,25 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("get_P", "set_P", "get_P", "set_P"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("get_P", "set_P", "get_P", "set_P", ".ctor"); g.VerifyDeletedMembers("C: {P, get_P, set_P}"); g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddField), Row(2, TableIndex.Field, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(1, TableIndex.PropertyMap, EditAndContinueOperation.AddProperty), Row(2, TableIndex.Property, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), @@ -4423,21 +4686,26 @@ class C Row(9, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(10, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(11, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(12, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(3, TableIndex.MethodSemantics, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodSemantics, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodSemantics, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), Handle(2, TableIndex.Field), + Handle(3, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef), Handle(5, TableIndex.MethodDef), + Handle(6, TableIndex.MethodDef), Handle(2, TableIndex.Param), Handle(8, TableIndex.CustomAttribute), Handle(9, TableIndex.CustomAttribute), Handle(10, TableIndex.CustomAttribute), Handle(11, TableIndex.CustomAttribute), + Handle(12, TableIndex.CustomAttribute), Handle(2, TableIndex.Property), Handle(3, TableIndex.MethodSemantics), Handle(4, TableIndex.MethodSemantics) @@ -4445,11 +4713,12 @@ class C var expectedIL = """ { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } { // Code size 7 (0x7) @@ -4466,12 +4735,25 @@ .maxstack 8 IL_0002: stfld 0x04000002 IL_0007: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret + } """; // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations g.VerifyIL(expectedIL); }) .AddGeneration( + // 2 source: $$""" class C { @@ -4536,11 +4818,12 @@ .maxstack 8 IL_0007: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000151 - IL_0005: newobj 0x0A00000C - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } """); }) @@ -4564,6 +4847,7 @@ class C g.VerifyMethodDefNames("get_P", "set_P", ".ctor"); }) .AddGeneration( + // 1 source: """ class C { @@ -4580,20 +4864,25 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("get_P", "set_P", "get_Q", "set_Q"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("get_P", "set_P", "get_Q", "set_Q", ".ctor"); g.VerifyDeletedMembers("C: {get_P, set_P, P}"); g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddField), Row(2, TableIndex.Field, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(1, TableIndex.PropertyMap, EditAndContinueOperation.AddProperty), Row(2, TableIndex.Property, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), @@ -4602,33 +4891,39 @@ class C Row(9, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(10, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(11, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(12, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(3, TableIndex.MethodSemantics, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodSemantics, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodSemantics, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), Handle(2, TableIndex.Field), + Handle(3, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef), Handle(5, TableIndex.MethodDef), + Handle(6, TableIndex.MethodDef), Handle(2, TableIndex.Param), Handle(8, TableIndex.CustomAttribute), Handle(9, TableIndex.CustomAttribute), Handle(10, TableIndex.CustomAttribute), Handle(11, TableIndex.CustomAttribute), + Handle(12, TableIndex.CustomAttribute), Handle(2, TableIndex.Property), Handle(3, TableIndex.MethodSemantics), - Handle(4, TableIndex.MethodSemantics), + Handle(4, TableIndex.MethodSemantics) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } { // Code size 7 (0x7) @@ -4645,9 +4940,22 @@ .maxstack 8 IL_0002: stfld 0x04000002 IL_0007: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret + } """); }) .AddGeneration( + // 2 source: $$""" class C { @@ -4712,11 +5020,12 @@ .maxstack 8 IL_0007: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000151 - IL_0005: newobj 0x0A00000C - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } """); }) @@ -4753,30 +5062,53 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("get_Item", "set_Item"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("get_Item", "set_Item", ".ctor"); g.VerifyDeletedMembers("C: {get_Item, set_Item, this[]}"); // Set the property name to "_deleted" // TODO: https://github.com/dotnet/roslyn/issues/69834 g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(5, TableIndex.CustomAttribute) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000006 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000007 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret } """); }) @@ -4800,6 +5132,7 @@ class C g.VerifyMethodDefNames("get_Item", ".ctor"); }) .AddGeneration( + // 1 source: $$""" class C { @@ -4814,39 +5147,50 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("get_Item", "get_Item"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("get_Item", "get_Item", ".ctor"); g.VerifyDeletedMembers("C: {this[], get_Item}"); g.VerifyEncLogDefinitions(new[] { Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(1, TableIndex.PropertyMap, EditAndContinueOperation.AddProperty), Row(2, TableIndex.Property, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), Row(2, TableIndex.Param, EditAndContinueOperation.Default), - Row(2, TableIndex.MethodSemantics, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodSemantics, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), Handle(2, TableIndex.Param), + Handle(5, TableIndex.CustomAttribute), Handle(2, TableIndex.StandAloneSig), Handle(2, TableIndex.Property), - Handle(2, TableIndex.MethodSemantics), + Handle(2, TableIndex.MethodSemantics) }); g.VerifyIL(""" - { - // Code size 11 (0xb) + { + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000007 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } { // Code size 7 (0x7) @@ -4858,9 +5202,22 @@ .maxstack 1 IL_0005: ldloc.0 IL_0006: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret + } """); }) .AddGeneration( + // 2 source: $$""" class C { @@ -4910,14 +5267,18 @@ .maxstack 1 IL_0006: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000151 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } """); - }).AddGeneration(""" + }) + .AddGeneration( + // 3 + source: """ class C { int this[int x] { get { return 2; } } @@ -5208,30 +5569,53 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("add_E", "remove_E"); - g.VerifyTypeRefNames("Object", "EventHandler", "MissingMethodException"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("add_E", "remove_E", ".ctor"); + g.VerifyTypeRefNames("Object", "EventHandler", "CompilerGeneratedAttribute", "Exception"); // Set the property name to "_deleted" // TODO: https://github.com/dotnet/roslyn/issues/69834 g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(2, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(8, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(2, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(8, TableIndex.CustomAttribute) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000002 + IL_000f: ret } """); }) @@ -5256,6 +5640,7 @@ class C }) .AddGeneration( + // 1 source: """ class C { @@ -5272,21 +5657,26 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("add_E", "remove_E", "add_F", "remove_F"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("add_E", "remove_E", "add_F", "remove_F", ".ctor"); g.VerifyEncLogDefinitions(new[] { Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), Row(1, TableIndex.EventMap, EditAndContinueOperation.AddEvent), Row(2, TableIndex.Event, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddField), Row(2, TableIndex.Field, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), Row(3, TableIndex.Param, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), @@ -5295,35 +5685,41 @@ class C Row(9, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(10, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(11, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(12, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(3, TableIndex.MethodSemantics, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodSemantics, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodSemantics, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), Handle(2, TableIndex.Field), + Handle(3, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef), Handle(5, TableIndex.MethodDef), + Handle(6, TableIndex.MethodDef), Handle(3, TableIndex.Param), Handle(4, TableIndex.Param), Handle(8, TableIndex.CustomAttribute), Handle(9, TableIndex.CustomAttribute), Handle(10, TableIndex.CustomAttribute), Handle(11, TableIndex.CustomAttribute), + Handle(12, TableIndex.CustomAttribute), Handle(2, TableIndex.StandAloneSig), Handle(2, TableIndex.Event), Handle(3, TableIndex.MethodSemantics), - Handle(4, TableIndex.MethodSemantics), + Handle(4, TableIndex.MethodSemantics) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000C - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } { // Code size 41 (0x29) @@ -5335,7 +5731,7 @@ .maxstack 3 IL_0008: stloc.1 IL_0009: ldloc.1 IL_000a: ldarg.1 - IL_000b: call 0x0A00000D + IL_000b: call 0x0A00000C IL_0010: castclass 0x0100000D IL_0015: stloc.2 IL_0016: ldarg.0 @@ -5359,7 +5755,7 @@ .maxstack 3 IL_0008: stloc.1 IL_0009: ldloc.1 IL_000a: ldarg.1 - IL_000b: call 0x0A00000F + IL_000b: call 0x0A00000E IL_0010: castclass 0x0100000D IL_0015: stloc.2 IL_0016: ldarg.0 @@ -5373,10 +5769,23 @@ .maxstack 3 IL_0026: bne.un.s IL_0007 IL_0028: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000F + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret + } """); }) .AddGeneration( + // 2 source: """ class C { @@ -5476,11 +5885,12 @@ .maxstack 3 IL_0028: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000151 - IL_0005: newobj 0x0A000015 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } """); }) @@ -9977,7 +10387,7 @@ from a in args var source1 = MarkedSource(template.Replace("<>", "1")); var source2 = MarkedSource(template.Replace("<>", "2")); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation0.WithSource(source2.Tree); @@ -10100,7 +10510,7 @@ from a in args var source1 = MarkedSource(template.Replace("<>", "1")); var source2 = MarkedSource(template.Replace("<>", "2")); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation0.WithSource(source2.Tree); @@ -10201,118 +10611,116 @@ .locals init (System.Collections.Generic.IEnumerable<result = - from a in args - let x = a.Reverse() - let y = x.Reverse() - where x.SequenceEqual(y) - select new { Value = a, Length = a.Length }; - - var newArgs = - from a in result - let value = a.Value - let length = a.Length - where value.Length == length - select value; - - args = args.Concat(newArgs).ToArray(); - System.Diagnostics.Debugger.Break(); - result.ToString(); - } -} -"); - var source1 = MarkedSource(@" -using System.Linq; - -class C -{ - static void F(string[] args) - { - args = new[] { ""a"", ""bB"", ""Cc"", ""DD"" }; - var list = false ? null : new { Head = (dynamic)null, Tail = (dynamic)null }; - for (int i = 0; i < 10; i++) - { - var result = - from a in args - let x = a.Reverse() - let y = x.Reverse() - where x.SequenceEqual(y) - orderby a.Length ascending, a descending - select new { Value = a, Length = x.Count() }; - - var linked = result.Aggregate( - false ? new { Head = (string)null, Tail = (dynamic)null } : null, - (total, curr) => new { Head = curr.Value, Tail = (dynamic)total }); - - var str = linked?.Tail?.Head; - - var newArgs = - from a in result - let value = a.Value - let length = a.Length - where value.Length == length - select value + value; - - args = args.Concat(newArgs).ToArray(); - list = new { Head = (dynamic)i, Tail = (dynamic)list }; - System.Diagnostics.Debugger.Break(); - } - System.Diagnostics.Debugger.Break(); - } -} -"); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); - var compilation1 = compilation0.WithSource(source1.Tree); - - var v0 = CompileAndVerify(compilation0); - v0.VerifyDiagnostics(); - var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - - var f0 = compilation0.GetMember("C.F"); - var f1 = compilation1.GetMember("C.F"); - - var generation0 = CreateInitialBaseline(compilation0, md0, v0.CreateSymReader().GetEncMethodDebugInfo); - - v0.VerifyLocalSignature("C.F", @" -.locals init (System.Collections.Generic.IEnumerable<> V_0, //result - System.Collections.Generic.IEnumerable V_1) //newArgs -"); + using var _ = new EditAndContinueTest(references: [CSharpRef]) + .AddBaseline( + source: """ + using System.Linq; - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); + class C + { + static void F(string[] args) + { + args = new[] { "a", "bB", "Cc", "DD" }; + var result = + from a in args + let x = a.Reverse() + let y = x.Reverse() + where x.SequenceEqual(y) + select new { Value = a, Length = a.Length }; + + var newArgs = + from a in result + let value = a.Value + let length = a.Length + where value.Length == length + select value; + + args = args.Concat(newArgs).ToArray(); + System.Diagnostics.Debugger.Break(); + result.ToString(); + } + } + """, + validator: v => + { + v.VerifyLocalSignature("C.F", """ + .locals init (System.Collections.Generic.IEnumerable<> V_0, //result + System.Collections.Generic.IEnumerable V_1) //newArgs + """); + }) + .AddGeneration( + // 1 + source: """ + using System.Linq; - diff1.VerifySynthesizedMembers( - "C.<>o__0#1: {<>p__0}", - "C: {<>c, <>o__0#1}", - "C.<>c: {<>9__0_0, <>9__0_1, <>9__0_2, <>9__0_3#1, <>9__0_4#1, <>9__0_3, <>9__0_6#1, <>9__0_4, <>9__0_5, <>9__0_6, <>9__0_10#1, b__0_0, b__0_1, b__0_2, b__0_3#1, b__0_4#1, b__0_3, b__0_6#1, b__0_4, b__0_5, b__0_6, b__0_10#1}", - "<>f__AnonymousType4<<<>h__TransparentIdentifier0>j__TPar, j__TPar>: {Equals, GetHashCode, ToString}", - "<>f__AnonymousType2<j__TPar, j__TPar>: {Equals, GetHashCode, ToString}", - "<>f__AnonymousType5<j__TPar, j__TPar>: {Equals, GetHashCode, ToString}", - "<>f__AnonymousType3<j__TPar, j__TPar>: {Equals, GetHashCode, ToString}", - "<>f__AnonymousType0<j__TPar, j__TPar>: {Equals, GetHashCode, ToString}", - "<>f__AnonymousType1<<<>h__TransparentIdentifier0>j__TPar, j__TPar>: {Equals, GetHashCode, ToString}"); - - diff1.VerifyLocalSignature("C.F", @" - .locals init (System.Collections.Generic.IEnumerable<> V_0, //result - System.Collections.Generic.IEnumerable V_1, //newArgs - <>f__AnonymousType5 V_2, //list - int V_3, //i - <>f__AnonymousType5 V_4, //linked - object V_5, //str - <>f__AnonymousType5 V_6, - object V_7, - bool V_8) -"); + class C + { + static void F(string[] args) + { + args = new[] { "a", "bB", "Cc", "DD" }; + var list = false ? null : new { Head = (dynamic)null, Tail = (dynamic)null }; + for (int i = 0; i < 10; i++) + { + var result = + from a in args + let x = a.Reverse() + let y = x.Reverse() + where x.SequenceEqual(y) + orderby a.Length ascending, a descending + select new { Value = a, Length = x.Count() }; + + var linked = result.Aggregate( + false ? new { Head = (string)null, Tail = (dynamic)null } : null, + (total, curr) => new { Head = curr.Value, Tail = (dynamic)total }); + + var str = linked?.Tail?.Head; + + var newArgs = + from a in result + let value = a.Value + let length = a.Length + where value.Length == length + select value + value; + + args = args.Concat(newArgs).ToArray(); + list = new { Head = (dynamic)i, Tail = (dynamic)list }; + System.Diagnostics.Debugger.Break(); + } + System.Diagnostics.Debugger.Break(); + } + } + """, + edits: + [ + Edit(SemanticEditKind.Update, c => c.GetMember("C.F"), preserveLocalVariables: true) + ], + validator: v => + { + v.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", + "C.<>o__0#1: {<>p__0}", + "C: {<>c, <>o__0#1}", + "C.<>c: {<>9__0_0, <>9__0_1, <>9__0_2, <>9__0_3#1, <>9__0_4#1, <>9__0_3, <>9__0_6#1, <>9__0_4, <>9__0_5, <>9__0_6, <>9__0_10#1, b__0_0, b__0_1, b__0_2, b__0_3#1, b__0_4#1, b__0_3, b__0_6#1, b__0_4, b__0_5, b__0_6, b__0_10#1}", + "<>f__AnonymousType4<<<>h__TransparentIdentifier0>j__TPar, j__TPar>: {Equals, GetHashCode, ToString}", + "<>f__AnonymousType2<j__TPar, j__TPar>: {Equals, GetHashCode, ToString}", + "<>f__AnonymousType5<j__TPar, j__TPar>: {Equals, GetHashCode, ToString}", + "<>f__AnonymousType3<j__TPar, j__TPar>: {Equals, GetHashCode, ToString}", + "<>f__AnonymousType0<j__TPar, j__TPar>: {Equals, GetHashCode, ToString}", + "<>f__AnonymousType1<<<>h__TransparentIdentifier0>j__TPar, j__TPar>: {Equals, GetHashCode, ToString}"); + + v.VerifyLocalSignature("C.F", """ + .locals init (System.Collections.Generic.IEnumerable<> V_0, //result + System.Collections.Generic.IEnumerable V_1, //newArgs + <>f__AnonymousType5 V_2, //list + int V_3, //i + <>f__AnonymousType5 V_4, //linked + object V_5, //str + <>f__AnonymousType5 V_6, + object V_7, + bool V_8) + """); + }) + .Verify(); } [Fact] @@ -10334,7 +10742,7 @@ public void F() var source1 = MarkedSource(template.Replace("<>", "1")); var source2 = MarkedSource(template.Replace("<>", "2")); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation1.WithSource(source2.Tree); @@ -11010,7 +11418,7 @@ public void F() var source0 = MarkedSource(template.Replace("<>", "0")); var source1 = MarkedSource(template.Replace("<>", "1")); var source2 = MarkedSource(template.Replace("<>", "2")); - var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation0 = CreateCompilationWithMscorlib461(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); var compilation1 = compilation0.WithSource(source1.Tree); var compilation2 = compilation1.WithSource(source2.Tree); @@ -11605,25 +12013,50 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("op_LogicalNot"); - g.VerifyMemberRefNames(/* MissingMethodException */ ".ctor"); - g.VerifyEncLogDefinitions(new[] - { + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("op_LogicalNot", ".ctor"); + g.VerifyMemberRefNames(/* Exception */ ".ctor", /* CompilerGeneratedAttribute */ ".ctor"); + + g.VerifyEncLogDefinitions( + [ + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - }); - g.VerifyEncMapDefinitions(new[] - { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) + ]); + + g.VerifyEncMapDefinitions( + [ + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(1, TableIndex.MethodDef), - }); + Handle(3, TableIndex.MethodDef), + Handle(4, TableIndex.CustomAttribute) + ]); var expectedIL = """ { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000003 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000006 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret } """; @@ -12327,9 +12760,39 @@ public void ManyGenerations() } } + [Theory] + [InlineData(typeof(IOException))] + [InlineData(typeof(BadImageFormatException))] + [InlineData(typeof(InvalidDataException))] [WorkItem(187868, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/187868")] + public void SymReaderErrors(Type exceptionType) + { + using var _ = new EditAndContinueTest(assemblyName: "test") + .AddBaseline( + """ + class C { void F() { int x = 1; } } + """, + debugInformationProvider: _ => throw (Exception)Activator.CreateInstance(exceptionType, ["bug!"])) + .AddGeneration( + // 1 + """ + class C { void F() { int x = 2; } } + """, + edits: + [ + Edit(SemanticEditKind.Update, c => c.GetMember("C.F"), preserveLocalVariables: true) + ], + expectedErrors: + [ + // (1,16): error CS7103: Unable to read debug information of method 'C.F()' (token 0x06000001) from assembly 'test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null': bug! + // class C { void F() { int x = 2; } } + Diagnostic(ErrorCode.ERR_InvalidDebugInfo, "F").WithArguments("C.F()", "100663297", "test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "bug!").WithLocation(1, 16) + ]) + .Verify(); + } + [Fact] - public void PdbReadingErrors() + public void PdbReadingErrors_PassThruExceptions() { var source0 = MarkedSource(@" using System; @@ -12363,57 +12826,10 @@ static void F() var generation0 = CreateInitialBaseline(compilation0, md0, methodHandle => { - throw new InvalidDataException("Bad PDB!"); + throw new ArgumentOutOfRangeException(); }); - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))); - - diff1.EmitResult.Diagnostics.Verify( - // (6,14): error CS7038: Failed to emit module 'Unable to read debug information of method 'C.F()' (token 0x06000001) from assembly 'PdbReadingErrorsAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null''. - Diagnostic(ErrorCode.ERR_InvalidDebugInfo, "F").WithArguments("C.F()", "100663297", "PdbReadingErrorsAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(6, 14)); - } - - [Fact] - public void PdbReadingErrors_PassThruExceptions() - { - var source0 = MarkedSource(@" -using System; - -class C -{ - static void F() - { - Console.WriteLine(1); - } -}"); - - var source1 = MarkedSource(@" -using System; - -class C -{ - static void F() - { - Console.WriteLine(2); - } -}"); - var compilation0 = CreateCompilation(source0.Tree, options: TestOptions.DebugDll, assemblyName: "PdbReadingErrorsAssembly"); - var compilation1 = compilation0.WithSource(source1.Tree); - - var v0 = CompileAndVerify(compilation0); - var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - - var f0 = compilation0.GetMember("C.F"); - var f1 = compilation1.GetMember("C.F"); - - var generation0 = CreateInitialBaseline(compilation0, md0, methodHandle => - { - throw new ArgumentOutOfRangeException(); - }); - - // the compiler should't swallow any exceptions but InvalidDataException + // the compiler should't swallow any exceptions but InvalidDataException, IOException and BadImageFormatException Assert.Throws(() => compilation1.EmitDifference( generation0, @@ -15164,10 +15580,9 @@ protected virtual bool PrintMembers(System.Text.StringBuilder sb) // note the di SemanticEdit.Create(SemanticEditKind.Update, printMembers0, printMembers1))); diff1.VerifySynthesizedMembers( - ": {Microsoft}", - "Microsoft: {CodeAnalysis}", - "Microsoft.CodeAnalysis: {EmbeddedAttribute}", - "System.Runtime.CompilerServices: {NullableAttribute, NullableContextAttribute}"); + "Microsoft.CodeAnalysis.EmbeddedAttribute", + "System.Runtime.CompilerServices.NullableAttribute", + "System.Runtime.CompilerServices.NullableContextAttribute"); // Verify delta metadata contains expected rows. using var md1 = diff1.GetMetadata(); @@ -15246,10 +15661,9 @@ record R(int X) SemanticEdit.Create(SemanticEditKind.Update, method0, method1))); diff1.VerifySynthesizedMembers( - ": {Microsoft}", - "Microsoft: {CodeAnalysis}", - "Microsoft.CodeAnalysis: {EmbeddedAttribute}", - "System.Runtime.CompilerServices: {NullableAttribute, NullableContextAttribute}"); + "Microsoft.CodeAnalysis.EmbeddedAttribute", + "System.Runtime.CompilerServices.NullableAttribute", + "System.Runtime.CompilerServices.NullableContextAttribute"); } [Fact] @@ -15294,12 +15708,16 @@ public void Records_AddPrimaryConstructor() ".ctor", // updated parameterless ctor "get_P", "set_P", - "Deconstruct"); + "Deconstruct", + ".ctor"); // Exception g.VerifyEncLogDefinitions(new[] { + Row(7, TableIndex.TypeDef, EditAndContinueOperation.Default), Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), Row(3, TableIndex.Field, EditAndContinueOperation.Default), + Row(7, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(4, TableIndex.Field, EditAndContinueOperation.Default), Row(15, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(16, TableIndex.MethodDef, EditAndContinueOperation.Default), @@ -15309,6 +15727,8 @@ public void Records_AddPrimaryConstructor() Row(18, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(19, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(7, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(20, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(1, TableIndex.PropertyMap, EditAndContinueOperation.AddProperty), Row(2, TableIndex.Property, EditAndContinueOperation.Default), Row(16, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), @@ -15322,6 +15742,7 @@ public void Records_AddPrimaryConstructor() Row(32, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(33, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(34, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(35, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(2, TableIndex.MethodSemantics, EditAndContinueOperation.Default), Row(3, TableIndex.MethodSemantics, EditAndContinueOperation.Default) }); @@ -15706,228 +16127,613 @@ .maxstack 1 }"); } - [Theory] - [InlineData("void M1() { }")] - [InlineData("void M1(string s) { }")] - [InlineData("void M1(C c) { }")] - [InlineData("C M1(C c) { return default; }")] - [InlineData("void M1(N n) { }")] - [InlineData("C M1() { return default; }")] - [InlineData("N M1() { return default; }")] - [InlineData("int M1(C c) { return 0; }")] - [InlineData("void M1(T t) { }")] - [InlineData("void M1(T t) where T : C { }")] - [InlineData("T M1() { return default; }")] - [InlineData("T M1() where T : C { return default; }")] - public void Method_Delete(string methodDef) + [Fact] + public void Method_Delete_SynthesizedHotReloadException_MissingExceptionType() { - using var _ = new EditAndContinueTest() + using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Minimal, verification: Verification.Skipped) .AddBaseline( - source: $$""" + source: """ class C { - {{methodDef}} + void F() {} } - - class N + """) + .AddGeneration( + // 1 + source: """ + class C { } """, - validator: g => + edits: + [ + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.F"), newSymbolProvider: c => c.GetMember("C")), + ], + expectedErrors: + [ + // error CS7043: Cannot emit update; constructor 'System.Exception..ctor(string)' is missing. + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingSymbol).WithArguments("constructor", "System.Exception..ctor(string)").WithLocation(1, 1) + ]) + .Verify(); + } + + [Fact] + public void Method_Delete_SynthesizedHotReloadException_MissingCompilerGeneratedAttribute() + { + var libs = """ + namespace System + { + public class Exception { - g.VerifyTypeDefNames("", "C", "N"); - g.VerifyMethodDefNames("M1", ".ctor", ".ctor"); - }) + public Exception(string message) {} + } + } + """; - .AddGeneration( - source: """ + using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Minimal, verification: Verification.Skipped) + .AddBaseline( + source: libs + """ class C { + void F() {} } - - class N + """) + .AddGeneration( + // 1 + source: libs + """ + class C { } """, - edits: new[] { - Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c => c.GetMember("C")), - }, + edits: + [ + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.F"), newSymbolProvider: c => c.GetMember("C")), + ], validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M1"); - g.VerifyMemberRefNames(/* MissingMethodException */ ".ctor"); - g.VerifyEncLogDefinitions(new[] - { - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default) - }); - g.VerifyEncMapDefinitions(new[] - { - Handle(1, TableIndex.MethodDef), - }); + g.VerifySynthesizedMembers("System.Runtime.CompilerServices.HotReloadException"); + g.VerifyTypeDefNames("HotReloadException"); - var expectedIL = """ - { - // Code size 11 (0xb) + // Note TypeRef CompilerGeneratedAttribute not present: + g.VerifyTypeRefNames("Object"); + + g.VerifyIL(""" + { + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x06000003 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret + } + """); }) .Verify(); } [Fact] - public void Method_AddThenDelete() + public void Method_Delete_PredefinedHotReloadException() { + var exceptionSource = """ + namespace System.Runtime.CompilerServices + { + public class HotReloadException : Exception + { + public HotReloadException(string message, int code) : base(message) {} + } + } + """; + using var _ = new EditAndContinueTest() .AddBaseline( - source: $$""" + source: exceptionSource + """ class C { - void M1() { } + void F1() {} + void F2() {} } - """, - validator: g => - { - g.VerifyTypeDefNames("", "C"); - g.VerifyMethodDefNames("M1", ".ctor"); - g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor"); - }) - + """) .AddGeneration( - source: """ + // 1 + source: exceptionSource + """ class C { - void M1() { } - void M2() { } + void F2() {} } """, - edits: new[] { - Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMember("C.M2")), - }, + edits: + [ + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.F1"), newSymbolProvider: c => c.GetMember("C")), + ], validator: g => { + g.VerifySynthesizedMembers(); g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M2"); - g.VerifyEncLogDefinitions(new[] - { - Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default) - }); - g.VerifyEncMapDefinitions(new[] - { - Handle(3, TableIndex.MethodDef), - }); + g.VerifyTypeRefNames("Object"); - var expectedIL = """ + g.VerifyIL(""" { - // Code size 2 (0x2) + // Code size 13 (0xd) .maxstack 8 - IL_0000: nop - IL_0001: ret + IL_0000: ldstr 0x70000005 + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) - .AddGeneration( - source: """ + // 2 + source: exceptionSource + """ class C { - void M1() { } } """, - edits: new[] { - Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M2"), newSymbolProvider: c => c.GetMember("C")), - }, + edits: + [ + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.F2"), newSymbolProvider: c => c.GetMember("C")), + ], validator: g => { + g.VerifySynthesizedMembers(); g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M2"); - g.VerifyEncLogDefinitions(new[] - { - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default) - }); - g.VerifyEncMapDefinitions(new[] - { - Handle(3, TableIndex.MethodDef), - }); + g.VerifyTypeRefNames("Object"); - var expectedIL = """ + g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 - IL_0000: ldstr 0x70000009 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0000: ldstr 0x70000151 + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .Verify(); } [Fact] - public void Method_DeleteThenAdd() + public void Method_Delete_PredefinedHotReloadException_Inserted() { + var exceptionSource = """ + namespace System.Runtime.CompilerServices + { + public class HotReloadException : Exception + { + public HotReloadException(string message, int code) : base(message) {} + } + } + """; + using var _ = new EditAndContinueTest() .AddBaseline( - source: $$""" + source: """ class C { - void M1() { } + void F1() {} + void F2() {} } - """, - validator: g => - { - g.VerifyTypeDefNames("", "C"); - g.VerifyMethodDefNames("M1", ".ctor"); - g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor"); - }) - + """) .AddGeneration( - source: """ + // 1 + source: exceptionSource + """ class C { + void F2() {} } """, - edits: new[] { - Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c => c.GetMember("C")), - }, + edits: + [ + Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMember("System.Runtime.CompilerServices.HotReloadException")), + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.F1"), newSymbolProvider: c => c.GetMember("C")), + ], validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M1"); - g.VerifyEncLogDefinitions(new[] - { - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default) - }); - g.VerifyEncMapDefinitions(new[] - { - Handle(1, TableIndex.MethodDef), - }); + g.VerifySynthesizedMembers(); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyTypeRefNames("Exception", "Object"); - var expectedIL = """ + g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + { + // Code size 10 (0xa) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000005 + IL_0007: nop + IL_0008: nop + IL_0009: ret + } + """); + }) + .AddGeneration( + // 2 + source: exceptionSource + """ + class C + { + } + """, + edits: + [ + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.F2"), newSymbolProvider: c => c.GetMember("C")), + ], + validator: g => + { + g.VerifySynthesizedMembers(); + g.VerifyTypeDefNames(); + g.VerifyTypeRefNames("Object"); + + g.VerifyIL(""" + { + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldstr 0x70000151 + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw + } + """); + }) + .Verify(); + } + + [Fact] + public void Method_Delete_PredefinedHotReloadException_BadConstructor() + { + var exceptionSource = """ + namespace System.Runtime.CompilerServices + { + public class HotReloadException : Exception + { + public HotReloadException(string message) : base(message) {} + } + } + """; + + using var _ = new EditAndContinueTest(assemblyName: "TestAssembly") + .AddBaseline( + source: exceptionSource + """ + class C + { + void F1() {} + void F2() {} + } + """) + .AddGeneration( + // 1 + source: exceptionSource + """ + class C + { + void F2() {} + } + """, + edits: + [ + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.F1"), newSymbolProvider: c => c.GetMember("C")), + ], + expectedErrors: + [ + // error CS7038: Failed to emit module 'TestAssembly': 'System.Runtime.CompilerServices.HotReloadException' type does not have the expected constructor + Diagnostic(ErrorCode.ERR_ModuleEmitFailure) + .WithArguments("TestAssembly", string.Format(CodeAnalysisResources.Type0DoesNotHaveExpectedConstructor, "System.Runtime.CompilerServices.HotReloadException")) + ]) + .Verify(); + } + + [Theory] + [InlineData("void M1() { }")] + [InlineData("void M1(string s) { }")] + [InlineData("void M1(C c) { }")] + [InlineData("C M1(C c) { return default; }")] + [InlineData("void M1(N n) { }")] + [InlineData("C M1() { return default; }")] + [InlineData("N M1() { return default; }")] + [InlineData("int M1(C c) { return 0; }")] + [InlineData("void M1(T t) { }")] + [InlineData("void M1(T t) where T : C { }")] + [InlineData("T M1() { return default; }")] + [InlineData("T M1() where T : C { return default; }")] + public void Method_Delete(string methodDef) + { + using var _ = new EditAndContinueTest() + .AddBaseline( + source: $$""" + class C + { + {{methodDef}} + } + + class N + { + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C", "N"); + g.VerifyMethodDefNames("M1", ".ctor", ".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + } + + class N + { + } + """, + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c => c.GetMember("C")), + }, + validator: g => + { + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("M1", ".ctor"); + g.VerifyMemberRefNames(".ctor", ".ctor"); + g.VerifyEncLogDefinitions( + [ + Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) + ]); + + g.VerifyEncMapDefinitions( + [ + Handle(4, TableIndex.TypeDef), + Handle(1, TableIndex.Field), + Handle(1, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(4, TableIndex.CustomAttribute) + ]); + + var expectedIL = """ + { + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldstr 0x70000005 + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000006 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + .Verify(); + } + + [Fact] + public void Method_AddThenDelete() + { + using var _ = new EditAndContinueTest() + .AddBaseline( + source: $$""" + class C + { + void M1() { } + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyMethodDefNames("M1", ".ctor"); + g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + void M1() { } + void M2() { } + } + """, + edits: new[] { + Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMember("C.M2")), + }, + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("M2"); + g.VerifyEncLogDefinitions(new[] + { + Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default) + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(3, TableIndex.MethodDef), + }); + + var expectedIL = """ + { + // Code size 2 (0x2) + .maxstack 8 + IL_0000: nop + IL_0001: ret + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + + .AddGeneration( + source: """ + class C + { + void M1() { } + } + """, + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M2"), newSymbolProvider: c => c.GetMember("C")), + }, + validator: g => + { + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("M2", ".ctor"); + g.VerifyEncLogDefinitions(new[] + { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) + }); + + g.VerifyEncMapDefinitions(new[] + { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), + Handle(3, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(4, TableIndex.CustomAttribute) + }); + + var expectedIL = """ + { + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldstr 0x70000009 + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000006 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations + g.VerifyIL(expectedIL); + }) + .Verify(); + } + + [Fact] + public void Method_DeleteThenAdd() + { + using var _ = new EditAndContinueTest() + .AddBaseline( + source: $$""" + class C + { + void M1() { } + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyMethodDefNames("M1", ".ctor"); + g.VerifyMemberRefNames(/*CompilationRelaxationsAttribute.*/".ctor", /*RuntimeCompatibilityAttribute.*/".ctor", /*Object.*/".ctor", /*DebuggableAttribute*/".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + } + """, + edits: new[] { + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c => c.GetMember("C")), + }, + validator: g => + { + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("M1", ".ctor"); + g.VerifyEncLogDefinitions(new[] + { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) + }); + g.VerifyEncMapDefinitions(new[] + { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), + Handle(1, TableIndex.MethodDef), + Handle(3, TableIndex.MethodDef), + Handle(4, TableIndex.CustomAttribute) + }); + + var expectedIL = """ + { + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldstr 0x70000005 + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000003 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000006 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret + } + """; + + // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations g.VerifyIL(expectedIL); }) @@ -15954,20 +16760,17 @@ class C Handle(1, TableIndex.MethodDef), }); - var expectedIL = """ + g.VerifyIL(""" { // Code size 9 (0x9) .maxstack 8 IL_0000: nop IL_0001: ldc.i4.1 - IL_0002: call 0x0A000006 + IL_0002: call 0x0A000007 IL_0007: nop IL_0008: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .Verify(); } @@ -16009,27 +16812,53 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M1"); - g.VerifyEncLogDefinitions(new[] - { + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("M1", ".ctor"); + g.VerifyEncLogDefinitions( + [ + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - }); + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default) + ]); - g.VerifyEncMapDefinitions(new[] - { + g.VerifyEncMapDefinitions( + [ + Handle(5, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(3, TableIndex.MethodDef), - }); + Handle(5, TableIndex.MethodDef), + Handle(7, TableIndex.CustomAttribute) + ]); - g.VerifyCustomAttributes(); + g.VerifyCustomAttributes( + [ + new CustomAttributeRow(Handle(5, TableIndex.TypeDef), Handle(6, TableIndex.MemberRef)) + ]); var expectedIL = """ - { - // Code size 11 (0xb) + { + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000006 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000005 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000007 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret } """; @@ -16116,6 +16945,7 @@ void Goo() { } }) .AddGeneration( + // 1 source: """ class C { @@ -16163,6 +16993,7 @@ .maxstack 1 }) .AddGeneration( + // 2 source: """ class C { @@ -16174,24 +17005,49 @@ void Goo() { } }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M1"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("M1", ".ctor"); + g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); + g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(3, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(4, TableIndex.CustomAttribute) }); var expectedIL = """ { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000009 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000006 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret } """; @@ -16201,6 +17057,7 @@ .maxstack 8 }) .AddGeneration( + // 3 source: """ class C { @@ -16234,7 +17091,7 @@ void Goo() { } .maxstack 1 IL_0000: nop IL_0001: ldc.i4.1 - IL_0002: call 0x0A000006 + IL_0002: call 0x0A000007 IL_0007: nop IL_0008: ldnull IL_0009: stloc.0 @@ -16270,6 +17127,7 @@ class C "C.<>c: {<>9__0_0, b__0_0}"); }) .AddGeneration( + // 1 source: """ using System; @@ -16283,42 +17141,68 @@ class C ], validator: g => { - g.VerifySynthesizedMembers(); + g.VerifySynthesizedMembers("System.Runtime.CompilerServices.HotReloadException"); - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("F", "b__0_0"); - g.VerifyTypeRefNames("Object", "MissingMethodException"); - g.VerifyMemberRefNames(".ctor"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("F", "b__0_0", ".ctor"); + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Exception"); + g.VerifyMemberRefNames(".ctor", ".ctor"); g.VerifyEncLogDefinitions(new[] { + Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); + g.VerifyEncMapDefinitions(new[] { + Handle(4, TableIndex.TypeDef), + Handle(3, TableIndex.Field), Handle(1, TableIndex.MethodDef), - Handle(5, TableIndex.MethodDef) + Handle(5, TableIndex.MethodDef), + Handle(6, TableIndex.MethodDef), + Handle(5, TableIndex.CustomAttribute) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x7000014E - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000006 + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret } """); }) .AddGeneration( + // 2 source: """ using System; @@ -16334,8 +17218,10 @@ class C validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c}", "C.<>c: {<>9__0#2_0#2, b__0#2_0#2}"); + g.VerifyTypeDefNames(); g.VerifyMethodDefNames("F", ".ctor", "b__0#2_0#2"); g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Action", "Console"); @@ -16343,18 +17229,19 @@ class C g.VerifyEncLogDefinitions(new[] { Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(3, TableIndex.Field, EditAndContinueOperation.Default), + Row(4, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default) }); + g.VerifyEncMapDefinitions(new[] { - Handle(3, TableIndex.Field), + Handle(4, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(4, TableIndex.MethodDef), - Handle(6, TableIndex.MethodDef) + Handle(7, TableIndex.MethodDef) }); g.VerifyIL(""" @@ -16362,19 +17249,19 @@ class C // Code size 30 (0x1e) .maxstack 8 IL_0000: nop - IL_0001: ldsfld 0x04000003 + IL_0001: ldsfld 0x04000004 IL_0006: brtrue.s IL_001d IL_0008: ldsfld 0x04000001 - IL_000d: ldftn 0x06000006 - IL_0013: newobj 0x0A00000A - IL_0018: stsfld 0x04000003 + IL_000d: ldftn 0x06000007 + IL_0013: newobj 0x0A00000B + IL_0018: stsfld 0x04000004 IL_001d: ret } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldarg.0 - IL_0001: call 0x0A00000B + IL_0001: call 0x0A00000C IL_0006: nop IL_0007: ret } @@ -16382,13 +17269,14 @@ .maxstack 8 // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.2 - IL_0001: call 0x0A00000C + IL_0001: call 0x0A00000D IL_0006: nop IL_0007: ret } """); }) .AddGeneration( + // 3 source: """ using System; @@ -16404,39 +17292,43 @@ class C { // unchanged from previous generation: g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c}", "C.<>c: {<>9__0#2_0#2, b__0#2_0#2}"); g.VerifyTypeDefNames(); g.VerifyMethodDefNames("F", "b__0#2_0#2"); - g.VerifyTypeRefNames("Object", "MissingMethodException"); - g.VerifyMemberRefNames(".ctor"); + g.VerifyTypeRefNames("Object"); + g.VerifyMemberRefNames(); g.VerifyEncLogDefinitions(new[] { Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default) }); + g.VerifyEncMapDefinitions(new[] { Handle(1, TableIndex.MethodDef), - Handle(6, TableIndex.MethodDef) + Handle(7, TableIndex.MethodDef) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000299 - IL_0005: newobj 0x0A00000D - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x700003E2 - IL_0005: newobj 0x0A00000D - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000006 + IL_000b: throw } """); }) @@ -16460,7 +17352,7 @@ class C g.VerifySynthesizedMembers(); }) .AddGeneration( - // Add method with a lambda + // 1: Add method with a lambda source: """ using System; @@ -16484,7 +17376,7 @@ class C } ) .AddGeneration( - // Delete the method + // 2: Delete the method source: """ using System; @@ -16499,39 +17391,65 @@ class C validator: g => { g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c}", "C.<>c: {<>9__0#1_0#1, b__0#1_0#1}"); - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("F", "b__0#1_0#1"); - g.VerifyTypeRefNames("Object", "MissingMethodException"); - g.VerifyMemberRefNames(".ctor"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("F", "b__0#1_0#1", ".ctor"); + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Exception"); + g.VerifyMemberRefNames(".ctor", ".ctor"); g.VerifyEncLogDefinitions(new[] { + Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); + g.VerifyEncMapDefinitions(new[] { + Handle(4, TableIndex.TypeDef), + Handle(3, TableIndex.Field), Handle(2, TableIndex.MethodDef), - Handle(5, TableIndex.MethodDef) + Handle(5, TableIndex.MethodDef), + Handle(6, TableIndex.MethodDef), + Handle(5, TableIndex.CustomAttribute) }); g.VerifyIL(""" - { - // Code size 11 (0xb) + { + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000009 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000152 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000006 + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000A + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000003 + IL_000f: ret } """); }) @@ -16548,12 +17466,9 @@ class A : Attribute { } var synthesized = new[] { - ": {Microsoft, System, System}", - "System: {Runtime, Runtime}", - "Microsoft: {CodeAnalysis}", - "Microsoft.CodeAnalysis: {EmbeddedAttribute}", - "System.Runtime: {CompilerServices, CompilerServices}", - "System.Runtime.CompilerServices: {IsReadOnlyAttribute, RequiresLocationAttribute}", + "Microsoft.CodeAnalysis.EmbeddedAttribute", + "System.Runtime.CompilerServices.IsReadOnlyAttribute", + "System.Runtime.CompilerServices.RequiresLocationAttribute", }; using var _ = new EditAndContinueTest(verification: Verification.Skipped) @@ -16578,6 +17493,7 @@ ref readonly S F<[A]S>([A]T a, ref readonly S b) where S : struct ]); }) .AddGeneration( + // 1 source: common + """ class C { @@ -16603,6 +17519,7 @@ ref readonly S F<[A]S>([A]T a, ref readonly S b) where S : struct ]); }) .AddGeneration( + // 2 source: common + """ class C { @@ -16621,11 +17538,15 @@ ref readonly S F<[A]S>([A]T a, ref readonly S b) where S : struct ], validator: g => { - g.VerifySynthesizedMembers([.. synthesized, + g.VerifySynthesizedMembers( + [ + .. synthesized, "C: {<>c__0}", - "C.<>c__0: {<>9__0_0, <>9__0_1#1, <>9__0_2#2, b__0_0, b__0_1#1, b__0_2#2}"]); + "C.<>c__0: {<>9__0_0, <>9__0_1#1, <>9__0_2#2, b__0_0, b__0_1#1, b__0_2#2}" + ]); }) .AddGeneration( + // 3 source: common + """ class C { @@ -16640,53 +17561,78 @@ class C g.VerifySynthesizedMembers( [ .. synthesized, + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__0}", "C.<>c__0: {<>9__0_0, <>9__0_1#1, <>9__0_2#2, b__0_0, b__0_1#1, b__0_2#2}" ]); - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("F", "b__0_0", "b__0_1#1", "b__0_2#2"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("F", "b__0_0", "b__0_1#1", "b__0_2#2", ".ctor"); // Note: InAttribute is a custom modifier included in the signature - g.VerifyTypeRefNames("Object", "InAttribute", "MissingMethodException"); + g.VerifyTypeRefNames("Object", "InAttribute", "CompilerGeneratedAttribute", "Exception"); - g.VerifyMemberRefNames(".ctor"); + g.VerifyMemberRefNames(".ctor", ".ctor"); g.VerifyEncLogDefinitions(new[] { + Row(8, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(8, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(5, TableIndex.Field, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(11, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(11, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(8, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(15, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(8, TableIndex.TypeDef), + Handle(5, TableIndex.Field), Handle(5, TableIndex.MethodDef), Handle(9, TableIndex.MethodDef), Handle(10, TableIndex.MethodDef), - Handle(11, TableIndex.MethodDef) + Handle(11, TableIndex.MethodDef), + Handle(12, TableIndex.MethodDef), + Handle(15, TableIndex.CustomAttribute) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x7000000D - IL_0005: newobj 0x0A000023 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x0600000C + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000156 - IL_0005: newobj 0x0A000023 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x0600000C + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000024 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000005 + IL_000f: ret } """); }) .AddGeneration( - // Add deleted method back with another lambda + // 4: Add deleted method back with another lambda source: common + """ class C { @@ -16705,6 +17651,7 @@ void F<[A]S>([A]T a, S b) where S : struct g.VerifySynthesizedMembers( [ .. synthesized, + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__0#4, <>c__0}", "C.<>c__0#4: {<>9__0#4_0#4, b__0#4_0#4}", "C.<>c__0: {<>9__0_0, <>9__0_1#1, <>9__0_2#2, b__0_0, b__0_1#1, b__0_2#2}" @@ -16720,26 +17667,26 @@ void F<[A]S>([A]T a, S b) where S : struct // Code size 30 (0x1e) .maxstack 8 IL_0000: nop - IL_0001: ldsfld 0x0A000025 + IL_0001: ldsfld 0x0A000026 IL_0006: brtrue.s IL_001d - IL_0008: ldsfld 0x0A000026 - IL_000d: ldftn 0x0A000027 - IL_0013: newobj 0x0A000028 - IL_0018: stsfld 0x0A000025 + IL_0008: ldsfld 0x0A000027 + IL_000d: ldftn 0x0A000028 + IL_0013: newobj 0x0A000029 + IL_0018: stsfld 0x0A000026 IL_001d: ret } { // Code size 11 (0xb) .maxstack 8 - IL_0000: newobj 0x0A000029 - IL_0005: stsfld 0x0A00002A + IL_0000: newobj 0x0A00002A + IL_0005: stsfld 0x0A00002B IL_000a: ret } { // Code size 8 (0x8) .maxstack 8 IL_0000: ldarg.0 - IL_0001: call 0x0A00002B + IL_0001: call 0x0A00002C IL_0006: nop IL_0007: ret } @@ -16747,14 +17694,14 @@ .maxstack 8 // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.4 - IL_0001: call 0x0A00002C + IL_0001: call 0x0A00002D IL_0006: nop IL_0007: ret } """); }) .AddGeneration( - // Delete the method again. + // 5: Delete the method again. source: common + """ class C { @@ -16769,6 +17716,7 @@ class C g.VerifySynthesizedMembers( [ .. synthesized, + "System.Runtime.CompilerServices.HotReloadException", "C: {<>c__0#4, <>c__0}", "C.<>c__0#4: {<>9__0#4_0#4, b__0#4_0#4}", "C.<>c__0: {<>9__0_0, <>9__0_1#1, <>9__0_2#2, b__0_0, b__0_1#1, b__0_2#2}" @@ -16779,35 +17727,37 @@ class C // Only lambdas that were not deleted before are updated: g.VerifyMethodDefNames("F", "b__0#4_0#4"); - g.VerifyTypeRefNames("Object", "MissingMethodException"); - g.VerifyMemberRefNames(".ctor"); + g.VerifyTypeRefNames("Object"); + g.VerifyMemberRefNames(); g.VerifyEncLogDefinitions(new[] { - Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(15, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(13, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(16, TableIndex.MethodDef, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { - Handle(12, TableIndex.MethodDef), - Handle(15, TableIndex.MethodDef), + Handle(13, TableIndex.MethodDef), + Handle(16, TableIndex.MethodDef) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x700002A1 - IL_0005: newobj 0x0A00002D - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x0600000C + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x700003EA - IL_0005: newobj 0x0A00002D - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x0600000C + IL_000b: throw } """); }) @@ -16824,12 +17774,9 @@ class A : Attribute { } var synthesized = new[] { - ": {Microsoft, System, System}", - "System: {Runtime, Runtime}", - "Microsoft: {CodeAnalysis}", - "Microsoft.CodeAnalysis: {EmbeddedAttribute}", - "System.Runtime: {CompilerServices, CompilerServices}", - "System.Runtime.CompilerServices: {IsReadOnlyAttribute, RequiresLocationAttribute}", + "Microsoft.CodeAnalysis.EmbeddedAttribute", + "System.Runtime.CompilerServices.IsReadOnlyAttribute", + "System.Runtime.CompilerServices.RequiresLocationAttribute", }; using var _ = new EditAndContinueTest(verification: Verification.Skipped) @@ -16853,6 +17800,7 @@ void F(T x, ref readonly int b) ]); }) .AddGeneration( + // 1 source: common + """ class C { @@ -16878,6 +17826,7 @@ void F(T x, ref readonly int b) ]); }) .AddGeneration( + // 2 source: common + """ class C { @@ -16892,48 +17841,73 @@ class C g.VerifySynthesizedMembers( [ .. synthesized, + "System.Runtime.CompilerServices.HotReloadException", "C: {g__L|0_0, g__M|0_1#1}" ]); - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("F", "g__L|0_0", "g__M|0_1#1"); - g.VerifyTypeRefNames("Object", "MissingMethodException"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("F", "g__L|0_0", "g__M|0_1#1", ".ctor"); + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "Exception"); - g.VerifyMemberRefNames(".ctor"); + g.VerifyMemberRefNames(".ctor", ".ctor"); g.VerifyEncLogDefinitions(new[] { + Row(7, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(7, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(7, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(18, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(7, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(5, TableIndex.MethodDef), Handle(7, TableIndex.MethodDef), Handle(8, TableIndex.MethodDef), + Handle(9, TableIndex.MethodDef), + Handle(18, TableIndex.CustomAttribute) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000009 - IL_0005: newobj 0x0A00000C - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000009 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000152 - IL_0005: newobj 0x0A00000C - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000009 + IL_000b: throw + } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000D + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret } """); }) .AddGeneration( - // Add deleted method back with another local function and lambda + // 3: Add deleted method back with another local function and lambda source: common + """ class C { @@ -16958,6 +17932,7 @@ ref readonly T O(ref readonly T b) g.VerifySynthesizedMembers( [ .. synthesized, + "System.Runtime.CompilerServices.HotReloadException", "C: {g__N|0#3_1#3, <>c__DisplayClass0#3_0#3, g__L|0_0, g__M|0_1#1}", "C.<>c__DisplayClass0#3_0#3: {x, g__O|0#3, b__2#3}" ]); @@ -16971,17 +17946,17 @@ ref readonly T O(ref readonly T b) { // Code size 29 (0x1d) .maxstack 2 - IL_0000: newobj 0x0A00000E + IL_0000: newobj 0x0A00000F IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldarg.1 - IL_0008: stfld 0x0A00000F + IL_0008: stfld 0x0A000010 IL_000d: nop IL_000e: nop IL_000f: ldloc.0 IL_0010: ldloc.0 - IL_0011: ldflda 0x0A00000F - IL_0016: callvirt 0x0A000010 + IL_0011: ldflda 0x0A000010 + IL_0016: callvirt 0x0A000011 IL_001b: pop IL_001c: ret } @@ -16995,7 +17970,7 @@ .maxstack 8 // Code size 8 (0x8) .maxstack 8 IL_0000: ldarg.0 - IL_0001: call 0x0A000011 + IL_0001: call 0x0A000012 IL_0006: nop IL_0007: ret } @@ -17015,14 +17990,14 @@ .maxstack 1 // Code size 12 (0xc) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld 0x0A00000F - IL_0006: call 0x0A000012 + IL_0001: ldfld 0x0A000010 + IL_0006: call 0x0A000013 IL_000b: ret } """); }) .AddGeneration( - // Delete the method again. + // 4: Delete the method again. source: common + """ class C { @@ -17037,6 +18012,7 @@ class C g.VerifySynthesizedMembers( [ .. synthesized, + "System.Runtime.CompilerServices.HotReloadException", "C: {g__N|0#3_1#3, <>c__DisplayClass0#3_0#3, g__L|0_0, g__M|0_1#1}", "C.<>c__DisplayClass0#3_0#3: {x, g__O|0#3, b__2#3}" ]); @@ -17046,31 +18022,33 @@ class C // Only lambdas that were not deleted before are updated: g.VerifyMethodDefNames("F", "g__N|0#3_1#3", "g__O|0#3", "b__2#3"); - g.VerifyTypeRefNames("Object", "MissingMethodException"); - g.VerifyMemberRefNames(".ctor"); + g.VerifyTypeRefNames("Object"); + g.VerifyMemberRefNames(); g.VerifyEncLogDefinitions( [ Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(11, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(13, TableIndex.MethodDef, EditAndContinueOperation.Default) ]); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x7000029D - IL_0005: newobj 0x0A000013 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000009 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x700003E6 - IL_0005: newobj 0x0A000013 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000009 + IL_000b: throw } """); }) @@ -17097,6 +18075,7 @@ class C for (int i = 0; i < 10; i++) { +#pragma warning disable format // https://github.com/dotnet/roslyn/issues/38588 test.AddGeneration( source: @$" class C @@ -17107,12 +18086,19 @@ class C Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.M1"), newSymbolProvider: c => c.GetMember("C")), Edit(SemanticEditKind.Insert, symbolProvider: c => c.GetMember("C.M2")), }, - validator: g => - { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M1", "M2"); - g.VerifyDeletedMembers("C: {M1}"); - }) + validator: (i == 0) + ? g => + { + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("M1", "M2", ".ctor"); + g.VerifyDeletedMembers("C: {M1}"); + } + : g => + { + g.VerifyTypeDefNames(); + g.VerifyMethodDefNames("M1", "M2"); + g.VerifyDeletedMembers("C: {M1}"); + }) .AddGeneration( source: @$" class C @@ -17129,6 +18115,7 @@ class C g.VerifyMethodDefNames("M1", "M2"); g.VerifyDeletedMembers("C: {M2}"); }); +#pragma warning restore format } test.Verify(); @@ -17139,7 +18126,7 @@ public void Method_ChangeParameterType() { using var _ = new EditAndContinueTest() .AddBaseline( - source: $$""" + source: """ class C { void M(int someInt) { someInt.ToString(); } @@ -17151,7 +18138,8 @@ class C g.VerifyMethodDefNames("M", ".ctor"); }) .AddGeneration( - source: $$""" + // 1 + source: """ class C { void M(bool someBool) { someBool.ToString(); } @@ -17163,32 +18151,43 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M", "M"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("M", "M", ".ctor"); g.VerifyDeletedMembers("C: {M}"); g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), - Row(2, TableIndex.Param, EditAndContinueOperation.Default) + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef), - Handle(2, TableIndex.Param) + Handle(4, TableIndex.MethodDef), + Handle(2, TableIndex.Param), + Handle(4, TableIndex.CustomAttribute) }); - var expectedIL = """ + g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000006 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } { // Code size 10 (0xa) @@ -17199,13 +18198,23 @@ .maxstack 8 IL_0008: pop IL_0009: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret + } + """); }) .AddGeneration( - source: $$""" + // 2 + source: """ class C { void M(int someInt) { someInt.ToString(); } @@ -17225,13 +18234,14 @@ class C { Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default) }); + g.VerifyEncMapDefinitions(new[] { Handle(1, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef), - Handle(1, TableIndex.Param), + Handle(1, TableIndex.Param) }); g.VerifyIL(""" @@ -17240,16 +18250,17 @@ class C .maxstack 8 IL_0000: nop IL_0001: ldarga.s V_1 - IL_0003: call 0x0A000008 + IL_0003: call 0x0A000009 IL_0008: pop IL_0009: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000151 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } """); }) @@ -17273,6 +18284,7 @@ class C g.VerifyMethodDefNames("M", ".ctor"); }) .AddGeneration( + // 1 source: $$""" class C { @@ -17285,34 +18297,46 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M", "M"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("M", "M", ".ctor"); g.VerifyDeletedMembers("C: {M}"); g.VerifyEncLogDefinitions(new[] { Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), - Row(2, TableIndex.Param, EditAndContinueOperation.Default) + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); + g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), Handle(2, TableIndex.Param), + Handle(4, TableIndex.CustomAttribute), Handle(2, TableIndex.StandAloneSig) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000006 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } { // Code size 7 (0x7) @@ -17324,9 +18348,22 @@ .maxstack 1 IL_0005: ldloc.0 IL_0006: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000007 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret + } """); }) .AddGeneration( + // 2 source: $$""" class C { @@ -17364,18 +18401,19 @@ class C .maxstack 1 IL_0000: nop IL_0001: ldarga.s V_1 - IL_0003: call 0x0A000007 + IL_0003: call 0x0A000008 IL_0008: stloc.0 IL_0009: br.s IL_000b IL_000b: ldloc.0 IL_000c: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000151 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } """); }) @@ -17399,6 +18437,7 @@ class C g.VerifyMethodDefNames("M", ".ctor"); }) .AddGeneration( + // 1 source: $$""" class C { @@ -17411,35 +18450,47 @@ class C }, validator: g => { - g.VerifyTypeDefNames(); - g.VerifyMethodDefNames("M", "M"); + g.VerifyTypeDefNames("HotReloadException"); + g.VerifyMethodDefNames("M", "M", ".ctor"); g.VerifyDeletedMembers("C: {M}"); g.VerifyEncLogDefinitions(new[] { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), Row(2, TableIndex.Param, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), - Row(3, TableIndex.Param, EditAndContinueOperation.Default) + Row(3, TableIndex.Param, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default) }); + g.VerifyEncMapDefinitions(new[] { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), Handle(1, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), Handle(2, TableIndex.Param), - Handle(3, TableIndex.Param) + Handle(3, TableIndex.Param), + Handle(4, TableIndex.CustomAttribute) }); g.VerifyIL(""" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000006 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } { // Code size 10 (0xa) @@ -17450,9 +18501,22 @@ .maxstack 8 IL_0008: pop IL_0009: ret } + { + // Code size 16 (0x10) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldarg.2 + IL_000a: stfld 0x04000001 + IL_000f: ret + } """); }) .AddGeneration( + // 2 source: $$""" class C { @@ -17488,16 +18552,17 @@ class C .maxstack 8 IL_0000: nop IL_0001: ldarga.s V_1 - IL_0003: call 0x0A000008 + IL_0003: call 0x0A000009 IL_0008: pop IL_0009: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000151 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw } """); }) diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/LocalSlotMappingTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/LocalSlotMappingTests.cs index e0a1c151e92d1..9eb04c19f54e6 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/LocalSlotMappingTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/LocalSlotMappingTests.cs @@ -906,95 +906,222 @@ .locals init (int V_0, [Fact] public void Lock() { - var source = -@"class C -{ - static object F() - { - return null; - } - static void M() - { - lock (F()) - { - lock (F()) - { - } + var source = """ + class C + { + static object F() => null; + + static void M() + { + lock (F()) + { + lock (F()) + { + } + } + } + } + """; + + using var _ = new EditAndContinueTest() + .AddBaseline( + source, + validator: v => + { + v.VerifyCustomDebugInformation("C.M", """ + + + + + + + + + + + + + + + + """); + }) + .AddGeneration( + source, + edits: + [ + Edit(SemanticEditKind.Update, c => c.GetMember("C.M"), preserveLocalVariables: true), + ], + validator: v => + { + v.VerifyMethodBody("C.M", """ + { + // Code size 66 (0x42) + .maxstack 2 + .locals init (object V_0, + bool V_1, + object V_2, + bool V_3) + -IL_0000: nop + -IL_0001: call "object C.F()" + IL_0006: stloc.0 + IL_0007: ldc.i4.0 + IL_0008: stloc.1 + .try + { + IL_0009: ldloc.0 + IL_000a: ldloca.s V_1 + IL_000c: call "void System.Threading.Monitor.Enter(object, ref bool)" + IL_0011: nop + -IL_0012: nop + -IL_0013: call "object C.F()" + IL_0018: stloc.2 + IL_0019: ldc.i4.0 + IL_001a: stloc.3 + .try + { + IL_001b: ldloc.2 + IL_001c: ldloca.s V_3 + IL_001e: call "void System.Threading.Monitor.Enter(object, ref bool)" + IL_0023: nop + -IL_0024: nop + -IL_0025: nop + IL_0026: leave.s IL_0033 + } + finally + { + ~IL_0028: ldloc.3 + IL_0029: brfalse.s IL_0032 + IL_002b: ldloc.2 + IL_002c: call "void System.Threading.Monitor.Exit(object)" + IL_0031: nop + ~IL_0032: endfinally + } + -IL_0033: nop + IL_0034: leave.s IL_0041 + } + finally + { + ~IL_0036: ldloc.1 + IL_0037: brfalse.s IL_0040 + IL_0039: ldloc.0 + IL_003a: call "void System.Threading.Monitor.Exit(object)" + IL_003f: nop + ~IL_0040: endfinally + } + -IL_0041: ret + } + """); + }) + .Verify(); } - } -}"; - var compilation0 = CreateCompilation(source, options: TestOptions.DebugDll); - var compilation1 = compilation0.WithSource(source); - - var testData0 = new CompilationTestData(); - var bytes0 = compilation0.EmitToArray(testData: testData0); - var methodData0 = testData0.GetMethodData("C.M"); - var method0 = compilation0.GetMember("C.M"); - var generation0 = CreateInitialBaseline(compilation0, ModuleMetadata.CreateFromImage(bytes0), methodData0.EncDebugInfoProvider()); - var method1 = compilation1.GetMember("C.M"); - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetEquivalentNodesMap(method1, method0)))); + [Fact] + public void Lock_SystemThreadingLock() + { + var source = """ + namespace System.Threading + { + public sealed class Lock + { + public Scope EnterScope() => new(); + + public ref struct Scope + { + public void Dispose() { } + } + } + } - diff1.VerifyIL("C.M", @" -{ - // Code size 66 (0x42) - .maxstack 2 - .locals init (object V_0, - bool V_1, - object V_2, - bool V_3) - -IL_0000: nop - -IL_0001: call ""object C.F()"" - IL_0006: stloc.0 - IL_0007: ldc.i4.0 - IL_0008: stloc.1 - .try - { - IL_0009: ldloc.0 - IL_000a: ldloca.s V_1 - IL_000c: call ""void System.Threading.Monitor.Enter(object, ref bool)"" - IL_0011: nop - -IL_0012: nop - -IL_0013: call ""object C.F()"" - IL_0018: stloc.2 - IL_0019: ldc.i4.0 - IL_001a: stloc.3 - .try - { - IL_001b: ldloc.2 - IL_001c: ldloca.s V_3 - IL_001e: call ""void System.Threading.Monitor.Enter(object, ref bool)"" - IL_0023: nop - -IL_0024: nop - -IL_0025: nop - IL_0026: leave.s IL_0033 - } - finally - { - ~IL_0028: ldloc.3 - IL_0029: brfalse.s IL_0032 - IL_002b: ldloc.2 - IL_002c: call ""void System.Threading.Monitor.Exit(object)"" - IL_0031: nop - ~IL_0032: endfinally - } - -IL_0033: nop - IL_0034: leave.s IL_0041 - } - finally - { - ~IL_0036: ldloc.1 - IL_0037: brfalse.s IL_0040 - IL_0039: ldloc.0 - IL_003a: call ""void System.Threading.Monitor.Exit(object)"" - IL_003f: nop - ~IL_0040: endfinally - } - -IL_0041: ret -} -", methodToken: diff1.EmitResult.UpdatedMethods.Single()); + class C + { + static System.Threading.Lock F() => new(); + + static void M() + { + lock (F()) + { + lock (F()) + { + } + } + } + } + """; + + using var _ = new EditAndContinueTest(verification: Verification.Skipped) + .AddBaseline( + source, + validator: v => + { + v.VerifyCustomDebugInformation("C.M", """ + + + + + + + + + + + + + + """); + }) + .AddGeneration( + source, + edits: + [ + Edit(SemanticEditKind.Update, c => c.GetMember("C.M"), preserveLocalVariables: true), + ], + validator: g => + { + g.VerifyMethodBody("C.M", """ + { + // Code size 50 (0x32) + .maxstack 1 + .locals init (System.Threading.Lock.Scope V_0, + System.Threading.Lock.Scope V_1) + -IL_0000: nop + IL_0001: call "System.Threading.Lock C.F()" + IL_0006: callvirt "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_000b: stloc.0 + .try + { + -IL_000c: nop + IL_000d: call "System.Threading.Lock C.F()" + IL_0012: callvirt "System.Threading.Lock.Scope System.Threading.Lock.EnterScope()" + IL_0017: stloc.1 + .try + { + -IL_0018: nop + -IL_0019: nop + IL_001a: leave.s IL_0025 + } + finally + { + ~IL_001c: ldloca.s V_1 + IL_001e: call "void System.Threading.Lock.Scope.Dispose()" + IL_0023: nop + IL_0024: endfinally + } + -IL_0025: nop + IL_0026: leave.s IL_0031 + } + finally + { + ~IL_0028: ldloca.s V_0 + IL_002a: call "void System.Threading.Lock.Scope.Dispose()" + IL_002f: nop + IL_0030: endfinally + } + -IL_0031: ret + } + """); + }) + .Verify(); } /// @@ -3949,7 +4076,7 @@ public async Task F() } } "; - var compilation0 = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation0 = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); var compilation1 = compilation0.WithSource(source); var v0 = CompileAndVerify(compilation0); diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/UnmanagedTypeModifierTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/UnmanagedTypeModifierTests.cs index 9b8a6a638be50..3436b9a10cb13 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/UnmanagedTypeModifierTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/UnmanagedTypeModifierTests.cs @@ -576,13 +576,13 @@ public class Child : Parent Assert.True(parentTypeParameter.HasValueTypeConstraint); Assert.True(parentTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name); var childTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single(); Assert.True(childTypeParameter.HasValueTypeConstraint); Assert.True(childTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name); }); CompileAndVerify(@" @@ -611,7 +611,7 @@ public class Parent Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); var child = CompileAndVerify(@" @@ -624,7 +624,7 @@ public class Child : Parent Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); CompileAndVerify(@" @@ -657,13 +657,13 @@ public class Child : Parent Assert.True(parentTypeParameter.HasValueTypeConstraint); Assert.True(parentTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name); var childTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single(); Assert.True(childTypeParameter.HasValueTypeConstraint); Assert.True(childTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name); }); CompileAndVerify(@" @@ -689,7 +689,7 @@ public abstract class Parent Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); var child = CompileAndVerify(@" @@ -702,7 +702,7 @@ public class Child : Parent Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); CompileAndVerify(@" @@ -732,13 +732,13 @@ public class Child : Parent Assert.True(parentTypeParameter.HasValueTypeConstraint); Assert.True(parentTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name); var childTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single(); Assert.True(childTypeParameter.HasValueTypeConstraint); Assert.True(childTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name); }); CompileAndVerify(@" @@ -764,7 +764,7 @@ public interface Parent Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); var child = CompileAndVerify(@" @@ -777,7 +777,7 @@ public class Child : Parent Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); CompileAndVerify(@" @@ -807,13 +807,13 @@ public class Child : Parent Assert.True(parentTypeParameter.HasValueTypeConstraint); Assert.True(parentTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name); var childTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("M").TypeParameters.Single(); Assert.True(childTypeParameter.HasValueTypeConstraint); Assert.True(childTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name); }); CompileAndVerify(@" @@ -839,7 +839,7 @@ public interface Parent Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); var child = CompileAndVerify(@" @@ -852,7 +852,7 @@ public class Child : Parent Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); CompileAndVerify(@" @@ -882,13 +882,13 @@ public class Child : Parent Assert.True(parentTypeParameter.HasValueTypeConstraint); Assert.True(parentTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, parentTypeParameter, module.ContainingAssembly.Name); var childTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Child").GetMethod("Parent.M").TypeParameters.Single(); Assert.True(childTypeParameter.HasValueTypeConstraint); Assert.True(childTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, childTypeParameter, module.ContainingAssembly.Name); }); CompileAndVerify(@" @@ -915,7 +915,7 @@ public interface Parent Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); var child = CompileAndVerify(@" @@ -928,7 +928,7 @@ public class Child : Parent Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); CompileAndVerify(@" @@ -974,13 +974,13 @@ public static void Main() Assert.True(delegateTypeParameter.HasValueTypeConstraint); Assert.True(delegateTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, delegateTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, delegateTypeParameter, module.ContainingAssembly.Name); var lambdaTypeParameter = module.ContainingAssembly.GetTypeByMetadataName("Program").GetTypeMember("<>c__DisplayClass0_0").TypeParameters.Single(); Assert.True(lambdaTypeParameter.HasValueTypeConstraint); Assert.True(lambdaTypeParameter.HasUnmanagedTypeConstraint); - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, lambdaTypeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, lambdaTypeParameter, module.ContainingAssembly.Name); }); } @@ -1002,7 +1002,7 @@ public static void Print(D lambda) where T : unmanaged Assert.True(typeParameter.HasUnmanagedTypeConstraint); Assert.False(typeParameter.HasConstructorConstraint); // .ctor is an artifact of emit, we will ignore it on importing. - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); CompileAndVerify(@" @@ -1028,7 +1028,7 @@ public static void Main() Assert.True(typeParameter.HasUnmanagedTypeConstraint); Assert.False(typeParameter.HasConstructorConstraint); // .ctor is an artifact of emit, we will ignore it on importing. - AttributeTests_IsUnmanaged.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); } diff --git a/src/Compilers/CSharp/Test/Emit2/PDB/PDBAsyncTests.cs b/src/Compilers/CSharp/Test/Emit2/PDB/PDBAsyncTests.cs index bf90f82712010..e60ce9795253e 100644 --- a/src/Compilers/CSharp/Test/Emit2/PDB/PDBAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/PDB/PDBAsyncTests.cs @@ -67,7 +67,7 @@ static int Main() void verify(string text) { - var compilation = CreateCompilationWithMscorlib45(text, options: TestOptions.DebugDll).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(text, options: TestOptions.DebugDll).VerifyDiagnostics(); var v = CompileAndVerify(compilation); v.VerifyIL("TestCase.d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" @@ -383,7 +383,7 @@ private Task GetNextInt(Random random) } } }"); - var compilation = CreateCompilationWithMscorlib45(text, options: TestOptions.DebugDll).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(text, options: TestOptions.DebugDll).VerifyDiagnostics(); compilation.VerifyPdb(@" @@ -540,7 +540,7 @@ static async void Await(dynamic d) int rez = await d; } }"); - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( text, options: TestOptions.DebugDll, references: new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }) @@ -618,7 +618,7 @@ static async Task F() return 1; } }"; - var v = CompileAndVerify(CreateCompilationWithMscorlib45(text, options: TestOptions.DebugDll)); + var v = CompileAndVerify(CreateCompilationWithMscorlib461(text, options: TestOptions.DebugDll)); v.VerifyIL("C.F", @" { @@ -756,7 +756,7 @@ static async Task M(int b) // TODO: Currently we don't have means necessary to pass information about the display // class being pushed on evaluation stack, so that EE could find the locals. // Thus the locals are not available in EE. - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -844,7 +844,7 @@ static async Task M(int b) } } "); - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -949,7 +949,7 @@ static async Task M(int b) } } "; - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -1036,7 +1036,7 @@ static async Task M(int b) } } "); - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -1152,7 +1152,7 @@ static async Task M(int b) } } "; - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -1256,7 +1256,7 @@ static async Task M(int b) } } "); - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -1363,7 +1363,7 @@ static async Task M() } } "); - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -1461,7 +1461,7 @@ static async Task M() } } "; - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -1547,7 +1547,7 @@ static async Task M() } } "); - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -1655,7 +1655,7 @@ static async Task M() // Console.WriteLine(x); // } - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -1691,7 +1691,7 @@ static async Task G() return x; } }"); - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -1945,7 +1945,7 @@ static async Task G() static int H(ref int a, int b, ref int c, int d) => 1; static int F(int a) => a; }"); - var v = CompileAndVerify(CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => + var v = CompileAndVerify(CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef, CSharpRef }, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All)), symbolValidator: module => { Assert.Equal(new[] { @@ -2014,7 +2014,7 @@ public partial class C partial void M(); async partial void M() {} }"; - var compilation = CreateCompilationWithMscorlib45(src, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); + var compilation = CreateCompilationWithMscorlib461(src, parseOptions: TestOptions.Regular.WithNoRefSafetyRulesAttribute(), options: TestOptions.DebugDll); var v = CompileAndVerify(compilation); v.VerifyPdb("C.M", @" diff --git a/src/Compilers/CSharp/Test/Emit2/PDB/PDBDynamicLocalsTests.cs b/src/Compilers/CSharp/Test/Emit2/PDB/PDBDynamicLocalsTests.cs index a1f47885298b6..609973fb80b61 100644 --- a/src/Compilers/CSharp/Test/Emit2/PDB/PDBDynamicLocalsTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/PDB/PDBDynamicLocalsTests.cs @@ -660,7 +660,7 @@ public dynamic Field { get { - dynamic d = field + field; + dynamic d = @field + @field; return d; } set @@ -695,7 +695,7 @@ public static void Main(string[] args) - + diff --git a/src/Compilers/CSharp/Test/Emit2/PDB/PDBTests.cs b/src/Compilers/CSharp/Test/Emit2/PDB/PDBTests.cs index 40709f0d06d4b..78ef00e6a8aaa 100644 --- a/src/Compilers/CSharp/Test/Emit2/PDB/PDBTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/PDB/PDBTests.cs @@ -7989,7 +7989,7 @@ public int M() return 2; } }"); - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics(); comp.VerifyPdb(@" @@ -8022,7 +8022,7 @@ public int M() [Fact] public void ExpressionBodiedIndexer() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" using System; class C @@ -8069,7 +8069,7 @@ public int M() [Fact] public void ExpressionBodiedMethod() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" using System; class C @@ -8104,7 +8104,7 @@ class C [Fact] public void ExpressionBodiedOperator() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public static C operator ++(C c) => c; @@ -8134,7 +8134,7 @@ class C [Fact] public void ExpressionBodiedConversion() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" using System; class C @@ -8170,7 +8170,7 @@ class C [Fact] public void ExpressionBodiedConstructor() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" using System; class C @@ -8207,7 +8207,7 @@ class C [Fact] public void ExpressionBodiedDestructor() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public int X; @@ -8240,7 +8240,7 @@ class C [Fact] public void ExpressionBodiedAccessor() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public int x; @@ -8322,7 +8322,7 @@ static void M() f(); } }"); - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, references: new[] { SystemCoreRef }); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, references: new[] { SystemCoreRef }); c.VerifyPdb("C+<>c.b__0_0", @" @@ -8367,7 +8367,7 @@ static IEnumerable F() } } }"); - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, references: new[] { SystemCoreRef }); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, references: new[] { SystemCoreRef }); c.VerifyPdb("C+d__0.MoveNext", @" @@ -8422,7 +8422,7 @@ static async Task F() c.Select(i => i); } }"); - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, references: new[] { SystemCoreRef }); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, references: new[] { SystemCoreRef }); c.VerifyPdb("C+d__0.MoveNext", @" @@ -8474,7 +8474,7 @@ static void M() }; } }"); - var c = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, references: new[] { SystemCoreRef }); + var c = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, references: new[] { SystemCoreRef }); c.VerifyPdb("C+<>c.b__0_0", @" diff --git a/src/Compilers/CSharp/Test/Emit2/PDB/PDBUsingTests.cs b/src/Compilers/CSharp/Test/Emit2/PDB/PDBUsingTests.cs index 5b1dc439dace6..620709f79c097 100644 --- a/src/Compilers/CSharp/Test/Emit2/PDB/PDBUsingTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/PDB/PDBUsingTests.cs @@ -843,6 +843,548 @@ static void F(A2::A? a) { } "); } + [WorkItem("https://github.com/dotnet/roslyn/issues/74872")] + [Fact] + public void ExternAliases6() + { + string sourceA1 = +@" +namespace N +{ + public class A { } +} +"; + var comp = CreateCompilation(sourceA1, assemblyName: "A1"); + var refA1 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A2")); + + string sourceA4 = +@" +namespace N +{ + public class A4 { } +} +"; + comp = CreateCompilation(sourceA4, assemblyName: "A4"); + var refA4 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A5")); + + string sourceB = +@" +class B +{ + static void F(A x) { } +} +"; + string sourceC = +@" +extern alias A2; +global using A2::N; +"; + comp = CreateCompilation([sourceB, sourceC], references: new[] { refA1, refA4 }, options: TestOptions.DebugDll); + comp.VerifyDiagnostics(); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + + + + + + + + + + + +", + format: DebugInformationFormat.Pdb); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + +", + format: DebugInformationFormat.PortablePdb); + } + + [WorkItem("https://github.com/dotnet/roslyn/issues/74872")] + [Fact] + public void ExternAliases7() + { + string sourceA1 = +@" +namespace N +{ + public class A { } +} +"; + var comp = CreateCompilation(sourceA1, assemblyName: "A1"); + var refA1 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A2")); + + string sourceA4 = +@" +namespace N +{ + public class A4 { } +} +"; + comp = CreateCompilation(sourceA4, assemblyName: "A4"); + var refA4 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A5")); + + string sourceB = +@" +class B +{ + static void F(N2.A x) { } +} +"; + string sourceC = +@" +extern alias A2; +global using N2 = A2::N; +"; + comp = CreateCompilation([sourceB, sourceC], references: new[] { refA1, refA4 }, options: TestOptions.DebugDll); + comp.VerifyDiagnostics(); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + + + + + + + + + + + +", + format: DebugInformationFormat.Pdb); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + +", + format: DebugInformationFormat.PortablePdb); + } + + [WorkItem("https://github.com/dotnet/roslyn/issues/74872")] + [Fact] + public void ExternAliases8() + { + string sourceA1 = +@" +namespace N +{ + public class A { } +} +"; + var comp = CreateCompilation(sourceA1, assemblyName: "A1"); + var refA1 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A2", "A3")); + + string sourceA4 = +@" +namespace N +{ + public class A4 { } +} +"; + comp = CreateCompilation(sourceA4, assemblyName: "A4"); + var refA4 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A5")); + + string sourceB = +@" +extern alias A3; +class B +{ + static void F(A x) { } +} +"; + string sourceC = +@" +extern alias A2; +global using A2::N; +"; + comp = CreateCompilation([sourceB, sourceC], references: new[] { refA1, refA4 }, options: TestOptions.DebugDll); + comp.VerifyDiagnostics( + // (2,1): hidden CS8020: Unused extern alias. + // extern alias A3; + Diagnostic(ErrorCode.HDN_UnusedExternAlias, "extern alias A3;").WithLocation(2, 1) + ); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + + + + + + + + + + + + + +", + format: DebugInformationFormat.Pdb); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + +", + format: DebugInformationFormat.PortablePdb); + } + + [WorkItem("https://github.com/dotnet/roslyn/issues/74872")] + [Fact] + public void ExternAliases9() + { + string sourceA1 = +@" +namespace N +{ + public class A { } +} +"; + var comp = CreateCompilation(sourceA1, assemblyName: "A1"); + var refA1 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A2", "A3")); + + string sourceA4 = +@" +namespace N +{ + public class A4 { } +} +"; + comp = CreateCompilation(sourceA4, assemblyName: "A4"); + var refA4 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A5")); + + string sourceB = +@" +extern alias A3; +class B +{ + static void F(N2.A x) { } +} +"; + string sourceC = +@" +extern alias A2; +global using N2 = A2::N; +"; + comp = CreateCompilation([sourceB, sourceC], references: new[] { refA1, refA4 }, options: TestOptions.DebugDll); + comp.VerifyDiagnostics( + // (2,1): hidden CS8020: Unused extern alias. + // extern alias A3; + Diagnostic(ErrorCode.HDN_UnusedExternAlias, "extern alias A3;").WithLocation(2, 1) + ); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + + + + + + + + + + + + + +", + format: DebugInformationFormat.Pdb); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + +", + format: DebugInformationFormat.PortablePdb); + } + + [WorkItem("https://github.com/dotnet/roslyn/issues/74872")] + [Fact] + public void ExternAliases10() + { + string sourceA1 = +@" +namespace N +{ + public class A { } +} +"; + var comp = CreateCompilation(sourceA1, assemblyName: "A1"); + var refA1 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A2")); + + string sourceA4 = +@" +namespace N +{ + public class A4 { } +} +"; + comp = CreateCompilation(sourceA4, assemblyName: "A4"); + var refA4 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A5")); + + string sourceB = +@" +extern alias A5; +class B +{ + static void F(A x) { } +} +"; + string sourceC = +@" +extern alias A2; +global using A2::N; +"; + comp = CreateCompilation([sourceB, sourceC], references: new[] { refA1, refA4 }, options: TestOptions.DebugDll); + comp.VerifyDiagnostics( + // (2,1): hidden CS8020: Unused extern alias. + // extern alias A5; + Diagnostic(ErrorCode.HDN_UnusedExternAlias, "extern alias A5;").WithLocation(2, 1) + ); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + + + + + + + + + + + + +", + format: DebugInformationFormat.Pdb); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + +", + format: DebugInformationFormat.PortablePdb); + } + + [WorkItem("https://github.com/dotnet/roslyn/issues/74872")] + [Fact] + public void ExternAliases11() + { + string sourceA1 = +@" +namespace N +{ + public class A { } +} +"; + var comp = CreateCompilation(sourceA1, assemblyName: "A1"); + var refA1 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A2")); + + string sourceA4 = +@" +namespace N +{ + public class A4 { } +} +"; + comp = CreateCompilation(sourceA4, assemblyName: "A4"); + var refA4 = comp.EmitToImageReference(aliases: ImmutableArray.Create("A5")); + + string sourceB = +@" +extern alias A5; +class B +{ + static void F(N2.A x) { } +} +"; + string sourceC = +@" +extern alias A2; +global using N2 = A2::N; +"; + comp = CreateCompilation([sourceB, sourceC], references: new[] { refA1, refA4 }, options: TestOptions.DebugDll); + comp.VerifyDiagnostics( + // (2,1): hidden CS8020: Unused extern alias. + // extern alias A5; + Diagnostic(ErrorCode.HDN_UnusedExternAlias, "extern alias A5;").WithLocation(2, 1) + ); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + + + + + + + + + + + + +", + format: DebugInformationFormat.Pdb); + + comp.VerifyPdb( +@" + + + + + + + + + + + + + +", + format: DebugInformationFormat.PortablePdb); + } + [Fact(Skip = "https://github.com/dotnet/roslyn/issues/25737")] public void TestExternAliases_ExplicitAndGlobal() { diff --git a/src/Compilers/CSharp/Test/Emit2/PDB/PDBWinMdExpTests.cs b/src/Compilers/CSharp/Test/Emit2/PDB/PDBWinMdExpTests.cs index 544095b648524..7729bae715707 100644 --- a/src/Compilers/CSharp/Test/Emit2/PDB/PDBWinMdExpTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/PDB/PDBWinMdExpTests.cs @@ -24,7 +24,7 @@ public void TestWinMdExpData_Empty() "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( text, options: TestOptions.ReleaseWinMD, sourceFileName: "source.cs").VerifyDiagnostics(); @@ -105,7 +105,7 @@ static int Main() "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( text, options: TestOptions.ReleaseWinMD, sourceFileName: "source.cs").VerifyDiagnostics(); @@ -152,7 +152,7 @@ enum HRESULT : int "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( text, options: TestOptions.ReleaseWinMD, sourceFileName: "source.cs").VerifyDiagnostics(); @@ -231,7 +231,7 @@ public int this[int a] "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( text, options: TestOptions.ReleaseWinMD, sourceFileName: "source.cs").VerifyDiagnostics( @@ -267,7 +267,7 @@ public void M() "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( text, options: TestOptions.ReleaseWinMD, sourceFileName: "source.cs").VerifyDiagnostics(); diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests.cs index b25606241d2b2..620867a4028d8 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests.cs @@ -10040,7 +10040,7 @@ internal sealed class CSharpCompilerDiagnosticAnalyzer Diagnostic(ErrorCode.ERR_ModuleEmitFailure).WithArguments("Test.dll", "Module has invalid attributes.").WithLocation(1, 1)); // Use different mscorlib to test retargeting scenario - var compilation3 = CreateCompilationWithMscorlib45(source2, new[] { new CSharpCompilationReference(compilation1) }, options: TestOptions.DebugDll); + var compilation3 = CreateCompilationWithMscorlib461(source2, new[] { new CSharpCompilationReference(compilation1) }, options: TestOptions.DebugDll); Assert.NotSame(compilation1.Assembly, compilation3.SourceModule.ReferencedAssemblySymbols[1]); compilation3.VerifyDiagnostics( // (2,35): error CS0246: The type or namespace name 'xyz' could not be found (are you missing a using directive or an assembly reference?) diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Assembly.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Assembly.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Assembly.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Assembly.cs index 5e8a6c51e9b0b..ee99a5e6e6d60 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Assembly.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Assembly.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -1739,14 +1740,14 @@ public static class Extensions { public class Test { } "; - var netModuleRef = GetNetModuleWithAssemblyAttributesRef(mod, new[] { TestMetadata.Net40.SystemCore }); + var netModuleRef = GetNetModuleWithAssemblyAttributesRef(mod, new[] { Net40.References.SystemCore }); var appCompilation = CreateCompilationWithMscorlib40(app, references: new[] { netModuleRef }, options: TestOptions.ReleaseDll); appCompilation.VerifyDiagnostics( // error CS0012: The type 'ExtensionAttribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Diagnostic(ErrorCode.ERR_NoTypeDef).WithArguments("System.Runtime.CompilerServices.ExtensionAttribute", "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089").WithLocation(1, 1) ); - appCompilation = CreateCompilationWithMscorlib40(app, references: new[] { netModuleRef, TestMetadata.Net40.SystemCore }, options: TestOptions.ReleaseDll); + appCompilation = CreateCompilationWithMscorlib40(app, references: new[] { netModuleRef, Net40.References.SystemCore }, options: TestOptions.ReleaseDll); appCompilation.VerifyEmitDiagnostics(); } diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_CallerInfoAttributes.cs similarity index 96% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_CallerInfoAttributes.cs index bf4053c6fd9f2..237d5381bfd0d 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_CallerInfoAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_CallerInfoAttributes.cs @@ -2526,7 +2526,7 @@ static void LogCallerFilePath([CallerFilePath] string filePath = """") { } static void LogCallerMemberName([CallerMemberName] string memberName = """") { } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -2543,7 +2543,7 @@ static void LogCallerFilePath([CallerFilePath] string filePath) { } static void LogCallerMemberName([CallerMemberName] string memberName) { } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,38): error CS4020: The CallerLineNumberAttribute may only be applied to parameters with default values // static void LogCallerLineNumber([CallerLineNumber] int lineNumber) { } Diagnostic(ErrorCode.ERR_BadCallerLineNumberParamWithoutDefaultValue, @"CallerLineNumber").WithLocation(5, 38), @@ -2674,7 +2674,7 @@ public static void Main() { line: 78 line: 79 "; - var compilation = CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -2708,7 +2708,7 @@ public static void Main() { line: -1 "; - var compilation = CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -2752,7 +2752,7 @@ public static void Main() { line: 26 "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -2782,7 +2782,7 @@ static void LogCallerMemberName4([CallerMemberName] float memberName = 0) { } static void LogCallerMemberName5([CallerMemberName] int? memberName = 0) { } }"; - CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { SystemRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { SystemRef }).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_NoConversionForCallerLineNumberParam, "CallerLineNumber").WithLocation(5, 39).WithArguments("int", "string"), Diagnostic(ErrorCode.ERR_NoConversionForCallerLineNumberParam, "CallerLineNumber").WithLocation(6, 39).WithArguments("int", "char"), Diagnostic(ErrorCode.ERR_NoConversionForCallerLineNumberParam, "CallerLineNumber").WithLocation(7, 39).WithArguments("int", "bool"), @@ -2843,7 +2843,7 @@ public static void Main() line: 21 "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -2923,7 +2923,7 @@ public static void Main() line: -1 "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -2954,7 +2954,7 @@ public static void Main() line: 17 "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -3043,7 +3043,7 @@ public static void Main() line: 55 "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -3074,7 +3074,7 @@ public static void Main() line: 17 "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -3167,7 +3167,7 @@ public static void Main() { "; MetadataReference libReference = CompileIL(iLSource); - var compilation = CreateCompilationWithMscorlib45(source, new[] { libReference }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { libReference }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -3193,7 +3193,7 @@ public static void Main() } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_DuplicateAttribute, "CallerLineNumber").WithArguments("CallerLineNumber"), Diagnostic(ErrorCode.WRN_CallerLineNumberParamForUnconsumedLocation, "CallerLineNumber").WithArguments("x").WithLocation(11, 23)); } @@ -3221,7 +3221,7 @@ public static void Main() } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (12,10): warning CS4024: The CallerLineNumberAttribute applied to parameter 'line' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments // [CallerLineNumber] int line, Diagnostic(ErrorCode.WRN_CallerLineNumberParamForUnconsumedLocation, "CallerLineNumber").WithArguments("line"), @@ -3275,7 +3275,7 @@ public static void Main() line: 18 "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -3320,7 +3320,7 @@ public static void Log20([CallerMemberName, CallerFilePath] int x = 1) { } public static void Log23([CallerMemberName, CallerLineNumber] int x = 1) { Console.WriteLine(""line: "" + x); } public static void Log24([CallerLineNumber, CallerMemberName] int x = 1) { Console.WriteLine(""line: "" + x); } }"; - CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseDll.WithWarningLevel(0)).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseDll.WithWarningLevel(0)).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_NoConversionForCallerFilePathParam, "CallerFilePath").WithLocation(7, 48).WithArguments("string", "int"), Diagnostic(ErrorCode.ERR_NoConversionForCallerMemberNameParam, "CallerMemberName").WithLocation(7, 64).WithArguments("string", "int"), Diagnostic(ErrorCode.ERR_NoConversionForCallerMemberNameParam, "CallerMemberName").WithLocation(8, 48).WithArguments("string", "int"), @@ -3383,7 +3383,7 @@ public static void Main() C:\file.cs "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { Parse(source, @"C:\file.cs") }, new[] { SystemRef }, TestOptions.ReleaseExe); @@ -3425,7 +3425,7 @@ public static void Main() line: 15 "; - var compilation = CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -3451,7 +3451,7 @@ public static void Main() } }"; - var compilation = CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { SystemRef }); + var compilation = CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { SystemRef }); compilation.VerifyDiagnostics( Diagnostic(ErrorCode.WRN_CallerLineNumberParamForUnconsumedLocation, "CallerLineNumber").WithArguments("x").WithLocation(11, 23)); } @@ -3482,7 +3482,7 @@ public static void Main() } }"; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemRef }, TestOptions.ReleaseExe); compilation.VerifyEmitDiagnostics( // (12,23): warning CS4026: The CallerMemberNameAttribute applied to parameter 'x' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments @@ -3518,7 +3518,7 @@ public static void Main() } }"; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemRef }, TestOptions.ReleaseExe); compilation.VerifyEmitDiagnostics(); CompileAndVerify(compilation, expectedOutput: "Main"); } @@ -3560,7 +3560,7 @@ public static void Main() name: LambdaCaller "; - var compilation = CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -3603,7 +3603,7 @@ public static void Main() name: LocalFunctionCaller "; - var compilation = CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -3779,7 +3779,7 @@ public static void Main() name: op_Increment "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -3827,7 +3827,7 @@ public static void Main() name: IsTrue "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -3865,7 +3865,7 @@ public static void Main() name: MyMethod "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -3902,7 +3902,7 @@ public static void Main() name: Compare "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( source, new[] { SystemRef }, TestOptions.ReleaseExe); @@ -3963,7 +3963,7 @@ public static void Main() name: HasThing "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4005,7 +4005,7 @@ public static void Main() name: ThingHappened "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4057,7 +4057,7 @@ public static void Main() name: Finalize "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4131,7 +4131,7 @@ public static void Main() name: Item "; - var compilation = CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4163,7 +4163,7 @@ public static void Main() string source3 = @"partial class A { static void Main3() { Log(); } }"; string source4 = @"partial class A { static void Main4() { Log(); } }"; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(source1, path: @"C:\filename", encoding: Encoding.UTF8), @@ -4258,7 +4258,7 @@ partial class A { static void Main4() { Log(); } } partial class A { static void Main5() { Log(); } } "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(source1, path: @"C:\filename", encoding: Encoding.UTF8), @@ -4333,7 +4333,7 @@ public static void Main() member: "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4376,7 +4376,7 @@ public static void Main() member: MyMethod "; - var compilation = CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4398,7 +4398,7 @@ class Test public static void Main() { } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: ""); var ctor = compilation.GetMember("Goo..ctor"); @@ -4428,7 +4428,7 @@ class Test public static void Main() { } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { SystemRef }, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: ""); var ctor = compilation.GetMember("Goo..ctor"); @@ -4481,7 +4481,7 @@ public static void Main() { } var expected = @""; MetadataReference libReference = CompileIL(iLSource); - var compilation = CreateCompilationWithMscorlib45(source, new[] { libReference }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new[] { libReference }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4516,7 +4516,7 @@ public static void Main() var expected = @"Bar"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4631,7 +4631,7 @@ public static void Main() { MetadataReference libReference = CompileIL(iLSource); - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { Parse(source, @"C:\file.cs") }, new[] { libReference }, TestOptions.ReleaseExe); @@ -4666,7 +4666,7 @@ public static void Main() var expected = @"13"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4717,7 +4717,7 @@ static void Main(string[] args) CallerInfoAttributed: (, 22, Property1) "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4787,7 +4787,7 @@ public static void Main() MyMethod "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4820,7 +4820,7 @@ static void Main() 13 "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4858,7 +4858,7 @@ static void Main() } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (21,2): error CS0181: Attribute constructor parameter 'lineNumber' has type 'int?', which is not a valid attribute parameter type // [LineNumber2NullableInt, LineNumber2ValueType] Diagnostic(ErrorCode.ERR_BadAttributeParamType, "LineNumber2NullableInt").WithArguments("lineNumber", "int?"), @@ -4903,7 +4903,7 @@ public static void Main() 19 "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -4932,7 +4932,7 @@ public static void Main() } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (13,2): error CS0181: Attribute constructor parameter 'lineNumber' has type 'decimal', which is not a valid attribute parameter type // [LineNumber2DecimalAttribute] Diagnostic(ErrorCode.ERR_BadAttributeParamType, "LineNumber2DecimalAttribute").WithArguments("lineNumber", "decimal")); @@ -5021,7 +5021,7 @@ public static void Main() 61 "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -5060,7 +5060,7 @@ public bool M2(string expected, [CallerMemberName] Test line = null) } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (19,38): error CS4017: CallerLineNumberAttribute cannot be applied because there are no standard conversions from type 'int' to type 'Test' // public bool M1(string expected, [CallerLineNumber] Test line = null) Diagnostic(ErrorCode.ERR_NoConversionForCallerLineNumberParam, "CallerLineNumber").WithArguments("int", "Test"), @@ -5167,7 +5167,7 @@ where x.GetInt query path : C:\filename "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(source, path: @"C:\filename", encoding: Encoding.UTF8) }, new[] { SystemCoreRef }, TestOptions.ReleaseExe); @@ -5218,7 +5218,7 @@ static void Main(string[] args) 25 "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.Regular7, path: @"C:\filename", encoding: Encoding.UTF8) }, options: TestOptions.ReleaseExe); @@ -5289,7 +5289,7 @@ static void Main(string[] args) } "; - var compilation = CreateCompilationWithMscorlib45(new SyntaxTree[] { SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.Regular7, path: @"C:\filename") }).VerifyDiagnostics( + var compilation = CreateCompilationWithMscorlib461(new SyntaxTree[] { SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.Regular7, path: @"C:\filename") }).VerifyDiagnostics( // C:\filename(7,38): error CS4018: CallerFilePathAttribute cannot be applied because there are no standard conversions from type 'string' to type 'int' // static void M1([CallerLineNumber,CallerFilePath,CallerMemberName] int i = 0) { Console.WriteLine(); } Diagnostic(ErrorCode.ERR_NoConversionForCallerFilePathParam, "CallerFilePath").WithArguments("string", "int").WithLocation(7, 38), @@ -5381,7 +5381,7 @@ public Test Where( }"; string expected = @"PASS"; - var compilation = CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -5417,7 +5417,7 @@ static object Test([CallerMemberName] string bar = null) string expected = @"F1 F2"; - var compilation = CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -5453,7 +5453,7 @@ static object Test([CallerMemberName] string bar = null) string expected = @"F1 F2"; - var compilation = CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -5492,7 +5492,7 @@ static object Test([CallerMemberName] string bar = null) "; string expected = @"F2"; - var compilation = CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef }, TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: expected); } @@ -5551,7 +5551,7 @@ public static void Main() Caller file path: C:\filename C:\filename"; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(source, path: @"C:\filename", encoding: Encoding.UTF8) }, new[] { SystemCoreRef }, TestOptions.ReleaseExe); @@ -5611,7 +5611,7 @@ public static void Add(this C c, string s, [CallerMemberName] string m = ""Defau Main 21"; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(source, path: @"C:\filename", encoding: Encoding.UTF8) }, new[] { SystemCoreRef }, TestOptions.ReleaseExe); @@ -5666,7 +5666,7 @@ static void Main() } } "; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(csSource, path: @"C:\filename", encoding: Encoding.UTF8) }, new[] { SystemCoreRef, vbReference }, TestOptions.ReleaseExe); @@ -5705,7 +5705,7 @@ static void Main() const string expected = "Main"; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( source, new[] { SystemCoreRef }, TestOptions.ReleaseExe); @@ -5751,7 +5751,7 @@ static void Main() Console.WriteLine(from y in x select y); } }"; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( csSource, new[] { SystemCoreRef, vbReference }, TestOptions.ReleaseExe); diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Conditional.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Conditional.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Conditional.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Conditional.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Dynamic.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Dynamic.cs similarity index 98% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Dynamic.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Dynamic.cs index 49540e6d63139..196956dbe0955 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Dynamic.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Dynamic.cs @@ -816,7 +816,7 @@ public void TestDynamicAttributeForScript_Field() string source = @" dynamic x = 0; "; - var comp = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( source: source, parseOptions: TestOptions.Script, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), @@ -836,7 +836,7 @@ public void TestDynamicAttributeForScript_NoCore() dynamic x = 0; "; - CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script).VerifyDiagnostics( // (2,1): error CS1980: Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference? // dynamic x = 0; Diagnostic(ErrorCode.ERR_DynamicAttributeMissing, "dynamic").WithArguments("System.Runtime.CompilerServices.DynamicAttribute")); @@ -848,7 +848,7 @@ public void TestDynamicAttributeForScript_DynamicTypeArgument() var source = GetNoCS1980String(typeName: @"Gen") + @" Gen x = null;"; - var comp = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( source: source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), parseOptions: TestOptions.Script, @@ -868,7 +868,7 @@ public void TestDynamicAttributeForScript_DynamicTypeArgument_NoCore() var source = GetNoCS1980String(typeName: "Gen") + @" Gen x = null;"; - var comp = CreateCompilationWithMscorlib45(source: source, parseOptions: TestOptions.Script).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlib461(source: source, parseOptions: TestOptions.Script).VerifyDiagnostics( // (21,5): error CS1980: Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference? // Gen x = null; Diagnostic(ErrorCode.ERR_DynamicAttributeMissing, "dynamic").WithArguments("System.Runtime.CompilerServices.DynamicAttribute").WithLocation(21, 5) @@ -883,7 +883,7 @@ public void TestDynamicAttributeForScript_DynamicTypeInAliasTarget1() + GetNoCS1980String(typeName: @"Gen") + "X x = null;"; - var comp = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( source: source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), parseOptions: TestOptions.Script, @@ -905,7 +905,7 @@ public void TestDynamicAttributeForScript_DynamicTypeInAliasTarget2() + GetNoCS1980String(typeName: @"dynamic[]") + "X x = null;"; - var comp = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( source: source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), parseOptions: TestOptions.Script.WithLanguageVersion(LanguageVersion.Preview), @@ -927,7 +927,7 @@ public void TestDynamicAttributeForScript_DynamicTypeInAliasTarget_NoCore1() + GetNoCS1980String(typeName: @"Gen") + "X x = null;"; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script).VerifyDiagnostics( // (20,1): error CS1980: Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference? // X x = null; Diagnostic(ErrorCode.ERR_DynamicAttributeMissing, "X").WithArguments("System.Runtime.CompilerServices.DynamicAttribute").WithLocation(20, 1)); @@ -941,7 +941,7 @@ public void TestDynamicAttributeForScript_DynamicTypeInAliasTarget_NoCore2() + GetNoCS1980String(typeName: @"dynamic[]") + "X x = null;"; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script).VerifyDiagnostics( + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script).VerifyDiagnostics( // (20,1): error CS1980: Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference? // X x = null; Diagnostic(ErrorCode.ERR_DynamicAttributeMissing, "X").WithArguments("System.Runtime.CompilerServices.DynamicAttribute").WithLocation(20, 1)); @@ -1294,7 +1294,7 @@ static void Main() [InlineData(SourceCodeKind.Script)] public void TestNoCS1980WhenNotInContextWhichNeedsDynamicAttribute(SourceCodeKind sourceCodeKind) { - CompileAndVerify(CreateCompilationWithMscorlib45( + CompileAndVerify(CreateCompilationWithMscorlib461( source: GetNoCS1980String(typeName: @"Gen"), parseOptions: new CSharpParseOptions(kind: sourceCodeKind, languageVersion: LanguageVersion.CSharp7_2))); } @@ -1304,7 +1304,7 @@ public void TestNoCS1980WhenNotInContextWhichNeedsDynamicAttribute(SourceCodeKin [InlineData(SourceCodeKind.Script)] public void TestNoCS1980WhenNotInContextWhichNeedsDynamicAttribute_Errors(SourceCodeKind sourceCodeKind) { - var comp = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( source: GetNoCS1980String(typeName: @"dynamic"), parseOptions: new CSharpParseOptions(kind: sourceCodeKind, languageVersion: LanguageVersion.CSharp7_2)); @@ -1330,7 +1330,7 @@ public void TestDynamicAttributeForSubmissionGlobalStatement() + "System.Console.WriteLine(typeof(Gen));" + "System.Console.WriteLine(typeof(X));"; - CreateCompilationWithMscorlib45(source: source, parseOptions: TestOptions.Script).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source: source, parseOptions: TestOptions.Script).VerifyDiagnostics( // (20,26): error CS1962: The typeof operator cannot be used on the dynamic type // System.Console.WriteLine(typeof(dynamic));System.Console.WriteLine(typeof(Gen));System.Console.WriteLine(typeof(X)); Diagnostic(ErrorCode.ERR_BadDynamicTypeof, "typeof(dynamic)").WithLocation(20, 26) @@ -1346,7 +1346,7 @@ public void TestDynamicAttributeInAliasContext1(SourceCodeKind sourceCodeKind) "using X = Gen; // No CS1980" + GetNoCS1980String(typeName: "X"); - CompileAndVerify(CreateCompilationWithMscorlib45( + CompileAndVerify(CreateCompilationWithMscorlib461( source: source, parseOptions: new CSharpParseOptions(kind: sourceCodeKind, languageVersion: LanguageVersion.CSharp7_2))); } @@ -1360,7 +1360,7 @@ public void TestDynamicAttributeInAliasContext2(SourceCodeKind sourceCodeKind) "using X = dynamic[]; // No CS1980" + GetNoCS1980String(typeName: "X"); - CompileAndVerify(CreateCompilationWithMscorlib45( + CompileAndVerify(CreateCompilationWithMscorlib461( source: source, parseOptions: new CSharpParseOptions(kind: sourceCodeKind, languageVersion: LanguageVersion.Preview))); } @@ -1391,7 +1391,7 @@ private X Method(X param) // CS1980, CS1980 } }"; - CreateCompilationWithMscorlib45(source: source, parseOptions: new CSharpParseOptions(kind: sourceCodeKind, languageVersion: LanguageVersion.CSharp7_2)).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source: source, parseOptions: new CSharpParseOptions(kind: sourceCodeKind, languageVersion: LanguageVersion.CSharp7_2)).VerifyDiagnostics( // (21,24): error CS1980: Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference? // public class Gen2 : X // CS1980 Diagnostic(ErrorCode.ERR_DynamicAttributeMissing, "X").WithArguments("System.Runtime.CompilerServices.DynamicAttribute").WithLocation(21, 24), diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Embedded.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Embedded.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Embedded.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Embedded.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Experimental.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Experimental.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Experimental.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Experimental.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsByRefLike.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_IsByRefLike.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsByRefLike.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_IsByRefLike.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsUnmanaged.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_IsUnmanaged.cs similarity index 87% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsUnmanaged.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_IsUnmanaged.cs index 06e06479ff2b9..5f536c37ab2b0 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsUnmanaged.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_IsUnmanaged.cs @@ -42,7 +42,7 @@ public void M() where T : unmanaged { } Assert.True(typeParameter.HasUnmanagedTypeConstraint); Assert.Null(module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName)); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, module.ContainingAssembly.Name); }); } @@ -66,7 +66,7 @@ public class Test where T : unmanaged Assert.True(typeParameter.HasUnmanagedTypeConstraint); Assert.Null(module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName)); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, module.ContainingAssembly.Name); }); } @@ -96,7 +96,7 @@ void N(T arg) where T : unmanaged Assert.True(typeParameter.HasUnmanagedTypeConstraint); Assert.Null(module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName)); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, module.ContainingAssembly.Name); }); } @@ -118,7 +118,7 @@ public class IsUnmanagedAttribute : System.Attribute { } Assert.True(typeParameter.HasUnmanagedTypeConstraint); Assert.Null(module.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName)); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, module.ContainingAssembly.Name); }); } @@ -144,7 +144,7 @@ public void M() where T : unmanaged { } Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); AssertNoIsUnmanagedAttributeExists(module.ContainingAssembly); }); } @@ -170,7 +170,7 @@ public class Test where T : unmanaged Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); AssertNoIsUnmanagedAttributeExists(module.ContainingAssembly); }); } @@ -206,7 +206,7 @@ void N() where T : unmanaged Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); AssertNoIsUnmanagedAttributeExists(module.ContainingAssembly); }); } @@ -234,7 +234,7 @@ public class IsUnmanagedAttribute : System.Attribute { } Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); AssertNoIsUnmanagedAttributeExists(module.ContainingAssembly); }); } @@ -261,7 +261,7 @@ public void M() where T : unmanaged { } Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); AssertNoIsUnmanagedAttributeExists(module.ContainingAssembly); }); } @@ -287,7 +287,7 @@ public class Test where T : unmanaged Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); AssertNoIsUnmanagedAttributeExists(module.ContainingAssembly); }); } @@ -324,7 +324,7 @@ void N() where T : unmanaged Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); AssertNoIsUnmanagedAttributeExists(module.ContainingAssembly); }); } @@ -353,7 +353,7 @@ public class IsUnmanagedAttribute : System.Attribute { } Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Public, typeParameter, reference.Display); AssertNoIsUnmanagedAttributeExists(module.ContainingAssembly); }); } @@ -374,7 +374,7 @@ public void M() where T : unmanaged { } Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); } @@ -393,7 +393,7 @@ public class Test where T : unmanaged Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); } @@ -421,7 +421,7 @@ void N() where T : unmanaged { } Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); } @@ -441,7 +441,7 @@ public void AttributeGeneratedIfNotExists_FromSource_Delegate() Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); } @@ -650,7 +650,7 @@ public class Test2 : Test1 where T : unmanaged { } Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); } @@ -733,7 +733,7 @@ public class Test1 where T : unmanaged Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); var code2 = @" @@ -747,7 +747,7 @@ public class Test2 : Test1 where T : unmanaged Assert.True(typeParameter.HasValueTypeConstraint); Assert.True(typeParameter.HasUnmanagedTypeConstraint); - AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); + AttributeValidation.AssertReferencedIsUnmanagedAttribute(Accessibility.Internal, typeParameter, module.ContainingAssembly.Name); }); } @@ -817,41 +817,6 @@ class Test where T : unmanaged Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "T").WithArguments("System.Runtime.CompilerServices.IsUnmanagedAttribute", ".ctor").WithLocation(6, 12)); } - internal static void AssertReferencedIsUnmanagedAttribute(Accessibility accessibility, TypeParameterSymbol typeParameter, string assemblyName) - { - var attributes = ((PEModuleSymbol)typeParameter.ContainingModule).GetCustomAttributesForToken(((PETypeParameterSymbol)typeParameter).Handle); - NamedTypeSymbol attributeType = attributes.Single().AttributeClass; - - Assert.Equal("IsUnmanagedAttribute", attributeType.Name); - Assert.Equal(assemblyName, attributeType.ContainingAssembly.Name); - Assert.Equal(accessibility, attributeType.DeclaredAccessibility); - - switch (accessibility) - { - case Accessibility.Internal: - { - var isUnmanagedTypeAttributes = attributeType.GetAttributes().OrderBy(attribute => attribute.AttributeClass.Name).ToArray(); - Assert.Equal(2, isUnmanagedTypeAttributes.Length); - - Assert.Equal(WellKnownTypes.GetMetadataName(WellKnownType.System_Runtime_CompilerServices_CompilerGeneratedAttribute), isUnmanagedTypeAttributes[0].AttributeClass.ToDisplayString()); - Assert.Equal(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName, isUnmanagedTypeAttributes[1].AttributeClass.ToDisplayString()); - break; - } - - case Accessibility.Public: - { - var refSafetyRulesAttribute = attributeType.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.RefSafetyRulesAttribute.FullName); - var embeddedAttribute = attributeType.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName); - Assert.Equal(refSafetyRulesAttribute is null, embeddedAttribute is null); - break; - } - - default: - throw ExceptionUtilities.UnexpectedValue(accessibility); - } - - } - private void AssertNoIsUnmanagedAttributeExists(AssemblySymbol assembly) { var isUnmanagedAttributeTypeName = WellKnownTypes.GetMetadataName(WellKnownType.System_Runtime_CompilerServices_IsUnmanagedAttribute); diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_LifetimeAnnotation.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_LifetimeAnnotation.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_LifetimeAnnotation.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Locations.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Locations.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Locations.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Locations.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_MarshalAs.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_MarshalAs.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_MarshalAs.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_MarshalAs.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NativeInteger.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_NativeInteger.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NativeInteger.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_NativeInteger.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Nullable.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Nullable.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Nullable.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Nullable.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NullableContext.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_NullableContext.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NullableContext.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_NullableContext.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NullablePublicOnly.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_NullablePublicOnly.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_NullablePublicOnly.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_NullablePublicOnly.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_ReadOnlyStruct.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_ReadOnlyStruct.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_ReadOnlyStruct.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_ReadOnlyStruct.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_RefReadOnly.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_RefReadOnly.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_RefReadOnly.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_RefReadOnly.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_RefSafetyRules.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_RefSafetyRules.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_RefSafetyRules.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_RefSafetyRules.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Security.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Security.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Security.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Security.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_StructLayout.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_StructLayout.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_StructLayout.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_StructLayout.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Synthesized.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Synthesized.cs similarity index 98% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Synthesized.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Synthesized.cs index 27689ff4616be..a9ef0d6138448 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Synthesized.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Synthesized.cs @@ -480,7 +480,7 @@ public async Task Goo() var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel) .WithMetadataImportOptions(MetadataImportOptions.All); - CompileAndVerify(CreateCompilationWithMscorlib45(source, options: options), symbolValidator: module => + CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module => { var goo = module.GlobalNamespace.GetMember("C.Goo"); AssertEx.SetEqual(options.OptimizationLevel == OptimizationLevel.Debug ? @@ -538,7 +538,7 @@ public override async Task GetIntAsync() var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel) .WithMetadataImportOptions(MetadataImportOptions.All); - CompileAndVerify(CreateCompilationWithMscorlib45(source, options: options), symbolValidator: module => + CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module => { var attributes = module.GlobalNamespace.GetTypeMember("B").GetMember("<>n__0").GetAttributes(); @@ -576,7 +576,7 @@ public override async Task GetIntAsync(int x) var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel) .WithMetadataImportOptions(MetadataImportOptions.All); - CompileAndVerify(CreateCompilationWithMscorlib45(source, options: options), symbolValidator: module => + CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module => { var baseMethodWrapper = module.GlobalNamespace.GetTypeMember("B").GetMember("<>n__0"); AssertEx.SetEqual(new[] { "CompilerGeneratedAttribute", "DebuggerHiddenAttribute" }, GetAttributeNames(baseMethodWrapper.GetAttributes())); @@ -619,7 +619,7 @@ public override async Task GetAsync<[Attr] T>([Attr] T t) var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel) .WithMetadataImportOptions(MetadataImportOptions.All); - CompileAndVerify(CreateCompilationWithMscorlib45(source, options: options), symbolValidator: module => + CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module => { var baseMethodWrapper = module.GlobalNamespace.GetTypeMember("B").GetMember("<>n__0"); AssertEx.SetEqual(new[] { "CompilerGeneratedAttribute", "DebuggerHiddenAttribute" }, GetAttributeNames(baseMethodWrapper.GetAttributes())); @@ -1671,7 +1671,7 @@ public static async void F() var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel) .WithMetadataImportOptions(MetadataImportOptions.All); - CompileAndVerify(CreateCompilationWithMscorlib45(source, options: options), symbolValidator: module => + CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module => { var type = module.GlobalNamespace.GetMember("Test"); var stateMachine = type.GetTypeMember("d__0"); @@ -1714,7 +1714,7 @@ public static void F() var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel) .WithMetadataImportOptions(MetadataImportOptions.All); - CompileAndVerify(CreateCompilationWithMscorlib45(source, options: options), symbolValidator: module => + CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module => { var type = module.GlobalNamespace.GetMember("Test").GetTypeMember("<>c"); var stateMachine = type.GetTypeMember("<b__0_0>d"); @@ -1756,7 +1756,7 @@ public class Test var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel) .WithMetadataImportOptions(MetadataImportOptions.All); - CompileAndVerify(CreateCompilationWithMscorlib45(source, options: options), symbolValidator: module => + CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module => { var type = module.GlobalNamespace.GetMember("Test"); var stateMachine = type.GetTypeMember("d__0"); @@ -1797,10 +1797,10 @@ public static async void F() var referenceOptions = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel) .WithMetadataImportOptions(MetadataImportOptions.All); - var reference = CreateCompilationWithMscorlib45(source, options: referenceOptions).EmitToImageReference(options: new EmitOptions(metadataOnly: true)); + var reference = CreateCompilationWithMscorlib461(source, options: referenceOptions).EmitToImageReference(options: new EmitOptions(metadataOnly: true)); var options = TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All); - var compilation = CreateCompilationWithMscorlib45("", new[] { reference }, options: options); + var compilation = CreateCompilationWithMscorlib461("", new[] { reference }, options: options); var type = compilation.GlobalNamespace.GetMember("Test"); Assert.Equal(new[] { "F", ".ctor" }, type.GetMembers().SelectAsArray(m => m.Name)); @@ -1837,7 +1837,7 @@ public static IEnumerable F() var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel) .WithMetadataImportOptions(MetadataImportOptions.All); - CompileAndVerify(CreateCompilationWithMscorlib45(source, options: options), symbolValidator: module => + CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module => { var type = module.GlobalNamespace.GetMember("Test"); var stateMachine = type.GetTypeMember("d__0"); @@ -1867,7 +1867,7 @@ public class Test var options = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel) .WithMetadataImportOptions(MetadataImportOptions.All); - CompileAndVerify(CreateCompilationWithMscorlib45(source, options: options), symbolValidator: module => + CompileAndVerify(CreateCompilationWithMscorlib461(source, options: options), symbolValidator: module => { var type = module.GlobalNamespace.GetMember("Test"); var stateMachine = type.GetTypeMember("d__0"); @@ -1896,10 +1896,10 @@ public class Test var referenceOptions = TestOptions.CreateTestOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel) .WithMetadataImportOptions(MetadataImportOptions.All); - var reference = CreateCompilationWithMscorlib45(source, options: referenceOptions).EmitToImageReference(options: new EmitOptions(metadataOnly: true)); + var reference = CreateCompilationWithMscorlib461(source, options: referenceOptions).EmitToImageReference(options: new EmitOptions(metadataOnly: true)); var options = TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All); - var compilation = CreateCompilationWithMscorlib45("", new[] { reference }, options: options); + var compilation = CreateCompilationWithMscorlib461("", new[] { reference }, options: options); var type = compilation.GlobalNamespace.GetMember("Test"); Assert.Equal(new[] { "F", ".ctor" }, type.GetMembers().SelectAsArray(m => m.Name)); diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Tuples.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Tuples.cs similarity index 97% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Tuples.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Tuples.cs index 8e7a84e934681..c9b301a768a5f 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Tuples.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_Tuples.cs @@ -221,12 +221,12 @@ class C // (4,12): error CS0518: Predefined type 'System.String' is not defined or imported // static (int x, int y) M() => (0, 0); Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "(int x, int y)").WithArguments("System.String").WithLocation(4, 12), - // (4,12): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. + // (4,12): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. // static (int x, int y) M() => (0, 0); - Diagnostic(ErrorCode.ERR_NoTypeDef, "(int x, int y)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(4, 12), - // (4,34): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. + Diagnostic(ErrorCode.ERR_NoTypeDef, "(int x, int y)").WithArguments("System.ValueType", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089").WithLocation(4, 12), + // (4,34): error CS0012: The type 'ValueType' is defined in an assembly that is not referenced. You must add a reference to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. // static (int x, int y) M() => (0, 0); - Diagnostic(ErrorCode.ERR_NoTypeDef, "(0, 0)").WithArguments("System.ValueType", "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a").WithLocation(4, 34) + Diagnostic(ErrorCode.ERR_NoTypeDef, "(0, 0)").WithArguments("System.ValueType", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089").WithLocation(4, 34) ); } @@ -816,34 +816,34 @@ public struct S }"; var comp = CreateCompilationWithMscorlib40(text, references: s_attributeRefs); comp.VerifyDiagnostics( - // (31,2): error CS8331: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. - // [TupleElementNames(new[] { "a", "b" })] - Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""a"", ""b"" })").WithLocation(31, 2), - // (5,2): error CS8331: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. + // (5,2): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. // [TupleElementNames(new[] { "a", "b" })] Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""a"", ""b"" })").WithLocation(5, 2), - // (18,10): error CS8331: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. + // (31,2): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. + // [TupleElementNames(new[] { "a", "b" })] + Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""a"", ""b"" })").WithLocation(31, 2), + // (18,10): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. // [TupleElementNames(new[] { "x" })]ValueTuple args); Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""x"" })").WithLocation(18, 10), - // (11,6): error CS8331: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. + // (11,6): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. // [TupleElementNames(new[] { "x", "y" })] Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""x"", ""y"" })").WithLocation(11, 6), - // (14,14): error CS8331: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. + // (14,14): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. // [return: TupleElementNames(new string[] { null, null })] Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, "TupleElementNames(new string[] { null, null })").WithLocation(14, 14), - // (15,36): error CS8331: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. + // (15,36): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. // public ValueTuple M([TupleElementNames(new string[] { null})] ValueTuple x) => (0, 0); Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, "TupleElementNames(new string[] { null})").WithLocation(15, 36), - // (20,6): error CS0592: Attribute 'TupleElementNames' is not valid on this declaration type. It is only valid on 'class, struct, property, indexer, field, parameter, return' declarations. + // (20,6): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. // [TupleElementNames(new[] { "y" })] - Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "TupleElementNames").WithArguments("TupleElementNames", "class, struct, property, indexer, field, parameter, return").WithLocation(20, 6), - // (27,6): error CS8331: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. + Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""y"" })").WithLocation(20, 6), + // (27,6): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. // [TupleElementNames(new[] { "a", "b" })] Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, @"TupleElementNames(new[] { ""a"", ""b"" })").WithLocation(27, 6), - // (28,33): error CS8331: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. + // (28,33): error CS7036: There is no argument given that corresponds to the required parameter 'transformNames' of 'TupleElementNamesAttribute.TupleElementNamesAttribute(string[])' // public (int x, int y) this[[TupleElementNames](int a, int b) t] => t; - Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, "TupleElementNames").WithLocation(28, 33), - // (8,6): error CS8331: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "TupleElementNames").WithArguments("transformNames", "System.Runtime.CompilerServices.TupleElementNamesAttribute.TupleElementNamesAttribute(string[])").WithLocation(28, 33), + // (8,6): error CS8138: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. // [TupleElementNames(new string[] { null, null })] Diagnostic(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, "TupleElementNames(new string[] { null, null })").WithLocation(8, 6)); } diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_WellKnownAttributes.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_WellKnownAttributes.cs index 5ce634fdea9c3..d731b5cf5b410 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/AttributeTests_WellKnownAttributes.cs @@ -21,6 +21,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -6033,7 +6034,7 @@ public static class TestExtension public static void ObsoleteExtensionMethod1(this Test t) { } } "; - CreateCompilationWithMscorlib40(source, new[] { TestMetadata.Net40.SystemCore }).VerifyDiagnostics( + CreateCompilationWithMscorlib40(source, new[] { Net40.References.SystemCore }).VerifyDiagnostics( // (98,10): error CS8423: Attribute 'System.ObsoleteAttribute' is not valid on event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. // [Obsolete] add {} Diagnostic(ErrorCode.ERR_AttributeNotOnEventAccessor, "Obsolete").WithArguments("System.ObsoleteAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(98, 10), @@ -13119,7 +13120,7 @@ public class SkipLocalsInitAttribute : System.Attribute [Fact, WorkItem(807, "https://github.com/dotnet/roslyn/issues/807")] public void TestAttributePropagationForAsyncAndIterators_01() { - var source = CreateCompilationWithMscorlib45(@" + var source = CreateCompilationWithMscorlib461(@" using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -13235,7 +13236,7 @@ private static string CheckAttributePropagation(Symbol symbol) [Fact, WorkItem(4521, "https://github.com/dotnet/roslyn/issues/4521")] public void TestAttributePropagationForAsyncAndIterators_02() { - var source = CreateCompilationWithMscorlib45(@" + var source = CreateCompilationWithMscorlib461(@" using System; using System.Collections.Generic; using System.Threading.Tasks; diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/EmitTestStrongNameProvider.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/EmitTestStrongNameProvider.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/EmitTestStrongNameProvider.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/EmitTestStrongNameProvider.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/InternalsVisibleToAndStrongNameTests.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/InternalsVisibleToAndStrongNameTests.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/Attributes/InternalsVisibleToAndStrongNameTests.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/InternalsVisibleToAndStrongNameTests.cs index 6c404e71e15e8..05425c8c2ce7d 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/InternalsVisibleToAndStrongNameTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Attributes/InternalsVisibleToAndStrongNameTests.cs @@ -2082,15 +2082,16 @@ void TestET() } "; - var comp1 = CreateCompilationWithMscorlib45(source1, options: TestOptions.SigningReleaseDll, assemblyName: "asm1", parseOptions: parseOptions); + var comp1 = CreateCompilationWithMscorlib461(source1, options: TestOptions.SigningReleaseDll, assemblyName: "asm1", parseOptions: parseOptions); comp1.VerifyDiagnostics(); var ref1 = new CSharpCompilationReference(comp1); - var comp2 = CreateCompilationWithMscorlib45(source2, new[] { ref1 }, options: TestOptions.SigningReleaseDll, assemblyName: "asm2", parseOptions: parseOptions); + var comp2 = CreateCompilationWithMscorlib461(source2, new[] { ref1 }, options: TestOptions.SigningReleaseDll, assemblyName: "asm2", parseOptions: parseOptions); comp2.VerifyDiagnostics(); var ref2 = new CSharpCompilationReference(comp2); - var comp3 = CreateCompilationWithMscorlib45(source3, new[] { SystemCoreRef, ref1, ref2 }, options: TestOptions.SigningReleaseDll, assemblyName: "asm3", parseOptions: parseOptions); + var comp3 = CreateCompilationWithMscorlib461(source3, new[] { SystemCoreRef, ref1, ref2 }, options: TestOptions.SigningReleaseDll, assemblyName: "asm3", parseOptions: parseOptions); + comp3.MakeMemberMissing(SpecialMember.System_Array__Empty); comp3.VerifyDiagnostics(); // Note: calls B.M, not A.M, since asm1 is not accessible. @@ -2200,19 +2201,20 @@ void TestET() } "; - var comp1 = CreateCompilationWithMscorlib45(source1, options: TestOptions.SigningReleaseDll, assemblyName: "asm1", parseOptions: parseOptions); + var comp1 = CreateCompilationWithMscorlib461(source1, options: TestOptions.SigningReleaseDll, assemblyName: "asm1", parseOptions: parseOptions); comp1.VerifyDiagnostics(); var ref1 = new CSharpCompilationReference(comp1); - var comp2 = CreateCompilationWithMscorlib45(source2, new[] { ref1 }, options: TestOptions.SigningReleaseDll, assemblyName: "asm2", parseOptions: parseOptions); + var comp2 = CreateCompilationWithMscorlib461(source2, new[] { ref1 }, options: TestOptions.SigningReleaseDll, assemblyName: "asm2", parseOptions: parseOptions); comp2.VerifyDiagnostics(); var ref2 = new CSharpCompilationReference(comp2); - var comp3 = CreateCompilationWithMscorlib45(source3, new[] { ref1, ref2 }, options: TestOptions.SigningReleaseDll, assemblyName: "asm3", parseOptions: parseOptions); + var comp3 = CreateCompilationWithMscorlib461(source3, new[] { ref1, ref2 }, options: TestOptions.SigningReleaseDll, assemblyName: "asm3", parseOptions: parseOptions); comp3.VerifyDiagnostics(); var ref3 = new CSharpCompilationReference(comp3); - var comp4 = CreateCompilationWithMscorlib45(source4, new[] { SystemCoreRef, ref1, ref2, ref3 }, options: TestOptions.SigningReleaseDll, assemblyName: "asm4", parseOptions: parseOptions); + var comp4 = CreateCompilationWithMscorlib461(source4, new[] { SystemCoreRef, ref1, ref2, ref3 }, options: TestOptions.SigningReleaseDll, assemblyName: "asm4", parseOptions: parseOptions); + comp4.MakeMemberMissing(SpecialMember.System_Array__Empty); comp4.VerifyDiagnostics(); // Note: calls C.M, not A.M, since asm2 is not accessible (stops search). diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/WellKnownAttributesTestBase.cs b/src/Compilers/CSharp/Test/Emit3/Attributes/WellKnownAttributesTestBase.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Attributes/WellKnownAttributesTestBase.cs rename to src/Compilers/CSharp/Test/Emit3/Attributes/WellKnownAttributesTestBase.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/CompilationEventTests.cs b/src/Compilers/CSharp/Test/Emit3/Diagnostics/CompilationEventTests.cs similarity index 94% rename from src/Compilers/CSharp/Test/Emit2/Diagnostics/CompilationEventTests.cs rename to src/Compilers/CSharp/Test/Emit3/Diagnostics/CompilationEventTests.cs index 46d111a1d2c8d..3aaad2eb5e93a 100644 --- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/CompilationEventTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Diagnostics/CompilationEventTests.cs @@ -92,7 +92,7 @@ partial void M(int x2) {} } }"; var q = new AsyncQueue(); - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .WithEventQueue(q) .VerifyDiagnostics( // (12,18): warning CS8826: Partial method declarations 'void C.M(int x1)' and 'void C.M(int x2)' have signature differences. @@ -146,12 +146,12 @@ partial void M(int x2) {} } }"; var q = new AsyncQueue(); - var comp = CreateCompilationWithMscorlib45(source).WithEventQueue(q); + var comp = CreateCompilationWithMscorlib461(source).WithEventQueue(q); comp.GetUsedAssemblyReferences(); VerifyEvents(q); q = new AsyncQueue(); - comp = CreateCompilationWithMscorlib45(source).WithEventQueue(q); + comp = CreateCompilationWithMscorlib461(source).WithEventQueue(q); comp.VerifyDiagnostics( // (12,18): warning CS8826: Partial method declarations 'void C.M(int x1)' and 'void C.M(int x2)' have signature differences. // partial void M(int x2) {} @@ -161,7 +161,7 @@ partial void M(int x2) {} VerifyEvents(q); q = new AsyncQueue(); - comp = CreateCompilationWithMscorlib45(source).WithEventQueue(q); + comp = CreateCompilationWithMscorlib461(source).WithEventQueue(q); comp.GetUsedAssemblyReferences(); comp.VerifyDiagnostics( // (12,18): warning CS8826: Partial method declarations 'void C.M(int x1)' and 'void C.M(int x2)' have signature differences. @@ -171,7 +171,7 @@ partial void M(int x2) {} VerifyEvents(q); q = new AsyncQueue(); - comp = CreateCompilationWithMscorlib45(source).WithEventQueue(q); + comp = CreateCompilationWithMscorlib461(source).WithEventQueue(q); comp.GetUsedAssemblyReferences(); comp.GetUsedAssemblyReferences(); VerifyEvents(q); diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs b/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs similarity index 86% rename from src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs rename to src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs index 6faa5984d11a6..971a72c210829 100644 --- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs +++ b/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs @@ -39,7 +39,7 @@ public void DiagnosticAnalyzerAllInOne() var analyzer = new CSharpTrackingDiagnosticAnalyzer(); var options = new AnalyzerOptions(new[] { new TestAdditionalText() }.ToImmutableArray()); - CreateCompilationWithMscorlib45(source).VerifyAnalyzerDiagnostics(new[] { analyzer }, options); + CreateCompilationWithMscorlib461(source).VerifyAnalyzerDiagnostics(new[] { analyzer }, options); analyzer.VerifyAllAnalyzerMembersWereCalled(); analyzer.VerifyAnalyzeSymbolCalledForAllSymbolKinds(); analyzer.VerifyAnalyzeNodeCalledForAllSyntaxKinds(missingSyntaxKinds); @@ -60,7 +60,7 @@ public string this[int index] } } "; - CreateCompilationWithMscorlib45(source).VerifyAnalyzerDiagnostics(new[] { new CSharpTrackingDiagnosticAnalyzer() }); + CreateCompilationWithMscorlib461(source).VerifyAnalyzerDiagnostics(new[] { new CSharpTrackingDiagnosticAnalyzer() }); } // AllInOne does not include experimental features. @@ -79,13 +79,13 @@ public string this[int index] } } "; - CreateCompilationWithMscorlib45(source).VerifyAnalyzerDiagnostics(new[] { new CSharpTrackingDiagnosticAnalyzer() }); + CreateCompilationWithMscorlib461(source).VerifyAnalyzerDiagnostics(new[] { new CSharpTrackingDiagnosticAnalyzer() }); } [Fact] public void DiagnosticAnalyzerExpressionBodiedProperty() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" public class C { public int P => 10; @@ -98,7 +98,7 @@ public class C [WorkItem(759, "https://github.com/dotnet/roslyn/issues/759")] public void AnalyzerDriverIsSafeAgainstAnalyzerExceptions() { - var compilation = CreateCompilationWithMscorlib45(TestResource.AllInOneCSharpCode); + var compilation = CreateCompilationWithMscorlib461(TestResource.AllInOneCSharpCode); var options = new AnalyzerOptions(new[] { new TestAdditionalText() }.ToImmutableArray()); ThrowingDiagnosticAnalyzer.VerifyAnalyzerEngineIsSafeAgainstExceptions(analyzer => @@ -114,7 +114,7 @@ public void AnalyzerOptionsArePassedToAllAnalyzers() new[] { new TestAdditionalText("myfilepath", text) }.ToImmutableArray() ); - var compilation = CreateCompilationWithMscorlib45(TestResource.AllInOneCSharpCode); + var compilation = CreateCompilationWithMscorlib461(TestResource.AllInOneCSharpCode); var analyzer = new OptionsDiagnosticAnalyzer(options); compilation.GetAnalyzerDiagnostics(new[] { analyzer }, options); analyzer.VerifyAnalyzerOptions(); diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.cs b/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.cs similarity index 96% rename from src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.cs rename to src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.cs index 796d42b643321..770ca4c93fc5f 100644 --- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.cs @@ -73,7 +73,7 @@ int x1(int x2) return x3 + 1; } }"; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics( // (1,18): error CS0246: The type or namespace name 'NotFound' could not be found (are you missing a using directive or an assembly reference?) // public class C : NotFound @@ -106,7 +106,7 @@ public class C : NotFound D d1 = (out int x4) => (x4 = 1) + @x4; }"; // TODO: Compilation create doesn't accept analyzers anymore. - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (2,18): error CS0246: The type or namespace name 'NotFound' could not be found (are you missing a using directive or an assembly reference?) // public class C : NotFound Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "NotFound").WithArguments("NotFound") @@ -144,7 +144,7 @@ int x1(int x2) var options = TestOptions.ReleaseDll.WithSpecificDiagnosticOptions( new[] { KeyValuePairUtil.Create("CA9999_UseOfVariableThatStartsWithX", ReportDiagnostic.Suppress) }); - CreateCompilationWithMscorlib45(source, options: options/*, analyzers: new IDiagnosticAnalyzerFactory[] { new ComplainAboutX() }*/).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: options/*, analyzers: new IDiagnosticAnalyzerFactory[] { new ComplainAboutX() }*/).VerifyDiagnostics( // (2,18): error CS0246: The type or namespace name 'NotFound' could not be found (are you missing a using directive or an assembly reference?) // public class C : NotFound Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "NotFound").WithArguments("NotFound")); @@ -167,7 +167,7 @@ int x1(int x2) var options = TestOptions.ReleaseDll.WithSpecificDiagnosticOptions( new[] { KeyValuePairUtil.Create("CA9999_UseOfVariableThatStartsWithX", ReportDiagnostic.Error) }); - CreateCompilationWithMscorlib45(source, options: options).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: options).VerifyDiagnostics( // (2,18): error CS0246: The type or namespace name 'NotFound' could not be found (are you missing a using directive or an assembly reference?) // public class C : NotFound Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "NotFound").WithArguments("NotFound")) @@ -199,7 +199,7 @@ int x1(int x2) }"; var options = TestOptions.ReleaseDll.WithGeneralDiagnosticOption(ReportDiagnostic.Error); - CreateCompilationWithMscorlib45(source, options: options).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: options).VerifyDiagnostics( // (2,18): error CS0246: The type or namespace name 'NotFound' could not be found (are you missing a using directive or an assembly reference?) // public class C : NotFound Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "NotFound").WithArguments("NotFound") @@ -225,7 +225,7 @@ public class C { public event EventHandler e; }"; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new ImplicitlyDeclaredSymbolAnalyzer() }); } @@ -285,7 +285,7 @@ public void DiagnosticAnalyzerSyntaxNodeAndSymbolAnalysis() public class C { }"; var options = TestOptions.ReleaseDll.WithGeneralDiagnosticOption(ReportDiagnostic.Error); - CreateCompilationWithMscorlib45(source, options: options) + CreateCompilationWithMscorlib461(source, options: options) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new SyntaxAndSymbolAnalyzer() }, null, null, // Symbol diagnostics @@ -319,7 +319,7 @@ public void TestGetEffectiveDiagnostics() specificDiagOptions.Add(warningDiagDescriptor.Id, ReportDiagnostic.Error); var options = TestOptions.ReleaseDll.WithSpecificDiagnosticOptions(specificDiagOptions); - var comp = CreateCompilationWithMscorlib45("", options: options); + var comp = CreateCompilationWithMscorlib461("", options: options); var effectiveDiags = comp.GetEffectiveDiagnostics(diags).ToArray(); Assert.Equal(diags.Length, effectiveDiags.Length); foreach (var effectiveDiag in effectiveDiags) @@ -335,7 +335,7 @@ public void TestGetEffectiveDiagnostics() specificDiagOptions.Add(errorDiagDescriptor.Id, ReportDiagnostic.Suppress); options = TestOptions.ReleaseDll.WithSpecificDiagnosticOptions(specificDiagOptions); - comp = CreateCompilationWithMscorlib45("", options: options); + comp = CreateCompilationWithMscorlib461("", options: options); effectiveDiags = comp.GetEffectiveDiagnostics(diags).ToArray(); Assert.Equal(0, effectiveDiags.Length); @@ -347,7 +347,7 @@ public void TestGetEffectiveDiagnostics() specificDiagOptions.Add(errorDiagDescriptor.Id, ReportDiagnostic.Warn); options = TestOptions.ReleaseDll.WithSpecificDiagnosticOptions(specificDiagOptions); - comp = CreateCompilationWithMscorlib45("", options: options); + comp = CreateCompilationWithMscorlib461("", options: options); effectiveDiags = comp.GetEffectiveDiagnostics(diags).ToArray(); Assert.Equal(diags.Length, effectiveDiags.Length); var diagIds = new HashSet(diags.Select(d => d.Id)); @@ -397,39 +397,39 @@ public void TestGetEffectiveDiagnosticsGlobal() var diags = new[] { noneDiag, infoDiag, warningDiag, errorDiag }; var options = TestOptions.ReleaseDll.WithGeneralDiagnosticOption(ReportDiagnostic.Default); - var comp = CreateCompilationWithMscorlib45("", options: options); + var comp = CreateCompilationWithMscorlib461("", options: options); var effectiveDiags = comp.GetEffectiveDiagnostics(diags).ToArray(); Assert.Equal(4, effectiveDiags.Length); options = TestOptions.ReleaseDll.WithGeneralDiagnosticOption(ReportDiagnostic.Error); - comp = CreateCompilationWithMscorlib45("", options: options); + comp = CreateCompilationWithMscorlib461("", options: options); effectiveDiags = comp.GetEffectiveDiagnostics(diags).ToArray(); Assert.Equal(4, effectiveDiags.Length); Assert.Equal(1, effectiveDiags.Count(d => d.IsWarningAsError)); options = TestOptions.ReleaseDll.WithGeneralDiagnosticOption(ReportDiagnostic.Warn); - comp = CreateCompilationWithMscorlib45("", options: options); + comp = CreateCompilationWithMscorlib461("", options: options); effectiveDiags = comp.GetEffectiveDiagnostics(diags).ToArray(); Assert.Equal(4, effectiveDiags.Length); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error)); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Warning)); options = TestOptions.ReleaseDll.WithGeneralDiagnosticOption(ReportDiagnostic.Info); - comp = CreateCompilationWithMscorlib45("", options: options); + comp = CreateCompilationWithMscorlib461("", options: options); effectiveDiags = comp.GetEffectiveDiagnostics(diags).ToArray(); Assert.Equal(4, effectiveDiags.Length); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error)); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Info)); options = TestOptions.ReleaseDll.WithGeneralDiagnosticOption(ReportDiagnostic.Hidden); - comp = CreateCompilationWithMscorlib45("", options: options); + comp = CreateCompilationWithMscorlib461("", options: options); effectiveDiags = comp.GetEffectiveDiagnostics(diags).ToArray(); Assert.Equal(4, effectiveDiags.Length); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error)); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Hidden)); options = TestOptions.ReleaseDll.WithGeneralDiagnosticOption(ReportDiagnostic.Suppress); - comp = CreateCompilationWithMscorlib45("", options: options); + comp = CreateCompilationWithMscorlib461("", options: options); effectiveDiags = comp.GetEffectiveDiagnostics(diags).ToArray(); Assert.Equal(2, effectiveDiags.Length); Assert.Equal(1, effectiveDiags.Count(d => d.Severity == DiagnosticSeverity.Error)); @@ -449,7 +449,7 @@ public void TestDisabledDiagnostics() // Verify that only the enabled diag shows up after filtering. var options = TestOptions.ReleaseDll; - var comp = CreateCompilationWithMscorlib45("", options: options); + var comp = CreateCompilationWithMscorlib461("", options: options); var effectiveDiags = comp.GetEffectiveDiagnostics(diags).ToArray(); Assert.Equal(1, effectiveDiags.Length); Assert.Contains(enabledDiag, effectiveDiags); @@ -460,7 +460,7 @@ public void TestDisabledDiagnostics() specificDiagOptions.Add(enabledDiagDescriptor.Id, ReportDiagnostic.Suppress); options = TestOptions.ReleaseDll.WithSpecificDiagnosticOptions(specificDiagOptions); - comp = CreateCompilationWithMscorlib45("", options: options); + comp = CreateCompilationWithMscorlib461("", options: options); effectiveDiags = comp.GetEffectiveDiagnostics(diags).ToArray(); Assert.Equal(1, effectiveDiags.Length); Assert.Contains(disabledDiag, effectiveDiags); @@ -554,7 +554,7 @@ public abstract class C }"; var analyzers = new DiagnosticAnalyzer[] { new CodeBlockOrSyntaxNodeAnalyzer(isCodeBlockAnalyzer: true) }; - CreateCompilationWithMscorlib45(noExecutableCodeSource) + CreateCompilationWithMscorlib461(noExecutableCodeSource) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers); } @@ -574,7 +574,7 @@ public C() : base(x: 10) {} }"; var analyzers = new DiagnosticAnalyzer[] { new CodeBlockOrSyntaxNodeAnalyzer(isCodeBlockAnalyzer: true) }; - CreateCompilationWithMscorlib45(baseCtorSource) + CreateCompilationWithMscorlib461(baseCtorSource) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, Diagnostic("ConstructorInitializerDiagnostic"), @@ -594,7 +594,7 @@ public class B }"; var analyzers = new DiagnosticAnalyzer[] { new CodeBlockOrSyntaxNodeAnalyzer(isCodeBlockAnalyzer: true) }; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, Diagnostic("CodeBlockDiagnostic"), @@ -617,7 +617,7 @@ public class B }"; var analyzers = new DiagnosticAnalyzer[] { new CodeBlockOrSyntaxNodeAnalyzer(isCodeBlockAnalyzer: false) }; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, Diagnostic("PropertyExpressionBodyDiagnostic"), @@ -637,7 +637,7 @@ public class B }"; var analyzers = new DiagnosticAnalyzer[] { new MethodSymbolAnalyzer() }; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, Diagnostic("MethodSymbolDiagnostic", "0").WithArguments("B.Property.get").WithLocation(4, 28), @@ -680,7 +680,7 @@ public class B }"; var analyzers = new DiagnosticAnalyzer[] { new FieldDeclarationAnalyzer() }; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, Diagnostic("MyFieldDiagnostic", @"public string field = ""field"";").WithLocation(4, 5)); @@ -698,7 +698,7 @@ public class B }"; var analyzers = new DiagnosticAnalyzer[] { new FieldDeclarationAnalyzer() }; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, Diagnostic("MyFieldDiagnostic", @"public string field1, field2;").WithLocation(4, 5), @@ -847,7 +847,7 @@ public override void Initialize(AnalysisContext context) public void TestReportingUnsupportedDiagnostic() { string source = @""; - CSharpCompilation compilation = CreateCompilationWithMscorlib45(source); + CSharpCompilation compilation = CreateCompilationWithMscorlib461(source); var analyzer = new AnalyzerReportingUnsupportedDiagnostic(); var analyzers = new DiagnosticAnalyzer[] { analyzer }; @@ -907,7 +907,7 @@ public override void Initialize(AnalysisContext context) public void TestReportingDiagnosticWithInvalidId() { string source = @""; - CSharpCompilation compilation = CreateCompilationWithMscorlib45(source); + CSharpCompilation compilation = CreateCompilationWithMscorlib461(source); var analyzers = new DiagnosticAnalyzer[] { new AnalyzerWithInvalidDiagnosticId() }; string message = new ArgumentException(string.Format(CodeAnalysisResources.InvalidDiagnosticIdReported, AnalyzerWithInvalidDiagnosticId.Descriptor.Id), "diagnostic").Message; Exception analyzerException = null; @@ -967,7 +967,7 @@ public void TestAnalyzerWithNullDescriptor() { AppDomain.CurrentDomain.FirstChanceException += firstChanceException; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, expected: Diagnostic("AD0001") .WithArguments(analyzerFullName, "System.ArgumentException", message, context) @@ -985,7 +985,7 @@ public void TestReportingDiagnosticWithCSharpCompilerId() string source = @""; var analyzers = new DiagnosticAnalyzer[] { new AnalyzerWithCSharpCompilerDiagnosticId() }; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, Diagnostic("CS101").WithLocation(1, 1)); } @@ -996,7 +996,7 @@ public void TestReportingDiagnosticWithBasicCompilerId() string source = @""; var analyzers = new DiagnosticAnalyzer[] { new AnalyzerWithBasicCompilerDiagnosticId() }; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, Diagnostic("BC101").WithLocation(1, 1)); } @@ -1007,8 +1007,8 @@ public void TestReportingDiagnosticWithInvalidLocation(AnalyzerWithInvalidDiagno { var source1 = @"class C1 { void M() { int i = 0; i++; } }"; var source2 = @"class C2 { void M() { int i = 0; i++; } }"; - var compilation = CreateCompilationWithMscorlib45(source1); - var anotherCompilation = CreateCompilationWithMscorlib45(source2); + var compilation = CreateCompilationWithMscorlib461(source1); + var anotherCompilation = CreateCompilationWithMscorlib461(source2); var treeInAnotherCompilation = anotherCompilation.SyntaxTrees.Single(); string message = new ArgumentException( @@ -1098,7 +1098,7 @@ public void TestReportingDiagnosticWithInvalidLocation(AnalyzerWithInvalidDiagno public void TestReportingDiagnosticWithInvalidSpan() { var source1 = @"class C1 { void M() { int i = 0; i++; } }"; - var compilation = CreateCompilationWithMscorlib45(source1); + var compilation = CreateCompilationWithMscorlib461(source1); var treeInAnotherCompilation = compilation.SyntaxTrees.Single(); var badSpan = new Text.TextSpan(100000, 10000); @@ -1132,7 +1132,7 @@ public void TestReportingNotConfigurableDiagnostic() var analyzers = new DiagnosticAnalyzer[] { new NotConfigurableDiagnosticAnalyzer() }; // Verify, not configurable enabled diagnostic is always reported and disabled diagnostic is never reported.. - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, expected: Diagnostic(NotConfigurableDiagnosticAnalyzer.EnabledRule.Id)); @@ -1141,7 +1141,7 @@ public void TestReportingNotConfigurableDiagnostic() specificDiagOptions.Add(NotConfigurableDiagnosticAnalyzer.EnabledRule.Id, ReportDiagnostic.Suppress); var options = TestOptions.ReleaseDll.WithSpecificDiagnosticOptions(specificDiagOptions); - CreateCompilationWithMscorlib45(source, options: options) + CreateCompilationWithMscorlib461(source, options: options) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, expected: Diagnostic(NotConfigurableDiagnosticAnalyzer.EnabledRule.Id)); @@ -1150,7 +1150,7 @@ public void TestReportingNotConfigurableDiagnostic() specificDiagOptions.Add(NotConfigurableDiagnosticAnalyzer.DisabledRule.Id, ReportDiagnostic.Warn); options = TestOptions.ReleaseDll.WithSpecificDiagnosticOptions(specificDiagOptions); - CreateCompilationWithMscorlib45(source, options: options) + CreateCompilationWithMscorlib461(source, options: options) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, expected: Diagnostic(NotConfigurableDiagnosticAnalyzer.EnabledRule.Id)); } @@ -1166,7 +1166,7 @@ public void M() {} var analyzers = new DiagnosticAnalyzer[] { new CodeBlockActionAnalyzer() }; // Verify, code block action diagnostics. - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, expected: new[] { Diagnostic(CodeBlockActionAnalyzer.CodeBlockTopLevelRule.Id, "M").WithArguments("M").WithLocation(4, 17), @@ -1185,7 +1185,7 @@ public void M() {} var analyzers = new DiagnosticAnalyzer[] { new CodeBlockActionAnalyzer(onlyStatelessAction: true) }; // Verify, code block action diagnostics. - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, expected: Diagnostic(CodeBlockActionAnalyzer.CodeBlockTopLevelRule.Id, "M").WithArguments("M").WithLocation(4, 17)); } @@ -1215,7 +1215,7 @@ void Method() private void TestGenericNameCore(string source, params DiagnosticAnalyzer[] analyzers) { // Verify, no duplicate diagnostics on generic name. - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyAnalyzerDiagnostics(analyzers, null, null, Diagnostic(CSharpGenericNameAnalyzer.DiagnosticId, @"Nullable").WithLocation(9, 17)); } @@ -1229,7 +1229,7 @@ namespace Goo.Bar.GooBar { } var analyzers = new DiagnosticAnalyzer[] { new CSharpNamespaceDeclarationAnalyzer() }; // Verify, no duplicate diagnostics on qualified name. - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyAnalyzerDiagnostics(analyzers, null, null, Diagnostic(CSharpNamespaceDeclarationAnalyzer.DiagnosticId, @"namespace Goo.Bar.GooBar { }").WithLocation(2, 1)); } @@ -1267,7 +1267,7 @@ class MyClass }"; // Ensure that adding a dummy analyzer with no supported diagnostics doesn't bring down entire analysis. var analyzers = new DiagnosticAnalyzer[] { new AnalyzerWithNoSupportedDiagnostics() }; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers); } @@ -1362,7 +1362,7 @@ class D var analyzers = new DiagnosticAnalyzer[] { new CSharpCodeBlockObjectCreationAnalyzer() }; // Verify, code block action diagnostics. - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(analyzers, null, null, expected: new[] { Diagnostic(CSharpCodeBlockObjectCreationAnalyzer.DiagnosticDescriptor.Id, "new C()").WithLocation(5, 18) @@ -1371,7 +1371,7 @@ class D private static Compilation GetCompilationWithConcurrentBuildEnabled(string source) { - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); // NOTE: We set the concurrentBuild option to true after creating the compilation as CreateCompilationWithMscorlib // always sets concurrentBuild to false if debugger is attached, even if we had passed options with concurrentBuild = true to that API. @@ -1533,7 +1533,7 @@ private class NestedGeneratedCode{0} {{ void NestedGeneratedCodeMethod() {{ Syst // Verify no compiler diagnostics. var trees = builder.ToImmutable(); - var compilation = CreateCompilationWithMscorlib45(trees, new MetadataReference[] { SystemRef }); + var compilation = CreateCompilationWithMscorlib461(trees, new MetadataReference[] { SystemRef }); compilation.VerifyDiagnostics(); Func isGeneratedFile = fileName => fileName.Contains("SourceFileWithAutoGeneratedComment") || generatedFileNames.Contains(fileName); @@ -1568,7 +1568,7 @@ partial class PartialType } "; var tree = CSharpSyntaxTree.ParseText(source, path: "SourceFileRegular.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }, new MetadataReference[] { SystemRef }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }, new MetadataReference[] { SystemRef }); compilation.VerifyDiagnostics(); var builder = ArrayBuilder.GetInstance(); @@ -1611,7 +1611,7 @@ class TypeInGeneratedFile { } "; var tree1 = CSharpSyntaxTree.ParseText(source1, path: "SourceFileRegular.cs"); var tree2 = CSharpSyntaxTree.ParseText(source2, path: "SourceFileRegular.Designer.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree1, tree2 }, new MetadataReference[] { SystemRef }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree1, tree2 }, new MetadataReference[] { SystemRef }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new GeneratedCodeAnalyzer2() }; @@ -1682,7 +1682,7 @@ public void FunkyMethod() public int UnFunkyField = 12; } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new OwningSymbolTestAnalyzer() }, null, null, Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "0").WithLocation(12, 17), @@ -1908,7 +1908,7 @@ public partial class C33 { } var tree4 = CSharpSyntaxTree.ParseText(source3, path: "Source3_File4.generated.cs"); var tree5 = CSharpSyntaxTree.ParseText(source3, path: "Source3_File5.designer.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree1, tree2, tree3, tree4, tree5 }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree1, tree2, tree3, tree4, tree5 }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new SharedStateAnalyzer() }; @@ -1941,7 +1941,7 @@ public C(int a, int b) } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() }; @@ -1962,7 +1962,7 @@ void M1(string a, string b) } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() }; @@ -1985,7 +1985,7 @@ public int this[int index] } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() }; @@ -2006,7 +2006,7 @@ void M2() } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() }; @@ -2031,7 +2031,7 @@ void M4(System.Action a) { } } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() }; @@ -2051,7 +2051,7 @@ public class C } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() }; @@ -2070,7 +2070,7 @@ public class C } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() }; @@ -2093,7 +2093,7 @@ void I.M(int c, int d) { } } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() }; @@ -2114,7 +2114,7 @@ static void M(this int x, int y) { } } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() }; @@ -2140,7 +2140,7 @@ void M2(int a, int b) } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() }; @@ -2173,7 +2173,7 @@ public class RegularClass } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new GeneratedCodeAnalyzer(GeneratedCodeAnalysisFlags.None) }; @@ -2238,7 +2238,7 @@ void MixMethod() } "; var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var syntaxKinds = ImmutableArray.Create(SyntaxKind.VariableDeclaration); @@ -2455,7 +2455,7 @@ private int P3 } } "; - var compilation = CreateCompilationWithMscorlib45(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (51,32): warning CS0067: The event 'C.MyEvent' is never used // public event Delegate MyEvent; @@ -2530,7 +2530,7 @@ public Derived() : base(Field) }"; var tree = CSharpSyntaxTree.ParseText(source); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); // Test RegisterOperationBlockAction @@ -2559,7 +2559,7 @@ internal class C }"; var tree = CSharpSyntaxTree.ParseText(source); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); // Test RegisterOperationBlockAction @@ -2587,7 +2587,7 @@ public void M() { } }"; var tree = CSharpSyntaxTree.ParseText(source); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new MethodOrConstructorBodyOperationAnalyzer() }; @@ -2605,7 +2605,7 @@ public void M(int p = 0) { } }"; var tree = CSharpSyntaxTree.ParseText(source); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new MethodOrConstructorBodyOperationAnalyzer() }; @@ -2623,7 +2623,7 @@ internal class A }"; var tree = CSharpSyntaxTree.ParseText(source); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics( // (4,5): error CS8057: Block bodies and expression bodies cannot both be provided. // public int M() { return 0; } => 0; @@ -2651,7 +2651,7 @@ public Derived() : base(Field) { } }"; var tree = CSharpSyntaxTree.ParseText(source); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new MethodOrConstructorBodyOperationAnalyzer() }; @@ -2668,7 +2668,7 @@ public void TestGetControlFlowGraphInOperationAnalyzers() { string source = @"class C { void M(int p = 0) { int x = 1 + 2; } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyDiagnostics( // (1,35): warning CS0219: The variable 'x' is assigned but its value is never used // class C { void M(int p = 0) { int x = 1 + 2; } } @@ -2847,7 +2847,7 @@ void M10() { } } "; var tree = CSharpSyntaxTree.ParseText(source); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); compilation.VerifyAnalyzerDiagnostics(analyzers, expected: diagnostics); @@ -3185,7 +3185,7 @@ static partial void PartialMethod() private static void M() { } }"; - var compilation = CreateCompilationWithMscorlib45(new[] { source1, source2 }); + var compilation = CreateCompilationWithMscorlib461(new[] { source1, source2 }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new SymbolStartAnalyzer(topLevelAction: false, SymbolKind.NamedType, OperationKind.Invocation) }; @@ -3217,7 +3217,7 @@ static partial void PartialMethod() private static int _field = 0; }"; - var compilation = CreateCompilationWithMscorlib45(new[] { source1, source2 }); + var compilation = CreateCompilationWithMscorlib461(new[] { source1, source2 }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new SymbolStartAnalyzer(topLevelAction: true, SymbolKind.NamedType, OperationKind.FieldReference) }; @@ -3231,7 +3231,7 @@ static partial void PartialMethod() } [Theory, CombinatorialData, WorkItem(32702, "https://github.com/dotnet/roslyn/issues/71149")] - public async Task TestPartialFileSymbolEndDiagnosticsAsync(bool separateFiles) + public async Task TestPartialMethodFileSymbolEndDiagnosticsAsync(bool separateFiles) { string definition1 = @" internal partial class Test @@ -3257,7 +3257,53 @@ internal partial class Test source2 = string.Empty; } - var compilation = CreateCompilationWithMscorlib45([source1, source2]); + var compilation = CreateCompilationWithMscorlib461([source1, source2]); + compilation.VerifyDiagnostics(); + + var tree1 = compilation.SyntaxTrees[0]; + var semanticModel1 = compilation.GetSemanticModel(tree1); + var analyzers = ImmutableArray.Create(new SymbolStartAnalyzer(topLevelAction: false, SymbolKind.NamedType)); + var compilationWithAnalyzers = compilation.WithAnalyzers(analyzers); + + // Requesting diagnostics on a single tree should run the SymbolStart/End actions on all the partials across the compilation + // and the analysis result should contain the diagnostics reported at SymbolEnd action. + var analysisResult = await compilationWithAnalyzers.GetAnalysisResultAsync(semanticModel1, filterSpan: null, analyzers, CancellationToken.None); + Assert.Empty(analysisResult.SyntaxDiagnostics); + Assert.Empty(analysisResult.SemanticDiagnostics); + var compilationDiagnostics = analysisResult.CompilationDiagnostics[analyzers[0]]; + compilationDiagnostics.Verify( + Diagnostic("SymbolStartRuleId").WithArguments("Test", "Analyzer1").WithLocation(1, 1) + ); + } + + [Theory, CombinatorialData, WorkItem(32702, "https://github.com/dotnet/roslyn/issues/71149")] + public async Task TestPartialPropertyFileSymbolEndDiagnosticsAsync(bool separateFiles) + { + string definition1 = @" +internal partial class Test +{ + private partial object Prop { get; set; } + public Test(object _) { } +}"; + string definition2 = @" +internal partial class Test +{ + private partial object Prop { get => new(); set { } } +}"; + + string source1, source2; + if (separateFiles) + { + source1 = definition1; + source2 = definition2; + } + else + { + source1 = definition1 + definition2; + source2 = string.Empty; + } + + var compilation = CreateCompilationWithMscorlib461([source1, source2]); compilation.VerifyDiagnostics(); var tree1 = compilation.SyntaxTrees[0]; @@ -3295,7 +3341,7 @@ class C private int _field3 = 3; }"; - var compilation = CreateCompilationWithMscorlib45(new[] { source1, source2, source3 }); + var compilation = CreateCompilationWithMscorlib461(new[] { source1, source2, source3 }); var tree1 = compilation.SyntaxTrees[0]; var semanticModel1 = compilation.GetSemanticModel(tree1); var analyzer1 = new SymbolStartAnalyzer(topLevelAction: true, SymbolKind.Field, analyzerId: 1); @@ -3322,7 +3368,7 @@ public void TestAnalyzerCallbacksWithSuppressedFile_SymbolAction() { var tree1 = Parse("partial class A { }"); var tree2 = Parse("partial class A { private class B { } }"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree1, tree2 }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree1, tree2 }); compilation.VerifyDiagnostics(); // Verify analyzer diagnostics and callbacks without suppression. @@ -3365,7 +3411,7 @@ public void TestAnalyzerCallbacksWithSuppressedFile_SymbolStartEndAction() { var tree1 = Parse("partial class A { }"); var tree2 = Parse("partial class A { private class B { } }"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree1, tree2 }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree1, tree2 }); compilation.VerifyDiagnostics(); // Verify analyzer diagnostics and callbacks without suppression. @@ -3418,7 +3464,7 @@ public void TestAnalyzerCallbacksWithSuppressedFile_CompilationStartEndAction() { var tree1 = Parse("partial class A { }"); var tree2 = Parse("partial class A { private class B { } }"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree1, tree2 }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree1, tree2 }); compilation.VerifyDiagnostics(); // Verify analyzer diagnostics and callbacks without suppression. @@ -3469,7 +3515,7 @@ public void TestAnalyzerCallbacksWithGloballySuppressedFile_SymbolAction() { var tree1 = Parse("partial class A { }"); var tree2 = Parse("partial class A { private class B { } }"); - var compilation = CreateCompilationWithMscorlib45(new[] { tree1, tree2 }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree1, tree2 }); compilation.VerifyDiagnostics(); // Verify analyzer diagnostics and callbacks without suppression. @@ -3543,7 +3589,7 @@ public void M() { } }"; var tree = CSharpSyntaxTree.ParseText(source); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); // Verify analyzer execution from command line @@ -3573,7 +3619,7 @@ class C }"; var tree = CSharpSyntaxTree.ParseText(source); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var analyzers = new DiagnosticAnalyzer[] { new RegisterOperationBlockAndOperationActionAnalyzer() }; @@ -3594,7 +3640,7 @@ public B(int a) { } }"; var tree = CSharpSyntaxTree.ParseText(source); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics( // (5,12): error CS0501: 'B.B()' must declare a body because it is not marked abstract, extern, or partial // public B() : this(1) @@ -3631,7 +3677,7 @@ class C private int _field3 = 3; }"; - var compilation = CreateCompilationWithMscorlib45(new[] { source1, source2, source3 }); + var compilation = CreateCompilationWithMscorlib461(new[] { source1, source2, source3 }); var tree1 = compilation.SyntaxTrees[0]; var field1 = tree1.GetRoot().DescendantNodes().OfType().Single().Declaration.Variables.Single().Identifier; var semanticModel1 = compilation.GetSemanticModel(tree1); @@ -3698,7 +3744,7 @@ void M2() } }"; - var compilation = CreateCompilationWithMscorlib45(new[] { source }); + var compilation = CreateCompilationWithMscorlib461(new[] { source }); var tree = compilation.SyntaxTrees[0]; var localDecl1 = tree.GetRoot().DescendantNodes().OfType().First(); var semanticModel = compilation.GetSemanticModel(tree); @@ -3866,7 +3912,7 @@ void verifyDiagnostics(ImmutableArray diagnostics) public async Task TestMultipleAdditionalFileAnalyzers(bool registerFromInitialize, bool additionalFilesHaveSamePaths, bool firstAdditionalFileHasNullPath) { var tree = CSharpSyntaxTree.ParseText(string.Empty); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics(); var path1 = firstAdditionalFileHasNullPath ? null : @"c:\file.txt"; @@ -4259,7 +4305,7 @@ void M2() }"; string additionalText = @"This is an additional file!"; - var compilation = CreateCompilationWithMscorlib45(new[] { source1, source2 }); + var compilation = CreateCompilationWithMscorlib461(new[] { source1, source2 }); var tree = compilation.SyntaxTrees[0]; var localDeclaration = tree.GetRoot().DescendantNodes().OfType().First(); var semanticModel = compilation.GetSemanticModel(tree); diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticSuppressorTests.cs b/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticSuppressorTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticSuppressorTests.cs rename to src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticSuppressorTests.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/GetDiagnosticsTests.cs b/src/Compilers/CSharp/Test/Emit3/Diagnostics/GetDiagnosticsTests.cs similarity index 98% rename from src/Compilers/CSharp/Test/Emit2/Diagnostics/GetDiagnosticsTests.cs rename to src/Compilers/CSharp/Test/Emit3/Diagnostics/GetDiagnosticsTests.cs index 92cfc8eb21ea7..da6e2ff2751c5 100644 --- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/GetDiagnosticsTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Diagnostics/GetDiagnosticsTests.cs @@ -40,7 +40,7 @@ void M() } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); var model = compilation.GetSemanticModel(compilation.SyntaxTrees.Single()); DiagnosticsHelper.VerifyDiagnostics(model, source, @"(?s)^.*$", "CS1646", "CS1024", "CS1525", "CS1002"); @@ -75,7 +75,7 @@ int P } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); var model = compilation.GetSemanticModel(compilation.SyntaxTrees.Single()); DiagnosticsHelper.VerifyDiagnostics(model, source, @"var x = X;", "CS0103"); @@ -90,7 +90,7 @@ class C : Abracadabra { } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); var model = compilation.GetSemanticModel(compilation.SyntaxTrees.Single()); const string ErrorId = "CS0246"; @@ -114,7 +114,7 @@ public void Goo() } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); var diag = compilation.GetDiagnostics().Single(); Assert.Equal(DiagnosticSeverity.Warning, diag.Severity); @@ -166,7 +166,7 @@ private void NonPartialMethod2() { } var tree1 = CSharpSyntaxTree.ParseText(source1, path: "file1"); var tree2 = CSharpSyntaxTree.ParseText(source2, path: "file2"); var eventQueue = new AsyncQueue(); - var compilation = CreateCompilationWithMscorlib45(new[] { tree1, tree2 }).WithEventQueue(eventQueue); + var compilation = CreateCompilationWithMscorlib461(new[] { tree1, tree2 }).WithEventQueue(eventQueue); // Invoke SemanticModel.GetDiagnostics to force populate the event queue for symbols in the first source file. var model = compilation.GetSemanticModel(tree1); @@ -215,7 +215,7 @@ partial void PartialMethod() { } var tree1 = CSharpSyntaxTree.ParseText(source1, path: "file1"); var tree2 = CSharpSyntaxTree.ParseText(source2, path: "file2"); var eventQueue = new AsyncQueue(); - var compilation = CreateCompilationWithMscorlib45(new[] { tree1, tree2 }).WithEventQueue(eventQueue); + var compilation = CreateCompilationWithMscorlib461(new[] { tree1, tree2 }).WithEventQueue(eventQueue); // Invoke SemanticModel.GetDiagnostics to force populate the event queue for symbols in the first source file. var model = compilation.GetSemanticModel(tree1); @@ -267,7 +267,7 @@ partial class Class var tree1 = CSharpSyntaxTree.ParseText(source1, path: "file1"); var tree2 = CSharpSyntaxTree.ParseText(source2, path: "file2"); var eventQueue = new AsyncQueue(); - var compilation = CreateCompilationWithMscorlib45(new[] { tree1, tree2 }).WithEventQueue(eventQueue); + var compilation = CreateCompilationWithMscorlib461(new[] { tree1, tree2 }).WithEventQueue(eventQueue); // Invoke SemanticModel.GetDiagnostics to force populate the event queue for symbols in the first source file. var model = compilation.GetSemanticModel(tree1); @@ -286,6 +286,7 @@ partial class Class "", "Class", "DefOnlyPartialProp", + "get_DefOnlyPartialProp", "get_ImplOnlyPartialProp", "get_NonPartialProp1", "get_PartialProp", @@ -293,6 +294,7 @@ partial class Class "N1", "NonPartialProp1", "PartialProp", + "set_DefOnlyPartialProp", "set_ImplOnlyPartialProp", "set_NonPartialProp1", "set_PartialProp" @@ -316,7 +318,7 @@ private void NonPartialMethod1() { } "; var tree = CSharpSyntaxTree.ParseText(source, path: "file1"); var eventQueue = new AsyncQueue(); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }).WithEventQueue(eventQueue); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }).WithEventQueue(eventQueue); eventQueue.TryComplete(); // complete the queue before the compiler is finished with it var model = compilation.GetSemanticModel(tree); model.GetDiagnostics(tree.GetRoot().FullSpan); @@ -369,7 +371,7 @@ private static bool DequeueCompilationEvents(AsyncQueue eventQ [Fact] public void TestEventQueueCompletionForEmptyCompilation() { - var compilation = CreateCompilationWithMscorlib45(CSharpTestSource.None).WithEventQueue(new AsyncQueue()); + var compilation = CreateCompilationWithMscorlib461(CSharpTestSource.None).WithEventQueue(new AsyncQueue()); // Force complete compilation event queue var unused = compilation.GetDiagnostics(); @@ -392,7 +394,7 @@ public void CompilingCodeWithInvalidPreProcessorSymbolsShouldProvideDiagnostics( public void CompilingCodeWithInvalidSourceCodeKindShouldProvideDiagnostics() { #pragma warning disable CS0618 // Type or member is obsolete - var compilation = CreateCompilationWithMscorlib45(string.Empty, parseOptions: new CSharpParseOptions().WithKind(SourceCodeKind.Interactive)); + var compilation = CreateCompilationWithMscorlib461(string.Empty, parseOptions: new CSharpParseOptions().WithKind(SourceCodeKind.Interactive)); #pragma warning restore CS0618 // Type or member is obsolete compilation.VerifyDiagnostics( diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/MethodGroupConversion.cs b/src/Compilers/CSharp/Test/Emit3/Diagnostics/MethodGroupConversion.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Diagnostics/MethodGroupConversion.cs rename to src/Compilers/CSharp/Test/Emit3/Diagnostics/MethodGroupConversion.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs b/src/Compilers/CSharp/Test/Emit3/Diagnostics/OperationAnalyzerTests.cs similarity index 96% rename from src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs rename to src/Compilers/CSharp/Test/Emit3/Diagnostics/OperationAnalyzerTests.cs index 4e1c7d5874980..ba4a16beb50a5 100644 --- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Diagnostics/OperationAnalyzerTests.cs @@ -43,7 +43,7 @@ void M1() int[,][] arr12 = new int[0,0][]; // no } }"; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new EmptyArrayAnalyzer() }, null, null, Diagnostic(EmptyArrayAnalyzer.UseArrayEmptyDescriptor.Id, "new int[0]").WithLocation(6, 22), @@ -105,7 +105,7 @@ class D object OField = 33; object SField = ""Zap""; }"; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new BoxingOperationAnalyzer() }, null, null, Diagnostic(BoxingOperationAnalyzer.BoxingDescriptor.Id, "3").WithLocation(9, 25), @@ -136,7 +136,7 @@ public void M1(int z) } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new BadStuffTestAnalyzer() }, null, null, Diagnostic(BadStuffTestAnalyzer.InvalidExpressionDescriptor.Id, "Framitz()").WithLocation(6, 9), Diagnostic(BadStuffTestAnalyzer.IsInvalidDescriptor.Id, "Framitz()").WithLocation(6, 9), @@ -184,7 +184,7 @@ public void M1(object o) } } "; - CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe) + CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new BadStuffTestAnalyzer() }, null, null); } @@ -212,7 +212,7 @@ public void M1() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new BigForTestAnalyzer() }, null, null, Diagnostic(BigForTestAnalyzer.BigForDescriptor.Id, "for (x = 0; x < 2000000; x++) {}").WithLocation(9, 9), @@ -275,7 +275,7 @@ public void M1(int x, int y) } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics( Diagnostic(ErrorCode.WRN_EmptySwitch, "{").WithLocation(40, 20), Diagnostic(ErrorCode.ERR_ConstantExpected, ":").WithLocation(44, 18)) @@ -342,7 +342,7 @@ public void M6() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new InvocationTestAnalyzer() }, null, null, Diagnostic(InvocationTestAnalyzer.BigParamArrayArgumentsDescriptor.Id, "M0(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)").WithLocation(19, 9), @@ -419,7 +419,7 @@ class C1 } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new FieldCouldBeReadOnlyAnalyzer() }, null, null, Diagnostic(FieldCouldBeReadOnlyAnalyzer.FieldCouldBeReadOnlyDescriptor.Id, "F5").WithLocation(8, 9), @@ -491,7 +491,7 @@ class C1 } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new FieldCouldBeReadOnlyAnalyzer() }, null, null, Diagnostic(FieldCouldBeReadOnlyAnalyzer.FieldCouldBeReadOnlyDescriptor.Id, "F5").WithLocation(8, 16), @@ -546,7 +546,7 @@ class C1 } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new LocalCouldBeConstAnalyzer() }, null, null, Diagnostic(LocalCouldBeConstAnalyzer.LocalCouldBeConstDescriptor.Id, "e").WithLocation(13, 13), @@ -717,7 +717,7 @@ interface IDerived : IMiddle, IBase2 } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new SymbolCouldHaveMoreSpecificTypeAnalyzer() }, null, null, Diagnostic(SymbolCouldHaveMoreSpecificTypeAnalyzer.LocalCouldHaveMoreSpecificTypeDescriptor.Id, "a").WithArguments("a", "Middle").WithLocation(6, 16), @@ -782,7 +782,7 @@ enum E D = 18 } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new SeventeenTestAnalyzer() }, null, null, Diagnostic(SeventeenTestAnalyzer.SeventeenDescriptor.Id, "17").WithLocation(4, 40), @@ -822,7 +822,7 @@ public void M3() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new NullArgumentTestAnalyzer() }, null, null, Diagnostic(NullArgumentTestAnalyzer.NullArgumentsDescriptor.Id, "null").WithLocation(16, 12), @@ -863,7 +863,7 @@ public void M1() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics( // (25,30): error CS1010: Newline in constant // var e2 = new Goo() { " }; @@ -925,7 +925,7 @@ public void M2() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new AssignmentTestAnalyzer() }, null, null, Diagnostic("DoNotUseMemberAssignment", "Property2 = new Bar { Field = true }").WithLocation(27, 30), @@ -974,7 +974,7 @@ void M1() int[][] arr14 = new int[][] { new int[] { 1,2,3 }, new[] { 1, 2, 3, 4, 5, 6 } }; // LargeList } }"; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new ArrayInitializerTestAnalyzer() }, null, null, Diagnostic(ArrayInitializerTestAnalyzer.DoNotUseLargeListOfArrayInitializersDescriptor.Id, "{ 1, 2, 3, 4, 5, 6 }").WithLocation(14, 32), @@ -1008,7 +1008,7 @@ public void M1() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics( Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(12, 25), Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(13, 29)) @@ -1073,7 +1073,7 @@ public void M1(int x, int y) } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics(Diagnostic(ErrorCode.WRN_EmptySwitch, "{").WithLocation(37, 20), Diagnostic(ErrorCode.ERR_ConstantExpected, ":").WithLocation(41, 18)) .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new CaseTestAnalyzer() }, null, null, @@ -1115,7 +1115,7 @@ public override void M1() M2(); } }"; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new ExplicitVsImplicitInstanceAnalyzer() }, null, null, Diagnostic(ExplicitVsImplicitInstanceAnalyzer.ExplicitInstanceDescriptor.Id, "this").WithLocation(6, 9), @@ -1151,7 +1151,7 @@ private void Mumbler(object sender, System.EventArgs args) { } }"; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new MemberReferenceAnalyzer() }, null, null, // Bug: we are missing diagnostics of "MethodBindingDescriptor" here. https://github.com/dotnet/roslyn/issues/20095 @@ -1214,7 +1214,7 @@ public D(string a, params int[] b) } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new ParamsArrayTestAnalyzer() }, null, null, Diagnostic(ParamsArrayTestAnalyzer.LongParamsDescriptor.Id, "M0(1, 2, 3, 4, 5)").WithLocation(13, 9), @@ -1239,7 +1239,7 @@ class C static int Bar(int P1 = 15, int F2 = 33) { return P1 + F2; } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new EqualsValueTestAnalyzer() }, null, null, Diagnostic(EqualsValueTestAnalyzer.EqualsValueDescriptor.Id, "= 44").WithLocation(4, 19), @@ -1270,7 +1270,7 @@ public void FunkyMethod() public int UnFunkyField = 12; } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new OwningSymbolTestAnalyzer() }, null, null, Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "0").WithLocation(12, 17), @@ -1294,7 +1294,7 @@ public void M0() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new NoneOperationTestAnalyzer() }, null, null); } @@ -1334,7 +1334,7 @@ public static long Calculate1(long[] f) } }"; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new AssignmentOperationSyntaxTestAnalyzer() }, null, null, Diagnostic(AssignmentOperationSyntaxTestAnalyzer.AssignmentOperationDescriptor.Id, $"x = {expr}").WithLocation(7, 9), @@ -1383,7 +1383,7 @@ public unsafe void M1() private int _i = 0; }"; - CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeReleaseDll) + CreateCompilationWithMscorlib461(source, options: TestOptions.UnsafeReleaseDll) .VerifyDiagnostics(Diagnostic(ErrorCode.ERR_InvalidAddrOp, "a + b").WithLocation(7, 18)) .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new AddressOfTestAnalyzer() }, null, null, Diagnostic("AddressOfOperation", "&(a + b)").WithLocation(7, 16), @@ -1427,7 +1427,7 @@ public void OnMumble(System.EventArgs args) } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new LambdaTestAnalyzer() }, null, null, Diagnostic(LambdaTestAnalyzer.LambdaExpressionDescriptor.Id, "input => { }").WithLocation(8, 31), @@ -1476,7 +1476,7 @@ void Goo() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics(Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("D.E").WithLocation(6, 32)) .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new StaticMemberTestAnalyzer() }, null, null, Diagnostic(StaticMemberTestAnalyzer.StaticMemberDescriptor.Id, "C.E").WithLocation(23, 9), @@ -1502,7 +1502,7 @@ public void Fred() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new LabelOperationsTestAnalyzer() }, null, null, Diagnostic(LabelOperationsTestAnalyzer.LabelDescriptor.Id, "Wilma: goto Betty;").WithLocation(6, 9), @@ -1561,7 +1561,7 @@ static void Main() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new UnaryAndBinaryOperationsTestAnalyzer() }, null, null, Diagnostic(UnaryAndBinaryOperationsTestAnalyzer.BooleanNotDescriptor.Id, "!b").WithLocation(41, 13), @@ -1607,7 +1607,7 @@ static void Main() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics(Diagnostic(ErrorCode.ERR_BadBinaryOps, "x + 10", new object[] { "+", "A", "int" }).WithLocation(29, 13), Diagnostic(ErrorCode.ERR_BadUnaryOp, "-x", new object[] { "-", "A" }).WithLocation(31, 13)) // no diagnostics from the analyzer since node it is looking for is invalid @@ -1635,7 +1635,7 @@ public void M1() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new NullOperationSyntaxTestAnalyzer() }, null, null, Diagnostic(NullOperationSyntaxTestAnalyzer.ParamsArrayOperationDescriptor.Id, "M0()"), @@ -1661,7 +1661,7 @@ static void Main() int i = global::MyType(); } }"; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics( // (8,17): error CS0023: Operator '.' cannot be applied to operand of type '' // int x = null.Length; @@ -1701,7 +1701,7 @@ public void Increment(string f) } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics( Diagnostic(ErrorCode.ERR_NoSuchMember, "Nan").WithArguments("float", "Nan").WithLocation(6, 27), Diagnostic(ErrorCode.ERR_BadUnaryOp, "-f").WithArguments("-", "string").WithLocation(11, 16), @@ -1728,7 +1728,7 @@ public static int Main() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics( // (4,28): error CS0225: The params parameter must have a valid collection type // public static void Goo(params int a) {} @@ -1777,7 +1777,7 @@ public void M0(C p) } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new ConditionalAccessOperationTestAnalyzer() }, null, null, Diagnostic(ConditionalAccessOperationTestAnalyzer.ConditionalAccessOperationDescriptor.Id, "p?.Prop").WithLocation(24, 17), @@ -1822,7 +1822,7 @@ void M( } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics(Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "a").WithArguments("a").WithLocation(6, 16)) .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new LiteralTestAnalyzer() }, null, null, Diagnostic("Literal", "null").WithArguments("null").WithLocation(6, 20), Diagnostic("Literal", "1").WithArguments("1").WithLocation(13, 17), @@ -1868,7 +1868,7 @@ public void M() } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new TrueFalseUnaryOperationTestAnalyzer() }, null, null, Diagnostic(TrueFalseUnaryOperationTestAnalyzer.UnaryTrueDescriptor.Id, "x && y").WithLocation(29, 13), @@ -1894,7 +1894,7 @@ public void M3(int i = 0) } } "; - CreateCompilationWithMscorlib45(source) + CreateCompilationWithMscorlib461(source) .VerifyDiagnostics() .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new OperationBlockAnalyzer() }, null, null, Diagnostic("ID", "M2").WithArguments("M2", "Block").WithLocation(8, 17), diff --git a/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs new file mode 100644 index 0000000000000..6e7364596a931 --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit3/FieldKeywordTests.cs @@ -0,0 +1,9684 @@ +// 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 Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using System.Collections.Immutable; +using System.Linq; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public class FieldKeywordTests : CSharpTestBase + { + private static TargetFramework GetTargetFramework(bool useInit) => useInit ? TargetFramework.Net80 : TargetFramework.Standard; + + private static string IncludeExpectedOutput(string expectedOutput) => ExecutionConditionUtil.IsMonoOrCoreClr ? expectedOutput : null; + + private static string IncludeExpectedOutput(bool useInit, string expectedOutput) => !useInit ? expectedOutput : null; + + [Fact] + public void Field_01() + { + string source = """ + using System; + using System.Reflection; + class C + { + public object P => field = 1; + public static object Q { get => field = 2; } + } + class Program + { + static void Main() + { + Console.WriteLine((new C().P, C.Q)); + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + Console.WriteLine("{0}: {1}", field.Name, field.IsInitOnly); + } + } + """; + var verifier = CompileAndVerify(source, expectedOutput: """ + (1, 2) +

k__BackingField: False + k__BackingField: False + """); + verifier.VerifyIL("C.P.get", """ + { + // Code size 16 (0x10) + .maxstack 3 + .locals init (object V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: box "int" + IL_0007: dup + IL_0008: stloc.0 + IL_0009: stfld "object C.

k__BackingField" + IL_000e: ldloc.0 + IL_000f: ret + } + """); + verifier.VerifyIL("C.Q.get", """ + { + // Code size 13 (0xd) + .maxstack 2 + IL_0000: ldc.i4.2 + IL_0001: box "int" + IL_0006: dup + IL_0007: stsfld "object C.k__BackingField" + IL_000c: ret + } + """); + var comp = (CSharpCompilation)verifier.Compilation; + var actualMembers = comp.GetMember("C").GetMembers().ToTestDisplayStrings(); + var expectedMembers = new[] + { + "System.Object C.

k__BackingField", + "System.Object C.P { get; }", + "System.Object C.P.get", + "System.Object C.k__BackingField", + "System.Object C.Q { get; }", + "System.Object C.Q.get", + "C..ctor()" + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + + [Fact] + public void Field_02() + { + string source = """ + using System; + class C + { + public object P => Initialize(out field, 1); + public object Q { get => Initialize(out field, 2); } + static object Initialize(out object field, object value) + { + field = value; + return field; + } + } + class Program + { + static void Main() + { + var c = new C(); + Console.WriteLine((c.P, c.Q)); + } + } + """; + var verifier = CompileAndVerify(source, expectedOutput: "(1, 2)"); + verifier.VerifyIL("C.P.get", """ + { + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldflda "object C.

k__BackingField" + IL_0006: ldc.i4.1 + IL_0007: box "int" + IL_000c: call "object C.Initialize(out object, object)" + IL_0011: ret + } + """); + verifier.VerifyIL("C.Q.get", """ + { + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldflda "object C.k__BackingField" + IL_0006: ldc.i4.2 + IL_0007: box "int" + IL_000c: call "object C.Initialize(out object, object)" + IL_0011: ret + } + """); + var comp = (CSharpCompilation)verifier.Compilation; + var actualMembers = comp.GetMember("C").GetMembers().ToTestDisplayStrings(); + var expectedMembers = new[] + { + "System.Object C.

k__BackingField", + "System.Object C.P { get; }", + "System.Object C.P.get", + "System.Object C.k__BackingField", + "System.Object C.Q { get; }", + "System.Object C.Q.get", + "System.Object C.Initialize(out System.Object field, System.Object value)", + "C..ctor()" + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + + [Fact] + public void Field_03() + { + string source = """ + using System; + using System.Reflection; + class C + { + public object P { get { return field; } init { field = 1; } } + public object Q { init { field = 2; } } + } + class Program + { + static void Main() + { + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance)) + Console.WriteLine("{0}: {1}", field.Name, field.IsInitOnly); + } + } + """; + CompileAndVerify(source, targetFramework: TargetFramework.Net80, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(""" +

k__BackingField: False + k__BackingField: True + """)); + } + + [Fact] + public void FieldReference_01() + { + string source = """ + class C + { + static C _other = new(); + object P + { + get { return _other.field; } + set { _ = field; } + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (6,29): error CS1061: 'C' does not contain a definition for 'field' and no accessible extension method 'field' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // get { return _other.field; } + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "field").WithArguments("C", "field").WithLocation(6, 29)); + } + + [Fact] + public void FieldReference_02() + { + string source = """ + class C + { + C P + { + get { return null; } + set { field = value.field; } + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (6,29): error CS1061: 'C' does not contain a definition for 'field' and no accessible extension method 'field' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) + // set { field = value.field; } + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "field").WithArguments("C", "field").WithLocation(6, 29)); + var actualMembers = comp.GetMember("C").GetMembers().ToTestDisplayStrings(); + var expectedMembers = new[] + { + "C C.

k__BackingField", + "C C.P { get; set; }", + "C C.P.get", + "void C.P.set", + "C..ctor()" + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + + [Fact] + public void FieldReference_03() + { + string source = """ + class C + { + int P + { + get { return field; } + set { _ = this is { field: 0 }; } + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (6,29): error CS0117: 'C' does not contain a definition for 'field' + // set { _ = this is { field: 0 }; } + Diagnostic(ErrorCode.ERR_NoSuchMember, "field").WithArguments("C", "field").WithLocation(6, 29)); + } + + [Fact] + public void FieldInInitializer_01() + { + string source = """ + class C + { + object P { get; } = F(field); + static object F(object value) => value; + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (3,27): error CS0103: The name 'field' does not exist in the current context + // object P { get; } = F(field); + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(3, 27)); + var actualMembers = comp.GetMember("C").GetMembers().ToTestDisplayStrings(); + var expectedMembers = new[] + { + "System.Object C.

k__BackingField", + "System.Object C.P { get; }", + "System.Object C.P.get", + "System.Object C.F(System.Object value)", + "C..ctor()" + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + + [Fact] + public void FieldInInitializer_02() + { + string source = """ + class C + { + object P { get => field; } = field; + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (3,34): error CS0103: The name 'field' does not exist in the current context + // object P { get => field; } = field; + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(3, 34)); + } + + [Fact] + public void FieldInInitializer_03() + { + string source = """ + class C + { + object P { set { } } = field; + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (3,12): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // object P { set { } } = field; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P").WithLocation(3, 12), + // (3,28): error CS0103: The name 'field' does not exist in the current context + // object P { set { } } = field; + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(3, 28)); + } + + [Fact] + public void Lambda_01() + { + string source = """ + using System; + using System.Reflection; + class C + { + public object P1 => F(() => field); + public object P2 { set { F(() => field = value); } } + public static object P3 => F(static () => field); + static object F(Func f) => f(); + } + class Program + { + static void Main() + { + Console.WriteLine((new C().P1, C.P3)); + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + Console.WriteLine("{0}", field.Name); + } + } + """; + var verifier = CompileAndVerify(source, expectedOutput: """ + (, ) + k__BackingField + k__BackingField + k__BackingField + """); + verifier.VerifyIL("C.b__2_0()", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld "object C.k__BackingField" + IL_0006: ret + } + """); + verifier.VerifyIL("C.<>c__DisplayClass5_0.b__0()", """ + { + // Code size 21 (0x15) + .maxstack 3 + .locals init (object V_0) + IL_0000: ldarg.0 + IL_0001: ldfld "C C.<>c__DisplayClass5_0.<>4__this" + IL_0006: ldarg.0 + IL_0007: ldfld "object C.<>c__DisplayClass5_0.value" + IL_000c: dup + IL_000d: stloc.0 + IL_000e: stfld "object C.k__BackingField" + IL_0013: ldloc.0 + IL_0014: ret + } + """); + verifier.VerifyIL("C.<>c.b__8_0()", """ + { + // Code size 6 (0x6) + .maxstack 1 + IL_0000: ldsfld "object C.k__BackingField" + IL_0005: ret + } + """); + } + + [Fact] + public void Lambda_02() + { + string source = """ + using System; + class C + { + public object P => F(static () => field); + static object F(Func f) => f(); + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,39): error CS8821: A static anonymous function cannot contain a reference to 'this' or 'base'. + // public object P => F(static () => field); + Diagnostic(ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureThis, "field").WithLocation(4, 39)); + } + + [Fact] + public void LocalFunction_01() + { + string source = """ + using System; + using System.Reflection; + class C + { + public object P + { + get + { + object F() => field; + return F(); + } + } + public static object Q + { + get + { + object F() => field; + return F(); + } + } + } + class Program + { + static void Main() + { + Console.WriteLine((new C().P, C.Q)); + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + Console.WriteLine("{0}", field.Name); + } + } + """; + var verifier = CompileAndVerify(source, expectedOutput: """ + (, ) +

k__BackingField + k__BackingField + """); + verifier.VerifyIL("C.g__F|2_0()", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld "object C.

k__BackingField" + IL_0006: ret + } + """); + verifier.VerifyIL("C.g__F|5_0()", """ + { + // Code size 6 (0x6) + .maxstack 1 + IL_0000: ldsfld "object C.k__BackingField" + IL_0005: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void ImplicitAccessorBody_01( + [CombinatorialValues("class", "struct", "ref struct", "record", "record struct")] string typeKind, + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = $$""" + {{typeKind}} A + { + public static object P1 { get; set { _ = field; } } + public static object P2 { get { return field; } set; } + public static object P3 { get { return null; } set; } + public object Q1 { get; set { _ = field; } } + public object Q2 { get { return field; } set; } + public object Q3 { get { return field; } init; } + public object Q4 { get; set { } } + public object Q5 { get; init { } } + } + class Program + { + static void Main() + { + _ = new A(); + } + } + """; + + var comp = CreateCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe, + targetFramework: TargetFramework.Net80); + + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (3,26): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static object P1 { get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(3, 26), + // (3,46): error CS0103: The name 'field' does not exist in the current context + // public static object P1 { get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(3, 46), + // (4,26): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static object P2 { get { return field; } set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P2").WithArguments("field keyword").WithLocation(4, 26), + // (4,44): error CS0103: The name 'field' does not exist in the current context + // public static object P2 { get { return field; } set; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(4, 44), + // (5,26): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static object P3 { get { return null; } set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P3").WithArguments("field keyword").WithLocation(5, 26), + // (6,19): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public object Q1 { get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Q1").WithArguments("field keyword").WithLocation(6, 19), + // (6,39): error CS0103: The name 'field' does not exist in the current context + // public object Q1 { get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(6, 39), + // (7,19): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public object Q2 { get { return field; } set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Q2").WithArguments("field keyword").WithLocation(7, 19), + // (7,37): error CS0103: The name 'field' does not exist in the current context + // public object Q2 { get { return field; } set; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(7, 37), + // (8,19): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public object Q3 { get { return field; } init; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Q3").WithArguments("field keyword").WithLocation(8, 19), + // (8,37): error CS0103: The name 'field' does not exist in the current context + // public object Q3 { get { return field; } init; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(8, 37), + // (9,19): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public object Q4 { get; set { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Q4").WithArguments("field keyword").WithLocation(9, 19), + // (10,19): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public object Q5 { get; init { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Q5").WithArguments("field keyword").WithLocation(10, 19)); + } + else + { + var verifier = CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("")); + verifier.VerifyIL("A.P1.get", """ + { + // Code size 6 (0x6) + .maxstack 1 + IL_0000: ldsfld "object A.k__BackingField" + IL_0005: ret + } + """); + verifier.VerifyIL("A.P2.set", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: stsfld "object A.k__BackingField" + IL_0006: ret + } + """); + verifier.VerifyIL("A.Q1.get", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld "object A.k__BackingField" + IL_0006: ret + } + """); + verifier.VerifyIL("A.Q2.set", """ + { + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld "object A.k__BackingField" + IL_0007: ret + } + """); + verifier.VerifyIL("A.Q3.init", """ + { + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld "object A.k__BackingField" + IL_0007: ret + } + """); + } + + if (!typeKind.StartsWith("record")) + { + var actualMembers = comp.GetMember("A").GetMembers().ToTestDisplayStrings(); + string readonlyQualifier = typeKind.EndsWith("struct") ? "readonly " : ""; + var expectedMembers = new[] + { + "System.Object A.k__BackingField", + "System.Object A.P1 { get; set; }", + "System.Object A.P1.get", + "void A.P1.set", + "System.Object A.k__BackingField", + "System.Object A.P2 { get; set; }", + "System.Object A.P2.get", + "void A.P2.set", + "System.Object A.k__BackingField", + "System.Object A.P3 { get; set; }", + "System.Object A.P3.get", + "void A.P3.set", + "System.Object A.k__BackingField", + "System.Object A.Q1 { get; set; }", + readonlyQualifier + "System.Object A.Q1.get", + "void A.Q1.set", + "System.Object A.k__BackingField", + "System.Object A.Q2 { get; set; }", + "System.Object A.Q2.get", + "void A.Q2.set", + "System.Object A.k__BackingField", + "System.Object A.Q3 { get; init; }", + "System.Object A.Q3.get", + "void modreq(System.Runtime.CompilerServices.IsExternalInit) A.Q3.init", + "System.Object A.k__BackingField", + "System.Object A.Q4 { get; set; }", + readonlyQualifier + "System.Object A.Q4.get", + "void A.Q4.set", + "System.Object A.k__BackingField", + "System.Object A.Q5 { get; init; }", + readonlyQualifier + "System.Object A.Q5.get", + "void modreq(System.Runtime.CompilerServices.IsExternalInit) A.Q5.init", + "A..ctor()" + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + } + + [Theory] + [CombinatorialData] + public void ImplicitAccessorBody_02( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = """ + interface I + { + static object P1 { get; set { _ = field; } } + static object P2 { get { return field; } set; } + static object P3 { get; set { } } + static object P4 { get { return null; } set; } + static object P5 { get; } + static object P6 { get; set; } + } + """; + + var comp = CreateCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + targetFramework: TargetFramework.Net80); + + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (3,19): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static object P1 { get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(3, 19), + // (3,39): error CS0103: The name 'field' does not exist in the current context + // static object P1 { get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(3, 39), + // (4,19): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static object P2 { get { return field; } set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P2").WithArguments("field keyword").WithLocation(4, 19), + // (4,37): error CS0103: The name 'field' does not exist in the current context + // static object P2 { get { return field; } set; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(4, 37), + // (5,19): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static object P3 { get; set { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P3").WithArguments("field keyword").WithLocation(5, 19), + // (6,19): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static object P4 { get { return null; } set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P4").WithArguments("field keyword").WithLocation(6, 19)); + } + else + { + var verifier = CompileAndVerify(comp, verify: Verification.Skipped); + verifier.VerifyIL("I.P1.get", """ + { + // Code size 6 (0x6) + .maxstack 1 + IL_0000: ldsfld "object I.k__BackingField" + IL_0005: ret + } + """); + verifier.VerifyIL("I.P2.set", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: stsfld "object I.k__BackingField" + IL_0006: ret + } + """); + verifier.VerifyIL("I.P5.get", """ + { + // Code size 6 (0x6) + .maxstack 1 + IL_0000: ldsfld "object I.k__BackingField" + IL_0005: ret + } + """); + verifier.VerifyIL("I.P6.set", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: stsfld "object I.k__BackingField" + IL_0006: ret + } + """); + } + + var containingType = comp.GetMember("I"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(6, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsAutoProperty: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsAutoProperty: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P5", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "P6", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.Equal(languageVersion > LanguageVersion.CSharp13, ((SourcePropertySymbol)actualProperties[0]).UsesFieldKeyword); + Assert.Equal(languageVersion > LanguageVersion.CSharp13, ((SourcePropertySymbol)actualProperties[1]).UsesFieldKeyword); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void ImplicitAccessorBody_03( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, bool useInit) + { + string setter = useInit ? "init" : "set "; + string source = $$""" + interface I + { + object Q1 { get; {{setter}} { _ = field; } } + object Q2 { get { return field; } {{setter}}; } + object Q3 { get; {{setter}} { } } + object Q4 { get { return null; } {{setter}}; } + } + """; + + var comp = CreateCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + targetFramework: TargetFramework.Net80); + + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (3,12): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // object Q1 { get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Q1").WithArguments("field keyword").WithLocation(3, 12), + // (3,12): error CS0525: Interfaces cannot contain instance fields + // object Q1 { get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Q1").WithLocation(3, 12), + // (3,33): error CS0103: The name 'field' does not exist in the current context + // object Q1 { get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(3, 33), + // (4,12): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // object Q2 { get { return field; } set ; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Q2").WithArguments("field keyword").WithLocation(4, 12), + // (4,12): error CS0525: Interfaces cannot contain instance fields + // object Q2 { get { return field; } set ; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Q2").WithLocation(4, 12), + // (4,30): error CS0103: The name 'field' does not exist in the current context + // object Q2 { get { return field; } set ; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(4, 30), + // (5,12): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // object Q3 { get; set { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Q3").WithArguments("field keyword").WithLocation(5, 12), + // (5,12): error CS0525: Interfaces cannot contain instance fields + // object Q3 { get; set { } } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Q3").WithLocation(5, 12), + // (6,12): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // object Q4 { get { return null; } set ; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Q4").WithArguments("field keyword").WithLocation(6, 12), + // (6,12): error CS0525: Interfaces cannot contain instance fields + // object Q4 { get { return null; } set ; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Q4").WithLocation(6, 12)); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,12): error CS0525: Interfaces cannot contain instance fields + // object Q1 { get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Q1").WithLocation(3, 12), + // (4,12): error CS0525: Interfaces cannot contain instance fields + // object Q2 { get { return field; } set ; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Q2").WithLocation(4, 12), + // (5,12): error CS0525: Interfaces cannot contain instance fields + // object Q3 { get; set { } } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Q3").WithLocation(5, 12), + // (6,12): error CS0525: Interfaces cannot contain instance fields + // object Q4 { get { return null; } set ; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Q4").WithLocation(6, 12)); + } + + var containingType = comp.GetMember("I"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(4, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "Q1", IsAutoProperty: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "Q2", IsAutoProperty: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "Q3", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "Q4", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.Equal(languageVersion > LanguageVersion.CSharp13, ((SourcePropertySymbol)actualProperties[0]).UsesFieldKeyword); + Assert.Equal(languageVersion > LanguageVersion.CSharp13, ((SourcePropertySymbol)actualProperties[1]).UsesFieldKeyword); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void ImplicitAccessorBody_04( + [CombinatorialValues("class", "struct", "ref struct", "record", "record struct")] string typeKind, + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = $$""" + {{typeKind}} A + { + public static int P1 { get; set { } } + public static int P2 { get { return -2; } set; } + public int P3 { get; set { } } + public int P4 { get { return -4; } set; } + public int P5 { get; init { } } + public int P6 { get { return -6; } init; } + } + class Program + { + static void Main() + { + A.P1 = 1; + A.P2 = 2; + var a = new A() { P3 = 3, P4 = 4, P5 = 5, P6 = 6 }; + System.Console.WriteLine((A.P1, A.P2, a.P3, a.P4, a.P5, a.P6)); + } + } + """; + + var comp = CreateCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe, + targetFramework: TargetFramework.Net80); + + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (3,23): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static int P1 { get; set { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(3, 23), + // (4,23): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static int P2 { get { return -2; } set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P2").WithArguments("field keyword").WithLocation(4, 23), + // (5,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int P3 { get; set { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P3").WithArguments("field keyword").WithLocation(5, 16), + // (6,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int P4 { get { return -4; } set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P4").WithArguments("field keyword").WithLocation(6, 16), + // (7,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int P5 { get; init { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P5").WithArguments("field keyword").WithLocation(7, 16), + // (8,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int P6 { get { return -6; } init; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P6").WithArguments("field keyword").WithLocation(8, 16)); + } + else + { + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(0, -2, 0, -4, 0, -6)")); + } + + if (!typeKind.StartsWith("record")) + { + var actualMembers = comp.GetMember("A").GetMembers().ToTestDisplayStrings(); + string readonlyQualifier = typeKind.EndsWith("struct") ? "readonly " : ""; + var expectedMembers = new[] + { + "System.Int32 A.k__BackingField", + "System.Int32 A.P1 { get; set; }", + "System.Int32 A.P1.get", + "void A.P1.set", + "System.Int32 A.k__BackingField", + "System.Int32 A.P2 { get; set; }", + "System.Int32 A.P2.get", + "void A.P2.set", + "System.Int32 A.k__BackingField", + "System.Int32 A.P3 { get; set; }", + readonlyQualifier + "System.Int32 A.P3.get", + "void A.P3.set", + "System.Int32 A.k__BackingField", + "System.Int32 A.P4 { get; set; }", + "System.Int32 A.P4.get", + "void A.P4.set", + "System.Int32 A.k__BackingField", + "System.Int32 A.P5 { get; init; }", + readonlyQualifier + "System.Int32 A.P5.get", + "void modreq(System.Runtime.CompilerServices.IsExternalInit) A.P5.init", + "System.Int32 A.k__BackingField", + "System.Int32 A.P6 { get; init; }", + "System.Int32 A.P6.get", + "void modreq(System.Runtime.CompilerServices.IsExternalInit) A.P6.init", + "A..ctor()", + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + } + + [Theory] + [CombinatorialData] + public void ImplicitAccessorBody_05( + [CombinatorialValues("class", "struct", "ref struct", "record", "record struct")] string typeKind, + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = $$""" + {{typeKind}} A + { + public static int P1 { get; set { field = value * 2; } } + public static int P2 { get { return field * -1; } set; } + public int P3 { get; set { field = value * 2; } } + public int P4 { get { return field * -1; } set; } + public int P5 { get; init { field = value * 2; } } + public int P6 { get { return field * -1; } init; } + } + class Program + { + static void Main() + { + A.P1 = 1; + A.P2 = 2; + var a = new A() { P3 = 3, P4 = 4, P5 = 5, P6 = 6 }; + System.Console.WriteLine((A.P1, A.P2, a.P3, a.P4, a.P5, a.P6)); + } + } + """; + + var comp = CreateCompilation( + source, + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe, + targetFramework: TargetFramework.Net80); + + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (3,23): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static int P1 { get; set { field = value * 2; } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(3, 23), + // (3,39): error CS0103: The name 'field' does not exist in the current context + // public static int P1 { get; set { field = value * 2; } } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(3, 39), + // (4,23): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static int P2 { get { return field * -1; } set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P2").WithArguments("field keyword").WithLocation(4, 23), + // (4,41): error CS0103: The name 'field' does not exist in the current context + // public static int P2 { get { return field * -1; } set; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(4, 41), + // (5,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int P3 { get; set { field = value * 2; } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P3").WithArguments("field keyword").WithLocation(5, 16), + // (5,32): error CS0103: The name 'field' does not exist in the current context + // public int P3 { get; set { field = value * 2; } } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(5, 32), + // (6,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int P4 { get { return field * -1; } set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P4").WithArguments("field keyword").WithLocation(6, 16), + // (6,34): error CS0103: The name 'field' does not exist in the current context + // public int P4 { get { return field * -1; } set; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(6, 34), + // (7,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int P5 { get; init { field = value * 2; } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P5").WithArguments("field keyword").WithLocation(7, 16), + // (7,33): error CS0103: The name 'field' does not exist in the current context + // public int P5 { get; init { field = value * 2; } } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(7, 33), + // (8,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int P6 { get { return field * -1; } init; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P6").WithArguments("field keyword").WithLocation(8, 16), + // (8,34): error CS0103: The name 'field' does not exist in the current context + // public int P6 { get { return field * -1; } init; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(8, 34)); + } + else + { + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("(2, -2, 6, -4, 10, -6)")); + } + + if (!typeKind.StartsWith("record")) + { + var actualMembers = comp.GetMember("A").GetMembers().ToTestDisplayStrings(); + string readonlyQualifier = typeKind.EndsWith("struct") ? "readonly " : ""; + var expectedMembers = new[] + { + "System.Int32 A.k__BackingField", + "System.Int32 A.P1 { get; set; }", + "System.Int32 A.P1.get", + "void A.P1.set", + "System.Int32 A.k__BackingField", + "System.Int32 A.P2 { get; set; }", + "System.Int32 A.P2.get", + "void A.P2.set", + "System.Int32 A.k__BackingField", + "System.Int32 A.P3 { get; set; }", + readonlyQualifier + "System.Int32 A.P3.get", + "void A.P3.set", + "System.Int32 A.k__BackingField", + "System.Int32 A.P4 { get; set; }", + "System.Int32 A.P4.get", + "void A.P4.set", + "System.Int32 A.k__BackingField", + "System.Int32 A.P5 { get; init; }", + readonlyQualifier + "System.Int32 A.P5.get", + "void modreq(System.Runtime.CompilerServices.IsExternalInit) A.P5.init", + "System.Int32 A.k__BackingField", + "System.Int32 A.P6 { get; init; }", + "System.Int32 A.P6.get", + "void modreq(System.Runtime.CompilerServices.IsExternalInit) A.P6.init", + "A..ctor()", + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + } + + [Fact] + public void Attribute_01() + { + string source = """ + using System; + class A : Attribute + { + public A(object o) { } + } + class B + { + [A(field)] object P1 { get { return null; } set { } } + } + class C + { + const object field = null; + [A(field)] object P2 { get { return null; } set { } } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (8,8): error CS0103: The name 'field' does not exist in the current context + // [A(field)] object P1 { get { return null; } } + Diagnostic(ErrorCode.ERR_NameNotInContext, "field").WithArguments("field").WithLocation(8, 8)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var attributeArguments = tree.GetRoot().DescendantNodes().OfType().Select(arg => arg.Expression).ToArray(); + + var argument = attributeArguments[0]; + Assert.IsType(argument); + Assert.Null(model.GetSymbolInfo(argument).Symbol); + + argument = attributeArguments[1]; + Assert.IsType(argument); + Assert.Equal("System.Object C.field", model.GetSymbolInfo(argument).Symbol.ToTestDisplayString()); + } + + [Fact] + public void Attribute_02() + { + string source = """ + using System; + class A : Attribute + { + public A(object o) { } + } + class B + { + object P1 { [A(field)] get { return null; } set { } } + object P2 { get { return null; } [A(field)] set { } } + } + class C + { + const object field = null; + object P3 { [A(field)] get { return null; } set { } } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (8,20): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // object P1 { [A(field)] get { return null; } set { } } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(8, 20), + // (9,41): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // object P2 { get { return null; } [A(field)] set { } } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(9, 41), + // (14,20): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P3 { [A(field)] get { return null; } set { } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(14, 20), + // (14,20): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // object P3 { [A(field)] get { return null; } set { } } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(14, 20)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var attributeArguments = tree.GetRoot().DescendantNodes().OfType().Select(arg => arg.Expression).ToArray(); + + var argument = attributeArguments[0]; + Assert.IsType(argument); + Assert.Equal("System.Object B.k__BackingField", model.GetSymbolInfo(argument).Symbol.ToTestDisplayString()); + + argument = attributeArguments[1]; + Assert.IsType(argument); + Assert.Equal("System.Object B.k__BackingField", model.GetSymbolInfo(argument).Symbol.ToTestDisplayString()); + + argument = attributeArguments[2]; + Assert.IsType(argument); + Assert.Equal("System.Object C.k__BackingField", model.GetSymbolInfo(argument).Symbol.ToTestDisplayString()); + } + + [Fact] + public void Attribute_03() + { + string source = $$""" + using System; + using System.Reflection; + + [AttributeUsage(AttributeTargets.All, AllowMultiple=true)] + class A : Attribute + { + private readonly object _obj; + public A(object obj) { _obj = obj; } + public override string ToString() => $"A({_obj})"; + } + + class B + { + [A(0)][field: A(1)] public object P1 { get; } + [field: A(2)][field: A(-2)] public static object P2 { get; set; } + [field: A(3)] public object P3 { get; init; } + public object P4 { [field: A(4)] get; } + public static object P5 { get; [field: A(5)] set; } + [A(0)][field: A(1)] public object Q1 => field; + [field: A(2)][field: A(-2)] public static object Q2 { get { return field; } set { } } + [field: A(3)] public object Q3 { get { return field; } init { } } + public object Q4 { [field: A(4)] get => field; } + public static object Q5 { get { return field; } [field: A(5)] set { } } + [field: A(6)] public static object Q6 { set { _ = field; } } + [field: A(7)] public object Q7 { init { _ = field; } } + } + + class Program + { + static void Main() + { + foreach (var property in typeof(B).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportMember(property); + foreach (var field in typeof(B).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportMember(field); + } + + static void ReportMember(MemberInfo member) + { + Console.Write("{0}.{1}:", member.DeclaringType.Name, member.Name); + foreach (var obj in member.GetCustomAttributes()) + Console.Write(" {0},", obj.ToString()); + Console.WriteLine(); + } + } + """; + + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (17,25): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, return'. All attributes in this block will be ignored. + // public object P4 { [field: A(4)] get; } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, return").WithLocation(17, 25), + // (18,37): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, param, return'. All attributes in this block will be ignored. + // public static object P5 { get; [field: A(5)] set; } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, param, return").WithLocation(18, 37), + // (22,25): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, return'. All attributes in this block will be ignored. + // public object Q4 { [field: A(4)] get => field; } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, return").WithLocation(22, 25), + // (23,54): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, param, return'. All attributes in this block will be ignored. + // public static object Q5 { get { return field; } [field: A(5)] set { } } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "method, param, return").WithLocation(23, 54)); + + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(""" + B.P1: A(0), + B.P2: + B.P3: + B.P4: + B.P5: + B.Q1: A(0), + B.Q2: + B.Q3: + B.Q4: + B.Q5: + B.Q6: + B.Q7: + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(1), + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(3), + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(1), + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(3), + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(7), + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(2), A(-2), + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(2), A(-2), + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + B.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(6), + """)); + } + + [Fact] + public void ObsoleteAttribute() + { + string source = $$""" + using System; + using System.Reflection; + class C + { + [Obsolete] public static object P1 { get => field; set { } } + [field: Obsolete] public static object P2 { get => field; set { } } + [Obsolete] public object P3 { get => field; set { } } + [field: Obsolete] public object P4 { get => field; set { } } + } + + class Program + { + static void Main() + { + _ = C.P1; + _ = C.P2; + C.P1 = 1; + C.P2 = 2; + var c = new C(); + _ = c.P3; + _ = c.P4; + c.P3 = 3; + c.P4 = 4; + foreach (var property in typeof(C).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportMember(property); + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportMember(field); + } + + static void ReportMember(MemberInfo member) + { + Console.Write("{0}.{1}:", member.DeclaringType.Name, member.Name); + foreach (var obj in member.GetCustomAttributes()) + Console.Write(" {0},", obj.ToString()); + Console.WriteLine(); + } + } + """; + var verifier = CompileAndVerify(source, verify: Verification.Skipped, expectedOutput: """ + C.P1: System.ObsoleteAttribute, + C.P2: + C.P3: System.ObsoleteAttribute, + C.P4: + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, System.ObsoleteAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, System.ObsoleteAttribute, + """); + verifier.VerifyDiagnostics( + // (15,13): warning CS0612: 'C.P1' is obsolete + // _ = C.P1; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "C.P1").WithArguments("C.P1").WithLocation(15, 13), + // (17,9): warning CS0612: 'C.P1' is obsolete + // C.P1 = 1; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "C.P1").WithArguments("C.P1").WithLocation(17, 9), + // (20,13): warning CS0612: 'C.P3' is obsolete + // _ = c.P3; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "c.P3").WithArguments("C.P3").WithLocation(20, 13), + // (22,9): warning CS0612: 'C.P3' is obsolete + // c.P3 = 3; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "c.P3").WithArguments("C.P3").WithLocation(22, 9)); + } + + [Theory] + [CombinatorialData] + public void Initializer_01A([CombinatorialValues("class", "struct", "ref struct", "interface")] string typeKind) + { + string source = $$""" + using System; + {{typeKind}} C + { + public static int P1 { get; } = 1; + public static int P2 { get => field; } = 2; + public static int P3 { get => field; set; } = 3; + public static int P4 { get => field; set { } } = 4; + public static int P5 { get => 0; set; } = 5; + public static int P6 { get; set; } = 6; + public static int P7 { get; set { } } = 7; + public static int P8 { set { field = value; } } = 8; + public static int P9 { get { return field; } set { field = value; } } = 9; + } + class Program + { + static void Main() + { + Console.WriteLine((C.P1, C.P2, C.P3, C.P4, C.P5, C.P6, C.P7, C.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 6, 7, 9)")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C..cctor", """ + { + // Code size 56 (0x38) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: stsfld "int C.k__BackingField" + IL_0006: ldc.i4.2 + IL_0007: stsfld "int C.k__BackingField" + IL_000c: ldc.i4.3 + IL_000d: stsfld "int C.k__BackingField" + IL_0012: ldc.i4.4 + IL_0013: stsfld "int C.k__BackingField" + IL_0018: ldc.i4.5 + IL_0019: stsfld "int C.k__BackingField" + IL_001e: ldc.i4.6 + IL_001f: stsfld "int C.k__BackingField" + IL_0024: ldc.i4.7 + IL_0025: stsfld "int C.k__BackingField" + IL_002a: ldc.i4.8 + IL_002b: stsfld "int C.k__BackingField" + IL_0030: ldc.i4.s 9 + IL_0032: stsfld "int C.k__BackingField" + IL_0037: ret + } + """); + + var comp = (CSharpCompilation)verifier.Compilation; + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(9, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P5", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "P6", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[6] is SourcePropertySymbol { Name: "P7", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[7] is SourcePropertySymbol { Name: "P8", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[8] is SourcePropertySymbol { Name: "P9", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Fact] + public void Initializer_01B() + { + string source = """ + using System; + interface C + { + public static int P1 { get; } = 1; + public static int P2 { get => field; } = 2; + public static int P3 { get => field; set; } = 3; + public static int P4 { get => field; set { } } = 4; + public static int P5 { get => 0; set; } = 5; + public static int P6 { get; set; } = 6; + public static int P7 { get; set { } } = 7; + public static int P8 { set { field = value; } } = 8; + public static int P9 { get { return field; } set { field = value; } } = 9; + } + class Program + { + static void Main() + { + Console.WriteLine((C.P1, C.P2, C.P3, C.P4, C.P5, C.P6, C.P7, C.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("(1, 2, 3, 4, 0, 6, 7, 9)")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C..cctor", """ + { + // Code size 56 (0x38) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: stsfld "int C.k__BackingField" + IL_0006: ldc.i4.2 + IL_0007: stsfld "int C.k__BackingField" + IL_000c: ldc.i4.3 + IL_000d: stsfld "int C.k__BackingField" + IL_0012: ldc.i4.4 + IL_0013: stsfld "int C.k__BackingField" + IL_0018: ldc.i4.5 + IL_0019: stsfld "int C.k__BackingField" + IL_001e: ldc.i4.6 + IL_001f: stsfld "int C.k__BackingField" + IL_0024: ldc.i4.7 + IL_0025: stsfld "int C.k__BackingField" + IL_002a: ldc.i4.8 + IL_002b: stsfld "int C.k__BackingField" + IL_0030: ldc.i4.s 9 + IL_0032: stsfld "int C.k__BackingField" + IL_0037: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void Initializer_02A(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + using System; + class C + { + public int P1 { get; } = 1; + public int P2 { get => field; } = 2; + public int P3 { get => field; {{setter}}; } = 3; + public int P4 { get => field; {{setter}} { } } = 4; + public int P5 { get => 0; {{setter}}; } = 5; + public int P6 { get; {{setter}}; } = 6; + public int P7 { get; {{setter}} { } } = 7; + public int P8 { {{setter}} { field = value; } } = 8; + public int P9 { get { return field; } {{setter}} { field = value; } } = 9; + } + class Program + { + static void Main() + { + var c = new C(); + Console.WriteLine((c.P1, c.P2, c.P3, c.P4, c.P5, c.P6, c.P7, c.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, "(1, 2, 3, 4, 0, 6, 7, 9)")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C..ctor", """ + { + // Code size 71 (0x47) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: stfld "int C.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldc.i4.2 + IL_0009: stfld "int C.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldc.i4.3 + IL_0010: stfld "int C.k__BackingField" + IL_0015: ldarg.0 + IL_0016: ldc.i4.4 + IL_0017: stfld "int C.k__BackingField" + IL_001c: ldarg.0 + IL_001d: ldc.i4.5 + IL_001e: stfld "int C.k__BackingField" + IL_0023: ldarg.0 + IL_0024: ldc.i4.6 + IL_0025: stfld "int C.k__BackingField" + IL_002a: ldarg.0 + IL_002b: ldc.i4.7 + IL_002c: stfld "int C.k__BackingField" + IL_0031: ldarg.0 + IL_0032: ldc.i4.8 + IL_0033: stfld "int C.k__BackingField" + IL_0038: ldarg.0 + IL_0039: ldc.i4.s 9 + IL_003b: stfld "int C.k__BackingField" + IL_0040: ldarg.0 + IL_0041: call "object..ctor()" + IL_0046: ret + } + """); + + var comp = (CSharpCompilation)verifier.Compilation; + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(9, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P5", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "P6", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[6] is SourcePropertySymbol { Name: "P7", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[7] is SourcePropertySymbol { Name: "P8", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[8] is SourcePropertySymbol { Name: "P9", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void Initializer_02B(bool useRefStruct, bool useInit) + { + string setter = useInit ? "init" : "set"; + string typeKind = useRefStruct ? "ref struct" : "struct"; + string source = $$""" + using System; + {{typeKind}} C + { + public int P1 { get; } = 1; + public int P2 { get => field; } = 2; + public int P3 { get => field; {{setter}}; } = 3; + public int P4 { get => field; {{setter}} { } } = 4; + public int P5 { get => 0; {{setter}}; } = 5; + public int P6 { get; {{setter}}; } = 6; + public int P7 { get; {{setter}} { } } = 7; + public int P8 { {{setter}} { field = value; } } = 8; + public int P9 { get { return field; } {{setter}} { field = value; } } = 9; + public C() { } + } + class Program + { + static void Main() + { + var c = new C(); + Console.WriteLine((c.P1, c.P2, c.P3, c.P4, c.P5, c.P6, c.P7, c.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, "(1, 2, 3, 4, 0, 6, 7, 9)")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C..ctor", """ + { + // Code size 65 (0x41) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: stfld "int C.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldc.i4.2 + IL_0009: stfld "int C.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldc.i4.3 + IL_0010: stfld "int C.k__BackingField" + IL_0015: ldarg.0 + IL_0016: ldc.i4.4 + IL_0017: stfld "int C.k__BackingField" + IL_001c: ldarg.0 + IL_001d: ldc.i4.5 + IL_001e: stfld "int C.k__BackingField" + IL_0023: ldarg.0 + IL_0024: ldc.i4.6 + IL_0025: stfld "int C.k__BackingField" + IL_002a: ldarg.0 + IL_002b: ldc.i4.7 + IL_002c: stfld "int C.k__BackingField" + IL_0031: ldarg.0 + IL_0032: ldc.i4.8 + IL_0033: stfld "int C.k__BackingField" + IL_0038: ldarg.0 + IL_0039: ldc.i4.s 9 + IL_003b: stfld "int C.k__BackingField" + IL_0040: ret + } + """); + + var comp = (CSharpCompilation)verifier.Compilation; + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + "System.Int32 C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(9, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P5", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "P6", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[6] is SourcePropertySymbol { Name: "P7", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[7] is SourcePropertySymbol { Name: "P8", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[8] is SourcePropertySymbol { Name: "P9", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void Initializer_02C(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + using System; + interface I + { + public int P1 { get; } = 1; + public int P2 { get => field; } = 2; + public int P3 { get => field; {{setter}}; } = 3; + public int P4 { get => field; {{setter}} { } } = 4; + public int P5 { get => 0; {{setter}}; } = 5; + public int P6 { get; {{setter}}; } = 6; + public int P7 { get; {{setter}} { } } = 7; + public int P8 { {{setter}} { field = value; } } = 8; + public int P9 { get { return field; } {{setter}} { field = value; } } = 9; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (4,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P1 { get; } = 1; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithLocation(4, 16), + // (5,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P2 { get => field; } = 2; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P2").WithLocation(5, 16), + // (6,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P3 { get => field; set; } = 3; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P3").WithLocation(6, 16), + // (7,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P4 { get => field; set { } } = 4; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P4").WithLocation(7, 16), + // (8,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P5 { get => 0; set; } = 5; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P5").WithLocation(8, 16), + // (9,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P6 { get; set; } = 6; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P6").WithLocation(9, 16), + // (10,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P7 { get; set { } } = 7; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P7").WithLocation(10, 16), + // (11,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P8 { set { field = value; } } = 8; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P8").WithLocation(11, 16), + // (12,16): error CS8053: Instance properties in interfaces cannot have initializers. + // public int P9 { get { return field; } set { field = value; } } = 9; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P9").WithLocation(12, 16)); + + var containingType = comp.GetMember("I"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(9, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P5", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "P6", IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[6] is SourcePropertySymbol { Name: "P7", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[7] is SourcePropertySymbol { Name: "P8", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[8] is SourcePropertySymbol { Name: "P9", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void Initializer_02D(bool useRefStruct, bool useInit) + { + string setter = useInit ? "init" : "set"; + string typeKind = useRefStruct ? "ref struct" : " struct"; + string source = $$""" + {{typeKind}} S1 + { + public int P1 { get; } = 1; + } + {{typeKind}} S2 + { + public int P2 { get => field; } = 2; + } + {{typeKind}} S3 + { + public int P3 { get => field; {{setter}}; } = 3; + } + {{typeKind}} S6 + { + public int P6 { get; {{setter}}; } = 6; + } + """; + var comp = CreateCompilation(source, targetFramework: GetTargetFramework(useInit)); + comp.VerifyEmitDiagnostics( + // (1,12): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. + // struct S1 + Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S1").WithLocation(1, 12), + // (5,12): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. + // struct S2 + Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S2").WithLocation(5, 12), + // (9,12): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. + // struct S3 + Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S3").WithLocation(9, 12), + // (13,12): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. + // struct S6 + Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S6").WithLocation(13, 12)); + } + + [Theory] + [CombinatorialData] + public void Interfaces_01(bool includeAccessibility) + { + string accessibility = includeAccessibility ? "public" : " "; + string source = $$""" + using System; + interface I + { + {{accessibility}} static int P1 { get; } + {{accessibility}} static int P2 { get => field; } + {{accessibility}} static int P3 { get => field; set; } + {{accessibility}} static int P4 { get => field; set { } } + {{accessibility}} static int P5 { get => 0; set; } + {{accessibility}} static int P6 { get; set; } + {{accessibility}} static int P7 { get; set { } } + {{accessibility}} static int P8 { set { field = value; } } + {{accessibility}} static int P9 { get { return field; } set { field = value; } } + } + class Program + { + static void Main() + { + I.P3 = 3; + I.P4 = 4; + I.P5 = 5; + I.P6 = 6; + I.P7 = 7; + I.P9 = 9; + Console.WriteLine((I.P1, I.P2, I.P3, I.P4, I.P5, I.P6, I.P7, I.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("(0, 0, 3, 0, 0, 6, 0, 9)")); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var containingType = comp.GetMember("I"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(9, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P5", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "P6", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[6] is SourcePropertySymbol { Name: "P7", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[7] is SourcePropertySymbol { Name: "P8", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[8] is SourcePropertySymbol { Name: "P9", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void Interfaces_02(bool includeAccessibility, bool useInit) + { + string accessibility = includeAccessibility ? "public" : " "; + string setter = useInit ? "init" : "set"; + string source = $$""" + interface I + { + {{accessibility}} int P1 { get; } + {{accessibility}} int P2 { get => field; } + {{accessibility}} int P3 { get => field; {{setter}}; } + {{accessibility}} int P4 { get => field; {{setter}} { } } + {{accessibility}} int P5 { get => 0; {{setter}}; } + {{accessibility}} int P6 { get; {{setter}}; } + {{accessibility}} int P7 { get; {{setter}} { } } + {{accessibility}} int P8 { {{setter}} { field = value; } } + {{accessibility}} int P9 { get { return field; } {{setter}} { field = value; } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (4,16): error CS0525: Interfaces cannot contain instance fields + // int P2 { get => field; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P2").WithLocation(4, 16), + // (5,16): error CS0525: Interfaces cannot contain instance fields + // int P3 { get => field; set; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P3").WithLocation(5, 16), + // (6,16): error CS0525: Interfaces cannot contain instance fields + // int P4 { get => field; set { } } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P4").WithLocation(6, 16), + // (7,16): error CS0525: Interfaces cannot contain instance fields + // int P5 { get => 0; set; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P5").WithLocation(7, 16), + // (9,16): error CS0525: Interfaces cannot contain instance fields + // int P7 { get; set { } } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P7").WithLocation(9, 16), + // (10,16): error CS0525: Interfaces cannot contain instance fields + // int P8 { set { field = value; } } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P8").WithLocation(10, 16), + // (11,16): error CS0525: Interfaces cannot contain instance fields + // int P9 { get { return field; } set { field = value; } } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P9").WithLocation(11, 16)); + + var containingType = comp.GetMember("I"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + "System.Int32 I.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(9, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P5", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "P6", IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + Assert.True(actualProperties[6] is SourcePropertySymbol { Name: "P7", IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[7] is SourcePropertySymbol { Name: "P8", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[8] is SourcePropertySymbol { Name: "P9", IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Fact] + public void Initializer_03() + { + string source = """ + class C + { + public static int PA { get => 0; } = 10; + public static int PB { get => 0; set { } } = 11; + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (3,23): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // public static int PA { get => 0; } = 10; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(3, 23), + // (4,23): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // public static int PB { get => 0; set { } } = 11; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(4, 23)); + } + + [Theory] + [CombinatorialData] + public void Initializer_04(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + class C + { + public int PA { get => 0; } = 10; + public int PB { get => 0; {{setter}} { } } = 11; + } + """; + var comp = CreateCompilation(source, targetFramework: GetTargetFramework(useInit)); + comp.VerifyEmitDiagnostics( + // (3,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // public int PA { get => 0; } = 10; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PA").WithLocation(3, 16), + // (4,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // public int PB { get => 0; set { } } = 11; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "PB").WithLocation(4, 16)); + } + + [Theory] + [CombinatorialData] + public void ConstructorAssignment_01([CombinatorialValues("class", "struct", "ref struct", "interface")] string typeKind) + { + string source = $$""" + using System; + {{typeKind}} C + { + public static int P1 { get; } + public static int P2 { get => field; } + public static int P3 { get => field; set; } + public static int P4 { get => field; set { } } + public static int P5 { get => 0; set; } + public static int P6 { get; set; } + public static int P7 { get; set { } } + public static int P8 { set { field = value; } } + public static int P9 { get { return field; } set { field = value; } } + static C() + { + P1 = 1; + P2 = 2; + P3 = 3; + P4 = 4; + P5 = 5; + P6 = 6; + P7 = 7; + P8 = 8; + P9 = 9; + } + } + class Program + { + static void Main() + { + Console.WriteLine((C.P1, C.P2, C.P3, C.P4, C.P5, C.P6, C.P7, C.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("(1, 2, 3, 0, 0, 6, 0, 9)")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C..cctor", """ + { + // Code size 56 (0x38) + .maxstack 1 + IL_0000: ldc.i4.1 + IL_0001: stsfld "int C.k__BackingField" + IL_0006: ldc.i4.2 + IL_0007: stsfld "int C.k__BackingField" + IL_000c: ldc.i4.3 + IL_000d: call "void C.P3.set" + IL_0012: ldc.i4.4 + IL_0013: call "void C.P4.set" + IL_0018: ldc.i4.5 + IL_0019: call "void C.P5.set" + IL_001e: ldc.i4.6 + IL_001f: call "void C.P6.set" + IL_0024: ldc.i4.7 + IL_0025: call "void C.P7.set" + IL_002a: ldc.i4.8 + IL_002b: call "void C.P8.set" + IL_0030: ldc.i4.s 9 + IL_0032: call "void C.P9.set" + IL_0037: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void ConstructorAssignment_02A([CombinatorialValues("class", "struct", "ref struct")] string typeKind, bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + #pragma warning disable 649 + using System; + {{typeKind}} C1 + { + public int F1; + public int P1 { get; } + public C1(int i) { P1 = i; } + public C1(int x, out int y) { y = P1; F1 = x; } + } + {{typeKind}} C2 + { + public int F2; + public int P2 { get => field; } + public C2(int i) { P2 = i; } + public C2(int x, out int y) { y = P2; F2 = x; } + } + {{typeKind}} C3 + { + public int F3; + public int P3 { get => field; {{setter}}; } + public C3(int i) { P3 = i; } + public C3(int x, out int y) { y = P3; F3 = x; } + } + {{typeKind}} C4 + { + public int F4; + public int P4 { get => field; {{setter}} { } } + public C4(int i) { P4 = i; } + public C4(int x, out int y) { y = P4; F4 = x; } + } + {{typeKind}} C5 + { + public int F5; + public int P5 { get => default; {{setter}}; } + public C5(int i) { P5 = i; } + public C5(int x, out int y) { y = P5; F5 = x; } + } + {{typeKind}} C6 + { + public int F6; + public int P6 { get; {{setter}}; } + public C6(int i) { P6 = i; } + public C6(int x, out int y) { y = P6; F6 = x; } + } + {{typeKind}} C7 + { + public int F7; + public int P7 { get; {{setter}} { } } + public C7(int i) { P7 = i; } + public C7(int x, out int y) { y = P7; F7 = x; } + } + {{typeKind}} C8 + { + public int F8; + public int P8 { {{setter}} { field = value; } } + public C8(int i) { P8 = i; } + } + {{typeKind}} C9 + { + public int F9; + public int P9 { get { return field; } {{setter}} { field = value; } } + public C9(int i) { P9 = i; } + public C9(int x, out int y) { y = P9; F9 = x; } + } + class Program + { + static void Main() + { + var c1 = new C1(1); + var c2 = new C2(2); + var c3 = new C3(3); + var c4 = new C4(4); + var c5 = new C5(5); + var c6 = new C6(6); + var c7 = new C7(7); + var c8 = new C8(8); + var c9 = new C9(9); + Console.WriteLine((c1.P1, c2.P2, c3.P3, c4.P4, c5.P5, c6.P6, c7.P7, c9.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, "(1, 2, 3, 0, 0, 6, 0, 9)")); + verifier.VerifyDiagnostics(); + if (typeKind == "class") + { + verifier.VerifyIL("C1..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld "int C1.k__BackingField" + IL_000d: ret + } + """); + verifier.VerifyIL("C2..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld "int C2.k__BackingField" + IL_000d: ret + } + """); + verifier.VerifyIL("C3..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: call "void C3.P3.{{setter}}" + IL_000d: ret + } + """); + verifier.VerifyIL("C4..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: call "void C4.P4.{{setter}}" + IL_000d: ret + } + """); + verifier.VerifyIL("C5..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: call "void C5.P5.{{setter}}" + IL_000d: ret + } + """); + verifier.VerifyIL("C6..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: call "void C6.P6.{{setter}}" + IL_000d: ret + } + """); + verifier.VerifyIL("C7..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: call "void C7.P7.{{setter}}" + IL_000d: ret + } + """); + verifier.VerifyIL("C8..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: call "void C8.P8.{{setter}}" + IL_000d: ret + } + """); + verifier.VerifyIL("C9..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: call "void C9.P9.{{setter}}" + IL_000d: ret + } + """); + } + else + { + verifier.VerifyIL("C1..ctor(int)", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C1.F1" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: stfld "int C1.k__BackingField" + IL_000e: ret + } + """); + verifier.VerifyIL("C2..ctor(int)", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C2.F2" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: stfld "int C2.k__BackingField" + IL_000e: ret + } + """); + verifier.VerifyIL("C3..ctor(int)", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C3.F3" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: call "void C3.P3.{{setter}}" + IL_000e: ret + } + """); + verifier.VerifyIL("C4..ctor(int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C4.F4" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C4.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: call "void C4.P4.{{setter}}" + IL_0015: ret + } + """); + verifier.VerifyIL("C5..ctor(int)", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C5.F5" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: call "void C5.P5.{{setter}}" + IL_000e: ret + } + """); + verifier.VerifyIL("C6..ctor(int)", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C6.F6" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: call "void C6.P6.{{setter}}" + IL_000e: ret + } + """); + verifier.VerifyIL("C7..ctor(int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C7.F7" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C7.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: call "void C7.P7.{{setter}}" + IL_0015: ret + } + """); + verifier.VerifyIL("C8..ctor(int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C8.F8" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C8.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: call "void C8.P8.{{setter}}" + IL_0015: ret + } + """); + verifier.VerifyIL("C9..ctor(int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C9.F9" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C9.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: call "void C9.P9.{{setter}}" + IL_0015: ret + } + """); + } + if (typeKind == "class") + { + verifier.VerifyIL("C1..ctor(int, out int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.2 + IL_0007: ldarg.0 + IL_0008: call "int C1.P1.get" + IL_000d: stind.i4 + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int C1.F1" + IL_0015: ret + } + """); + verifier.VerifyIL("C2..ctor(int, out int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.2 + IL_0007: ldarg.0 + IL_0008: call "int C2.P2.get" + IL_000d: stind.i4 + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int C2.F2" + IL_0015: ret + } + """); + verifier.VerifyIL("C3..ctor(int, out int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.2 + IL_0007: ldarg.0 + IL_0008: call "int C3.P3.get" + IL_000d: stind.i4 + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int C3.F3" + IL_0015: ret + } + """); + verifier.VerifyIL("C4..ctor(int, out int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.2 + IL_0007: ldarg.0 + IL_0008: call "int C4.P4.get" + IL_000d: stind.i4 + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int C4.F4" + IL_0015: ret + } + """); + verifier.VerifyIL("C5..ctor(int, out int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.2 + IL_0007: ldarg.0 + IL_0008: call "int C5.P5.get" + IL_000d: stind.i4 + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int C5.F5" + IL_0015: ret + } + """); + verifier.VerifyIL("C6..ctor(int, out int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.2 + IL_0007: ldarg.0 + IL_0008: call "int C6.P6.get" + IL_000d: stind.i4 + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int C6.F6" + IL_0015: ret + } + """); + verifier.VerifyIL("C7..ctor(int, out int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.2 + IL_0007: ldarg.0 + IL_0008: call "int C7.P7.get" + IL_000d: stind.i4 + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int C7.F7" + IL_0015: ret + } + """); + verifier.VerifyIL("C9..ctor(int, out int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.2 + IL_0007: ldarg.0 + IL_0008: call "int C9.P9.get" + IL_000d: stind.i4 + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int C9.F9" + IL_0015: ret + } + """); + } + else + { + verifier.VerifyIL("C1..ctor(int, out int)", $$""" + { + // Code size 23 (0x17) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C1.k__BackingField" + IL_0007: ldarg.2 + IL_0008: ldarg.0 + IL_0009: call "readonly int C1.P1.get" + IL_000e: stind.i4 + IL_000f: ldarg.0 + IL_0010: ldarg.1 + IL_0011: stfld "int C1.F1" + IL_0016: ret + } + """); + verifier.VerifyIL("C2..ctor(int, out int)", $$""" + { + // Code size 30 (0x1e) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C2.F2" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C2.k__BackingField" + IL_000e: ldarg.2 + IL_000f: ldarg.0 + IL_0010: call "int C2.P2.get" + IL_0015: stind.i4 + IL_0016: ldarg.0 + IL_0017: ldarg.1 + IL_0018: stfld "int C2.F2" + IL_001d: ret + } + """); + verifier.VerifyIL("C3..ctor(int, out int)", $$""" + { + // Code size 30 (0x1e) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C3.F3" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C3.k__BackingField" + IL_000e: ldarg.2 + IL_000f: ldarg.0 + IL_0010: call "int C3.P3.get" + IL_0015: stind.i4 + IL_0016: ldarg.0 + IL_0017: ldarg.1 + IL_0018: stfld "int C3.F3" + IL_001d: ret + } + """); + verifier.VerifyIL("C4..ctor(int, out int)", $$""" + { + // Code size 30 (0x1e) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C4.F4" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C4.k__BackingField" + IL_000e: ldarg.2 + IL_000f: ldarg.0 + IL_0010: call "int C4.P4.get" + IL_0015: stind.i4 + IL_0016: ldarg.0 + IL_0017: ldarg.1 + IL_0018: stfld "int C4.F4" + IL_001d: ret + } + """); + verifier.VerifyIL("C5..ctor(int, out int)", $$""" + { + // Code size 30 (0x1e) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C5.F5" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C5.k__BackingField" + IL_000e: ldarg.2 + IL_000f: ldarg.0 + IL_0010: call "int C5.P5.get" + IL_0015: stind.i4 + IL_0016: ldarg.0 + IL_0017: ldarg.1 + IL_0018: stfld "int C5.F5" + IL_001d: ret + } + """); + verifier.VerifyIL("C6..ctor(int, out int)", $$""" + { + // Code size 23 (0x17) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C6.k__BackingField" + IL_0007: ldarg.2 + IL_0008: ldarg.0 + IL_0009: call "readonly int C6.P6.get" + IL_000e: stind.i4 + IL_000f: ldarg.0 + IL_0010: ldarg.1 + IL_0011: stfld "int C6.F6" + IL_0016: ret + } + """); + verifier.VerifyIL("C7..ctor(int, out int)", $$""" + { + // Code size 23 (0x17) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C7.k__BackingField" + IL_0007: ldarg.2 + IL_0008: ldarg.0 + IL_0009: call "readonly int C7.P7.get" + IL_000e: stind.i4 + IL_000f: ldarg.0 + IL_0010: ldarg.1 + IL_0011: stfld "int C7.F7" + IL_0016: ret + } + """); + verifier.VerifyIL("C9..ctor(int, out int)", $$""" + { + // Code size 30 (0x1e) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C9.F9" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C9.k__BackingField" + IL_000e: ldarg.2 + IL_000f: ldarg.0 + IL_0010: call "int C9.P9.get" + IL_0015: stind.i4 + IL_0016: ldarg.0 + IL_0017: ldarg.1 + IL_0018: stfld "int C9.F9" + IL_001d: ret + } + """); + } + } + + [Theory] + [CombinatorialData] + public void ConstructorAssignment_02B(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + #pragma warning disable 649 + using System; + class C3 + { + public int F3; + public virtual int P3 { get => field; {{setter}}; } + public C3(int i) { P3 = i; } + public C3(int x, out int y) { y = P3; F3 = x; } + } + class C6 + { + public int F6; + public virtual int P6 { get; {{setter}}; } + public C6(int i) { P6 = i; } + public C6(int x, out int y) { y = P6; F6 = x; } + } + class C9 + { + public int F9; + public virtual int P9 { get { return field; } {{setter}} { field = value; } } + public C9(int i) { P9 = i; } + public C9(int x, out int y) { y = P9; F9 = x; } + } + class Program + { + static void Main() + { + var c3 = new C3(3); + var c6 = new C6(6); + var c9 = new C9(9); + Console.WriteLine((c3.P3, c6.P6, c9.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, "(3, 6, 9)")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C3..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: callvirt "void C3.P3.{{setter}}" + IL_000d: ret + } + """); + verifier.VerifyIL("C6..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: callvirt "void C6.P6.{{setter}}" + IL_000d: ret + } + """); + verifier.VerifyIL("C9..ctor(int)", $$""" + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: callvirt "void C9.P9.{{setter}}" + IL_000d: ret + } + """); + verifier.VerifyIL("C3..ctor(int, out int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.2 + IL_0007: ldarg.0 + IL_0008: callvirt "int C3.P3.get" + IL_000d: stind.i4 + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int C3.F3" + IL_0015: ret + } + """); + verifier.VerifyIL("C6..ctor(int, out int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.2 + IL_0007: ldarg.0 + IL_0008: callvirt "int C6.P6.get" + IL_000d: stind.i4 + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int C6.F6" + IL_0015: ret + } + """); + verifier.VerifyIL("C9..ctor(int, out int)", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call "object..ctor()" + IL_0006: ldarg.2 + IL_0007: ldarg.0 + IL_0008: callvirt "int C9.P9.get" + IL_000d: stind.i4 + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: stfld "int C9.F9" + IL_0015: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void ConstructorAssignment_02C(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + #pragma warning disable 649 + using System; + struct C1 + { + public int F1; + public int P1 { get; } + public C1(int i) { P1 += i; F1 = i; } + } + struct C2 + { + public int F2; + public int P2 { get => field; } + public C2(int i) { P2 += i; F2 = i; } + } + struct C3 + { + public int F3; + public int P3 { get => field; {{setter}}; } + public C3(int i) { P3 += i; F3 = i; } + } + struct C6 + { + public int F6; + public int P6 { get; {{setter}}; } + public C6(int i) { P6 += i; F6 = i; } + } + struct C7 + { + public int F7; + public int P7 { get; {{setter}} { field = value; } } + public C7(int i) { P7 += i; F7 = i; } + } + struct C9 + { + public int F9; + public int P9 { get { return field; } {{setter}} { field = value; } } + public C9(int i) { P9 += i; F9 = i; } + } + struct Program + { + static void Main() + { + var c1 = new C1(1); + var c2 = new C2(2); + var c3 = new C3(3); + var c6 = new C6(6); + var c7 = new C7(7); + var c9 = new C9(9); + Console.WriteLine((c1.F1, c1.P1, c2.F2, c2.P2, c3.F3, c3.P3, c6.F6, c6.P6, c7.F7, c7.P7, c9.F9, c9.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, "(1, 1, 2, 2, 3, 3, 6, 6, 7, 7, 9, 9)")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C1..ctor(int)", $$""" + { + // Code size 29 (0x1d) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C1.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldarg.0 + IL_0009: call "readonly int C1.P1.get" + IL_000e: ldarg.1 + IL_000f: add + IL_0010: stfld "int C1.k__BackingField" + IL_0015: ldarg.0 + IL_0016: ldarg.1 + IL_0017: stfld "int C1.F1" + IL_001c: ret + } + """); + verifier.VerifyIL("C2..ctor(int)", $$""" + { + // Code size 29 (0x1d) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C2.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldarg.0 + IL_0009: call "int C2.P2.get" + IL_000e: ldarg.1 + IL_000f: add + IL_0010: stfld "int C2.k__BackingField" + IL_0015: ldarg.0 + IL_0016: ldarg.1 + IL_0017: stfld "int C2.F2" + IL_001c: ret + } + """); + verifier.VerifyIL("C3..ctor(int)", $$""" + { + // Code size 29 (0x1d) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C3.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldarg.0 + IL_0009: call "int C3.P3.get" + IL_000e: ldarg.1 + IL_000f: add + IL_0010: call "void C3.P3.{{setter}}" + IL_0015: ldarg.0 + IL_0016: ldarg.1 + IL_0017: stfld "int C3.F3" + IL_001c: ret + } + """); + verifier.VerifyIL("C6..ctor(int)", $$""" + { + // Code size 29 (0x1d) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C6.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldarg.0 + IL_0009: call "readonly int C6.P6.get" + IL_000e: ldarg.1 + IL_000f: add + IL_0010: call "void C6.P6.{{setter}}" + IL_0015: ldarg.0 + IL_0016: ldarg.1 + IL_0017: stfld "int C6.F6" + IL_001c: ret + } + """); + verifier.VerifyIL("C7..ctor(int)", $$""" + { + // Code size 36 (0x24) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C7.F7" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C7.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldarg.0 + IL_0010: call "readonly int C7.P7.get" + IL_0015: ldarg.1 + IL_0016: add + IL_0017: call "void C7.P7.{{setter}}" + IL_001c: ldarg.0 + IL_001d: ldarg.1 + IL_001e: stfld "int C7.F7" + IL_0023: ret + } + """); + verifier.VerifyIL("C9..ctor(int)", $$""" + { + // Code size 36 (0x24) + .maxstack 3 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C9.F9" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C9.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldarg.0 + IL_0010: call "int C9.P9.get" + IL_0015: ldarg.1 + IL_0016: add + IL_0017: call "void C9.P9.{{setter}}" + IL_001c: ldarg.0 + IL_001d: ldarg.1 + IL_001e: stfld "int C9.F9" + IL_0023: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void ConstructorAssignment_02D(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + #pragma warning disable 649 + using System; + struct C1 + { + public int F1; + public int P1 { get; } + public C1(int i) { P1++; F1 = i; } + } + struct C2 + { + public int F2; + public int P2 { get => field; } + public C2(int i) { P2++; F2 = i; } + } + struct C3 + { + public int F3; + public int P3 { get => field; {{setter}}; } + public C3(int i) { P3++; F3 = i; } + } + struct C6 + { + public int F6; + public int P6 { get; {{setter}}; } + public C6(int i) { P6++; F6 = i; } + } + struct C7 + { + public int F7; + public int P7 { get; {{setter}} { field = value; } } + public C7(int i) { P7++; F7 = i; } + } + struct C9 + { + public int F9; + public int P9 { get { return field; } {{setter}} { field = value; } } + public C9(int i) { P9++; F9 = i; } + } + struct Program + { + static void Main() + { + var c1 = new C1(1); + var c2 = new C2(2); + var c3 = new C3(3); + var c6 = new C6(6); + var c7 = new C7(7); + var c9 = new C9(9); + Console.WriteLine((c1.F1, c1.P1, c2.F2, c2.P2, c3.F3, c3.P3, c6.F6, c6.P6, c7.F7, c7.P7, c9.F9, c9.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, "(1, 1, 2, 1, 3, 1, 6, 1, 7, 1, 9, 1)")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C1..ctor(int)", $$""" + { + // Code size 31 (0x1f) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C1.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "readonly int C1.P1.get" + IL_000d: stloc.0 + IL_000e: ldarg.0 + IL_000f: ldloc.0 + IL_0010: ldc.i4.1 + IL_0011: add + IL_0012: stfld "int C1.k__BackingField" + IL_0017: ldarg.0 + IL_0018: ldarg.1 + IL_0019: stfld "int C1.F1" + IL_001e: ret + } + """); + verifier.VerifyIL("C2..ctor(int)", $$""" + { + // Code size 31 (0x1f) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C2.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "int C2.P2.get" + IL_000d: stloc.0 + IL_000e: ldarg.0 + IL_000f: ldloc.0 + IL_0010: ldc.i4.1 + IL_0011: add + IL_0012: stfld "int C2.k__BackingField" + IL_0017: ldarg.0 + IL_0018: ldarg.1 + IL_0019: stfld "int C2.F2" + IL_001e: ret + } + """); + verifier.VerifyIL("C3..ctor(int)", $$""" + { + // Code size 31 (0x1f) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C3.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "int C3.P3.get" + IL_000d: stloc.0 + IL_000e: ldarg.0 + IL_000f: ldloc.0 + IL_0010: ldc.i4.1 + IL_0011: add + IL_0012: call "void C3.P3.{{setter}}" + IL_0017: ldarg.0 + IL_0018: ldarg.1 + IL_0019: stfld "int C3.F3" + IL_001e: ret + } + """); + verifier.VerifyIL("C6..ctor(int)", $$""" + { + // Code size 31 (0x1f) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C6.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "readonly int C6.P6.get" + IL_000d: stloc.0 + IL_000e: ldarg.0 + IL_000f: ldloc.0 + IL_0010: ldc.i4.1 + IL_0011: add + IL_0012: call "void C6.P6.{{setter}}" + IL_0017: ldarg.0 + IL_0018: ldarg.1 + IL_0019: stfld "int C6.F6" + IL_001e: ret + } + """); + verifier.VerifyIL("C7..ctor(int)", $$""" + { + // Code size 38 (0x26) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C7.F7" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C7.k__BackingField" + IL_000e: ldarg.0 + IL_000f: call "readonly int C7.P7.get" + IL_0014: stloc.0 + IL_0015: ldarg.0 + IL_0016: ldloc.0 + IL_0017: ldc.i4.1 + IL_0018: add + IL_0019: call "void C7.P7.{{setter}}" + IL_001e: ldarg.0 + IL_001f: ldarg.1 + IL_0020: stfld "int C7.F7" + IL_0025: ret + } + """); + verifier.VerifyIL("C9..ctor(int)", $$""" + { + // Code size 38 (0x26) + .maxstack 3 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C9.F9" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int C9.k__BackingField" + IL_000e: ldarg.0 + IL_000f: call "int C9.P9.get" + IL_0014: stloc.0 + IL_0015: ldarg.0 + IL_0016: ldloc.0 + IL_0017: ldc.i4.1 + IL_0018: add + IL_0019: call "void C9.P9.{{setter}}" + IL_001e: ldarg.0 + IL_001f: ldarg.1 + IL_0020: stfld "int C9.F9" + IL_0025: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void ConstructorAssignment_02E(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + #pragma warning disable 649 + using System; + struct C1 + { + public int F1; + public object P1 { get; } + public C1(int value) { P1 ??= value; F1 = value; } + } + struct C2 + { + public int F2; + public object P2 { get => field; } + public C2(int value) { P2 ??= value; F2 = value; } + } + struct C3 + { + public int F3; + public object P3 { get => field; {{setter}}; } + public C3(int value) { P3 ??= value; F3 = value; } + } + struct C6 + { + public int F6; + public object P6 { get; {{setter}}; } + public C6(int value) { P6 ??= value; F6 = value; } + } + struct C7 + { + public int F7; + public object P7 { get; {{setter}} { field = value; } } + public C7(int value) { P7 ??= value; F7 = value; } + } + struct C9 + { + public int F9; + public object P9 { get { return field; } {{setter}} { field = value; } } + public C9(int value) { P9 ??= value; F9 = value; } + } + struct Program + { + static void Main() + { + var c1 = new C1(1); + var c2 = new C2(2); + var c3 = new C3(3); + var c6 = new C6(6); + var c7 = new C7(7); + var c9 = new C9(9); + Console.WriteLine((c1.F1, c1.P1, c2.F2, c2.P2, c3.F3, c3.P3, c6.F6, c6.P6, c7.F7, c7.P7, c9.F9, c9.P9)); + } + } + """; + var verifier = CompileAndVerify( + source, + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, "(1, 1, 2, 2, 3, 3, 6, 6, 7, 7, 9, 9)")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C1..ctor", $$""" + { + // Code size 35 (0x23) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldnull + IL_0002: stfld "object C1.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "readonly object C1.P1.get" + IL_000d: brtrue.s IL_001b + IL_000f: ldarg.0 + IL_0010: ldarg.1 + IL_0011: box "int" + IL_0016: stfld "object C1.k__BackingField" + IL_001b: ldarg.0 + IL_001c: ldarg.1 + IL_001d: stfld "int C1.F1" + IL_0022: ret + } + """); + verifier.VerifyIL("C2..ctor", $$""" + { + // Code size 35 (0x23) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldnull + IL_0002: stfld "object C2.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "object C2.P2.get" + IL_000d: brtrue.s IL_001b + IL_000f: ldarg.0 + IL_0010: ldarg.1 + IL_0011: box "int" + IL_0016: stfld "object C2.k__BackingField" + IL_001b: ldarg.0 + IL_001c: ldarg.1 + IL_001d: stfld "int C2.F2" + IL_0022: ret + } + """); + verifier.VerifyIL("C3..ctor", $$""" + { + // Code size 37 (0x25) + .maxstack 3 + .locals init (object V_0) + IL_0000: ldarg.0 + IL_0001: ldnull + IL_0002: stfld "object C3.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "object C3.P3.get" + IL_000d: brtrue.s IL_001d + IL_000f: ldarg.0 + IL_0010: ldarg.1 + IL_0011: box "int" + IL_0016: dup + IL_0017: stloc.0 + IL_0018: call "void C3.P3.{{setter}}" + IL_001d: ldarg.0 + IL_001e: ldarg.1 + IL_001f: stfld "int C3.F3" + IL_0024: ret + } + """); + verifier.VerifyIL("C6..ctor", $$""" + { + // Code size 37 (0x25) + .maxstack 3 + .locals init (object V_0) + IL_0000: ldarg.0 + IL_0001: ldnull + IL_0002: stfld "object C6.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "readonly object C6.P6.get" + IL_000d: brtrue.s IL_001d + IL_000f: ldarg.0 + IL_0010: ldarg.1 + IL_0011: box "int" + IL_0016: dup + IL_0017: stloc.0 + IL_0018: call "void C6.P6.{{setter}}" + IL_001d: ldarg.0 + IL_001e: ldarg.1 + IL_001f: stfld "int C6.F6" + IL_0024: ret + } + """); + verifier.VerifyIL("C7..ctor", $$""" + { + // Code size 44 (0x2c) + .maxstack 3 + .locals init (object V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C7.F7" + IL_0007: ldarg.0 + IL_0008: ldnull + IL_0009: stfld "object C7.k__BackingField" + IL_000e: ldarg.0 + IL_000f: call "readonly object C7.P7.get" + IL_0014: brtrue.s IL_0024 + IL_0016: ldarg.0 + IL_0017: ldarg.1 + IL_0018: box "int" + IL_001d: dup + IL_001e: stloc.0 + IL_001f: call "void C7.P7.{{setter}}" + IL_0024: ldarg.0 + IL_0025: ldarg.1 + IL_0026: stfld "int C7.F7" + IL_002b: ret + } + """); + verifier.VerifyIL("C9..ctor", $$""" + { + // Code size 44 (0x2c) + .maxstack 3 + .locals init (object V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int C9.F9" + IL_0007: ldarg.0 + IL_0008: ldnull + IL_0009: stfld "object C9.k__BackingField" + IL_000e: ldarg.0 + IL_000f: call "object C9.P9.get" + IL_0014: brtrue.s IL_0024 + IL_0016: ldarg.0 + IL_0017: ldarg.1 + IL_0018: box "int" + IL_001d: dup + IL_001e: stloc.0 + IL_001f: call "void C9.P9.{{setter}}" + IL_0024: ldarg.0 + IL_0025: ldarg.1 + IL_0026: stfld "int C9.F9" + IL_002b: ret + } + """); + } + + [Fact] + public void ConstructorAssignment_03() + { + string source = """ + using System; + class C + { + static int P1 => field; + int P2 => field; + static C() + { + P1 = 1; + M(() => { P1 = 2; }); + } + C(object o) + { + P2 = 3; + M(() => { P2 = 4; }); + } + static void M(Action a) + { + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (9,19): error CS0200: Property or indexer 'C.P1' cannot be assigned to -- it is read only + // M(() => { P1 = 2; }); + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "P1").WithArguments("C.P1").WithLocation(9, 19), + // (14,19): error CS0200: Property or indexer 'C.P2' cannot be assigned to -- it is read only + // M(() => { P2 = 4; }); + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "P2").WithArguments("C.P2").WithLocation(14, 19)); + } + + [Fact] + public void ConstructorAssignment_04() + { + string source = """ + using System; + class A + { + public static int P1 { get; private set; } + public static int P3 { get => field; private set; } + public static int P5 { get => field; private set { } } + public static int P7 { get; private set { } } + } + class B : A + { + static B() + { + P1 = 1; + P3 = 3; + P5 = 5; + P7 = 7; + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (13,9): error CS0272: The property or indexer 'A.P1' cannot be used in this context because the set accessor is inaccessible + // P1 = 1; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P1").WithArguments("A.P1").WithLocation(13, 9), + // (14,9): error CS0272: The property or indexer 'A.P3' cannot be used in this context because the set accessor is inaccessible + // P3 = 3; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P3").WithArguments("A.P3").WithLocation(14, 9), + // (15,9): error CS0272: The property or indexer 'A.P5' cannot be used in this context because the set accessor is inaccessible + // P5 = 5; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P5").WithArguments("A.P5").WithLocation(15, 9), + // (16,9): error CS0272: The property or indexer 'A.P7' cannot be used in this context because the set accessor is inaccessible + // P7 = 7; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P7").WithArguments("A.P7").WithLocation(16, 9)); + } + + [Fact] + public void ConstructorAssignment_05() + { + string source = """ + using System; + class A + { + public int P1 { get; private set; } + public int P2 { get; private init; } + public int P3 { get => field; private set; } + public int P4 { get => field; private init; } + public int P5 { get => field; private set { } } + public int P6 { get => field; private init { } } + public int P7 { get; private set { } } + public int P8 { get; private init { } } + } + class B : A + { + public B() + { + P1 = 1; + P2 = 2; + P3 = 3; + P4 = 4; + P5 = 5; + P6 = 6; + P7 = 7; + P8 = 8; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (17,9): error CS0272: The property or indexer 'A.P1' cannot be used in this context because the set accessor is inaccessible + // P1 = 1; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P1").WithArguments("A.P1").WithLocation(17, 9), + // (18,9): error CS0272: The property or indexer 'A.P2' cannot be used in this context because the set accessor is inaccessible + // P2 = 2; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P2").WithArguments("A.P2").WithLocation(18, 9), + // (19,9): error CS0272: The property or indexer 'A.P3' cannot be used in this context because the set accessor is inaccessible + // P3 = 3; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P3").WithArguments("A.P3").WithLocation(19, 9), + // (20,9): error CS0272: The property or indexer 'A.P4' cannot be used in this context because the set accessor is inaccessible + // P4 = 4; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P4").WithArguments("A.P4").WithLocation(20, 9), + // (21,9): error CS0272: The property or indexer 'A.P5' cannot be used in this context because the set accessor is inaccessible + // P5 = 5; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P5").WithArguments("A.P5").WithLocation(21, 9), + // (22,9): error CS0272: The property or indexer 'A.P6' cannot be used in this context because the set accessor is inaccessible + // P6 = 6; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P6").WithArguments("A.P6").WithLocation(22, 9), + // (23,9): error CS0272: The property or indexer 'A.P7' cannot be used in this context because the set accessor is inaccessible + // P7 = 7; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P7").WithArguments("A.P7").WithLocation(23, 9), + // (24,9): error CS0272: The property or indexer 'A.P8' cannot be used in this context because the set accessor is inaccessible + // P8 = 8; + Diagnostic(ErrorCode.ERR_InaccessibleSetter, "P8").WithArguments("A.P8").WithLocation(24, 9)); + } + + [Fact] + public void ConstructorAssignment_06() + { + string source = $$""" + class A + { + public object P1 { get; } + public object P2 { get => field; } + public object P3 { get => field; init; } + public A() + { + this.P1 = 11; + this.P2 = 12; + this.P3 = 13; + } + A(A a) + { + a.P1 = 31; + a.P2 = 32; + a.P3 = 33; + } + } + class B : A + { + B() + { + base.P1 = 21; + base.P2 = 22; + base.P3 = 23; + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (14,9): error CS0200: Property or indexer 'A.P1' cannot be assigned to -- it is read only + // a.P1 = 31; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "a.P1").WithArguments("A.P1").WithLocation(14, 9), + // (15,9): error CS0200: Property or indexer 'A.P2' cannot be assigned to -- it is read only + // a.P2 = 32; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "a.P2").WithArguments("A.P2").WithLocation(15, 9), + // (16,9): error CS8852: Init-only property or indexer 'A.P3' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor. + // a.P3 = 33; + Diagnostic(ErrorCode.ERR_AssignmentInitOnly, "a.P3").WithArguments("A.P3").WithLocation(16, 9), + // (23,9): error CS0200: Property or indexer 'A.P1' cannot be assigned to -- it is read only + // base.P1 = 21; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "base.P1").WithArguments("A.P1").WithLocation(23, 9), + // (24,9): error CS0200: Property or indexer 'A.P2' cannot be assigned to -- it is read only + // base.P2 = 22; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "base.P2").WithArguments("A.P2").WithLocation(24, 9)); + } + + [Fact] + public void ConstructorAssignment_07() + { + string source = $$""" + using System; + class C + { + public static int P1 { get; } + public static int P2 { get => field; } + public static int P3 { get => field; set; } + public static int P4 { get => field; set { } } + public static int P5 = F( + P1 = 1, + P2 = 2, + P3 = 3, + P4 = 4); + static int F(int x, int y, int z, int w) => x; + } + class Program + { + static void Main() + { + Console.WriteLine((C.P1, C.P2, C.P3, C.P4)); + } + } + """; + var verifier = CompileAndVerify(source, expectedOutput: "(1, 2, 3, 0)"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C..cctor", """ + { + // Code size 39 (0x27) + .maxstack 5 + IL_0000: ldc.i4.1 + IL_0001: dup + IL_0002: stsfld "int C.k__BackingField" + IL_0007: ldc.i4.2 + IL_0008: dup + IL_0009: stsfld "int C.k__BackingField" + IL_000e: ldc.i4.3 + IL_000f: dup + IL_0010: call "void C.P3.set" + IL_0015: ldc.i4.4 + IL_0016: dup + IL_0017: call "void C.P4.set" + IL_001c: call "int C.F(int, int, int, int)" + IL_0021: stsfld "int C.P5" + IL_0026: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void DefaultInitialization_01A(bool useInit, bool includeStructInitializationWarnings) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + using System; + struct S1 + { + public int P1 { get; } + public S1(int unused) { _ = P1; } + } + struct S2 + { + public int P2 { get => field; } + public S2(int unused) { _ = P2; } + } + struct S3 + { + public int P3 { get; {{setter}}; } + public S3(int unused) { _ = P3; } + } + struct S4 + { + public int P4 { get => field; {{setter}} { field = value; } } + public S4(int unused) { _ = P4; } + } + struct S5 + { + public int P5 { get; {{setter}} { field = value; } } + public S5(int unused) { _ = P5; } + } + struct S6 + { + public int P6 { get => field; {{setter}}; } + public S6(int unused) { _ = P6; } + } + class Program + { + static void Main() + { + var s1 = new S1(1); + var s2 = new S2(2); + var s3 = new S3(3); + var s4 = new S4(4); + var s5 = new S5(5); + var s6 = new S6(6); + Console.WriteLine((s1.P1, s2.P2, s3.P3, s4.P4, s5.P5, s6.P6)); + } + } + """; + var verifier = CompileAndVerify( + source, + options: includeStructInitializationWarnings ? TestOptions.ReleaseExe.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings) : TestOptions.ReleaseExe, + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, "(0, 0, 0, 0, 0, 0)")); + if (includeStructInitializationWarnings) + { + verifier.VerifyDiagnostics( + // (5,12): warning CS9021: Control is returned to caller before auto-implemented property 'S1.P1' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S1(int unused) { _ = P1; } + Diagnostic(ErrorCode.WRN_UnassignedThisAutoPropertySupportedVersion, "S1").WithArguments("S1.P1").WithLocation(5, 12), + // (5,33): warning CS9018: Auto-implemented property 'P1' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S1(int unused) { _ = P1; } + Diagnostic(ErrorCode.WRN_UseDefViolationPropertySupportedVersion, "P1").WithArguments("P1").WithLocation(5, 33), + // (10,33): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S2(int unused) { _ = P2; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P2").WithLocation(10, 33), + // (15,12): warning CS9021: Control is returned to caller before auto-implemented property 'S3.P3' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S3(int unused) { _ = P3; } + Diagnostic(ErrorCode.WRN_UnassignedThisAutoPropertySupportedVersion, "S3").WithArguments("S3.P3").WithLocation(15, 12), + // (15,33): warning CS9018: Auto-implemented property 'P3' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S3(int unused) { _ = P3; } + Diagnostic(ErrorCode.WRN_UseDefViolationPropertySupportedVersion, "P3").WithArguments("P3").WithLocation(15, 33), + // (20,33): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S4(int unused) { _ = P4; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P4").WithLocation(20, 33), + // (25,12): warning CS9021: Control is returned to caller before auto-implemented property 'S5.P5' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S5(int unused) { _ = P5; } + Diagnostic(ErrorCode.WRN_UnassignedThisAutoPropertySupportedVersion, "S5").WithArguments("S5.P5").WithLocation(25, 12), + // (25,33): warning CS9018: Auto-implemented property 'P5' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S5(int unused) { _ = P5; } + Diagnostic(ErrorCode.WRN_UseDefViolationPropertySupportedVersion, "P5").WithArguments("P5").WithLocation(25, 33), + // (30,33): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S6(int unused) { _ = P6; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P6").WithLocation(30, 33)); + } + else + { + verifier.VerifyDiagnostics(); + } + verifier.VerifyIL("S1..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S1.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "readonly int S1.P1.get" + IL_000d: pop + IL_000e: ret + } + """); + verifier.VerifyIL("S2..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S2.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "int S2.P2.get" + IL_000d: pop + IL_000e: ret + } + """); + verifier.VerifyIL("S3..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S3.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "readonly int S3.P3.get" + IL_000d: pop + IL_000e: ret + } + """); + verifier.VerifyIL("S4..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S4.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "int S4.P4.get" + IL_000d: pop + IL_000e: ret + } + """); + verifier.VerifyIL("S5..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S5.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "readonly int S5.P5.get" + IL_000d: pop + IL_000e: ret + } + """); + verifier.VerifyIL("S6..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S6.k__BackingField" + IL_0007: ldarg.0 + IL_0008: call "int S6.P6.get" + IL_000d: pop + IL_000e: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void DefaultInitialization_01B(bool useInit, bool includeStructInitializationWarnings) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + using System; + struct S1 + { + public int F1; + public int P1 { get; } + public S1(int unused) { _ = P1; } + } + struct S2 + { + public int F2; + public int P2 { get => field; } + public S2(int unused) { _ = P2; } + } + class Program + { + static void Main() + { + var s1 = new S1(1); + var s2 = new S2(2); + Console.WriteLine((s1.F1, s1.P1)); + Console.WriteLine((s2.F2, s2.P2)); + } + } + """; + var verifier = CompileAndVerify( + source, + options: includeStructInitializationWarnings ? TestOptions.ReleaseExe.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings) : TestOptions.ReleaseExe, + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, """ + (0, 0) + (0, 0) + """)); + if (includeStructInitializationWarnings) + { + verifier.VerifyDiagnostics( + // (4,16): warning CS0649: Field 'S1.F1' is never assigned to, and will always have its default value 0 + // public int F1; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F1").WithArguments("S1.F1", "0").WithLocation(4, 16), + // (6,12): warning CS9021: Control is returned to caller before auto-implemented property 'S1.P1' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S1(int unused) { _ = P1; } + Diagnostic(ErrorCode.WRN_UnassignedThisAutoPropertySupportedVersion, "S1").WithArguments("S1.P1").WithLocation(6, 12), + // (6,12): warning CS9022: Control is returned to caller before field 'S1.F1' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S1(int unused) { _ = P1; } + Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S1").WithArguments("S1.F1").WithLocation(6, 12), + // (6,33): warning CS9018: Auto-implemented property 'P1' is read before being explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S1(int unused) { _ = P1; } + Diagnostic(ErrorCode.WRN_UseDefViolationPropertySupportedVersion, "P1").WithArguments("P1").WithLocation(6, 33), + // (10,16): warning CS0649: Field 'S2.F2' is never assigned to, and will always have its default value 0 + // public int F2; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F2").WithArguments("S2.F2", "0").WithLocation(10, 16), + // (12,33): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S2(int unused) { _ = P2; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P2").WithLocation(12, 33)); + } + else + { + verifier.VerifyDiagnostics( + // (4,16): warning CS0649: Field 'S1.F1' is never assigned to, and will always have its default value 0 + // public int F1; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F1").WithArguments("S1.F1", "0").WithLocation(4, 16), + // (10,16): warning CS0649: Field 'S2.F2' is never assigned to, and will always have its default value 0 + // public int F2; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F2").WithArguments("S2.F2", "0").WithLocation(10, 16)); + } + verifier.VerifyIL("S1..ctor", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S1.F1" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int S1.k__BackingField" + IL_000e: ldarg.0 + IL_000f: call "readonly int S1.P1.get" + IL_0014: pop + IL_0015: ret + } + """); + verifier.VerifyIL("S2..ctor", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S2.F2" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int S2.k__BackingField" + IL_000e: ldarg.0 + IL_000f: call "int S2.P2.get" + IL_0014: pop + IL_0015: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void DefaultInitialization_02A(bool useInit, bool includeStructInitializationWarnings) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + using System; + struct S1 + { + public int P1 { get; } + public S1(int i) { P1 = i; } + } + struct S2 + { + public int P2 { get => field; } + public S2(int i) { P2 = i; } + } + struct S3 + { + public int P3 { get; {{setter}}; } + public S3(int i) { P3 = i; } + } + struct S4 + { + public int P4 { get => field; {{setter}} { field = value; } } + public S4(int i) { P4 = i; } + } + struct S5 + { + public int P5 { get; {{setter}} { field = value; } } + public S5(int i) { P5 = i; } + } + struct S6 + { + public int P6 { get => field; {{setter}}; } + public S6(int i) { P6 = i; } + } + struct S7 + { + public int P7 { {{setter}} { field = value; } } + public S7(int i) { P7 = i; } + } + class Program + { + static void Main() + { + var s1 = new S1(1); + var s2 = new S2(2); + var s3 = new S3(3); + var s4 = new S4(4); + var s5 = new S5(5); + var s6 = new S6(6); + var s7 = new S7(7); + Console.WriteLine((s1.P1, s2.P2, s3.P3, s4.P4, s5.P5, s6.P6)); + } + } + """; + var verifier = CompileAndVerify( + source, + options: includeStructInitializationWarnings ? TestOptions.ReleaseExe.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings) : TestOptions.ReleaseExe, + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, "(1, 2, 3, 4, 5, 6)")); + if (includeStructInitializationWarnings) + { + verifier.VerifyDiagnostics( + // (20,24): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S4(int i) { P4 = i; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P4").WithLocation(20, 24), + // (25,24): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S5(int i) { P5 = i; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P5").WithLocation(25, 24), + // (35,24): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S7(int i) { P7 = i; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P7").WithLocation(35, 24)); + } + else + { + verifier.VerifyDiagnostics(); + } + verifier.VerifyIL("S1..ctor", $$""" + { + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld "int S1.k__BackingField" + IL_0007: ret + } + """); + verifier.VerifyIL("S2..ctor", $$""" + { + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld "int S2.k__BackingField" + IL_0007: ret + } + """); + verifier.VerifyIL("S3..ctor", $$""" + { + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call "void S3.P3.{{setter}}" + IL_0007: ret + } + """); + verifier.VerifyIL("S4..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S4.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: call "void S4.P4.{{setter}}" + IL_000e: ret + } + """); + verifier.VerifyIL("S5..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S5.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: call "void S5.P5.{{setter}}" + IL_000e: ret + } + """); + verifier.VerifyIL("S6..ctor", $$""" + { + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call "void S6.P6.{{setter}}" + IL_0007: ret + } + """); + verifier.VerifyIL("S7..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S7.k__BackingField" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: call "void S7.P7.{{setter}}" + IL_000e: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void DefaultInitialization_02B(bool useInit, bool includeStructInitializationWarnings) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + using System; + struct S3 + { + public int F3; + public int P3 { get; {{setter}}; } + public S3(int i) { P3 = i; } + } + struct S4 + { + public int F4; + public int P4 { get => field; {{setter}} { field = value; } } + public S4(int i) { P4 = i; } + } + class Program + { + static void Main() + { + var s3 = new S3(3); + var s4 = new S4(4); + Console.WriteLine((s3.F3, s3.P3)); + Console.WriteLine((s4.F4, s4.P4)); + } + } + """; + var verifier = CompileAndVerify( + source, + options: includeStructInitializationWarnings ? TestOptions.ReleaseExe.WithSpecificDiagnosticOptions(ReportStructInitializationWarnings) : TestOptions.ReleaseExe, + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, """ + (0, 3) + (0, 4) + """)); + if (includeStructInitializationWarnings) + { + verifier.VerifyDiagnostics( + // (4,16): warning CS0649: Field 'S3.F3' is never assigned to, and will always have its default value 0 + // public int F3; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F3").WithArguments("S3.F3", "0").WithLocation(4, 16), + // (6,12): warning CS9022: Control is returned to caller before field 'S3.F3' is explicitly assigned, causing a preceding implicit assignment of 'default'. + // public S3(int i) { P3 = i; } + Diagnostic(ErrorCode.WRN_UnassignedThisSupportedVersion, "S3").WithArguments("S3.F3").WithLocation(6, 12), + // (10,16): warning CS0649: Field 'S4.F4' is never assigned to, and will always have its default value 0 + // public int F4; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F4").WithArguments("S4.F4", "0").WithLocation(10, 16), + // (12,24): warning CS9020: The 'this' object is read before all of its fields have been assigned, causing preceding implicit assignments of 'default' to non-explicitly assigned fields. + // public S4(int i) { P4 = i; } + Diagnostic(ErrorCode.WRN_UseDefViolationThisSupportedVersion, "P4").WithLocation(12, 24)); + } + else + { + verifier.VerifyDiagnostics( + // (4,16): warning CS0649: Field 'S3.F3' is never assigned to, and will always have its default value 0 + // public int F3; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F3").WithArguments("S3.F3", "0").WithLocation(4, 16), + // (10,16): warning CS0649: Field 'S4.F4' is never assigned to, and will always have its default value 0 + // public int F4; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "F4").WithArguments("S4.F4", "0").WithLocation(10, 16)); + } + verifier.VerifyIL("S3..ctor", $$""" + { + // Code size 15 (0xf) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S3.F3" + IL_0007: ldarg.0 + IL_0008: ldarg.1 + IL_0009: call "void S3.P3.{{setter}}" + IL_000e: ret + } + """); + verifier.VerifyIL("S4..ctor", $$""" + { + // Code size 22 (0x16) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: stfld "int S4.F4" + IL_0007: ldarg.0 + IL_0008: ldc.i4.0 + IL_0009: stfld "int S4.k__BackingField" + IL_000e: ldarg.0 + IL_000f: ldarg.1 + IL_0010: call "void S4.P4.{{setter}}" + IL_0015: ret + } + """); + } + + [Theory] + [CombinatorialData] + public void ReadOnly_01(bool useReadOnlyType, bool useReadOnlyProperty, bool useInit) + { + static string getReadOnlyModifier(bool useReadOnly) => useReadOnly ? "readonly" : " "; + string typeModifier = getReadOnlyModifier(useReadOnlyType); + string propertyModifier = getReadOnlyModifier(useReadOnlyProperty); + string setter = useInit ? "init" : "set"; + string source = $$""" + {{typeModifier}} struct S + { + {{propertyModifier}} object P1 { get; } + {{propertyModifier}} object P2 { get => field; } + {{propertyModifier}} object P3 { get => field; {{setter}}; } + {{propertyModifier}} object P4 { get => field; {{setter}} { } } + {{propertyModifier}} object P5 { get => null; } + {{propertyModifier}} object P6 { get => null; {{setter}}; } + {{propertyModifier}} object P7 { get => null; {{setter}} { } } + {{propertyModifier}} object P8 { get => null; {{setter}} { _ = field; } } + {{propertyModifier}} object P9 { get; {{setter}}; } + {{propertyModifier}} object PA { get; {{setter}} { } } + {{propertyModifier}} object PB { {{setter}} { _ = field; } } + {{propertyModifier}} object PC { get; {{setter}} { field = value; } } + {{propertyModifier}} object PD { {{setter}} { field = value; } } + } + """; + var comp = CreateCompilation(source, targetFramework: GetTargetFramework(useInit)); + if (useInit) + { + comp.VerifyEmitDiagnostics(); + } + else if (useReadOnlyType) + { + comp.VerifyEmitDiagnostics( + // (5,21): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P3 { get => field; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P3").WithLocation(5, 21), + // (8,21): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P6 { get => null; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P6").WithLocation(8, 21), + // (11,21): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P9 { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P9").WithLocation(11, 21), + // (14,37): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // object PC { get; set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(14, 37), + // (15,32): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // object PD { set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(15, 32)); + } + else if (useReadOnlyProperty) + { + comp.VerifyEmitDiagnostics( + // (5,21): error CS8659: Auto-implemented property 'S.P3' cannot be marked 'readonly' because it has a 'set' accessor. + // readonly object P3 { get => field; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "P3").WithArguments("S.P3").WithLocation(5, 21), + // (8,21): error CS8659: Auto-implemented property 'S.P6' cannot be marked 'readonly' because it has a 'set' accessor. + // readonly object P6 { get => null; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "P6").WithArguments("S.P6").WithLocation(8, 21), + // (11,21): error CS8659: Auto-implemented property 'S.P9' cannot be marked 'readonly' because it has a 'set' accessor. + // readonly object P9 { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "P9").WithArguments("S.P9").WithLocation(11, 21), + // (14,37): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // readonly object PC { get; set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(14, 37), + // (15,32): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // readonly object PD { set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(15, 32)); + } + else + { + comp.VerifyEmitDiagnostics(); + } + var actualMembers = comp.GetMember("S").GetMembers().OfType().Select(f => $"{f.ToTestDisplayString()}: {f.IsReadOnly}"); + var expectedMembers = new[] + { + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyProperty}", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyProperty}", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyProperty}", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyProperty}", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyProperty}", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyProperty || useInit}", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyProperty || useInit}", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyProperty || useInit}", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyProperty || useInit}", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyProperty || useInit}", + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + + [Theory] + [CombinatorialData] + public void ReadOnly_02(bool useReadOnlyType, bool useReadOnlyOnGet) + { + static string getReadOnlyModifier(bool useReadOnly) => useReadOnly ? "readonly" : " "; + string typeModifier = getReadOnlyModifier(useReadOnlyType); + string getModifier = getReadOnlyModifier(useReadOnlyOnGet); + string setModifier = getReadOnlyModifier(!useReadOnlyOnGet); + string source = $$""" + {{typeModifier}} struct S + { + object P3 { {{getModifier}} get => field; {{setModifier}} set; } + object P4 { {{getModifier}} get => field; {{setModifier}} set { } } + object P6 { {{getModifier}} get => null; {{setModifier}} set; } + object P7 { {{getModifier}} get => null; {{setModifier}} set { } } + object P8 { {{getModifier}} get => null; {{setModifier}} set { _ = field; } } + object P9 { {{getModifier}} get; {{setModifier}} set; } + object PA { {{getModifier}} get; {{setModifier}} set { } } + object PC { {{getModifier}} get; {{setModifier}} set { field = value; } } + } + """; + var comp = CreateCompilation(source); + if (useReadOnlyType) + { + if (useReadOnlyOnGet) + { + comp.VerifyEmitDiagnostics( + // (3,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P3 { readonly get => field; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P3").WithLocation(3, 12), + // (5,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P6 { readonly get => null; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P6").WithLocation(5, 12), + // (8,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P9 { readonly get; set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P9").WithLocation(8, 12), + // (10,46): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // object PC { readonly get; set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(10, 46)); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P3 { get => field; readonly set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P3").WithLocation(3, 12), + // (3,49): error CS8658: Auto-implemented 'set' accessor 'S.P3.set' cannot be marked 'readonly'. + // object P3 { get => field; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P3.set").WithLocation(3, 49), + // (5,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P6 { get => null; readonly set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P6").WithLocation(5, 12), + // (5,48): error CS8658: Auto-implemented 'set' accessor 'S.P6.set' cannot be marked 'readonly'. + // object P6 { get => null; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P6.set").WithLocation(5, 48), + // (8,12): error CS8341: Auto-implemented instance properties in readonly structs must be readonly. + // object P9 { get; readonly set; } + Diagnostic(ErrorCode.ERR_AutoPropsInRoStruct, "P9").WithLocation(8, 12), + // (8,40): error CS8658: Auto-implemented 'set' accessor 'S.P9.set' cannot be marked 'readonly'. + // object P9 { get; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P9.set").WithLocation(8, 40), + // (10,46): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // object PC { get; readonly set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(10, 46)); + } + } + else + { + if (useReadOnlyOnGet) + { + comp.VerifyEmitDiagnostics(); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,49): error CS8658: Auto-implemented 'set' accessor 'S.P3.set' cannot be marked 'readonly'. + // object P3 { get => field; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P3.set").WithLocation(3, 49), + // (5,48): error CS8658: Auto-implemented 'set' accessor 'S.P6.set' cannot be marked 'readonly'. + // object P6 { get => null; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P6.set").WithLocation(5, 48), + // (8,40): error CS8658: Auto-implemented 'set' accessor 'S.P9.set' cannot be marked 'readonly'. + // object P9 { get; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P9.set").WithLocation(8, 40), + // (10,46): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // object PC { get; readonly set { field = value; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(10, 46)); + } + } + var actualMembers = comp.GetMember("S").GetMembers().OfType().Select(f => $"{f.ToTestDisplayString()}: {f.IsReadOnly}"); + var expectedMembers = new[] + { + $"System.Object S.k__BackingField: {useReadOnlyType}", + $"System.Object S.k__BackingField: {useReadOnlyType}", + $"System.Object S.k__BackingField: {useReadOnlyType}", + $"System.Object S.k__BackingField: {useReadOnlyType}", + $"System.Object S.k__BackingField: {useReadOnlyType || !useReadOnlyOnGet}", + $"System.Object S.k__BackingField: {useReadOnlyType || !useReadOnlyOnGet}", + $"System.Object S.k__BackingField: {useReadOnlyType || !useReadOnlyOnGet}", + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + + [Theory] + [CombinatorialData] + public void ReadOnly_03(bool useRefStruct, bool useReadOnlyType, bool useReadOnlyMember) + { + static string getReadOnlyModifier(bool useReadOnly) => useReadOnly ? "readonly" : " "; + string typeKind = useRefStruct ? "ref struct" : " struct"; + string typeModifier = getReadOnlyModifier(useReadOnlyType); + string memberModifier = getReadOnlyModifier(useReadOnlyMember); + string sourceA = $$""" + {{typeModifier}} {{typeKind}} S + { + {{memberModifier}} object P1 { get; } + {{memberModifier}} object P5 { get; init; } + object P7 { {{memberModifier}} get; init; } + {{memberModifier}} object Q1 { get => field; } + {{memberModifier}} object Q2 { set { _ = field; } } + {{memberModifier}} object Q3 { init { _ = field; } } + {{memberModifier}} object Q4 { get; set { _ = field; } } + {{memberModifier}} object Q5 { get; init { _ = field; } } + object Q6 { {{memberModifier}} get; set { _ = field; } } + object Q7 { {{memberModifier}} get; init { _ = field; } } + object Q8 { get; {{memberModifier}} set { _ = field; } } + } + """; + string sourceB = """ + using System; + using System.Reflection; + class Program + { + static void Main() + { + foreach (var field in typeof(S).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + Console.WriteLine("{0}: {1}", field.Name, field.IsInitOnly); + } + } + """; + var verifier = CompileAndVerify( + [sourceA, sourceB], + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput($$""" + k__BackingField: True + k__BackingField: True + k__BackingField: True + k__BackingField: {{useReadOnlyType || useReadOnlyMember}} + k__BackingField: {{useReadOnlyType || useReadOnlyMember}} + k__BackingField: True + k__BackingField: {{useReadOnlyType || useReadOnlyMember}} + k__BackingField: True + k__BackingField: {{useReadOnlyType}} + k__BackingField: True + k__BackingField: {{useReadOnlyType || useReadOnlyMember}} + """)); + var comp = (CSharpCompilation)verifier.Compilation; + var actualMembers = comp.GetMember("S").GetMembers().OfType().Select(f => $"{f.ToTestDisplayString()}: {f.IsReadOnly}"); + var expectedMembers = new[] + { + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyMember}", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyMember}", + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyMember}", + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: {useReadOnlyType}", + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: {useReadOnlyType || useReadOnlyMember}", + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + + [Theory] + [CombinatorialData] + public void ReadOnly_04(bool useRefStruct, bool useReadOnlyType, bool useReadOnlyMember) + { + static string getReadOnlyModifier(bool useReadOnly) => useReadOnly ? "readonly" : " "; + string typeKind = useRefStruct ? "ref struct" : " struct"; + string typeModifier = getReadOnlyModifier(useReadOnlyType); + string memberModifier = getReadOnlyModifier(useReadOnlyMember); + string sourceA = $$""" + {{typeModifier}} {{typeKind}} S + { + static {{memberModifier}} object P1 { get; } + static {{memberModifier}} object Q1 { get => field; } + static {{memberModifier}} object Q2 { set { _ = field; } } + static {{memberModifier}} object Q4 { get; set { _ = field; } } + static object Q6 { {{memberModifier}} get; set { _ = field; } } + static object Q8 { get; {{memberModifier}} set { _ = field; } } + } + """; + string sourceB = """ + using System; + using System.Reflection; + class Program + { + static void Main() + { + foreach (var field in typeof(S).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + Console.WriteLine("{0}: {1}", field.Name, field.IsInitOnly); + } + } + """; + var comp = CreateCompilation([sourceA, sourceB], options: TestOptions.ReleaseExe); + if (useReadOnlyMember) + { + comp.VerifyEmitDiagnostics( + // (3,28): error CS8657: Static member 'S.P1' cannot be marked 'readonly'. + // static readonly object P1 { get; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "P1").WithArguments("S.P1").WithLocation(3, 28), + // (4,28): error CS8657: Static member 'S.Q1' cannot be marked 'readonly'. + // static readonly object Q1 { get => field; } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "Q1").WithArguments("S.Q1").WithLocation(4, 28), + // (5,28): error CS8657: Static member 'S.Q2' cannot be marked 'readonly'. + // static readonly object Q2 { set { _ = field; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "Q2").WithArguments("S.Q2").WithLocation(5, 28), + // (6,28): error CS8657: Static member 'S.Q4' cannot be marked 'readonly'. + // static readonly object Q4 { get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "Q4").WithArguments("S.Q4").WithLocation(6, 28), + // (7,33): error CS8657: Static member 'S.Q6.get' cannot be marked 'readonly'. + // static object Q6 { readonly get; set { _ = field; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "get").WithArguments("S.Q6.get").WithLocation(7, 33), + // (8,38): error CS8657: Static member 'S.Q8.set' cannot be marked 'readonly'. + // static object Q8 { get; readonly set { _ = field; } } + Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "set").WithArguments("S.Q8.set").WithLocation(8, 38)); + } + else + { + comp.VerifyEmitDiagnostics(); + var verifier = CompileAndVerify(comp, expectedOutput: $$""" + k__BackingField: True + k__BackingField: {{useReadOnlyMember}} + k__BackingField: {{useReadOnlyMember}} + k__BackingField: {{useReadOnlyMember}} + k__BackingField: False + k__BackingField: {{useReadOnlyMember}} + """); + } + var actualMembers = comp.GetMember("S").GetMembers().OfType().Select(f => $"{f.ToTestDisplayString()}: {f.IsReadOnly}"); + var expectedMembers = new[] + { + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: {useReadOnlyMember}", + $"System.Object S.k__BackingField: {useReadOnlyMember}", + $"System.Object S.k__BackingField: {useReadOnlyMember}", + $"System.Object S.k__BackingField: False", + $"System.Object S.k__BackingField: {useReadOnlyMember}", + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + + [Theory] + [CombinatorialData] + public void ReadOnly_05(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + struct S + { + object P1 { readonly get; } + object P2 { readonly {{setter}}; } + object P3 { readonly get; {{setter}}; } + object P4 { get; readonly {{setter}}; } + object P5 { readonly get; readonly {{setter}}; } + object Q1 { readonly get => field; } + object Q2 { readonly {{setter}} { _ = field; } } + object Q3 { readonly get => field; {{setter}}; } + object Q4 { get; readonly {{setter}} { } } + object Q5 { readonly get => field; readonly {{setter}} { } } + } + """; + var comp = CreateCompilation(source, targetFramework: GetTargetFramework(useInit)); + if (useInit) + { + comp.VerifyEmitDiagnostics( + // (3,12): error CS8664: 'S.P1': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object P1 { readonly get; } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P1").WithArguments("S.P1").WithLocation(3, 12), + // (4,12): error CS8664: 'S.P2': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object P2 { readonly init; } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P2").WithArguments("S.P2").WithLocation(4, 12), + // (4,26): error CS8903: 'init' accessors cannot be marked 'readonly'. Mark 'S.P2' readonly instead. + // object P2 { readonly init; } + Diagnostic(ErrorCode.ERR_InitCannotBeReadonly, "init").WithArguments("S.P2").WithLocation(4, 26), + // (4,26): error CS8051: Auto-implemented properties must have get accessors. + // object P2 { readonly init; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "init").WithLocation(4, 26), + // (6,31): error CS8903: 'init' accessors cannot be marked 'readonly'. Mark 'S.P4' readonly instead. + // object P4 { get; readonly init; } + Diagnostic(ErrorCode.ERR_InitCannotBeReadonly, "init").WithArguments("S.P4").WithLocation(6, 31), + // (7,12): error CS8661: Cannot specify 'readonly' modifiers on both accessors of property or indexer 'S.P5'. Instead, put a 'readonly' modifier on the property itself. + // object P5 { readonly get; readonly init; } + Diagnostic(ErrorCode.ERR_DuplicatePropertyReadOnlyMods, "P5").WithArguments("S.P5").WithLocation(7, 12), + // (7,40): error CS8903: 'init' accessors cannot be marked 'readonly'. Mark 'S.P5' readonly instead. + // object P5 { readonly get; readonly init; } + Diagnostic(ErrorCode.ERR_InitCannotBeReadonly, "init").WithArguments("S.P5").WithLocation(7, 40), + // (8,12): error CS8664: 'S.Q1': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object Q1 { readonly get => field; } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "Q1").WithArguments("S.Q1").WithLocation(8, 12), + // (9,12): error CS8664: 'S.Q2': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object Q2 { readonly init { _ = field; } } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "Q2").WithArguments("S.Q2").WithLocation(9, 12), + // (9,26): error CS8903: 'init' accessors cannot be marked 'readonly'. Mark 'S.Q2' readonly instead. + // object Q2 { readonly init { _ = field; } } + Diagnostic(ErrorCode.ERR_InitCannotBeReadonly, "init").WithArguments("S.Q2").WithLocation(9, 26), + // (11,31): error CS8903: 'init' accessors cannot be marked 'readonly'. Mark 'S.Q4' readonly instead. + // object Q4 { get; readonly init { } } + Diagnostic(ErrorCode.ERR_InitCannotBeReadonly, "init").WithArguments("S.Q4").WithLocation(11, 31), + // (12,12): error CS8661: Cannot specify 'readonly' modifiers on both accessors of property or indexer 'S.Q5'. Instead, put a 'readonly' modifier on the property itself. + // object Q5 { readonly get => field; readonly init { } } + Diagnostic(ErrorCode.ERR_DuplicatePropertyReadOnlyMods, "Q5").WithArguments("S.Q5").WithLocation(12, 12), + // (12,49): error CS8903: 'init' accessors cannot be marked 'readonly'. Mark 'S.Q5' readonly instead. + // object Q5 { readonly get => field; readonly init { } } + Diagnostic(ErrorCode.ERR_InitCannotBeReadonly, "init").WithArguments("S.Q5").WithLocation(12, 49)); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,12): error CS8664: 'S.P1': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object P1 { readonly get; } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P1").WithArguments("S.P1").WithLocation(3, 12), + // (4,12): error CS8664: 'S.P2': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object P2 { readonly set; } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P2").WithArguments("S.P2").WithLocation(4, 12), + // (4,26): error CS8658: Auto-implemented 'set' accessor 'S.P2.set' cannot be marked 'readonly'. + // object P2 { readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P2.set").WithLocation(4, 26), + // (4,26): error CS8051: Auto-implemented properties must have get accessors. + // object P2 { readonly set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithLocation(4, 26), + // (6,31): error CS8658: Auto-implemented 'set' accessor 'S.P4.set' cannot be marked 'readonly'. + // object P4 { get; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P4.set").WithLocation(6, 31), + // (7,12): error CS8661: Cannot specify 'readonly' modifiers on both accessors of property or indexer 'S.P5'. Instead, put a 'readonly' modifier on the property itself. + // object P5 { readonly get; readonly set; } + Diagnostic(ErrorCode.ERR_DuplicatePropertyReadOnlyMods, "P5").WithArguments("S.P5").WithLocation(7, 12), + // (7,40): error CS8658: Auto-implemented 'set' accessor 'S.P5.set' cannot be marked 'readonly'. + // object P5 { readonly get; readonly set; } + Diagnostic(ErrorCode.ERR_AutoSetterCantBeReadOnly, "set").WithArguments("S.P5.set").WithLocation(7, 40), + // (8,12): error CS8664: 'S.Q1': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object Q1 { readonly get => field; } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "Q1").WithArguments("S.Q1").WithLocation(8, 12), + // (9,12): error CS8664: 'S.Q2': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object Q2 { readonly set { _ = field; } } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "Q2").WithArguments("S.Q2").WithLocation(9, 12), + // (12,12): error CS8661: Cannot specify 'readonly' modifiers on both accessors of property or indexer 'S.Q5'. Instead, put a 'readonly' modifier on the property itself. + // object Q5 { readonly get => field; readonly set { } } + Diagnostic(ErrorCode.ERR_DuplicatePropertyReadOnlyMods, "Q5").WithArguments("S.Q5").WithLocation(12, 12)); + } + var actualMembers = comp.GetMember("S").GetMembers().OfType().Select(f => $"{f.ToTestDisplayString()}: {f.IsReadOnly}"); + var expectedMembers = new[] + { + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: {useInit}", + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: {useInit}", + $"System.Object S.k__BackingField: True", + $"System.Object S.k__BackingField: True", + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + + [Theory] + [CombinatorialData] + public void ReadOnly_06(bool useStatic) + { + string propertyModifier = useStatic ? "static" : " "; + string source = $$""" + readonly class C1 + { + {{propertyModifier}} object P1 { get; } + {{propertyModifier}} object P2 { get; set; } + {{propertyModifier}} object P3 { get => field; } + {{propertyModifier}} object P4 { set { field = value; } } + } + class C2 + { + {{propertyModifier}} readonly object P1 { get; } + {{propertyModifier}} readonly object P2 { get; set; } + {{propertyModifier}} readonly object P3 { get => field; } + {{propertyModifier}} readonly object P4 { set { field = value; } } + {{propertyModifier}} object P5 { readonly get; set { field = value; } } + {{propertyModifier}} object P6 { get; readonly set { field = value; } } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (1,16): error CS0106: The modifier 'readonly' is not valid for this item + // readonly class C1 + Diagnostic(ErrorCode.ERR_BadMemberFlag, "C1").WithArguments("readonly").WithLocation(1, 16), + // (10,28): error CS0106: The modifier 'readonly' is not valid for this item + // readonly object P1 { get; } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "P1").WithArguments("readonly").WithLocation(10, 28), + // (11,28): error CS0106: The modifier 'readonly' is not valid for this item + // readonly object P2 { get; set; } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "P2").WithArguments("readonly").WithLocation(11, 28), + // (12,28): error CS0106: The modifier 'readonly' is not valid for this item + // readonly object P3 { get => field; } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "P3").WithArguments("readonly").WithLocation(12, 28), + // (13,28): error CS0106: The modifier 'readonly' is not valid for this item + // readonly object P4 { set { field = value; } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "P4").WithArguments("readonly").WithLocation(13, 28), + // (14,33): error CS0106: The modifier 'readonly' is not valid for this item + // object P5 { readonly get; set { field = value; } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "get").WithArguments("readonly").WithLocation(14, 33), + // (15,38): error CS0106: The modifier 'readonly' is not valid for this item + // object P6 { get; readonly set { field = value; } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "set").WithArguments("readonly").WithLocation(15, 38)); + var actualMembers = comp.GetMember("C1").GetMembers().OfType().Select(f => $"{f.ToTestDisplayString()}: {f.IsReadOnly}"); + var expectedMembers = new[] + { + $"System.Object C1.k__BackingField: True", + $"System.Object C1.k__BackingField: False", + $"System.Object C1.k__BackingField: False", + $"System.Object C1.k__BackingField: False", + }; + AssertEx.Equal(expectedMembers, actualMembers); + actualMembers = comp.GetMember("C2").GetMembers().OfType().Select(f => $"{f.ToTestDisplayString()}: {f.IsReadOnly}"); + expectedMembers = new[] + { + $"System.Object C2.k__BackingField: True", + $"System.Object C2.k__BackingField: False", + $"System.Object C2.k__BackingField: False", + $"System.Object C2.k__BackingField: False", + $"System.Object C2.k__BackingField: False", + $"System.Object C2.k__BackingField: False", + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + + [Fact] + public void ReadOnly_07() + { + string source = """ + struct S0 + { + object P0 { get { field = null; return null; } } + } + struct S1 + { + object P1 { readonly get { field = null; return null; } } + } + struct S2 + { + readonly object P2 { get { field = null; return null; } } + } + readonly struct S3 + { + object P3 { get { field = null; return null; } } + } + readonly struct S4 + { + object P4 { readonly get { field = null; return null; } } + } + readonly struct S5 + { + readonly object P5 { get { field = null; return null; } } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (7,12): error CS8664: 'S1.P1': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object P1 { readonly get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P1").WithArguments("S1.P1").WithLocation(7, 12), + // (7,32): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // object P1 { readonly get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(7, 32), + // (11,32): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // readonly object P2 { get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(11, 32), + // (15,23): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // object P3 { get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(15, 23), + // (19,12): error CS8664: 'S4.P4': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // object P4 { readonly get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P4").WithArguments("S4.P4").WithLocation(19, 12), + // (19,32): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // object P4 { readonly get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(19, 32), + // (23,32): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // readonly object P5 { get { field = null; return null; } } + Diagnostic(ErrorCode.ERR_AssgReadonly, "field").WithLocation(23, 32)); + } + + [Theory] + [CombinatorialData] + public void RefReturning_01(bool useStruct, bool useRefReadOnly) + { + string type = useStruct ? "struct" : "class"; + string refModifier = useRefReadOnly ? "ref readonly" : "ref "; + string source = $$""" + {{type}} S + { + {{refModifier}} object P1 { get; } + {{refModifier}} object P2 { get => ref field; } + {{refModifier}} object P3 { get => ref field; set; } + {{refModifier}} object P4 { get => ref field; init; } + {{refModifier}} object P5 { get => ref field; set { } } + {{refModifier}} object P6 { get => ref field; init { } } + {{refModifier}} object P7 { get => throw null; } + {{refModifier}} object P8 { get => throw null; set; } + {{refModifier}} object P9 { get => throw null; init; } + {{refModifier}} object PC { get => throw null; set { _ = field; } } + {{refModifier}} object PD { get => throw null; init { _ = field; } } + {{refModifier}} object PE { get; set; } + {{refModifier}} object PF { get; init; } + {{refModifier}} object PG { get; set { } } + {{refModifier}} object PH { get; init { } } + {{refModifier}} object PI { set { _ = field; } } + {{refModifier}} object PJ { init { _ = field; } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (3,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P1 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(3, 25), + // (4,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P2 { get => ref field; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(4, 25), + // (5,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P3 { get => ref field; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P3").WithLocation(5, 25), + // (5,48): error CS8147: Properties which return by reference cannot have set accessors + // ref object P3 { get => ref field; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 48), + // (6,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P4 { get => ref field; init; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P4").WithLocation(6, 25), + // (6,48): error CS8147: Properties which return by reference cannot have set accessors + // ref object P4 { get => ref field; init; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(6, 48), + // (7,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P5 { get => ref field; set { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P5").WithLocation(7, 25), + // (7,48): error CS8147: Properties which return by reference cannot have set accessors + // ref object P5 { get => ref field; set { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(7, 48), + // (8,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P6 { get => ref field; init { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P6").WithLocation(8, 25), + // (8,48): error CS8147: Properties which return by reference cannot have set accessors + // ref object P6 { get => ref field; init { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(8, 48), + // (10,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P8 { get => throw null; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P8").WithLocation(10, 25), + // (10,49): error CS8147: Properties which return by reference cannot have set accessors + // ref object P8 { get => throw null; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(10, 49), + // (11,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object P9 { get => throw null; init; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P9").WithLocation(11, 25), + // (11,49): error CS8147: Properties which return by reference cannot have set accessors + // ref object P9 { get => throw null; init; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(11, 49), + // (12,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PC { get => throw null; set { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PC").WithLocation(12, 25), + // (12,49): error CS8147: Properties which return by reference cannot have set accessors + // ref object PC { get => throw null; set { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(12, 49), + // (13,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PD { get => throw null; init { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PD").WithLocation(13, 25), + // (13,49): error CS8147: Properties which return by reference cannot have set accessors + // ref object PD { get => throw null; init { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(13, 49), + // (14,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PE { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PE").WithLocation(14, 25), + // (14,35): error CS8147: Properties which return by reference cannot have set accessors + // ref object PE { get; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(14, 35), + // (15,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PF { get; init; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PF").WithLocation(15, 25), + // (15,35): error CS8147: Properties which return by reference cannot have set accessors + // ref object PF { get; init; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(15, 35), + // (16,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PG { get; set { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PG").WithLocation(16, 25), + // (16,35): error CS8147: Properties which return by reference cannot have set accessors + // ref object PG { get; set { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(16, 35), + // (17,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PH { get; init { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PH").WithLocation(17, 25), + // (17,35): error CS8147: Properties which return by reference cannot have set accessors + // ref object PH { get; init { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(17, 35), + // (18,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PI { set { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PI").WithLocation(18, 25), + // (18,25): error CS8146: Properties which return by reference must have a get accessor + // ref object PI { set { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PI").WithLocation(18, 25), + // (19,25): error CS8145: Auto-implemented properties cannot return by reference + // ref object PJ { init { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PJ").WithLocation(19, 25), + // (19,25): error CS8146: Properties which return by reference must have a get accessor + // ref object PJ { init { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PJ").WithLocation(19, 25)); + } + + [Theory] + [CombinatorialData] + public void RefReturning_02(bool useStruct, bool useRefReadOnly) + { + string type = useStruct ? "struct" : "class"; + string refModifier = useRefReadOnly ? "ref readonly" : "ref "; + string source = $$""" + {{type}} S + { + static {{refModifier}} object P1 { get; } + static {{refModifier}} object P2 { get => ref field; } + static {{refModifier}} object P3 { get => ref field; set; } + static {{refModifier}} object P5 { get => ref field; set { } } + static {{refModifier}} object P7 { get => throw null; } + static {{refModifier}} object P8 { get => throw null; set; } + static {{refModifier}} object PC { get => throw null; set { _ = field; } } + static {{refModifier}} object PE { get; set; } + static {{refModifier}} object PG { get; set { } } + static {{refModifier}} object PI { set { _ = field; } } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (3,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object P1 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(3, 32), + // (4,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object P2 { get => ref field; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(4, 32), + // (5,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object P3 { get => ref field; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P3").WithLocation(5, 32), + // (5,55): error CS8147: Properties which return by reference cannot have set accessors + // static ref object P3 { get => ref field; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 55), + // (6,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object P5 { get => ref field; set { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P5").WithLocation(6, 32), + // (6,55): error CS8147: Properties which return by reference cannot have set accessors + // static ref object P5 { get => ref field; set { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(6, 55), + // (8,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object P8 { get => throw null; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P8").WithLocation(8, 32), + // (8,56): error CS8147: Properties which return by reference cannot have set accessors + // static ref object P8 { get => throw null; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(8, 56), + // (9,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object PC { get => throw null; set { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PC").WithLocation(9, 32), + // (9,56): error CS8147: Properties which return by reference cannot have set accessors + // static ref object PC { get => throw null; set { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(9, 56), + // (10,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object PE { get; set; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PE").WithLocation(10, 32), + // (10,42): error CS8147: Properties which return by reference cannot have set accessors + // static ref object PE { get; set; } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(10, 42), + // (11,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object PG { get; set { } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PG").WithLocation(11, 32), + // (11,42): error CS8147: Properties which return by reference cannot have set accessors + // static ref object PG { get; set { } } + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(11, 42), + // (12,32): error CS8145: Auto-implemented properties cannot return by reference + // static ref object PI { set { _ = field; } } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PI").WithLocation(12, 32), + // (12,32): error CS8146: Properties which return by reference must have a get accessor + // static ref object PI { set { _ = field; } } + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PI").WithLocation(12, 32)); + } + + [Fact] + public void PassByReference_01() + { + string source = $$""" + struct S + { + object P1 => F(ref field); + readonly object P2 => F(ref field); + object P3 { readonly get { return F(ref field); } set { } } + readonly object P4 { init { F(ref field); } } + static object F(ref object o) => o; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (4,33): error CS0192: A readonly field cannot be used as a ref or out value (except in a constructor) + // readonly object P2 => F(ref field); + Diagnostic(ErrorCode.ERR_RefReadonly, "field").WithLocation(4, 33), + // (5,45): error CS1605: Cannot use 'field' as a ref or out value because it is read-only + // object P3 { readonly get { return F(ref field); } set { } } + Diagnostic(ErrorCode.ERR_RefReadonlyLocal, "field").WithArguments("field").WithLocation(5, 45)); + } + + [Fact] + public void PassByReference_02() + { + string source = $$""" + struct S + { + object P1 => F(in field); + readonly object P2 => F(in field); + object P3 { readonly get { return F(in field); } set { } } + readonly object P4 { init { F(in field); } } + static object F(in object o) => o; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void PassByReference_03() + { + string source = $$""" + struct S + { + object P1 => F(field); + readonly object P2 => F(field); + object P3 { readonly get { return F(field); } set { } } + readonly object P4 { init { F(field); } } + static object F(in object o) => o; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void PassByReference_04() + { + string source = $$""" + struct S + { + object P1 => field; + readonly object P2 => field; + object P3 { readonly get => field; set { } } + readonly object P4 { init { field = value; } } + S(bool unused) + { + F(ref P1); + F(ref P2); + F(ref P3); + F(ref P4); + } + static object F(ref object o) => o; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (9,15): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value + // F(ref P1); + Diagnostic(ErrorCode.ERR_RefProperty, "P1").WithLocation(9, 15), + // (10,15): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value + // F(ref P2); + Diagnostic(ErrorCode.ERR_RefProperty, "P2").WithLocation(10, 15), + // (11,15): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value + // F(ref P3); + Diagnostic(ErrorCode.ERR_RefProperty, "P3").WithLocation(11, 15), + // (12,15): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value + // F(ref P4); + Diagnostic(ErrorCode.ERR_RefProperty, "P4").WithLocation(12, 15)); + } + + [Fact] + public void PassByReference_05() + { + string source = $$""" + struct S1 + { + ref object P1 => ref F1(ref field); + static ref object F1(ref object o) => ref o; + } + readonly struct S2 + { + ref readonly object P2 => ref F2(in field); + static ref readonly object F2(in object o) => ref o; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (3,16): error CS8145: Auto-implemented properties cannot return by reference + // ref object P1 => ref F1(ref field); + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(3, 16), + // (8,25): error CS8145: Auto-implemented properties cannot return by reference + // ref readonly object P2 => ref F2(in field); + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P2").WithLocation(8, 25)); + } + + [Theory] + [CombinatorialData] + public void Nullability_01(bool useNullableAnnotation) + { + string annotation = useNullableAnnotation ? "?" : " "; + string source = $$""" + #nullable enable + class C + { + object{{annotation}} P1 => field; + object{{annotation}} P2 { get => field; } + object{{annotation}} P3 { set { field = value; } } + object{{annotation}} P4 { get => field; set { field = value; } } + } + """; + var comp = CreateCompilation(source); + if (useNullableAnnotation) + { + comp.VerifyEmitDiagnostics(); + } + else + { + comp.VerifyEmitDiagnostics( + // (4,13): warning CS9264: Non-nullable property 'P1' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // object P1 => field; + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "P1").WithArguments("property", "P1").WithLocation(4, 13), + // (5,13): warning CS9264: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // object P2 { get => field; } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "P2").WithArguments("property", "P2").WithLocation(5, 13), + // (6,13): warning CS9264: Non-nullable property 'P3' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // object P3 { set { field = value; } } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "P3").WithArguments("property", "P3").WithLocation(6, 13), + // (7,13): warning CS9264: Non-nullable property 'P4' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // object P4 { get => field; set { field = value; } } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "P4").WithArguments("property", "P4").WithLocation(7, 13)); + } + } + + [Fact] + public void Nullability_02() + { + string source = """ + #nullable enable + class C + { + string? P1 => field.ToString(); // 1 + string P2 => field.ToString(); // 2 + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (4,19): warning CS8602: Dereference of a possibly null reference. + // string? P1 => field.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "field").WithLocation(4, 19), + // (5,12): warning CS9264: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // string P2 => field.ToString(); + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "P2").WithArguments("property", "P2").WithLocation(5, 12)); + } + + [Fact] + public void Nullability_03() + { + string source = """ + #nullable enable + class C + { + string P + { + get + { + if (field.Length == 0) return field; + if (field is null) return field; // 1 + return field; + } + } + C() { P = ""; } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (9,39): warning CS8603: Possible null reference return. + // if (field is null) return field; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(9, 39)); + } + + [Fact] + public void Nullability_04() + { + string source = """ + #nullable enable + class C + { + string? P + { + set + { + if (value is null) + { + field = value; + field.ToString(); // 1 + return; + } + field = value; + field.ToString(); + } + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (11,17): warning CS8602: Dereference of a possibly null reference. + // field.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "field").WithLocation(11, 17)); + } + + // NullableWalker assumes the backing field is used exactly as in an auto-property, + // (e.g. { get { return field; } set { field = value; } }), and therefore the inferred nullability + // of the initializer value can be used directly for the inferred nullability of the property. + [Theory] + [CombinatorialData] + public void Nullability_05(bool useNullableAnnotation, bool initializeNotNull, bool useInit) + { + string setter = useInit ? "init" : "set "; + string annotation = useNullableAnnotation ? "?" : " "; + string initializerValue = initializeNotNull ? "NotNull()" : "MaybeNull()"; + string source = $$""" + #nullable enable + class C + { + object{{annotation}} P1 { get; } = {{initializerValue}}; + object{{annotation}} P2 { get => field; } = {{initializerValue}}; + object{{annotation}} P3 { get => field; {{setter}}; } = {{initializerValue}}; + object{{annotation}} P4 { get; {{setter}}; } = {{initializerValue}}; + object{{annotation}} P5 { get; {{setter}} { field = value; } } = {{initializerValue}}; + object{{annotation}} P6 { {{setter}} { field = value; } } = {{initializerValue}}; + static object NotNull() => new object(); + static object? MaybeNull() => new object(); + C() + { + P1.ToString(); + P2.ToString(); + P3.ToString(); + P4.ToString(); + P5.ToString(); + } + } + """; + var comp = CreateCompilation(source, targetFramework: GetTargetFramework(useInit)); + if (initializeNotNull) + { + comp.VerifyEmitDiagnostics(); + } + else if (useNullableAnnotation) + { + comp.VerifyEmitDiagnostics( + // (14,9): warning CS8602: Dereference of a possibly null reference. + // P1.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P1").WithLocation(14, 9), + // (15,9): warning CS8602: Dereference of a possibly null reference. + // P2.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P2").WithLocation(15, 9), + // (16,9): warning CS8602: Dereference of a possibly null reference. + // P3.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P3").WithLocation(16, 9), + // (17,9): warning CS8602: Dereference of a possibly null reference. + // P4.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P4").WithLocation(17, 9), + // (18,9): warning CS8602: Dereference of a possibly null reference. + // P5.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P5").WithLocation(18, 9)); + } + else + { + comp.VerifyEmitDiagnostics( + // (4,27): warning CS8601: Possible null reference assignment. + // object P1 { get; } = MaybeNull(); + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "MaybeNull()").WithLocation(4, 27), + // (5,36): warning CS8601: Possible null reference assignment. + // object P2 { get => field; } = MaybeNull(); + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "MaybeNull()").WithLocation(5, 36), + // (6,42): warning CS8601: Possible null reference assignment. + // object P3 { get => field; set ; } = MaybeNull(); + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "MaybeNull()").WithLocation(6, 42), + // (7,33): warning CS8601: Possible null reference assignment. + // object P4 { get; set ; } = MaybeNull(); + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "MaybeNull()").WithLocation(7, 33), + // (8,51): warning CS8601: Possible null reference assignment. + // object P5 { get; set { field = value; } } = MaybeNull(); + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "MaybeNull()").WithLocation(8, 51), + // (9,46): warning CS8601: Possible null reference assignment. + // object P6 { set { field = value; } } = MaybeNull(); + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "MaybeNull()").WithLocation(9, 46), + // (14,9): warning CS8602: Dereference of a possibly null reference. + // P1.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P1").WithLocation(14, 9), + // (15,9): warning CS8602: Dereference of a possibly null reference. + // P2.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P2").WithLocation(15, 9), + // (16,9): warning CS8602: Dereference of a possibly null reference. + // P3.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P3").WithLocation(16, 9), + // (17,9): warning CS8602: Dereference of a possibly null reference. + // P4.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P4").WithLocation(17, 9), + // (18,9): warning CS8602: Dereference of a possibly null reference. + // P5.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P5").WithLocation(18, 9)); + } + } + + [Fact] + public void Nullability_06() + { + // Initialize by assigning in constructor + var source = """ + #nullable enable + + class C + { + public string Prop { get => field; set => field = value; } + public C() + { + Prop = "a"; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_06_GetterOnly() + { + // Initialize by assigning to field in constructor (due to absence of setter) + var source = """ + #nullable enable + + class C + { + public string Prop { get => field; } + public C() + { + Prop = "a"; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_06_NotInitialized() + { + var source = """ + #nullable enable + + class C + { + public string Prop { get => field; set => field = value; } + public C() { } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public C() { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(6, 12)); + } + + [Fact] + public void Nullability_06_NotInitialized_GetterOnly() + { + var source = """ + #nullable enable + + class C + { + public string Prop { get => field; } + public C() { } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public C() { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(6, 12)); + } + + [Fact] + public void Nullability_06_Static() + { + // Initialize by assigning in constructor + var source = """ + #nullable enable + + class C + { + public static string Prop { get => field; set => field = value; } + static C() + { + Prop = "a"; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_06_Static_GetterOnly() + { + // Initialize by assigning to field in constructor (due to absence of setter) + var source = """ + #nullable enable + + class C + { + public static string Prop { get => field; } + static C() + { + Prop = "a"; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_06_Static_NotInitialized() + { + var source = """ + #nullable enable + + class C + { + public static string Prop { get => field; set => field = value; } + static C() { } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // static C() { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(6, 12)); + } + + [Fact] + public void Nullability_06_Static_NotInitialized_GetterOnly() + { + var source = """ + #nullable enable + + class C + { + public static string Prop { get => field; } + static C() { } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (6,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // static C() { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(6, 12)); + } + + [Fact] + public void Nullability_07() + { + // Initialize using a property initializer + var source = """ + #nullable enable + + class C + { + public string Prop { get => field; set => field = value; } = "a"; + public C() + { + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_07_GetterOnly() + { + // Initialize using a property initializer + var source = """ + #nullable enable + + class C + { + public string Prop { get => field; } = "a"; + public C() + { + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_08() + { + // Initialize using a property initializer and read it in the constructor + var source = """ + #nullable enable + + class C + { + public string Prop { get => field; set => field = value; } = "a"; + public C() + { + Prop.ToString(); + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_08_GetterOnly() + { + // Initialize using a property initializer and read it in the constructor + var source = """ + #nullable enable + + class C + { + public string Prop { get => field; } = "a"; + public C() + { + Prop.ToString(); + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_09() + { + // MaybeNull on the field + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: MaybeNull] + public string Prop + { + get => field; // 1 + set => field = value; + } + public C() + { + } + } + """; + + var comp = CreateCompilation([source, MaybeNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (9,16): warning CS8603: Possible null reference return. + // get => field; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(9, 16)); + } + + [Fact] + public void Nullability_10() + { + // MaybeNull on the field and assign null to it + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: MaybeNull] + public string Prop + { + get => field; // 1 + set => field = null; // 2 + } + public C() + { + } + } + """; + + var comp = CreateCompilation([source, MaybeNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (9,16): warning CS8603: Possible null reference return. + // get => field; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(9, 16), + // (10,24): warning CS8625: Cannot convert null literal to non-nullable reference type. + // set => field = null; // 2 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 24)); + } + + [Fact] + public void Nullability_11() + { + // MaybeNull on the field. Use an auto-getter. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: MaybeNull] + public string Prop + { + get; + set => field = value; + } + public C() + { + } + } + """; + + var comp = CreateCompilation([source, MaybeNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_12() + { + // MaybeNull+AllowNull on the field. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: MaybeNull, AllowNull] + public string Prop + { + get => field; // 1 + set => field = value; + } + public C() + { + } + } + """; + + var comp = CreateCompilation([source, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (9,16): warning CS8603: Possible null reference return. + // get => field; + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(9, 16)); + } + + [Fact] + public void Nullability_13() + { + // MaybeNull+AllowNull on the field, and assign null to the field. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: MaybeNull, AllowNull] + public string Prop + { + get => field; // 1 + set => field = null; + } + public C() + { + } + } + """; + + var comp = CreateCompilation([source, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (9,16): warning CS8603: Possible null reference return. + // get => field; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(9, 16)); + } + + [Fact] + public void Nullability_13_Prop() + { + // MaybeNull+AllowNull on the property, and assign null to the field. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [MaybeNull, AllowNull] + public string Prop + { + get => field; + set => field = null; // 1 + } + public C() // 2 + { + } + } + """; + + var comp = CreateCompilation([source, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (10,24): warning CS8625: Cannot convert null literal to non-nullable reference type. + // set => field = null; // 1 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 24), + // (12,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public C() // 2 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(12, 12)); + } + + [Fact] + public void Nullability_13_AllowNullProp() + { + // AllowNull only on the property, and assign null to the field. + // Constructor warning occurs because property `[AllowNull]` doesn't affect field initial state. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [AllowNull] + public string Prop + { + get => field; + set => field = null; // 1 + } + public C() // 2 + { + } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (10,24): warning CS8625: Cannot convert null literal to non-nullable reference type. + // set => field = null; // 1 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 24), + // (12,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public C() // 2 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(12, 12)); + } + + [Fact] + public void Nullability_13_AllowNullProp_AssignProp() + { + // AllowNull only on the property, and assign null to the field. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [AllowNull] + public string Prop + { + get => field; + set => field = null; // 1 + } + public C() + { + Prop = null; + } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (10,24): warning CS8625: Cannot convert null literal to non-nullable reference type. + // set => field = null; // 1 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 24)); + } + + [Fact] + public void Nullability_13_AllowNullProp_AssignValue() + { + // AllowNull only on the property, and assign 'value' to the field. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [AllowNull] + public string Prop + { + get => field; + set => field = value; // 1 + } + public C() // 2 + { + } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (10,24): warning CS8601: Possible null reference assignment. + // set => field = value; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(10, 24), + // (12,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public C() // 2 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(12, 12)); + } + + [Fact] + public void Nullability_13_AllowNullProp_AutoSetter() + { + // AllowNull only on the property + // https://github.com/dotnet/roslyn/issues/50244: Should auto accessor bodies be nullable analyzed? + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [AllowNull] + public string Prop + { + get => field; set; + } + public C() // 1 + { + } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (11,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public C() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(11, 12)); + } + + [Fact] + public void Nullability_13_AllowNullProp_NoSetter() + { + // AllowNull only on the property + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [AllowNull] + public string Prop + { + get => field; + } + public C() // 1 + { + } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (11,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public C() // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(11, 12)); + } + + [Theory] + [InlineData("")] + [InlineData("set;")] + public void Nullability_13_AllowNullProp_Initializer(string setAccessor) + { + // AllowNull only on the property and assign null + // A warning is reported because field keyword is being used, the field itself does not allow null, and the `= null` represents a direct assignment of the backing field. + var source = $$""" + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [AllowNull] + public string Prop + { + get => field; + {{setAccessor}} + } = null; // 1 + + public C() + { + } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (11,9): warning CS8625: Cannot convert null literal to non-nullable reference type. + // } = null; // 1 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(11, 9)); + } + + [Fact] + public void Nullability_13_AllowNullProp_Initializer_ManualSetter() + { + // AllowNull only on the property and assign null + // A warning is reported because field keyword is being used, the field itself does not allow null, and the `= null` represents a direct assignment of the backing field. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [AllowNull] + public string Prop + { + get => field; + set => field = value; // 1 + } = null; // 2 + + public C() + { + } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (10,24): warning CS8601: Possible null reference assignment. + // set => field = value; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(10, 24), + // (11,9): warning CS8625: Cannot convert null literal to non-nullable reference type. + // } = null; // 2 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(11, 9)); + } + + [Fact] + public void Nullability_13_ReadProp() + { + // MaybeNull+AllowNull on the property, and dereference the field, and write the value to the field. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [MaybeNull, AllowNull] + public string Prop + { + get => field.ToString(); + set => field = value; // 1 + } + public C() // 2 + { + } + } + """; + + var comp = CreateCompilation([source, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (10,24): warning CS8601: Possible null reference assignment. + // set => field = value; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(10, 24), + // (12,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public C() // 2 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(12, 12)); + } + + [Fact] + public void Nullability_14() + { + // AllowNull on the field, and assign null to the field. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: AllowNull] + public string Prop + { + get => field; + set => field = null; + } + public C() + { + } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_15() + { + // MaybeNull+AllowNull on the field, and getter has an attribute list. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class Attr : System.Attribute { } + + class C + { + [field: MaybeNull, AllowNull] + public string Prop + { + [Attr] + get => field; // 1 + set => field = value; + } + public C() + { + } + } + """; + + var comp = CreateCompilation([source, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (12,16): warning CS8603: Possible null reference return. + // get => field; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(12, 16)); + } + + [Fact] + public void Nullability_16() + { + // NotNull property using field keyword + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [NotNull] + public string? Prop => field; // 1 + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (7,28): warning CS8603: Possible null reference return. + // public string? Prop => field; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(7, 28)); + } + + [Fact] + public void Nullability_17() + { + // NotNull property auto-implemented + // This does not warn in the shipped impl + // https://github.com/dotnet/roslyn/issues/50244: should auto-accessor bodies be nullable analyzed? + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [NotNull] + public string? Prop { get; } + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_18() + { + // NotNull+DisallowNull property using field keyword + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [NotNull, DisallowNull] + public string? Prop => field; // 1 + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition, DisallowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (7,28): warning CS8603: Possible null reference return. + // public string? Prop => field; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(7, 28)); + } + + [Fact] + public void Nullability_19() + { + // NotNull on field with auto-getter + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: NotNull] + public string? Prop { get; } + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_20() + { + // NotNull on field with auto-getter and manual setter + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: NotNull] + public string? Prop { get; set => field = value; } + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (7,20): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public string? Prop { get; set => field = value; } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(7, 20)); + } + + [Fact] + public void Nullability_20_ManualGetter_AutoSetter() + { + // NotNull on field with manual getter and auto-setter + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: NotNull] + public string? Prop { get => field; set; } + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (7,20): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public string? Prop { get; set => field = value; } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop").WithArguments("property", "Prop").WithLocation(7, 20)); + } + + [Fact] + public void Nullability_20_ManualGetter_AutoSetter_NullInitializer() + { + // NotNull on field with manual getter and auto-setter and null initializer + // No diagnostic is expected here as the field's nullability+attrs is equivalent to `[AllowNull] string`--so, assigning null to it actually puts it into a non-null state. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: NotNull] + public string? Prop { get => field; set; } = null; + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_20_ManualGetter_AutoSetter_NotNullInitializer() + { + // NotNull on field with manual getter and auto-setter and non-null initializer + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: NotNull] + public string? Prop { get => field; set; } = "a"; + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_20_ManualGetter_AutoSetter_NotNullInitializer_NullTest() + { + // NotNull on field with manual getter and auto-setter and non-null initializer and null test+throw in constructor + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: NotNull] + public string? Prop { get => field; set; } = "a"; + + public C() + { + if (Prop is null) + throw null!; + } + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_20_ManualGetter_AutoSetter_NullTest() + { + // NotNull on field with manual getter and auto-setter and null test+throw in constructor + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: NotNull] + public string? Prop { get => field; set; } + + public C() + { + if (Prop is null) + throw null!; + } + } + """; + + var comp = CreateCompilation([source, NotNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_21() + { + // DisallowNull on field with auto-getter + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: DisallowNull] + public string? Prop { get; } + } + """; + + var comp = CreateCompilation([source, DisallowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_22() + { + // DisallowNull on field with auto-getter and manual setter + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: DisallowNull] + public string? Prop + { + get; + set => field = value; // 1 + } + } + """; + + var comp = CreateCompilation([source, DisallowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (10,24): warning CS8601: Possible null reference assignment. + // set => field = value; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(10, 24)); + } + + [Fact] + public void Nullability_23() + { + // AllowNull on field with auto-getter and manual setter + // AllowNull on fields/properties by itself suppresses constructor initialization warnings + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: AllowNull] + public string Prop + { + get; + set => field = value; + } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_24() + { + // AllowNull on field with fully auto property + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: AllowNull] + public string Prop { get; set; } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (7,19): warning CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public string Prop { get; set; } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Prop").WithArguments("property", "Prop").WithLocation(7, 19)); + } + + [Fact] + public void Nullability_25() + { + // AllowNull on field, assign in object initializer + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: AllowNull] + public string Prop { get => field; set; } + + public void M() + { + new C() + { + Prop = null + }; + } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (13,20): warning CS8625: Cannot convert null literal to non-nullable reference type. + // Prop = null + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(13, 20)); + } + + [Fact] + public void Nullability_26() + { + // AllowNull on field, assign in object initializer within constructor + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: AllowNull] + public string Prop { get => field; set; } + + public C() { } + public C(bool ignored) + { + new C() + { + Prop = null + }; + } + } + """; + + var comp = CreateCompilation([source, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (14,20): warning CS8625: Cannot convert null literal to non-nullable reference type. + // Prop = null + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(14, 20)); + } + + [Fact] + public void Nullability_27() + { + // DisallowNull on field, assign null in property initializer + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: DisallowNull] + public string? Prop { get => field; } = null; // 1 + + public C() { } + } + """; + + var comp = CreateCompilation([source, DisallowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (7,45): warning CS8625: Cannot convert null literal to non-nullable reference type. + // public string? Prop { get => field; } = null; // 1 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 45)); + } + + [Fact] + public void Nullability_27_AutoProp() + { + // DisallowNull on field, assign null in property initializer, field keyword is not used + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: DisallowNull] + public string? Prop { get; } = null; + + public C() { } + } + """; + + var comp = CreateCompilation([source, DisallowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_28() + { + // required property using field keyword + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + public required string Prop { get => field; set => field = value; } + + [SetsRequiredMembers] + public C() + { + } + } + """; + + var comp = CreateCompilation([source, RequiredMemberAttribute, CompilerFeatureRequiredAttribute, SetsRequiredMembersAttribute]); + comp.VerifyEmitDiagnostics( + // (9,12): warning CS9264: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public C() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "Prop").WithLocation(9, 12)); + } + + [Fact] + public void Nullability_29() + { + // required property using field keyword and nullable field + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: MaybeNull, AllowNull] + public required string Prop + { + get => field; + set => field = value; + } + + [SetsRequiredMembers] + public C() + { + } + } + """; + + var comp = CreateCompilation([source, RequiredMemberAttribute, CompilerFeatureRequiredAttribute, SetsRequiredMembersAttribute, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (9,16): warning CS8603: Possible null reference return. + // get => field; + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(9, 16)); + } + + [Fact] + public void Nullability_30_NonNullableField() + { + // chained constructor accessing a required property, which is field backed. + var source = """ + #nullable enable + + class C + { + public required string Prop + { + get => field; + set => field = value; + } + + public C(bool ignored) { } + public C() : this(false) + { + Prop.ToString(); + } + } + """; + + var comp = CreateCompilation([source, RequiredMemberAttribute, CompilerFeatureRequiredAttribute, SetsRequiredMembersAttribute, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (14,9): warning CS8602: Dereference of a possibly null reference. + // Prop.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop").WithLocation(14, 9)); + } + + [Fact] + public void Nullability_30_NullableAttributedField() + { + // chained constructor accessing a required property, which is field backed, and field has MaybeNull, AllowNull. + var source = """ + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + [field: MaybeNull, AllowNull] + public required string Prop + { + get => field; + set => field = value; + } + + public C(bool ignored) { } + public C() : this(false) + { + Prop.ToString(); + } + } + """; + + var comp = CreateCompilation([source, RequiredMemberAttribute, CompilerFeatureRequiredAttribute, SetsRequiredMembersAttribute, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (9,16): warning CS8603: Possible null reference return. + // get => field; + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(9, 16), + // (16,9): warning CS8602: Dereference of a possibly null reference. + // Prop.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop").WithLocation(16, 9)); + } + + [Theory] + [InlineData(""" + #nullable enable + #nullable disable warnings + """)] + [InlineData("#nullable enable annotations")] + public void Nullability_Suppression(string nullableDirective) + { + // new initialization warning is suppressed by nullable directives + var source = $$""" + {{nullableDirective}} + + class C + { + public string Prop1 { get => field; set => field = value; } + public string Prop2 { get; set; } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact] + public void Nullability_StaticMismatch_01() + { + // instance constructors do not share a slot between static property and backing field + var source = $$""" + #nullable enable + + class C + { + public static string Prop1 { get; set; } = null; // 1 + public static string Prop2 { get => field; set => field = value; } = null; // 2 + + public C() + { + Prop1.ToString(); + Prop2.ToString(); + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,48): warning CS8625: Cannot convert null literal to non-nullable reference type. + // public static string Prop1 { get; set; } = null; // 1 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(5, 48), + // (6,74): warning CS8625: Cannot convert null literal to non-nullable reference type. + // public static string Prop2 { get => field; set => field = value; } = null; // 2 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(6, 74)); + } + + [Fact] + public void Nullability_StaticMismatch_02() + { + // instance constructors do not share a slot between field-like event and event field + var source = $$""" + #nullable enable + + class C + { + public static event System.Action E = null; // 1 + public C() + { + E.Invoke(); + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,43): warning CS8625: Cannot convert null literal to non-nullable reference type. + // public static event System.Action E = null; + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(5, 43)); + } + + [Fact] + public void Nullability_StaticMismatch_03() + { + // instance constructors do not share a slot between field-like event and event field + var source = $$""" + #nullable enable + + class C + { + public static event System.Action E; // 1 + public C(bool b) + { + if (b) + { + E = null; // 2 + E.Invoke(); // 3 + } + + if (b) + { + E = () => { }; + E.Invoke(); + } + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,39): warning CS8618: Non-nullable event 'E' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the event as nullable. + // public static event System.Action E; // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "E").WithArguments("event", "E").WithLocation(5, 39), + // (10,17): warning CS8625: Cannot convert null literal to non-nullable reference type. + // E = null; // 2 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 17), + // (11,13): warning CS8602: Dereference of a possibly null reference. + // E.Invoke(); // 3 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "E").WithLocation(11, 13)); + } + + [Fact] + public void Nullability_LazyInitialized() + { + // property is initialized upon access + var source = $$""" + #nullable enable + using System.Diagnostics.CodeAnalysis; + + class C + { + public string Prop1 => field ??= "a"; // 1 + + [field: MaybeNull, AllowNull] + public string Prop2 => field ??= "a"; + } + """; + + var comp = CreateCompilation([source, MaybeNullAttributeDefinition, AllowNullAttributeDefinition]); + comp.VerifyEmitDiagnostics( + // (6,19): warning CS9264: Non-nullable property 'Prop1' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // public string Prop1 => field ??= "a"; // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "Prop1").WithArguments("property", "Prop1").WithLocation(6, 19)); + } + + // Based on NullableReferenceTypesTests.NotNull_Property_WithAssignment + [Fact] + public void NotNull_Property_WithAssignment() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +#nullable enable + +public class C +{ + [NotNull] + string? P + { + get => field; // 1 + set => field = value; + } + void M() + { + P.ToString(); + P = null; + P.ToString(); + } +}"; + + var comp = CreateCompilation(new[] { source, NotNullAttributeDefinition }); + comp.VerifyDiagnostics( + // 0.cs(9,16): warning CS8603: Possible null reference return. + // get => field; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "field").WithLocation(9, 16)); + } + + // Based on NullableReferenceTypesTests.AllowNull_Property_WithNotNull_NoSuppression + [Fact] + public void AllowNull_Property_WithNotNull_NoSuppression() + { + // When 'field' keyword is used, nullability attributes on the property do not affect the field. + var source = +@"using System.Diagnostics.CodeAnalysis; +#nullable enable +public class COpen +{ + [AllowNull, NotNull] + public TOpen P1 + { + get => field; // 1 + set => field = value; // 2 + } = default; // 3 +} +public class CNotNull where TNotNull : notnull +{ + [AllowNull, NotNull] + public TNotNull P1 + { + get => field; + set => field = value; // 4 + } = default; // 5 +} +public class CClass where TClass : class +{ + [AllowNull, NotNull] + public TClass P2 + { + get => field; + set => field = value; // 6 + } = null; // 7 +}"; + var comp = CreateCompilation(new[] { source, AllowNullAttributeDefinition, NotNullAttributeDefinition, MaybeNullAttributeDefinition }); + comp.VerifyDiagnostics( + // 0.cs(8,16): warning CS8607: A possible null value may not be used for a type marked with [NotNull] or [DisallowNull] + // get => field; // 1 + Diagnostic(ErrorCode.WRN_DisallowNullAttributeForbidsMaybeNullAssignment, "field").WithLocation(8, 16), + // 0.cs(9,24): warning CS8601: Possible null reference assignment. + // set => field = value; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(9, 24), + // 0.cs(10,9): warning CS8601: Possible null reference assignment. + // } = default; // 3 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(10, 9), + // 0.cs(18,24): warning CS8601: Possible null reference assignment. + // set => field = value; // 4 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(18, 24), + // 0.cs(19,9): warning CS8601: Possible null reference assignment. + // } = default; // 5 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(19, 9), + // 0.cs(27,24): warning CS8601: Possible null reference assignment. + // set => field = value; // 6 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(27, 24), + // 0.cs(28,9): warning CS8625: Cannot convert null literal to non-nullable reference type. + // } = null; // 7 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(28, 9)); + } + + // Based on NullableReferenceTypesTests.AllowNull_Property_InDeconstructionAssignment + [Fact] + public void AllowNull_Property_InDeconstructionAssignment() + { + var source = +@"using System.Diagnostics.CodeAnalysis; +#nullable enable +public class C +{ + [AllowNull] public C P + { + get => field; + set => field = value; // 1 + } = null; // 2 +} +class Program +{ + void M(C c) + { + (c.P, _) = (null, 1); + c.P.ToString(); + + ((c.P, _), _) = ((null, 1), 2); + c.P.ToString(); + + (c.P, _) = this; + c.P.ToString(); + + ((_, c.P), _) = (this, 1); + c.P.ToString(); + } + void Deconstruct(out C? x, out C? y) => throw null!; +}"; + var comp = CreateCompilation(new[] { source, AllowNullAttributeDefinition }); + comp.VerifyDiagnostics( + // 0.cs(8,24): warning CS8601: Possible null reference assignment. + // set => field = value; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(8, 24), + // 0.cs(9,9): warning CS8625: Cannot convert null literal to non-nullable reference type. + // } = null; // 2 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(9, 9)); + } + + // Based on NullableReferenceTypesTests.MaybeNullT_24 + [Fact] + public void MaybeNullT_24() + { + var source = +@"#nullable enable +using System.Diagnostics.CodeAnalysis; +class C +{ + [MaybeNull] + T P1 + { + get => field; + } = default; // 1 + + [AllowNull] + T P2 + { + get => field; + } = default; // 2 + + [MaybeNull, AllowNull] + T P3 + { + get => field; + } = default; // 3 + + [MaybeNull] + T P4 + { + get => field; + set => field = value; + } = default; // 4 + + [AllowNull] + T P5 + { + get => field; + set => field = value; // 5 + } = default; // 6 + + [MaybeNull, AllowNull] + T P6 + { + get => field; + set => field = value; // 7 + } = default; // 8 + + C([AllowNull]T t) + { + P1 = t; // 9 + P2 = t; + P3 = t; + P4 = t; // 10 + P5 = t; + P6 = t; + } +}"; + var comp = CreateCompilation(new[] { source, AllowNullAttributeDefinition, MaybeNullAttributeDefinition }); + comp.VerifyDiagnostics( + // 0.cs(9,9): warning CS8601: Possible null reference assignment. + // } = default; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(9, 9), + // 0.cs(15,9): warning CS8601: Possible null reference assignment. + // } = default; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(15, 9), + // 0.cs(21,9): warning CS8601: Possible null reference assignment. + // } = default; // 3 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(21, 9), + // 0.cs(28,9): warning CS8601: Possible null reference assignment. + // } = default; // 4 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(28, 9), + // 0.cs(34,24): warning CS8601: Possible null reference assignment. + // set => field = value; // 5 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(34, 24), + // 0.cs(35,9): warning CS8601: Possible null reference assignment. + // } = default; // 6 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(35, 9), + // 0.cs(41,24): warning CS8601: Possible null reference assignment. + // set => field = value; // 7 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "value").WithLocation(41, 24), + // 0.cs(42,9): warning CS8601: Possible null reference assignment. + // } = default; // 8 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "default").WithLocation(42, 9), + // 0.cs(46,14): warning CS8601: Possible null reference assignment. + // P1 = t; // 9 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "t").WithLocation(46, 14), + // 0.cs(49,14): warning CS8601: Possible null reference assignment. + // P4 = t; // 10 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "t").WithLocation(49, 14)); + } + + // Based on RequiredMembersTests.RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_01. + [Theory] + [CombinatorialData] + public void RequiredMemberNullability_01(bool includeRequired) + { + string modifier = includeRequired ? "required" : ""; + string source = $$""" + #nullable enable + class C + { + public {{modifier}} object P1 { get; } + public {{modifier}} object P2 { get => field; } + public {{modifier}} object P3 { get => ""; } + + C(bool unused) { } + + C() : this(true) + { + P1.ToString(); + P2.ToString(); + P3.ToString(); + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + if (includeRequired) + { + comp.VerifyEmitDiagnostics( + // (4,28): error CS9034: Required member 'C.P1' must be settable. + // public required object P1 { get; } + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSettable, "P1").WithArguments("C.P1").WithLocation(4, 28), + // (5,28): error CS9034: Required member 'C.P2' must be settable. + // public required object P2 { get => field; } + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSettable, "P2").WithArguments("C.P2").WithLocation(5, 28), + // (6,28): error CS9034: Required member 'C.P3' must be settable. + // public required object P3 { get => ""; } + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSettable, "P3").WithArguments("C.P3").WithLocation(6, 28), + // (12,9): warning CS8602: Dereference of a possibly null reference. + // P1.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P1").WithLocation(12, 9), + // (13,9): warning CS8602: Dereference of a possibly null reference. + // P2.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P2").WithLocation(13, 9), + // (14,9): warning CS8602: Dereference of a possibly null reference. + // P3.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P3").WithLocation(14, 9)); + } + else + { + comp.VerifyEmitDiagnostics( + // (8,5): warning CS9264: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // C(bool unused) { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "P2").WithLocation(8, 5), + // (8,5): warning CS8618: Non-nullable property 'P1' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // C(bool unused) { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("property", "P1").WithLocation(8, 5)); + } + } + + // Based on RequiredMembersTests.RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_01. + [Theory] + [CombinatorialData] + public void RequiredMemberNullability_02(bool includeRequired) + { + string modifier = includeRequired ? "required" : ""; + string source = $$""" + #nullable enable + class C + { + public {{modifier}} object P4 { get; set; } + public {{modifier}} object P5 { get => field; set; } + public {{modifier}} object P6 { get => field; set { field = value; } } + public {{modifier}} object P7 { get => ""; set { } } + + C(bool unused) { } + + C() : this(true) + { + P4.ToString(); + P5.ToString(); + P6.ToString(); + P7.ToString(); + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + if (includeRequired) + { + comp.VerifyEmitDiagnostics( + // (13,9): warning CS8602: Dereference of a possibly null reference. + // P4.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P4").WithLocation(13, 9), + // (14,9): warning CS8602: Dereference of a possibly null reference. + // P5.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P5").WithLocation(14, 9), + // (15,9): warning CS8602: Dereference of a possibly null reference. + // P6.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P6").WithLocation(15, 9), + // (16,9): warning CS8602: Dereference of a possibly null reference. + // P7.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "P7").WithLocation(16, 9)); + } + else + { + comp.VerifyEmitDiagnostics( + // (9,5): warning CS9264: Non-nullable property 'P5' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // C(bool unused) { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "P5").WithLocation(9, 5), + // (9,5): warning CS9264: Non-nullable property 'P6' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier, or declaring the property as nullable, or adding '[field: MaybeNull, AllowNull]' attributes. + // C(bool unused) { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableBackingField, "C").WithArguments("property", "P6").WithLocation(9, 5), + // (9,5): warning CS8618: Non-nullable property 'P4' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // C(bool unused) { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("property", "P4").WithLocation(9, 5)); + } + } + + [Theory] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + public void AutoPropertyMustHaveGetAccessor(bool useStatic, bool useInit) + { + string modifier = useStatic ? "static" : " "; + string setter = useInit ? "init" : "set"; + string source = $$""" + class C + { + {{modifier}} object P02 { {{setter}}; } + {{modifier}} object P03 { {{setter}} { } } + {{modifier}} object P04 { {{setter}} { field = value; } } + {{modifier}} object P11 { get; } + {{modifier}} object P12 { get; {{setter}}; } + {{modifier}} object P13 { get; {{setter}} { } } + {{modifier}} object P14 { get; {{setter}} { field = value; } } + {{modifier}} object P21 { get => field; } + {{modifier}} object P22 { get => field; {{setter}}; } + {{modifier}} object P23 { get => field; {{setter}} { } } + {{modifier}} object P24 { get => field; {{setter}} { field = value; } } + {{modifier}} object P31 { get => null; } + {{modifier}} object P32 { get => null; {{setter}}; } + {{modifier}} object P33 { get => null; {{setter}} { } } + {{modifier}} object P34 { get => null; {{setter}} { field = value; } } + {{modifier}} object P41 { get { return field; } } + {{modifier}} object P42 { get { return field; } {{setter}}; } + {{modifier}} object P43 { get { return field; } {{setter}} { } } + {{modifier}} object P44 { get { return field; } {{setter}} { field = value; } } + {{modifier}} object P51 { get { return null; } } + {{modifier}} object P52 { get { return null; } {{setter}}; } + {{modifier}} object P53 { get { return null; } {{setter}} { } } + {{modifier}} object P54 { get { return null; } {{setter}} { field = value; } } + } + """; + var comp = CreateCompilation(source, targetFramework: GetTargetFramework(useInit)); + comp.VerifyEmitDiagnostics( + // (3,25): error CS8051: Auto-implemented properties must have get accessors. + // object P02 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(3, 25)); + } + + [Theory] + [CombinatorialData] + public void Override_VirtualBase_01(bool useInit) + { + string setter = useInit ? "init" : "set"; + string sourceA = $$""" + class A + { + public virtual object P1 { get; {{setter}}; } + public virtual object P2 { get; } + public virtual object P3 { {{setter}}; } + } + """; + string sourceB0 = $$""" + class B0 : A + { + public override object P1 { get; } + public override object P2 { get; } + public override object P3 { get; } + } + """; + var targetFramework = GetTargetFramework(useInit); + var comp = CreateCompilation([sourceA, sourceB0], targetFramework: targetFramework); + comp.VerifyEmitDiagnostics( + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (5,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P3 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P3").WithLocation(5, 28), + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32), + // (5,33): error CS0545: 'B0.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B0.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB1 = $$""" + class B1 : A + { + public override object P1 { get; {{setter}}; } + public override object P2 { get; {{setter}}; } + public override object P3 { get; {{setter}}; } + } + """; + comp = CreateCompilation([sourceA, sourceB1], targetFramework: targetFramework); + comp.VerifyEmitDiagnostics( + // (4,38): error CS0546: 'B1.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { get; set; } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B1.P2.{setter}", "A.P2").WithLocation(4, 38), + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32), + // (5,33): error CS0545: 'B1.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get; set; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B1.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB2 = $$""" + class B2 : A + { + public override object P1 { get => field; {{setter}} { } } + public override object P2 { get => field; {{setter}} { } } + public override object P3 { get => field; {{setter}} { } } + } + """; + comp = CreateCompilation([sourceA, sourceB2], targetFramework: targetFramework); + comp.VerifyEmitDiagnostics( + // (4,47): error CS0546: 'B2.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { get => field; set { } } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B2.P2.{setter}", "A.P2").WithLocation(4, 47), + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32), + // (5,33): error CS0545: 'B2.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get => field; set { } } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B2.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB3 = $$""" + class B3 : A + { + public override object P1 { get => field; } + public override object P2 { get => field; } + public override object P3 { get => field; } + } + """; + comp = CreateCompilation([sourceA, sourceB3], targetFramework: targetFramework); + comp.VerifyEmitDiagnostics( + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { get => field; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (5,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P3 { get => field; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P3").WithLocation(5, 28), + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32), + // (5,33): error CS0545: 'B3.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get => field; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B3.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB4 = $$""" + class B4 : A + { + public override object P1 { {{setter}} { field = value; } } + public override object P2 { {{setter}} { field = value; } } + public override object P3 { {{setter}} { field = value; } } + } + """; + comp = CreateCompilation([sourceA, sourceB4], targetFramework: targetFramework); + comp.VerifyEmitDiagnostics( + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { set { field = value; } } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (4,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P2 { set { field = value; } } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P2").WithLocation(4, 28), + // (4,33): error CS0546: 'B4.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { set { field = value; } } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B4.P2.{setter}", "A.P2").WithLocation(4, 33), + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32)); + } + + [Theory] + [CombinatorialData] + public void Override_AbstractBase_01(bool useInit) + { + string setter = useInit ? "init" : "set"; + string sourceA = $$""" + abstract class A + { + public abstract object P1 { get; {{setter}}; } + public abstract object P2 { get; } + public abstract object P3 { {{setter}}; } + } + """; + string sourceB0 = $$""" + class B0 : A + { + public override object P1 { get; } + public override object P2 { get; } + public override object P3 { get; } + } + """; + var targetFramework = GetTargetFramework(useInit); + var comp = CreateCompilation([sourceA, sourceB0], targetFramework: targetFramework); + comp.VerifyEmitDiagnostics( + // (1,7): error CS0534: 'B0' does not implement inherited abstract member 'A.P3.set' + // class B0 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B0").WithArguments("B0", $"A.P3.{setter}").WithLocation(1, 7), + // (1,7): error CS0534: 'B0' does not implement inherited abstract member 'A.P1.set' + // class B0 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B0").WithArguments("B0", $"A.P1.{setter}").WithLocation(1, 7), + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (5,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P3 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P3").WithLocation(5, 28), + // (5,33): error CS0545: 'B0.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B0.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB1 = $$""" + class B1 : A + { + public override object P1 { get; {{setter}}; } + public override object P2 { get; {{setter}}; } + public override object P3 { get; {{setter}}; } + } + """; + comp = CreateCompilation([sourceA, sourceB1], targetFramework: targetFramework); + comp.VerifyEmitDiagnostics( + // (4,38): error CS0546: 'B1.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { get; set; } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B1.P2.{setter}", "A.P2").WithLocation(4, 38), + // (5,33): error CS0545: 'B1.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get; set; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B1.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB2 = $$""" + class B2 : A + { + public override object P1 { get => field; {{setter}} { } } + public override object P2 { get => field; {{setter}} { } } + public override object P3 { get => field; {{setter}} { } } + } + """; + comp = CreateCompilation([sourceA, sourceB2], targetFramework: targetFramework); + comp.VerifyEmitDiagnostics( + // (4,47): error CS0546: 'B2.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { get => field; set { } } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B2.P2.{setter}", "A.P2").WithLocation(4, 47), + // (5,33): error CS0545: 'B2.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get => field; set { } } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B2.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB3 = $$""" + class B3 : A + { + public override object P1 { get => field; } + public override object P2 { get => field; } + public override object P3 { get => field; } + } + """; + comp = CreateCompilation([sourceA, sourceB3], targetFramework: targetFramework); + comp.VerifyEmitDiagnostics( + // (1,7): error CS0534: 'B3' does not implement inherited abstract member 'A.P3.set' + // class B3 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B3").WithArguments("B3", $"A.P3.{setter}").WithLocation(1, 7), + // (1,7): error CS0534: 'B3' does not implement inherited abstract member 'A.P1.set' + // class B3 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B3").WithArguments("B3", $"A.P1.{setter}").WithLocation(1, 7), + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { get => field; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (5,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P3 { get => field; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P3").WithLocation(5, 28), + // (5,33): error CS0545: 'B3.P3.get': cannot override because 'A.P3' does not have an overridable get accessor + // public override object P3 { get => field; } + Diagnostic(ErrorCode.ERR_NoGetToOverride, "get").WithArguments("B3.P3.get", "A.P3").WithLocation(5, 33)); + + string sourceB4 = $$""" + class B4 : A + { + public override object P1 { {{setter}} { field = value; } } + public override object P2 { {{setter}} { field = value; } } + public override object P3 { {{setter}} { field = value; } } + } + """; + comp = CreateCompilation([sourceA, sourceB4], targetFramework: targetFramework); + comp.VerifyEmitDiagnostics( + // (1,7): error CS0534: 'B4' does not implement inherited abstract member 'A.P1.get' + // class B4 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B4").WithArguments("B4", "A.P1.get").WithLocation(1, 7), + // (1,7): error CS0534: 'B4' does not implement inherited abstract member 'A.P2.get' + // class B4 : A + Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "B4").WithArguments("B4", "A.P2.get").WithLocation(1, 7), + // (3,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P1 { set { field = value; } } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(3, 28), + // (4,28): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override object P2 { set { field = value; } } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P2").WithLocation(4, 28), + // (4,33): error CS0546: 'B4.P2.set': cannot override because 'A.P2' does not have an overridable set accessor + // public override object P2 { set { field = value; } } + Diagnostic(ErrorCode.ERR_NoSetToOverride, setter).WithArguments($"B4.P2.{setter}", "A.P2").WithLocation(4, 33)); + } + + [Theory] + [CombinatorialData] + public void New_01(bool useInit) + { + string setter = useInit ? "init" : "set"; + string source = $$""" + class A + { + public virtual object P1 { get; {{setter}}; } + public virtual object P2 { get; } + public virtual object P3 { {{setter}}; } + } + class B0 : A + { + public new object P1 { get; } + public new object P2 { get; } + public new object P3 { get; } + } + class B1 : A + { + public new object P1 { get; {{setter}}; } + public new object P2 { get; {{setter}}; } + public new object P3 { get; {{setter}}; } + } + class B2 : A + { + public new object P1 { get => field; {{setter}} { } } + public new object P2 { get => field; {{setter}} { } } + public new object P3 { get => field; {{setter}} { } } + } + class B3 : A + { + public new object P1 { get => field; } + public new object P2 { get => field; } + public new object P3 { get => field; } + } + class B4 : A + { + public new object P1 { {{setter}} { field = value; } } + public new object P2 { {{setter}} { field = value; } } + public new object P3 { {{setter}} { field = value; } } + } + """; + var comp = CreateCompilation(source, targetFramework: GetTargetFramework(useInit)); + comp.VerifyEmitDiagnostics( + // (5,32): error CS8051: Auto-implemented properties must have get accessors. + // public virtual object P3 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, setter).WithLocation(5, 32)); + } + + [Theory] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + public void CompilerGeneratedAttribute(bool missingType, bool missingConstructor) + { + string source = """ + using System; + using System.Reflection; + + class C + { + public int P1 { get; } + public int P2 { get => field; } + public int P3 { set { field = value; } } + public int P4 { init { field = value; } } + } + + class Program + { + static void Main() + { + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportField(field); + } + + static void ReportField(FieldInfo field) + { + Console.Write("{0}.{1}:", field.DeclaringType.Name, field.Name); + foreach (var obj in field.GetCustomAttributes()) + Console.Write(" {0},", obj.ToString()); + Console.WriteLine(); + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + if (missingType) + { + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_CompilerGeneratedAttribute); + } + if (missingConstructor) + { + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor); + } + string expectedAttributes = (missingType || missingConstructor) ? "" : " System.Runtime.CompilerServices.CompilerGeneratedAttribute,"; + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput($$""" + C.k__BackingField:{{expectedAttributes}} + C.k__BackingField:{{expectedAttributes}} + C.k__BackingField:{{expectedAttributes}} + C.k__BackingField:{{expectedAttributes}} + """)); + } + + [Theory] + [CombinatorialData] + public void Conditional(bool useDEBUG) + { + string sourceA = """ + using System.Diagnostics; + class C + { + public static object P1 { get { M(field); return null; } set { } } + public static object P2 { get { return null; } set { M(field); } } + public object P3 { get { M(field); return null; } } + public object P4 { set { M(field); } } + public object P5 { init { M(field); } } + [Conditional("DEBUG")] + static void M( object o) { } + } + """; + string sourceB = """ + using System; + using System.Reflection; + class Program + { + static void Main() + { + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportField(field); + } + static void ReportField(FieldInfo field) + { + Console.Write("{0}.{1}:", field.DeclaringType.Name, field.Name); + foreach (var obj in field.GetCustomAttributes()) + Console.Write(" {0},", obj.ToString()); + Console.WriteLine(); + } + } + """; + var parseOptions = TestOptions.RegularNext; + if (useDEBUG) + { + parseOptions = parseOptions.WithPreprocessorSymbols("DEBUG"); + } + var verifier = CompileAndVerify( + [sourceA, sourceB], + parseOptions: parseOptions, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(""" + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + C.k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + """)); + + if (useDEBUG) + { + verifier.VerifyIL("C.P1.get", """ + { + // Code size 12 (0xc) + .maxstack 1 + IL_0000: ldsfld "object C.k__BackingField" + IL_0005: call "void C.M(object)" + IL_000a: ldnull + IL_000b: ret + } + """); + verifier.VerifyIL("C.P4.set", """ + { + // Code size 12 (0xc) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld "object C.k__BackingField" + IL_0006: call "void C.M(object)" + IL_000b: ret + } + """); + } + else + { + verifier.VerifyIL("C.P1.get", """ + { + // Code size 2 (0x2) + .maxstack 1 + IL_0000: ldnull + IL_0001: ret + } + """); + verifier.VerifyIL("C.P4.set", """ + { + // Code size 1 (0x1) + .maxstack 0 + IL_0000: ret + } + """); + } + + var comp = (CSharpCompilation)verifier.Compilation; + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + VerifyMergedProperties(actualProperties, actualFields); + } + + [Fact] + public void RestrictedTypes() + { + string source = """ + using System; + + class C + { + static TypedReference P1 { get; } + ArgIterator P2 { get; set; } + static TypedReference Q1 => field; + ArgIterator Q2 { get { return field; } set { } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (5,12): error CS0610: Field or property cannot be of type 'TypedReference' + // static TypedReference P1 { get; } + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "TypedReference").WithArguments("System.TypedReference").WithLocation(5, 12), + // (6,5): error CS0610: Field or property cannot be of type 'ArgIterator' + // ArgIterator P2 { get; set; } + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "ArgIterator").WithArguments("System.ArgIterator").WithLocation(6, 5), + // (7,12): error CS0610: Field or property cannot be of type 'TypedReference' + // static TypedReference Q1 => field; + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "TypedReference").WithArguments("System.TypedReference").WithLocation(7, 12), + // (8,5): error CS0610: Field or property cannot be of type 'ArgIterator' + // ArgIterator Q2 { get { return field; } set { } } + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "ArgIterator").WithArguments("System.ArgIterator").WithLocation(8, 5)); + } + + [Theory] + [InlineData("class", false)] + [InlineData("struct", false)] + [InlineData("ref struct", true)] + [InlineData("record", false)] + [InlineData("record struct", false)] + public void ByRefLikeType_01(string typeKind, bool allow) + { + string source = $$""" + ref struct R + { + } + + {{typeKind}} C + { + R P1 { get; } + R P2 { get; set; } + R Q1 => field; + R Q2 { get => field; } + R Q3 { set { _ = field; } } + public override string ToString() => "C"; + } + + class Program + { + static void Main() + { + var c = new C(); + System.Console.WriteLine("{0}", c.ToString()); + } + } + """; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + if (allow) + { + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: "C"); + } + else + { + comp.VerifyEmitDiagnostics( + // (7,5): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // R P1 { get; } + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(7, 5), + // (8,5): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // R P2 { get; set; } + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(8, 5), + // (9,5): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // R Q1 => field; + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(9, 5), + // (10,5): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // R Q2 { get => field; } + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(10, 5), + // (11,5): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // R Q3 { set { _ = field; } } + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(11, 5)); + } + } + + [Theory] + [InlineData("class")] + [InlineData("struct")] + [InlineData("ref struct")] + [InlineData("record")] + [InlineData("record struct")] + public void ByRefLikeType_02(string typeKind) + { + string source = $$""" + ref struct R + { + } + + {{typeKind}} C + { + static R P1 { get; } + static R P2 { get; set; } + static R Q1 => field; + static R Q2 { get => field; } + static R Q3 { set { _ = field; } } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (7,12): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // static R P1 { get; } + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(7, 12), + // (8,12): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // static R P2 { get; set; } + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(8, 12), + // (9,12): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // static R Q1 => field; + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(9, 12), + // (10,12): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // static R Q2 { get => field; } + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(10, 12), + // (11,12): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // static R Q3 { set { _ = field; } } + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(11, 12)); + } + + [Fact] + public void ByRefLikeType_03() + { + string source = """ + ref struct R + { + } + + interface I + { + static R P1 { get; } + R P2 { get; set; } + static R Q1 => field; + R Q2 { get => field; } + R Q3 { set { _ = field; } } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (7,12): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // static R P1 { get; } + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(7, 12), + // (9,12): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // static R Q1 => field; + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(9, 12), + // (10,5): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // R Q2 { get => field; } + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(10, 5), + // (10,7): error CS0525: Interfaces cannot contain instance fields + // R Q2 { get => field; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Q2").WithLocation(10, 7), + // (11,5): error CS8345: Field or auto-implemented property cannot be of type 'R' unless it is an instance member of a ref struct. + // R Q3 { set { _ = field; } } + Diagnostic(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, "R").WithArguments("R").WithLocation(11, 5), + // (11,7): error CS0525: Interfaces cannot contain instance fields + // R Q3 { set { _ = field; } } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Q3").WithLocation(11, 7)); + } + + [Theory] + [CombinatorialData] + public void RefAssembly(bool useStatic, bool includePrivateMembers) + { + string modifier = useStatic ? "static" : " "; + string sourceA = $$""" + using System; + public struct S0 + { + public {{modifier}} object P0 { get; set; } + } + public struct S1 + { + public {{modifier}} object P1 { get => null; set { } } + } + public struct S2 + { + public {{modifier}} object P2 { get => field; set { field = value; } } + } + """; + var comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference( + Microsoft.CodeAnalysis.Emit.EmitOptions.Default.WithEmitMetadataOnly(true).WithIncludePrivateMembers(includePrivateMembers)); + + string sourceB = """ + class Program + { + static void Main() + { + S0 s0; + _ = s0.ToString(); + S1 s1; + _ = s1.ToString(); + S2 s2; + _ = s2.ToString(); + } + } + """; + comp = CreateCompilation(sourceB, references: [refA]); + if (useStatic) + { + comp.VerifyEmitDiagnostics(); + } + else + { + comp.VerifyEmitDiagnostics( + // (6,13): warning CS8887: Use of unassigned local variable 's0' + // _ = s0.ToString(); + Diagnostic(ErrorCode.WRN_UseDefViolation, "s0").WithArguments("s0").WithLocation(6, 13), + // (10,13): warning CS8887: Use of unassigned local variable 's2' + // _ = s2.ToString(); + Diagnostic(ErrorCode.WRN_UseDefViolation, "s2").WithArguments("s2").WithLocation(10, 13)); + } + } + + [Theory] + [CombinatorialData] + public void PartialProperty_01( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useInit) + { + string setter = useInit ? "init" : "set"; + string sourceA = $$""" + partial class C + { + public partial object P3 { get; {{setter}}; } + public partial object P3 { get; {{setter}} { } } + public partial object P4 { get; {{setter}}; } + public partial object P4 { get => null; {{setter}}; } + } + """; + string sourceB = """ + using System; + using System.Reflection; + class Program + { + static void Main() + { + var c = new C { P3 = 3, P4 = 4 }; + Console.WriteLine((c.P3, c.P4)); + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + Console.WriteLine("{0}", field.Name); + } + } + """; + var comp = CreateCompilation( + [sourceA, sourceB], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + options: TestOptions.ReleaseExe, + targetFramework: GetTargetFramework(useInit)); + + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (4,27): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public partial object P3 { get; set { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P3").WithArguments("field keyword").WithLocation(4, 27), + // (6,27): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public partial object P4 { get => null; set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P4").WithArguments("field keyword").WithLocation(6, 27)); + } + else + { + CompileAndVerify( + comp, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, """ + (, ) + k__BackingField + k__BackingField + """)); + } + + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(2, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P4", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_02(bool reverseOrder, bool useInit) + { + string setter = useInit ? "init" : "set"; + string sourceA = $$""" + partial class C + { + public partial object P1 { get; } + public partial object P2 { {{setter}}; } + public partial object P3 { get; {{setter}}; } + public partial object P4 { get; {{setter}}; } + public partial object P5 { get; {{setter}}; } + } + """; + string sourceB = $$""" + partial class C + { + public partial object P1 { get => field; } + public partial object P2 { {{setter}} { field = value; } } + public partial object P3 { get; {{setter}} { field = value; } } + public partial object P4 { get => field; {{setter}}; } + public partial object P5 { get => field; {{setter}} { field = value; } } + } + """; + string sourceC = """ + using System; + using System.Reflection; + class Program + { + static void Main() + { + var c = new C { P2 = 2, P3 = 3, P4 = 4, P5 = 5 }; + Console.WriteLine((c.P3, c.P4, c.P5)); + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + Console.WriteLine("{0}", field.Name); + } + } + """; + var verifier = CompileAndVerify( + reverseOrder ? [sourceC, sourceB, sourceA] : [sourceA, sourceB, sourceC], + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, """ + (3, 4, 5) + k__BackingField + k__BackingField + k__BackingField + k__BackingField + k__BackingField + """)); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(5, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P5", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_Interface_01( + [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.CSharp13)] LanguageVersion languageVersion, + bool reverseOrder, + bool includeRuntimeSupport) + { + string sourceA = $$""" + partial interface I + { + partial object P1 { get; } + partial object P2 { set; } + } + """; + string sourceB = $$""" + partial interface I + { + partial object P1 { get => null; } + partial object P2 { set { } } + } + """; + var comp = CreateCompilation( + reverseOrder ? [sourceB, sourceA] : [sourceA, sourceB], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + targetFramework: includeRuntimeSupport ? TargetFramework.Net80 : TargetFramework.Standard); + + Assert.Equal(includeRuntimeSupport, comp.Assembly.RuntimeSupportsDefaultInterfaceImplementation); + + switch (languageVersion, includeRuntimeSupport) + { + case (LanguageVersion.CSharp12, false): + comp.VerifyEmitDiagnostics( + // (3,20): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version '13.0' or greater. + // partial object P1 { get; } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("partial", "12.0", "13.0").WithLocation(3, 20), + // (3,20): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version '13.0' or greater. + // partial object P1 { get => null; } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("partial", "12.0", "13.0").WithLocation(3, 20), + // (3,25): error CS8701: Target runtime doesn't support default interface implementation. + // partial object P1 { get => null; } + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation, "get").WithLocation(3, 25), + // (4,20): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version '13.0' or greater. + // partial object P2 { set; } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P2").WithArguments("partial", "12.0", "13.0").WithLocation(4, 20), + // (4,20): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version '13.0' or greater. + // partial object P2 { set { } } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P2").WithArguments("partial", "12.0", "13.0").WithLocation(4, 20), + // (4,25): error CS8701: Target runtime doesn't support default interface implementation. + // partial object P2 { set { } } + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation, "set").WithLocation(4, 25)); + break; + case (LanguageVersion.CSharp12, true): + comp.VerifyEmitDiagnostics( + // (3,20): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version '13.0' or greater. + // partial object P1 { get; } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("partial", "12.0", "13.0").WithLocation(3, 20), + // (3,20): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version '13.0' or greater. + // partial object P1 { get => null; } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("partial", "12.0", "13.0").WithLocation(3, 20), + // (4,20): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version '13.0' or greater. + // partial object P2 { set; } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P2").WithArguments("partial", "12.0", "13.0").WithLocation(4, 20), + // (4,20): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version '13.0' or greater. + // partial object P2 { set { } } + Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P2").WithArguments("partial", "12.0", "13.0").WithLocation(4, 20)); + break; + case (LanguageVersion.CSharp13, false): + comp.VerifyEmitDiagnostics( + // (3,25): error CS8701: Target runtime doesn't support default interface implementation. + // partial object P1 { get => null; } + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation, "get").WithLocation(3, 25), + // (4,25): error CS8701: Target runtime doesn't support default interface implementation. + // partial object P2 { set { } } + Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportDefaultInterfaceImplementation, "set").WithLocation(4, 25)); + break; + case (LanguageVersion.CSharp13, true): + comp.VerifyEmitDiagnostics(); + break; + default: + Assert.True(false); + break; + } + + var containingType = comp.GetMember("I"); + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(2, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_Interface_02A( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool reverseOrder) + { + string sourceA = $$""" + partial interface I + { + partial object P1 { get; set; } + partial object P2 { get; init; } + } + """; + string sourceB = $$""" + partial interface I + { + partial object P1 { get; set { } } + partial object P2 { get => null; init; } + } + """; + var comp = CreateCompilation( + reverseOrder ? [sourceB, sourceA] : [sourceA, sourceB], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + targetFramework: TargetFramework.Net80); + + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (3,20): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // partial object P1 { get; set { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(3, 20), + // (3,20): error CS0525: Interfaces cannot contain instance fields + // partial object P1 { get; set; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P1").WithLocation(3, 20), + // (4,20): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // partial object P2 { get => null; init; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P2").WithArguments("field keyword").WithLocation(4, 20), + // (4,20): error CS0525: Interfaces cannot contain instance fields + // partial object P2 { get; init; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P2").WithLocation(4, 20)); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,20): error CS0525: Interfaces cannot contain instance fields + // partial object P1 { get; set; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P1").WithLocation(3, 20), + // (4,20): error CS0525: Interfaces cannot contain instance fields + // partial object P2 { get; init; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P2").WithLocation(4, 20)); + } + + var containingType = comp.GetMember("I"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(2, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_Interface_02B( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool reverseOrder) + { + string sourceA = $$""" + partial interface I + { + static partial object P1 { get; set; } + static partial object P2 { get; set; } + } + """; + string sourceB = $$""" + partial interface I + { + static partial object P1 { get; set { } } + static partial object P2 { get => null; set; } + } + """; + var comp = CreateCompilation( + reverseOrder ? [sourceB, sourceA] : [sourceA, sourceB], + parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + targetFramework: TargetFramework.Net80); + + if (languageVersion == LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (3,27): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static partial object P1 { get; set { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(3, 27), + // (4,27): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static partial object P2 { get => null; set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P2").WithArguments("field keyword").WithLocation(4, 27)); + } + else + { + comp.VerifyEmitDiagnostics(); + } + + var containingType = comp.GetMember("I"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(2, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_Interface_03(bool reverseOrder, bool useStatic) + { + string modifier = useStatic ? "static" : " "; + string sourceA = $$""" + partial interface I + { + {{modifier}} partial object P1 { get; } + {{modifier}} partial object P2 { set; } + } + """; + string sourceB = $$""" + partial interface I + { + {{modifier}} partial object P1 { get => field; } + {{modifier}} partial object P2 { set { field = value; } } + } + """; + var comp = CreateCompilation( + reverseOrder ? [sourceB, sourceA] : [sourceA, sourceB], + targetFramework: TargetFramework.Net80); + if (useStatic) + { + comp.VerifyEmitDiagnostics(); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,27): error CS0525: Interfaces cannot contain instance fields + // partial object P1 { get; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P1").WithLocation(3, 27), + // (4,27): error CS0525: Interfaces cannot contain instance fields + // partial object P2 { set; } + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P2").WithLocation(4, 27)); + } + + var containingType = comp.GetMember("I"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(2, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_Interface_04A(bool reverseOrder, bool useStatic) + { + string modifier = useStatic ? "static" : " "; + string sourceA = $$""" + partial interface I + { + {{modifier}} partial object P1 { get; } = 1; + {{modifier}} partial object P2 { set; } + {{modifier}} partial object P3 { get; set; } = 3; + {{modifier}} partial object P4 { get; set; } + } + """; + string sourceB = $$""" + partial interface I + { + {{modifier}} partial object P1 { get => null; } + {{modifier}} partial object P2 { set { } } = 2; + {{modifier}} partial object P3 { get => null; set { } } + {{modifier}} partial object P4 { get => null; set { } } = 4; + } + """; + var comp = CreateCompilation( + reverseOrder ? [sourceB, sourceA] : [sourceA, sourceB], + targetFramework: TargetFramework.Net80); + if (useStatic) + { + comp.VerifyEmitDiagnostics( + // (3,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // static partial object P1 { get; } = 1; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), + // (4,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // static partial object P2 { set { } } = 2; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(4, 27), + // (5,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // static partial object P3 { get; set; } = 3; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(5, 27), + // (6,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // static partial object P4 { get => null; set { } } = 4; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P4").WithLocation(6, 27)); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,27): error CS8053: Instance properties in interfaces cannot have initializers. + // partial object P1 { get; } = 1; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithLocation(3, 27), + // (4,27): error CS8053: Instance properties in interfaces cannot have initializers. + // partial object P2 { set { } } = 2; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P2").WithLocation(4, 27), + // (5,27): error CS8053: Instance properties in interfaces cannot have initializers. + // partial object P3 { get; set; } = 3; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P3").WithLocation(5, 27), + // (6,27): error CS8053: Instance properties in interfaces cannot have initializers. + // partial object P4 { get => null; set { } } = 4; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P4").WithLocation(6, 27)); + } + + var containingType = comp.GetMember("I"); + var actualFields = containingType.GetMembers().OfType().OrderBy(f => f.Name).ToImmutableArray(); + var expectedFields = new[] + { + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(4, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { HasInitializer: true } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + // As above, but using field. + [Theory] + [CombinatorialData] + public void PartialProperty_Interface_04B(bool reverseOrder, bool useStatic) + { + string modifier = useStatic ? "static" : " "; + string sourceA = $$""" + partial interface I + { + {{modifier}} partial object P1 { get; } = 1; + {{modifier}} partial object P2 { set; } + {{modifier}} partial object P3 { get; set; } = 3; + {{modifier}} partial object P4 { get; set; } + } + """; + string sourceB = $$""" + partial interface I + { + {{modifier}} partial object P1 { get => field; } + {{modifier}} partial object P2 { set { field = value; } } = 2; + {{modifier}} partial object P3 { get => field; set { } } + {{modifier}} partial object P4 { get => null; set { field = value; } } = 4; + } + """; + var comp = CreateCompilation( + reverseOrder ? [sourceB, sourceA] : [sourceA, sourceB], + targetFramework: TargetFramework.Net80); + if (useStatic) + { + comp.VerifyEmitDiagnostics(); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,27): error CS8053: Instance properties in interfaces cannot have initializers. + // partial object P1 { get; } = 1; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithLocation(3, 27), + // (4,27): error CS8053: Instance properties in interfaces cannot have initializers. + // partial object P2 { set { field = value; } } = 2; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P2").WithLocation(4, 27), + // (5,27): error CS8053: Instance properties in interfaces cannot have initializers. + // partial object P3 { get; set; } = 3; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P3").WithLocation(5, 27), + // (6,27): error CS8053: Instance properties in interfaces cannot have initializers. + // partial object P4 { get => null; set { field = value; } } = 4; + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P4").WithLocation(6, 27)); + } + + var containingType = comp.GetMember("I"); + var actualFields = containingType.GetMembers().OfType().OrderBy(f => f.Name).ToImmutableArray(); + var expectedFields = new[] + { + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + "System.Object I.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(4, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { HasInitializer: true } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + private static void VerifyMergedProperties(ImmutableArray properties, ImmutableArray fields) + { + int fieldIndex = 0; + for (int propertyIndex = 0; propertyIndex < properties.Length; propertyIndex++) + { + var property = (SourcePropertySymbol)properties[propertyIndex]; + var field = (property.BackingField is null) ? null : (SynthesizedBackingFieldSymbol)fields[fieldIndex++]; + Assert.Equal(property.IsPartial, property.IsPartialDefinition); + VerifyMergedProperty(property, field); + } + Assert.Equal(fields.Length, fieldIndex); + } + + private static void VerifyMergedProperty(SourcePropertySymbol property, SynthesizedBackingFieldSymbol fieldOpt) + { + Assert.Same(property.BackingField, fieldOpt); + if (property.OtherPartOfPartial is { } otherPart) + { + Assert.True(otherPart.IsPartial); + Assert.Equal(property.IsPartialDefinition, !otherPart.IsPartialDefinition); + Assert.Equal(property.IsPartialImplementation, !otherPart.IsPartialImplementation); + Assert.Same(property.BackingField, otherPart.BackingField); + } + } + + [Theory] + [CombinatorialData] + public void PartialProperty_ConstructorAssignment( + [CombinatorialValues("partial class", "partial struct", "ref partial struct", "partial record", "partial record struct")] string typeKind, + bool reverseOrder, + bool useStatic) + { + string modifier = useStatic ? "static" : " "; + string constructorModifier = useStatic ? "static" : "public"; + string sourceA = $$""" + {{typeKind}} C + { + internal {{modifier}} partial object P1 { get; } + internal {{modifier}} partial object P2 { get => field; } + } + """; + string sourceB = $$""" + {{typeKind}} C + { + internal {{modifier}} partial object P1 { get => field; } + internal {{modifier}} partial object P2 { get; } + {{constructorModifier}} C() + { + P1 = 1; + P2 = 2; + } + } + """; + string sourceC = useStatic ? + """ + using System; + class Program + { + static void Main() + { + Console.WriteLine((C.P1, C.P2)); + } + } + """ : + """ + using System; + class Program + { + static void Main() + { + var c = new C(); + Console.WriteLine((c.P1, c.P2)); + } + } + """; + var verifier = CompileAndVerify( + reverseOrder ? [sourceC, sourceB, sourceA] : [sourceA, sourceB, sourceC], + expectedOutput: "(1, 2)"); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().OrderBy(f => f.Name).ToImmutableArray(); + var expectedFields = new[] + { + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().Where(p => p.Name != "EqualityContract").OrderBy(p => p.Name).ToImmutableArray(); + Assert.Equal(2, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + public void PartialProperty_Initializer_01(bool useStatic, bool useInit) + { + string modifier = useStatic ? "static" : " "; + string setter = useInit ? "init" : "set"; + string source = $$""" + partial class C + { + {{modifier}} partial object P1 { get; } = 1; + {{modifier}} partial object P1 { get; } + {{modifier}} partial object P2 { {{setter}}; } = 2; + {{modifier}} partial object P2 { {{setter}}; } + {{modifier}} partial object P3 { get; {{setter}}; } = 3; + {{modifier}} partial object P3 { get; {{setter}}; } + } + """; + var comp = CreateCompilation(source, targetFramework: GetTargetFramework(useInit)); + comp.VerifyEmitDiagnostics( + // (3,27): error CS9248: Partial property 'C.P1' must have an implementation part. + // partial object P1 { get; } = 1; + Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "P1").WithArguments("C.P1").WithLocation(3, 27), + // (3,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P1 { get; } = 1; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), + // (4,27): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // partial object P1 { get; } + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "P1").WithLocation(4, 27), + // (4,27): error CS0102: The type 'C' already contains a definition for 'P1' + // partial object P1 { get; } + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P1").WithArguments("C", "P1").WithLocation(4, 27), + // (5,27): error CS9248: Partial property 'C.P2' must have an implementation part. + // partial object P2 { set; } = 2; + Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "P2").WithArguments("C.P2").WithLocation(5, 27), + // (5,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P2 { set; } = 2; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(5, 27), + // (6,27): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // partial object P2 { set; } + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "P2").WithLocation(6, 27), + // (6,27): error CS0102: The type 'C' already contains a definition for 'P2' + // partial object P2 { set; } + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P2").WithArguments("C", "P2").WithLocation(6, 27), + // (7,27): error CS9248: Partial property 'C.P3' must have an implementation part. + // partial object P3 { get; set; } = 3; + Diagnostic(ErrorCode.ERR_PartialPropertyMissingImplementation, "P3").WithArguments("C.P3").WithLocation(7, 27), + // (7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P3 { get; set; } = 3; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(7, 27), + // (8,27): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // partial object P3 { get; set; } + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "P3").WithLocation(8, 27), + // (8,27): error CS0102: The type 'C' already contains a definition for 'P3' + // partial object P3 { get; set; } + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P3").WithArguments("C", "P3").WithLocation(8, 27)); + + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(6, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_Initializer_02(bool reverseOrder, bool useStatic, bool useInit) + { + if (useStatic && useInit) return; + string modifier = useStatic ? "static" : " "; + string setter = useInit ? "init" : "set"; + string sourceA = $$""" + partial class C + { + {{modifier}} partial object P1 { get; } = 1; + {{modifier}} partial object P2 { {{setter}}; } = 2; + {{modifier}} partial object P3 { get; {{setter}}; } = 3; + {{modifier}} partial object Q1 { get => null; } = 1; + {{modifier}} partial object Q2 { {{setter}} { } } = 2; + {{modifier}} partial object Q3 { get => null; {{setter}} { } } = 3; + } + """; + string sourceB = $$""" + partial class C + { + {{modifier}} partial object P1 { get => null; } + {{modifier}} partial object P2 { {{setter}} { } } + {{modifier}} partial object P3 { get => null; {{setter}} { } } + {{modifier}} partial object Q1 { get; } + {{modifier}} partial object Q2 { {{setter}}; } + {{modifier}} partial object Q3 { get; {{setter}}; } + } + """; + var comp = CreateCompilation( + reverseOrder ? [sourceB, sourceA] : [sourceA, sourceB], + targetFramework: GetTargetFramework(useInit)); + comp.VerifyEmitDiagnostics( + // (3,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P1 { get; } = 1; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), + // (4,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P2 { set; } = 2; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(4, 27), + // (5,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P3 { get; set; } = 3; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(5, 27), + // (6,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object Q1 { get => null; } = 1; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "Q1").WithLocation(6, 27), + // (7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object Q2 { set { } } = 2; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "Q2").WithLocation(7, 27), + // (8,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object Q3 { get => null; set { } } = 3; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "Q3").WithLocation(8, 27)); + + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().OrderBy(p => p.Name).ToImmutableArray(); + Assert.Equal(6, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "Q1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "Q2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "Q3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_Initializer_03(bool reverseOrder, bool useStatic, bool useInit) + { + if (useStatic && useInit) return; + string modifier = useStatic ? "static" : " "; + string setter = useInit ? "init" : "set"; + string sourceA = $$""" + partial class C + { + public {{modifier}} partial object P1 { get; } = 1; + public {{modifier}} partial object P2 { {{setter}}; } = 2; + public {{modifier}} partial object P3 { get; {{setter}}; } = 3; + public {{modifier}} partial object P4 { get; {{setter}}; } = 4; + public {{modifier}} partial object P5 { get; {{setter}}; } = 5; + public {{modifier}} partial object P6 { get; {{setter}}; } = 6; + public {{modifier}} partial object P7 { get; {{setter}}; } = 7; + public {{modifier}} partial object Q1 { get => field; } = 1; + public {{modifier}} partial object Q2 { {{setter}} { field = value; } } = 2; + public {{modifier}} partial object Q3 { get; {{setter}} { field = value; } } = 3; + public {{modifier}} partial object Q4 { get => field; {{setter}}; } = 4; + public {{modifier}} partial object Q5 { get => field; {{setter}} { field = value; } } = 5; + public {{modifier}} partial object Q6 { get; {{setter}} { } } = 6; + public {{modifier}} partial object Q7 { get => null; {{setter}}; } = 7; + } + """; + string sourceB = $$""" + partial class C + { + public {{modifier}} partial object P1 { get => field; } + public {{modifier}} partial object P2 { {{setter}} { field = value; } } + public {{modifier}} partial object P3 { get; {{setter}} { field = value; } } + public {{modifier}} partial object P4 { get => field; {{setter}}; } + public {{modifier}} partial object P5 { get => field; {{setter}} { field = value; } } + public {{modifier}} partial object P6 { get; {{setter}} { } } + public {{modifier}} partial object P7 { get => null; {{setter}}; } + public {{modifier}} partial object Q1 { get; } + public {{modifier}} partial object Q2 { {{setter}}; } + public {{modifier}} partial object Q3 { get; {{setter}}; } + public {{modifier}} partial object Q4 { get; {{setter}}; } + public {{modifier}} partial object Q5 { get; {{setter}}; } + public {{modifier}} partial object Q6 { get; {{setter}}; } + public {{modifier}} partial object Q7 { get; {{setter}}; } + } + """; + string receiver = useStatic ? "C" : "c"; + string sourceC = $$""" + using System; + using System.Reflection; + class Program + { + static void Main() + { + var c = new C(); + Console.WriteLine(({{receiver}}.P1, {{receiver}}.P3, {{receiver}}.P4, {{receiver}}.P5, {{receiver}}.P6, {{receiver}}.P7, {{receiver}}.Q1, {{receiver}}.Q3, {{receiver}}.Q4, {{receiver}}.Q5, {{receiver}}.Q6, {{receiver}}.Q7)); + foreach (var field in typeof(C).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + Console.WriteLine("{0}", field.Name); + } + } + """; + var verifier = CompileAndVerify( + reverseOrder ? [sourceC, sourceB, sourceA] : [sourceA, sourceB, sourceC], + targetFramework: GetTargetFramework(useInit), + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput(useInit, """ + (1, 3, 4, 5, 6, , 1, 3, 4, 5, 6, ) + k__BackingField + k__BackingField + k__BackingField + k__BackingField + k__BackingField + k__BackingField + k__BackingField + k__BackingField + k__BackingField + k__BackingField + k__BackingField + k__BackingField + k__BackingField + k__BackingField + """)); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().OrderBy(p => p.Name).ToImmutableArray(); + Assert.Equal(14, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P5", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "P6", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[6] is SourcePropertySymbol { Name: "P7", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[7] is SourcePropertySymbol { Name: "Q1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[8] is SourcePropertySymbol { Name: "Q2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[9] is SourcePropertySymbol { Name: "Q3", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[10] is SourcePropertySymbol { Name: "Q4", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[11] is SourcePropertySymbol { Name: "Q5", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[12] is SourcePropertySymbol { Name: "Q6", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[13] is SourcePropertySymbol { Name: "Q7", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_Initializer_04(bool reverseOrder, bool useStatic, bool useInit) + { + if (useStatic && useInit) return; + string modifier = useStatic ? "static" : " "; + string setter = useInit ? "init" : "set"; + string sourceA = $$""" + partial class C + { + {{modifier}} partial object P1 { get; } = 1; + {{modifier}} partial object P2 { {{setter}}; } = 2; + {{modifier}} partial object P3 { get; {{setter}}; } = 3; + } + """; + string sourceB = $$""" + partial class C + { + {{modifier}} partial object P1 { get => null; } = 1; + {{modifier}} partial object P2 { {{setter}} { } } = 2; + {{modifier}} partial object P3 { get => null; {{setter}} { } } = 3; + } + """; + var comp = CreateCompilation( + reverseOrder ? [sourceB, sourceA] : [sourceA, sourceB], + targetFramework: GetTargetFramework(useInit)); + comp.VerifyEmitDiagnostics( + // (3,27): error CS9263: A partial property cannot have an initializer on both the definition and implementation. + // partial object P1 { get => null; } = 1; + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateInitializer, "P1").WithLocation(3, 27), + // (3,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P1 { get; } = 1; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), + // (3,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P1 { get => null; } = 1; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), + // (4,27): error CS9263: A partial property cannot have an initializer on both the definition and implementation. + // partial object P2 { set { } } = 2; + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateInitializer, "P2").WithLocation(4, 27), + // (4,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P2 { set; } = 2; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(4, 27), + // (4,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P2 { set { } } = 2; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(4, 27), + // (5,27): error CS9263: A partial property cannot have an initializer on both the definition and implementation. + // partial object P3 { get => null; set { } } = 3; + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateInitializer, "P3").WithLocation(5, 27), + // (5,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P3 { get; set; } = 3; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(5, 27), + // (5,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // partial object P3 { get => null; set { } } = 3; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(5, 27)); + + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(3, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_Initializer_05(bool reverseOrder, bool useStatic, bool useInit) + { + if (useStatic && useInit) return; + string modifier = useStatic ? "static" : " "; + string setter = useInit ? "init" : "set"; + string sourceA = $$""" + partial class C + { + public {{modifier}} partial object P1 { get; } = 1; + public {{modifier}} partial object P2 { {{setter}}; } = 2; + public {{modifier}} partial object P3 { get; {{setter}}; } = 3; + public {{modifier}} partial object P4 { get; {{setter}}; } = 4; + public {{modifier}} partial object P5 { get; {{setter}}; } = 5; + } + """; + string sourceB = $$""" + partial class C + { + public {{modifier}} partial object P1 { get => field; } = -1; + public {{modifier}} partial object P2 { {{setter}} { field = value; } } = -2; + public {{modifier}} partial object P3 { get; {{setter}} { field = value; } } = -3; + public {{modifier}} partial object P4 { get => field; {{setter}}; } = -4; + public {{modifier}} partial object P5 { get => field; {{setter}} { field = value; } } = -5; + } + """; + + var comp = CreateCompilation( + reverseOrder ? [sourceB, sourceA] : [sourceA, sourceB], + targetFramework: GetTargetFramework(useInit)); + comp.VerifyEmitDiagnostics( + // (3,34): error CS9263: A partial property cannot have an initializer on both the definition and implementation. + // public partial object P1 { get => field; } = -1; + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateInitializer, "P1").WithLocation(3, 34), + // (4,34): error CS9263: A partial property cannot have an initializer on both the definition and implementation. + // public partial object P2 { set { field = value; } } = -2; + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateInitializer, "P2").WithLocation(4, 34), + // (5,34): error CS9263: A partial property cannot have an initializer on both the definition and implementation. + // public partial object P3 { get; set { field = value; } } = -3; + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateInitializer, "P3").WithLocation(5, 34), + // (6,34): error CS9263: A partial property cannot have an initializer on both the definition and implementation. + // public partial object P4 { get => field; set; } = -4; + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateInitializer, "P4").WithLocation(6, 34), + // (7,34): error CS9263: A partial property cannot have an initializer on both the definition and implementation. + // public partial object P5 { get => field; set { field = value; } } = -5; + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateInitializer, "P5").WithLocation(7, 34)); + + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(5, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P5", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + + var actualValues = getInitializerValues(comp, comp.SyntaxTrees[reverseOrder ? 1 : 0]); + var expectedValues = new[] + { + ((object)1, "System.Int32", "System.Object"), + ((object)2, "System.Int32", "System.Object"), + ((object)3, "System.Int32", "System.Object"), + ((object)4, "System.Int32", "System.Object"), + ((object)5, "System.Int32", "System.Object"), + }; + AssertEx.Equal(expectedValues, actualValues); + + actualValues = getInitializerValues(comp, comp.SyntaxTrees[reverseOrder ? 0 : 1]); + expectedValues = new[] + { + ((object)-1, "System.Int32", "System.Object"), + ((object)-2, "System.Int32", "System.Object"), + ((object)-3, "System.Int32", "System.Object"), + ((object)-4, "System.Int32", "System.Object"), + ((object)-5, "System.Int32", "System.Object"), + }; + AssertEx.Equal(expectedValues, actualValues); + + static (object, string, string)[] getInitializerValues(CSharpCompilation comp, SyntaxTree tree) + { + var model = comp.GetSemanticModel(tree); + return tree.GetRoot().DescendantNodes().OfType(). + Select(p => + { + var value = p.Initializer.Value; + var typeInfo = model.GetTypeInfo(value); + return (model.GetConstantValue(value).Value, typeInfo.Type.ToTestDisplayString(), typeInfo.ConvertedType.ToTestDisplayString()); + + }).ToArray(); + } + } + + [Fact] + public void PartialProperty_Initializer_06() + { + string source = $$""" + partial class C + { + partial object P1 { get; set; } = 1; // A1 + partial object P2 { get; set; } // A2 + partial object P3 { get; set; } = 3; // A3 + partial object P4 { get; set; } // A4 + partial object P5 { get { return field; } set { field = value; } } = 5; // A5 + partial object P6 { get { return field; } set { field = value; } } // A6 + + partial object P1 { get; set; } // B1 + partial object P2 { get; set; } // B2 + partial object P3 { get { return field; } set { field = value; } } // B3 + partial object P4 { get { return field; } set { field = value; } } // B4 + partial object P5 { get; set; } // B5 + partial object P6 { get { return field; } set { field = value; } } // B6 + + partial object P1 { get { return field; } set { field = value; } } // C1 + partial object P2 { get { return field; } set { field = value; } } = 2; // C2 + partial object P3 { get { return field; } set { field = value; } } // C3 + partial object P4 { get { return field; } set { field = value; } } = 4; // C4 + partial object P5 { get; set; } // C5 + partial object P6 { get; set; } = 6; // C6 + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (10,20): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // partial object P1 { get; set; } // B1 + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "P1").WithLocation(10, 20), + // (10,20): error CS0102: The type 'C' already contains a definition for 'P1' + // partial object P1 { get; set; } // B1 + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P1").WithArguments("C", "P1").WithLocation(10, 20), + // (11,20): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // partial object P2 { get; set; } // B2 + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "P2").WithLocation(11, 20), + // (11,20): error CS0102: The type 'C' already contains a definition for 'P2' + // partial object P2 { get; set; } // B2 + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P2").WithArguments("C", "P2").WithLocation(11, 20), + // (15,20): error CS9251: A partial property may not have multiple implementing declarations + // partial object P6 { get { return field; } set { field = value; } } // B6 + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateImplementation, "P6").WithLocation(15, 20), + // (19,20): error CS9251: A partial property may not have multiple implementing declarations + // partial object P3 { get { return field; } set { field = value; } } // C3 + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateImplementation, "P3").WithLocation(19, 20), + // (19,20): error CS0102: The type 'C' already contains a definition for 'P3' + // partial object P3 { get { return field; } set { field = value; } } // C3 + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P3").WithArguments("C", "P3").WithLocation(19, 20), + // (20,20): error CS9251: A partial property may not have multiple implementing declarations + // partial object P4 { get { return field; } set { field = value; } } = 4; // C4 + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateImplementation, "P4").WithLocation(20, 20), + // (20,20): error CS0102: The type 'C' already contains a definition for 'P4' + // partial object P4 { get { return field; } set { field = value; } } = 4; // C4 + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P4").WithArguments("C", "P4").WithLocation(20, 20), + // (21,20): error CS9250: A partial property may not have multiple defining declarations, and cannot be an auto-property. + // partial object P5 { get; set; } // C5 + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateDefinition, "P5").WithLocation(21, 20), + // (21,20): error CS0102: The type 'C' already contains a definition for 'P5' + // partial object P5 { get; set; } // C5 + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P5").WithArguments("C", "P5").WithLocation(21, 20), + // (22,20): error CS0102: The type 'C' already contains a definition for 'P6' + // partial object P6 { get; set; } = 6; // C6 + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "P6").WithArguments("C", "P6").WithLocation(22, 20)); + + var containingType = comp.GetMember("C"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + "System.Object C.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(12, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + Assert.True(actualProperties[6] is SourcePropertySymbol { Name: "P5", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[7] is SourcePropertySymbol { Name: "P6", IsPartialDefinition: false, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[8] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: false, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[9] is SourcePropertySymbol { Name: "P4", IsPartialDefinition: false, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[10] is SourcePropertySymbol { Name: "P5", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + Assert.True(actualProperties[11] is SourcePropertySymbol { Name: "P6", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + + VerifyMergedProperty((SourcePropertySymbol)actualProperties[0], (SynthesizedBackingFieldSymbol)actualFields[0]); + VerifyMergedProperty((SourcePropertySymbol)actualProperties[1], (SynthesizedBackingFieldSymbol)actualFields[5]); + VerifyMergedProperty((SourcePropertySymbol)actualProperties[2], (SynthesizedBackingFieldSymbol)actualFields[1]); + VerifyMergedProperty((SourcePropertySymbol)actualProperties[3], (SynthesizedBackingFieldSymbol)actualFields[3]); + VerifyMergedProperty((SourcePropertySymbol)actualProperties[4], null); + VerifyMergedProperty((SourcePropertySymbol)actualProperties[5], null); + VerifyMergedProperty((SourcePropertySymbol)actualProperties[6], (SynthesizedBackingFieldSymbol)actualFields[2]); + VerifyMergedProperty((SourcePropertySymbol)actualProperties[7], (SynthesizedBackingFieldSymbol)actualFields[4]); + VerifyMergedProperty((SourcePropertySymbol)actualProperties[8], (SynthesizedBackingFieldSymbol)actualFields[6]); + VerifyMergedProperty((SourcePropertySymbol)actualProperties[9], (SynthesizedBackingFieldSymbol)actualFields[7]); + VerifyMergedProperty((SourcePropertySymbol)actualProperties[10], null); + VerifyMergedProperty((SourcePropertySymbol)actualProperties[11], (SynthesizedBackingFieldSymbol)actualFields[8]); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_ReadOnly(bool reverseOrder, bool useReadOnlyDefinition, bool useReadOnlyImplementation) + { + string modifierDefinition = useReadOnlyDefinition ? "readonly" : " "; + string modifierImplementation = useReadOnlyImplementation ? "readonly" : " "; + string sourceA = $$""" + partial struct S + { + {{modifierDefinition}} partial object P1 { get; } + {{modifierDefinition}} partial object P2 { set; } + partial object P3 { {{modifierDefinition}} get; } + partial object P4 { {{modifierDefinition}} set; } + {{modifierDefinition}} partial object P5 { get; set; } + partial object P6 { {{modifierDefinition}} get; set; } + partial object P7 { get; {{modifierDefinition}} set; } + partial object P8 { {{modifierDefinition}} get; set; } + partial object P9 { get; {{modifierDefinition}} set; } + } + """; + string sourceB = $$""" + partial struct S + { + {{modifierImplementation}} partial object P1 { get => field; } + {{modifierImplementation}} partial object P2 { set { _ = field; } } + partial object P3 { {{modifierImplementation}} get => field; } + partial object P4 { {{modifierImplementation}} set { _ = field; } } + {{modifierImplementation}} partial object P5 { get; set { } } + partial object P6 { {{modifierImplementation}} get; set { } } + partial object P7 { get; {{modifierImplementation}} set { } } + partial object P8 { {{modifierImplementation}} get => field; set { } } + partial object P9 { get => field; {{modifierImplementation}} set { } } + } + """; + var comp = CreateCompilation(reverseOrder ? [sourceB, sourceA] : [sourceA, sourceB]); + switch (useReadOnlyDefinition, useReadOnlyImplementation) + { + case (false, false): + comp.VerifyEmitDiagnostics(); + break; + case (false, true): + comp.VerifyEmitDiagnostics( + // (3,29): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // readonly partial object P1 { get => field; } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "P1").WithLocation(3, 29), + // (4,29): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // readonly partial object P2 { set { _ = field; } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "P2").WithLocation(4, 29), + // (5,34): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P3 { readonly get => field; } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "get").WithLocation(5, 34), + // (6,34): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P4 { readonly set { _ = field; } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "set").WithLocation(6, 34), + // (7,29): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // readonly partial object P5 { get; set { } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "P5").WithLocation(7, 29), + // (8,34): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P6 { readonly get; set { } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "get").WithLocation(8, 34), + // (9,39): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P7 { get; readonly set { } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "set").WithLocation(9, 39), + // (10,34): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P8 { readonly get => field; set { } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "get").WithLocation(10, 34), + // (11,48): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P9 { get => field; readonly set { } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "set").WithLocation(11, 48)); + break; + case (true, false): + comp.VerifyEmitDiagnostics( + // (3,29): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P1 { get => field; } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "P1").WithLocation(3, 29), + // (4,29): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P2 { set { _ = field; } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "P2").WithLocation(4, 29), + // (5,20): error CS8664: 'S.P3': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // partial object P3 { readonly get; } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P3").WithArguments("S.P3").WithLocation(5, 20), + // (5,34): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P3 { get => field; } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "get").WithLocation(5, 34), + // (6,20): error CS8664: 'S.P4': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // partial object P4 { readonly set; } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P4").WithArguments("S.P4").WithLocation(6, 20), + // (6,34): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P4 { set { _ = field; } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "set").WithLocation(6, 34), + // (7,29): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P5 { get; set { } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "P5").WithLocation(7, 29), + // (8,34): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P6 { get; set { } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "get").WithLocation(8, 34), + // (9,39): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P7 { get; set { } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "set").WithLocation(9, 39), + // (10,34): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P8 { get => field; set { } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "get").WithLocation(10, 34), + // (11,48): error CS8663: Both partial member declarations must be readonly or neither may be readonly + // partial object P9 { get => field; set { } } + Diagnostic(ErrorCode.ERR_PartialMemberReadOnlyDifference, "set").WithLocation(11, 48)); + break; + case (true, true): + comp.VerifyEmitDiagnostics( + // (5,20): error CS8664: 'S.P3': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // partial object P3 { readonly get; } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P3").WithArguments("S.P3").WithLocation(5, 20), + // (6,20): error CS8664: 'S.P4': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor + // partial object P4 { readonly set; } + Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P4").WithArguments("S.P4").WithLocation(6, 20)); + break; + } + + var containingType = comp.GetMember("S"); + var actualMembers = comp.GetMember("S"). + GetMembers(). + OfType(). + Select(p => + { + var property = (SourcePropertySymbol)p; + var field = property.BackingField; + return $"{field.ToTestDisplayString()}: IsAutoProperty: {property.IsAutoProperty}, UsesFieldKeyword: {property.UsesFieldKeyword}, BackingField.IsReadOnly: {field.IsReadOnly}"; + }). + ToArray(); + var expectedMembers = new[] + { + $"System.Object S.k__BackingField: IsAutoProperty: False, UsesFieldKeyword: True, BackingField.IsReadOnly: {useReadOnlyImplementation}", + $"System.Object S.k__BackingField: IsAutoProperty: False, UsesFieldKeyword: True, BackingField.IsReadOnly: {useReadOnlyImplementation}", + $"System.Object S.k__BackingField: IsAutoProperty: False, UsesFieldKeyword: True, BackingField.IsReadOnly: {useReadOnlyImplementation}", + $"System.Object S.k__BackingField: IsAutoProperty: False, UsesFieldKeyword: True, BackingField.IsReadOnly: {useReadOnlyImplementation}", + $"System.Object S.k__BackingField: IsAutoProperty: True, UsesFieldKeyword: False, BackingField.IsReadOnly: {useReadOnlyImplementation}", + $"System.Object S.k__BackingField: IsAutoProperty: True, UsesFieldKeyword: False, BackingField.IsReadOnly: False", + $"System.Object S.k__BackingField: IsAutoProperty: True, UsesFieldKeyword: False, BackingField.IsReadOnly: {useReadOnlyImplementation}", + $"System.Object S.k__BackingField: IsAutoProperty: False, UsesFieldKeyword: True, BackingField.IsReadOnly: False", + $"System.Object S.k__BackingField: IsAutoProperty: False, UsesFieldKeyword: True, BackingField.IsReadOnly: False", + }; + AssertEx.Equal(expectedMembers, actualMembers); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_Attribute_01(bool reverseOrder, bool useStatic) + { + string modifier = useStatic ? "static" : " "; + string sourceA = $$""" + using System; + class A : Attribute + { + public A(object o) { } + } + """; + string sourceB1 = $$""" + partial class B + { + {{modifier}} partial object P1 { get; } + {{modifier}} partial object P2 { get; set; } + {{modifier}} partial object P3 { [A(field)] get; } + {{modifier}} partial object P4 { get; [A(field)] set; } + } + """; + string sourceB2 = $$""" + partial class B + { + {{modifier}} partial object P1 { [A(field)] get { return null; } } + {{modifier}} partial object P2 { get { return null; } [A(field)] set { } } + {{modifier}} partial object P3 { get { return null; } } + {{modifier}} partial object P4 { get { return null; } set { } } + } + """; + var comp = CreateCompilation(reverseOrder ? [sourceB2, sourceB1, sourceA] : [sourceA, sourceB1, sourceB2]); + comp.VerifyEmitDiagnostics( + // (3,35): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // partial object P1 { [A(field)] get { return null; } } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(3, 35), + // (4,56): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // partial object P2 { get { return null; } [A(field)] set { } } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(4, 56), + // (5,35): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // partial object P3 { [A(field)] get; } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(5, 35), + // (6,40): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // partial object P4 { get; [A(field)] set; } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(6, 40)); + + var containingType = comp.GetMember("B"); + var actualFields = containingType.GetMembers().OfType().OrderBy(f => f.Name).ToImmutableArray(); + var expectedFields = new[] + { + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(4, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + // Similar to previous test, but using backing field within accessors as well as in attributes. + [Theory] + [CombinatorialData] + public void PartialProperty_Attribute_02(bool reverseOrder, bool useStatic, bool useInit) + { + if (useStatic && useInit) return; + string modifier = useStatic ? "static" : " "; + string setter = useInit ? "init" : "set"; + string sourceA = $$""" + using System; + class A : Attribute + { + public A(object o) { } + } + """; + string sourceB1 = $$""" + partial class B + { + {{modifier}} partial object P1 { get; } + {{modifier}} partial object P2 { get; {{setter}}; } + {{modifier}} partial object P3 { [A(field)] get; } + {{modifier}} partial object P4 { get; [A(field)] {{setter}}; } + } + """; + string sourceB2 = $$""" + partial class B + { + {{modifier}} partial object P1 { [A(field)] get { return field; } } + {{modifier}} partial object P2 { get { return null; } [A(field)] {{setter}}; } + {{modifier}} partial object P3 { get { return field; } } + {{modifier}} partial object P4 { get { return null; } {{setter}}; } + } + """; + var comp = CreateCompilation( + reverseOrder ? [sourceB2, sourceB1, sourceA] : [sourceA, sourceB1, sourceB2], + targetFramework: GetTargetFramework(useInit)); + comp.VerifyEmitDiagnostics( + // (3,35): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // partial object P1 { [A(field)] get { return field; } } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(3, 35), + // (4,56): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // partial object P2 { get { return null; } [A(field)] set; } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(4, 56), + // (5,35): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // partial object P3 { [A(field)] get; } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(5, 35), + // (6,40): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // partial object P4 { get; [A(field)] set; } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(6, 40)); + + var containingType = comp.GetMember("B"); + var actualFields = containingType.GetMembers().OfType().OrderBy(f => f.Name).ToImmutableArray(); + var expectedFields = new[] + { + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(4, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "P4", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: true, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [CombinatorialData] + public void PartialProperty_Attribute_03(bool reverseOrder) + { + string sourceA = """ + using System; + class A : Attribute + { + } + """; + string sourceB1 = """ + partial class B + { + [field: A] partial object P1 { get; set; } + [field: A] partial object P2 { get; set; } + [field: A] partial object P3 { get; set; } + partial object Q1 { get; set; } + partial object Q2 { get; set; } + partial object Q3 { get; set; } + } + """; + string sourceB2 = """ + partial class B + { + partial object P1 { get => null; set { } } + partial object P2 { get => field; set { } } + partial object P3 { get => null; set; } + [field: A] partial object Q1 { get => null; set { } } + [field: A] partial object Q2 { get => field; set { } } + [field: A] partial object Q3 { get => null; set; } + } + """; + var comp = CreateCompilation(reverseOrder ? [sourceB2, sourceB1, sourceA] : [sourceA, sourceB1, sourceB2]); + comp.VerifyEmitDiagnostics( + // (3,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. + // [field: A] partial object P1 { get; set; } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(3, 6), + // (6,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. + // [field: A] partial object Q1 { get => null; set { } } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(6, 6)); + + var containingType = comp.GetMember("B"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(6, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + Assert.True(actualProperties[3] is SourcePropertySymbol { Name: "Q1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: false, BackingField: null }); + Assert.True(actualProperties[4] is SourcePropertySymbol { Name: "Q2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[5] is SourcePropertySymbol { Name: "Q3", IsPartialDefinition: true, IsAutoProperty: true, UsesFieldKeyword: false, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + // Backing field required for implementation part only (no initializer), + // or required for both parts (with initializer). + [Theory] + [CombinatorialData] + public void PartialProperty_Attribute_04(bool reverseOrder, bool includeInitializer) + { + string getInitializer(int value) => includeInitializer ? $"= {value};" : ""; + string sourceA = """ + using System; + [AttributeUsage(AttributeTargets.All, AllowMultiple=true)] + class A : Attribute + { + private readonly object _obj; + public A(object obj) { _obj = obj; } + public override string ToString() => $"A({_obj})"; + } + """; + string sourceB1 = $$""" + partial class B + { + partial object P1 { get; } {{getInitializer(1)}} + [field: A(3)] partial object P2 { get; } {{getInitializer(2)}} + [field: A(5)] partial object P3 { get; } {{getInitializer(3)}} + } + """; + string sourceB2 = """ + partial class B + { + [field: A(2)] partial object P1 { get => field; } + partial object P2 { get => field; } + [field: A(6)] partial object P3 { get => field; } + } + """; + string sourceC = """ + using System; + using System.Reflection; + class Program + { + static void Main() + { + foreach (var field in typeof(B).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) + ReportField(field); + } + static void ReportField(FieldInfo field) + { + Console.Write("{0}:", field.Name); + foreach (var obj in field.GetCustomAttributes()) + Console.Write(" {0},", obj.ToString()); + Console.WriteLine(); + } + } + """; + var verifier = CompileAndVerify( + reverseOrder ? [sourceC, sourceB2, sourceB1, sourceA] : [sourceA, sourceB1, sourceB2, sourceC], + expectedOutput: """ + k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(2), + k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(3), + k__BackingField: System.Runtime.CompilerServices.CompilerGeneratedAttribute, A(5), A(6), + """); + verifier.VerifyDiagnostics(); + + var comp = (CSharpCompilation)verifier.Compilation; + var containingType = comp.GetMember("B"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + AssertEx.Equal(["A(2)"], actualFields[0].GetAttributes().ToStrings()); + AssertEx.Equal(["A(3)"], actualFields[1].GetAttributes().ToStrings()); + AssertEx.Equal(["A(5)", "A(6)"], actualFields[2].GetAttributes().ToStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(3, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + // Backing field required for definition part only. + [Theory] + [CombinatorialData] + public void PartialProperty_Attribute_05(bool reverseOrder) + { + string sourceA = """ + using System; + [AttributeUsage(AttributeTargets.All, AllowMultiple=true)] + class A : Attribute + { + private readonly object _obj; + public A(object obj) { _obj = obj; } + public override string ToString() => $"A({_obj})"; + } + """; + string sourceB1 = """ + partial class B + { + partial object P1 { [A(field)] get; } + [field: A(3)] partial object P2 { [A(field)] get; } + [field: A(5)] partial object P3 { [A(field)] get; } + } + """; + string sourceB2 = """ + partial class B + { + [field: A(2)] partial object P1 { get => null; } + partial object P2 { get => null; } + [field: A(6)] partial object P3 { get => null; } + } + """; + var comp = CreateCompilation( + reverseOrder ? [sourceB2, sourceB1, sourceA] : [sourceA, sourceB1, sourceB2]); + comp.VerifyEmitDiagnostics( + // (3,42): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // partial object P1 { [A(field)] get; } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(3, 42), + // (4,42): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [field: A(3)] partial object P2 { [A(field)] get; } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(4, 42), + // (5,42): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [field: A(5)] partial object P3 { [A(field)] get; } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "field").WithLocation(5, 42)); + + var containingType = comp.GetMember("B"); + var actualFields = containingType.GetMembers().OfType().ToImmutableArray(); + var expectedFields = new[] + { + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + "System.Object B.k__BackingField", + }; + AssertEx.Equal(expectedFields, actualFields.ToTestDisplayStrings()); + + AssertEx.Equal(["A(2)"], actualFields[0].GetAttributes().ToStrings()); + AssertEx.Equal(["A(3)"], actualFields[1].GetAttributes().ToStrings()); + AssertEx.Equal(["A(5)", "A(6)"], actualFields[2].GetAttributes().ToStrings()); + + var actualProperties = containingType.GetMembers().OfType().ToImmutableArray(); + Assert.Equal(3, actualProperties.Length); + Assert.True(actualProperties[0] is SourcePropertySymbol { Name: "P1", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[1] is SourcePropertySymbol { Name: "P2", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + Assert.True(actualProperties[2] is SourcePropertySymbol { Name: "P3", IsPartialDefinition: true, IsAutoProperty: false, UsesFieldKeyword: true, BackingField: { } }); + + VerifyMergedProperties(actualProperties, actualFields); + } + + [Theory] + [InlineData("{ get; }")] + [InlineData("{ get; set; }")] + [InlineData("{ get => field; }")] + [InlineData("{ set { field = value; } }")] + [InlineData("{ get => field; set; }")] + [InlineData("{ get; set { field = value; } }")] + [InlineData("{ get => field; set { field = value; } }")] + public void Nameof_01(string accessors) + { + string source = $$""" + #nullable enable + using static System.Console; + struct S1 + { + static object? P1 {{accessors}} + static S1() + { + WriteLine(nameof(P1)); + WriteLine(nameof(S1.P1)); + } + public static void M() + { + WriteLine(nameof(P1)); + WriteLine(nameof(S1.P1)); + } + } + struct S2 + { + object? P2 {{accessors}} + public S2(S2 s) + { + WriteLine(nameof(P2)); + WriteLine(nameof(S2.P2)); + WriteLine(nameof(this.P2)); + } + public void M(S2 s) + { + WriteLine(nameof(P2)); + WriteLine(nameof(S2.P2)); + WriteLine(nameof(this.P2)); + } + } + class Program + { + static void Main() + { + S1.M(); + new S2(default).M(default); + } + } + """; + var verifier = CompileAndVerify(source, expectedOutput: """ + P1 + P1 + P1 + P1 + P2 + P2 + P2 + P2 + P2 + P2 + """); + verifier.VerifyDiagnostics(); + } + + [Theory] + [InlineData("{ get; }")] + [InlineData("{ get; set; }")] + [InlineData("{ get => field; }")] + [InlineData("{ set { field = value; } }")] + [InlineData("{ get => field; set; }")] + [InlineData("{ get; set { field = value; } }")] + [InlineData("{ get => field; set { field = value; } }")] + public void Nameof_02(string accessors) + { + string source = $$""" + #nullable enable + struct S + { + object? P {{accessors}} + public S(bool unused) + { + _ = nameof(new S().P); + } + public void M() + { + _ = nameof(new S().P); + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (7,20): error CS8082: Sub-expression cannot be used in an argument to nameof. + // _ = nameof(new S().P); + Diagnostic(ErrorCode.ERR_SubexpressionNotInNameof, "new S()").WithLocation(7, 20), + // (11,20): error CS8082: Sub-expression cannot be used in an argument to nameof. + // _ = nameof(new S().P); + Diagnostic(ErrorCode.ERR_SubexpressionNotInNameof, "new S()").WithLocation(11, 20)); + } + + [Theory] + [InlineData("{ get; }")] + [InlineData("{ get => field; }")] + public void Nameof_03(string accessors) + { + string source = $$""" + #nullable enable + class C + { + public object? F = null; + } + struct S1 + { + static C? P1 {{accessors}} + static S1() + { + _ = nameof((P1 = new()).F); + } + static void M() + { + _ = nameof((P1 = new()).F); + } + } + struct S2 + { + C? P2 {{accessors}} + S2(bool unused) + { + _ = nameof((P2 = new()).F); + } + void M() + { + _ = nameof((P2 = new()).F); + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (11,20): error CS8082: Sub-expression cannot be used in an argument to nameof. + // _ = nameof((P1 = new()).F); + Diagnostic(ErrorCode.ERR_SubexpressionNotInNameof, "(P1 = new())").WithLocation(11, 20), + // (15,21): error CS0200: Property or indexer 'S1.P1' cannot be assigned to -- it is read only + // _ = nameof((P1 = new()).F); + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "P1").WithArguments("S1.P1").WithLocation(15, 21), + // (23,20): error CS8082: Sub-expression cannot be used in an argument to nameof. + // _ = nameof((P2 = new()).F); + Diagnostic(ErrorCode.ERR_SubexpressionNotInNameof, "(P2 = new())").WithLocation(23, 20), + // (27,21): error CS0200: Property or indexer 'S2.P2' cannot be assigned to -- it is read only + // _ = nameof((P2 = new()).F); + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "P2").WithArguments("S2.P2").WithLocation(27, 21)); + } + + [Theory] + [InlineData("{ get; }")] + [InlineData("{ get => field; }")] + public void RangeVariableValue_01(string accessors) + { + string source = $$""" + #nullable enable + using System.Linq; + struct S + { + object? P {{accessors}} + S(object value) + { + _ = from x in new [] { value } + let y = (P = x) + select (P = y); + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (9,22): error CS1673: Anonymous methods, lambda expressions, query expressions, and local functions inside structs cannot access instance members of 'this'. Consider copying 'this' to a local variable outside the anonymous method, lambda expression, query expression, or local function and using the local instead. + // let y = (P = x) + Diagnostic(ErrorCode.ERR_ThisStructNotInAnonMeth, "P").WithLocation(9, 22), + // (10,21): error CS1673: Anonymous methods, lambda expressions, query expressions, and local functions inside structs cannot access instance members of 'this'. Consider copying 'this' to a local variable outside the anonymous method, lambda expression, query expression, or local function and using the local instead. + // select (P = y); + Diagnostic(ErrorCode.ERR_ThisStructNotInAnonMeth, "P").WithLocation(10, 21)); + } + + [Theory] + [InlineData("{ get; set; }")] + [InlineData("{ get => field; set; }")] + public void RangeVariableValue_02(string accessors) + { + string source = $$""" + #nullable enable + using System.Linq; + struct S + { + object? P {{accessors}} + S(S s, object value) + { + _ = from x in new [] { value } + let y = (s.P = x) + select (s.P = y); + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + } +} diff --git a/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs b/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs index ba52f320b87c0..a03091a21ad6a 100644 --- a/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FirstClassSpanTests.cs @@ -7078,17 +7078,12 @@ public void OverloadResolution_ReadOnlySpanVsArray_02(LanguageVersion langVersio static class C { - public static void M(string[] x) { } - public static void M(ReadOnlySpan x) { } + public static void M(string[] x) => Console.Write(" s" + x[0]); + public static void M(ReadOnlySpan x) => Console.Write(" o" + x[0]); } """; - CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)).VerifyDiagnostics( - // (4,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(string[])' and 'C.M(ReadOnlySpan)' - // C.M([..a]); - Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(string[])", "C.M(System.ReadOnlySpan)").WithLocation(4, 3), - // (5,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(string[])' and 'C.M(ReadOnlySpan)' - // C.M(["a"]); - Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(string[])", "C.M(System.ReadOnlySpan)").WithLocation(5, 3)); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source, parseOptions: TestOptions.Regular.WithLanguageVersion(langVersion)); + CompileAndVerify(comp, expectedOutput: "sa sa").VerifyDiagnostics(); } [Fact] @@ -7292,17 +7287,12 @@ public void OverloadResolution_ReadOnlySpanVsArray_Params_02() static class C { - public static void M(params string[] x) { } - public static void M(params ReadOnlySpan x) { } + public static void M(params string[] x) => Console.Write(" s" + x[0]); + public static void M(params ReadOnlySpan x) => Console.Write(" o" + x[0]); } """; - CreateCompilationWithSpanAndMemoryExtensions(source).VerifyDiagnostics( - // (4,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(params string[])' and 'C.M(params ReadOnlySpan)' - // C.M([..a]); - Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(params string[])", "C.M(params System.ReadOnlySpan)").WithLocation(4, 3), - // (5,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(params string[])' and 'C.M(params ReadOnlySpan)' - // C.M(["a"]); - Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(params string[])", "C.M(params System.ReadOnlySpan)").WithLocation(5, 3)); + var comp = CreateCompilationWithSpanAndMemoryExtensions(source); + CompileAndVerify(comp, expectedOutput: "sa sa").VerifyDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowDiagnosticTests.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowDiagnosticTests.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowDiagnosticTests.cs rename to src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowDiagnosticTests.cs index 61eebf4976dd8..4a8797b493957 100644 --- a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowDiagnosticTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowDiagnosticTests.cs @@ -2113,7 +2113,7 @@ internal void OnNextValue(float? value) } } "; - CreateCompilationWithMscorlib45(program).VerifyEmitDiagnostics(); + CreateCompilationWithMscorlib461(program).VerifyEmitDiagnostics(); } #endregion diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTestBase.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTestBase.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTestBase.cs rename to src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTestBase.cs diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTests.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTests.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTests.cs rename to src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTests.cs index ecdf7d7ec72b2..a2adeb9f4169b 100644 --- a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/FlowTests.cs @@ -5336,7 +5336,7 @@ static void Main() } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (17,34): error CS0165: Use of unassigned local variable 'o' // System.Console.WriteLine(o); Diagnostic(ErrorCode.ERR_UseDefViolation, "o").WithArguments("o").WithLocation(17, 34) @@ -5368,7 +5368,7 @@ static void Main() } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -5397,7 +5397,7 @@ static void Main() } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -5426,7 +5426,7 @@ static void Main() } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( ); } @@ -5453,7 +5453,7 @@ void TestFunc(int i) } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } // DataFlowPass.VisitConversion with IsConditionalState. @@ -5554,7 +5554,7 @@ public static void Test() } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (28,17): error CS0165: Use of unassigned local variable 'obj' // obj.ToString(); Diagnostic(ErrorCode.ERR_UseDefViolation, "obj").WithArguments("obj").WithLocation(28, 17) diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/IterationJumpYieldStatementTests.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/IterationJumpYieldStatementTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/FlowAnalysis/IterationJumpYieldStatementTests.cs rename to src/Compilers/CSharp/Test/Emit3/FlowAnalysis/IterationJumpYieldStatementTests.cs diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/LocalFunctions.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/LocalFunctions.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/FlowAnalysis/LocalFunctions.cs rename to src/Compilers/CSharp/Test/Emit3/FlowAnalysis/LocalFunctions.cs diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/PatternMatchingTest5.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/PatternMatchingTest5.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/FlowAnalysis/PatternMatchingTest5.cs rename to src/Compilers/CSharp/Test/Emit3/FlowAnalysis/PatternMatchingTest5.cs diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/PatternsVsRegions.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/PatternsVsRegions.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/FlowAnalysis/PatternsVsRegions.cs rename to src/Compilers/CSharp/Test/Emit3/FlowAnalysis/PatternsVsRegions.cs diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/RegionAnalysisTests.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/RegionAnalysisTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/FlowAnalysis/RegionAnalysisTests.cs rename to src/Compilers/CSharp/Test/Emit3/FlowAnalysis/RegionAnalysisTests.cs diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/StructTests.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/StructTests.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/FlowAnalysis/StructTests.cs rename to src/Compilers/CSharp/Test/Emit3/FlowAnalysis/StructTests.cs index fd01c43e7352f..32248a37617e9 100644 --- a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/StructTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/StructTests.cs @@ -213,7 +213,7 @@ public void GenericStructWithPropertyUsingStruct() { S? P { get; set; } }"; - CreateCompilation(source, targetFramework: TargetFramework.Mscorlib45).VerifyDiagnostics( + CreateCompilation(source, targetFramework: TargetFramework.Mscorlib461).VerifyDiagnostics( // (3,13): error CS0523: Struct member 'S.P' of type 'S?' causes a cycle in the struct layout // S? P { get; set; } Diagnostic(ErrorCode.ERR_StructLayoutCycle, "P").WithArguments("S.P", "S?").WithLocation(3, 13)); diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/TryLockUsingStatementTests.cs b/src/Compilers/CSharp/Test/Emit3/FlowAnalysis/TryLockUsingStatementTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/FlowAnalysis/TryLockUsingStatementTests.cs rename to src/Compilers/CSharp/Test/Emit3/FlowAnalysis/TryLockUsingStatementTests.cs diff --git a/src/Compilers/CSharp/Test/Emit3/OverloadResolutionPriorityTests.cs b/src/Compilers/CSharp/Test/Emit3/OverloadResolutionPriorityTests.cs index 600ef85738564..1eaf022d7af20 100644 --- a/src/Compilers/CSharp/Test/Emit3/OverloadResolutionPriorityTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/OverloadResolutionPriorityTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -818,7 +818,7 @@ public class C { [OverloadResolutionPriority(1)] public void M(object o) => System.Console.Write("1"); - public void M(string s) => throw null; + public void M(string s) => System.Console.Write("5"); [OverloadResolutionPriority(1)] public int this[object o] @@ -835,8 +835,15 @@ public int this[object o] } public int this[string s] { - get => throw null; - set => throw null; + get + { + System.Console.Write("6"); + return 1; + } + set + { + System.Console.Write("7"); + } } [OverloadResolutionPriority(1)] @@ -847,7 +854,7 @@ public C(object o) public C(string s) { - throw null; + System.Console.Write("8"); } } """; @@ -859,9 +866,9 @@ public C(string s) // (9,6): error CS9202: Feature 'overload resolution priority' is not available in C# 12.0. Please use language version 13.0 or greater. // [OverloadResolutionPriority(1)] Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "OverloadResolutionPriority(1)").WithArguments("overload resolution priority", "13.0").WithLocation(9, 6), - // (28,6): error CS9202: Feature 'overload resolution priority' is not available in C# 12.0. Please use language version 13.0 or greater. + // (35,6): error CS9202: Feature 'overload resolution priority' is not available in C# 12.0. Please use language version 13.0 or greater. // [OverloadResolutionPriority(1)] - Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "OverloadResolutionPriority(1)").WithArguments("overload resolution priority", "13.0").WithLocation(28, 6)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "OverloadResolutionPriority(1)").WithArguments("overload resolution priority", "13.0").WithLocation(35, 6)); var definingComp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition], parseOptions: TestOptions.Regular13).VerifyDiagnostics(); @@ -872,8 +879,8 @@ public C(string s) c.M("test"); """; - // We don't error on consumption, only on definition, so this runs just fine. - CompileAndVerify(consumingSource, references: [definingComp.ToMetadataReference()], parseOptions: TestOptions.Regular12, expectedOutput: "4321").VerifyDiagnostics(); + CompileAndVerify(consumingSource, references: [definingComp.ToMetadataReference()], parseOptions: TestOptions.Regular12, expectedOutput: "8765").VerifyDiagnostics(); + CompileAndVerify(consumingSource, references: [definingComp.ToMetadataReference()], parseOptions: TestOptions.Regular13, expectedOutput: "4321").VerifyDiagnostics(); } [Fact] @@ -1723,10 +1730,10 @@ public int this[string o] c[arg] = 1; """; - CompileAndVerify([executable, source, OverloadResolutionPriorityAttributeDefinition], targetFramework: TargetFramework.Mscorlib45AndCSharp, expectedOutput: "1234").VerifyDiagnostics(); + CompileAndVerify([executable, source, OverloadResolutionPriorityAttributeDefinition], targetFramework: TargetFramework.Mscorlib461AndCSharp, expectedOutput: "1234").VerifyDiagnostics(); - var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition], targetFramework: TargetFramework.Mscorlib45AndCSharp); - CompileAndVerify(executable, references: new[] { AsReference(comp, useMetadataReference) }, targetFramework: TargetFramework.Mscorlib45AndCSharp, expectedOutput: "1234").VerifyDiagnostics(); + var comp = CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition], targetFramework: TargetFramework.Mscorlib461AndCSharp); + CompileAndVerify(executable, references: new[] { AsReference(comp, useMetadataReference) }, targetFramework: TargetFramework.Mscorlib461AndCSharp, expectedOutput: "1234").VerifyDiagnostics(); } [Fact] @@ -1822,7 +1829,11 @@ public static void Main() } """; - CompileAndVerify([source, OverloadResolutionPriorityAttributeDefinition], expectedOutput: "1").VerifyDiagnostics(); + CreateCompilation([source, OverloadResolutionPriorityAttributeDefinition]).VerifyDiagnostics( + // (9,10): error CS9262: Cannot use 'OverloadResolutionPriorityAttribute' on this member. + // [OverloadResolutionPriority(1)] + Diagnostic(ErrorCode.ERR_CannotApplyOverloadResolutionPriorityToMember, "OverloadResolutionPriority(1)").WithLocation(9, 10) + ); } [Fact] diff --git a/src/Compilers/CSharp/Test/Emit3/ParamsCollectionTests.cs b/src/Compilers/CSharp/Test/Emit3/ParamsCollectionTests.cs deleted file mode 100644 index 7d2ce4528690c..0000000000000 --- a/src/Compilers/CSharp/Test/Emit3/ParamsCollectionTests.cs +++ /dev/null @@ -1,554 +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 Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.CSharp.Test.Utilities; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics -{ - public class ParamsCollectionTests : CompilingTestBase - { - [Fact] - [WorkItem("https://github.com/dotnet/roslyn/issues/73743")] - public void ParamsSpanInExpression_01() - { - string source = """ -class Program -{ - public static void Test() - { - System.Linq.Expressions.Expression> e = (s) => M(s, s, s); - } - - static void M(params string[] p) {} - static void M(params System.Span p) {} -} -"""; - var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); - - comp.VerifyEmitDiagnostics( - // (5,78): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'Span'. - // System.Linq.Expressions.Expression> e = (s) => M(s, s, s); - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "M(s, s, s)").WithArguments("Span").WithLocation(5, 78), - // (5,78): error CS9226: An expression tree may not contain an expanded form of non-array params collection parameter. - // System.Linq.Expressions.Expression> e = (s) => M(s, s, s); - Diagnostic(ErrorCode.ERR_ParamsCollectionExpressionTree, "M(s, s, s)").WithLocation(5, 78) - ); - } - - [Fact] - [WorkItem("https://github.com/dotnet/roslyn/issues/73743")] - public void ParamsSpanInExpression_02() - { - string source = """ -class Program -{ - public static void Test() - { - System.Linq.Expressions.Expression> e = (s) => M(s, s, s); - } - - static void M(params System.Span p) {} -} -"""; - var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); - - comp.VerifyEmitDiagnostics( - // (5,78): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'Span'. - // System.Linq.Expressions.Expression> e = (s) => M(s, s, s); - Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "M(s, s, s)").WithArguments("Span").WithLocation(5, 78), - // (5,78): error CS9226: An expression tree may not contain an expanded form of non-array params collection parameter. - // System.Linq.Expressions.Expression> e = (s) => M(s, s, s); - Diagnostic(ErrorCode.ERR_ParamsCollectionExpressionTree, "M(s, s, s)").WithLocation(5, 78) - ); - } - - [Fact] - [WorkItem("https://github.com/dotnet/roslyn/issues/74163")] - public void StringInterpolation_01() - { - string source1 = """ -class Program -{ - public static void Test1() - { - System.Linq.Expressions.Expression> e = (s) => $"{s} {2} {s} {4}"; - } - - public static void Test2() - { - System.Linq.Expressions.Expression> e = (s) => $"{s} {2} {s} {4}"; - } -} -"""; - string core = """ -namespace System -{ - public class Object {} - - public class ValueType {} - public abstract partial class Enum {} - - public struct Void {} - public struct Boolean {} - public struct Byte {} - public struct Int16 {} - public struct Int32 {} - public struct Int64 {} - public struct IntPtr {} - - public partial class Exception {} - - public class String - { - public static string Format(string format, params object[] args) => null; - public static string Format(string format, params ReadOnlySpan args) => null; - } - - public abstract class FormattableString {} - - public abstract partial class Attribute {} - public sealed class ParamArrayAttribute : Attribute {} - - public enum AttributeTargets - { - Assembly = 1, - Module = 2, - Class = 4, - Struct = 8, - Enum = 16, - Constructor = 32, - Method = 64, - Property = 128, - Field = 256, - Event = 512, - Interface = 1024, - Parameter = 2048, - Delegate = 4096, - ReturnValue = 8192, - GenericParameter = 16384, - All = 32767 - } - - public sealed class AttributeUsageAttribute : Attribute - { - public AttributeUsageAttribute(AttributeTargets validOn) - { - } - - internal AttributeUsageAttribute(AttributeTargets validOn, bool allowMultiple, bool inherited) - { - } - - public AttributeTargets ValidOn {get; set;} - - public bool AllowMultiple {get; set;} - - public bool Inherited {get; set;} - } - - public abstract partial class Delegate {} - public abstract partial class MulticastDelegate : Delegate {} - - public delegate TResult Func(T arg); - - public interface IDisposable - { - void Dispose(); - } - - public partial struct Nullable where T : struct {} - - public unsafe partial struct RuntimeTypeHandle {} - public unsafe partial struct RuntimeMethodHandle {} - public abstract partial class Type - { - public static Type GetTypeFromHandle(RuntimeTypeHandle handle) => null; - } - - public ref struct ReadOnlySpan - { - public ReadOnlySpan(T[] array) - { - } - - public ReadOnlySpan(T[] array, int start, int length) - { - } - - public unsafe ReadOnlySpan(void* pointer, int length) - { - } - } -} - -namespace System.Collections -{ - public interface IEnumerator - { - object Current { get; } - bool MoveNext(); - void Reset(); - } - - public interface IEnumerable - { - IEnumerator GetEnumerator(); - } -} - -namespace System.Collections.Generic -{ - public interface IEnumerator : IEnumerator, IDisposable - { - new T Current { get; } - } - - public interface IEnumerable : IEnumerable - { - new IEnumerator GetEnumerator(); - } -} - -namespace System.Reflection -{ - public abstract unsafe partial class MethodBase - { - public static MethodBase GetMethodFromHandle(RuntimeMethodHandle handle) => null; - public static MethodBase GetMethodFromHandle(RuntimeMethodHandle handle, RuntimeTypeHandle declaringType) => null; - } - - public abstract partial class MethodInfo : MethodBase {} - - public abstract partial class ConstructorInfo : MethodBase {} -} - -namespace System.Linq.Expressions -{ - using System.Collections.Generic; - using System.Reflection; - - public partial class Expression - { - public static ParameterExpression Parameter(Type type) => null; - public static ParameterExpression Parameter(Type type, string name) => null; - public static ConstantExpression Constant(object value) => null; - public static ConstantExpression Constant(object value, Type type) => null; - - public static Expression Lambda(Expression body, params ParameterExpression[] parameters) => null; - public static NewArrayExpression NewArrayInit(Type type, params Expression[] initializers) => null; - public static NewExpression New(ConstructorInfo constructor, IEnumerable arguments) => null; - public static MethodCallExpression Call(Expression instance, MethodInfo method, params Expression[] arguments) => null; - public static UnaryExpression Convert(Expression expression, Type type) => null; - } - - public abstract class LambdaExpression : Expression {} - - public class Expression : LambdaExpression {} - - public class ParameterExpression : Expression {} - public class ConstantExpression : Expression {} - public class NewArrayExpression : Expression {} - public class NewExpression : Expression {} - public class MethodCallExpression : Expression {} - public class UnaryExpression : Expression {} -} - -namespace System.Runtime.CompilerServices -{ - public sealed class InlineArrayAttribute : Attribute - { - public InlineArrayAttribute(int length) - { - } - } - - public sealed class IsReadOnlyAttribute : Attribute - {} - - public static class FormattableStringFactory - { - public static FormattableString Create(string format, params object[] arguments) => null; - public static FormattableString Create(string format, params ReadOnlySpan arguments) => null; - } - - public static unsafe partial class Unsafe - { - public static ref TTo As(ref TFrom source) => throw null; - public static ref T AsRef(scoped ref readonly T source) => throw null; - public static ref T Add(ref T source, int elementOffset) => throw null; - } -} - -namespace System.Runtime.InteropServices -{ - public static partial class MemoryMarshal - { - public static ReadOnlySpan CreateReadOnlySpan(ref readonly T reference, int length) => default; - } -} -"""; - - var comp = CreateEmptyCompilation([source1, core], options: TestOptions.ReleaseDll.WithAllowUnsafe(true)); - var verifier = CompileAndVerify(comp, verify: Verification.Skipped).VerifyDiagnostics( - // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options. - Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1) - ); - - verifier.VerifyIL("Program.Test1", -@" -{ - // Code size 198 (0xc6) - .maxstack 11 - .locals init (System.Linq.Expressions.ParameterExpression V_0) - IL_0000: ldtoken ""string"" - IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_000a: ldstr ""s"" - IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)"" - IL_0014: stloc.0 - IL_0015: ldnull - IL_0016: ldtoken ""string string.Format(string, params object[])"" - IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" - IL_0020: castclass ""System.Reflection.MethodInfo"" - IL_0025: ldc.i4.2 - IL_0026: newarr ""System.Linq.Expressions.Expression"" - IL_002b: dup - IL_002c: ldc.i4.0 - IL_002d: ldstr ""{0} {1} {2} {3}"" - IL_0032: ldtoken ""string"" - IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" - IL_0041: stelem.ref - IL_0042: dup - IL_0043: ldc.i4.1 - IL_0044: ldtoken ""object"" - IL_0049: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_004e: ldc.i4.4 - IL_004f: newarr ""System.Linq.Expressions.Expression"" - IL_0054: dup - IL_0055: ldc.i4.0 - IL_0056: ldloc.0 - IL_0057: stelem.ref - IL_0058: dup - IL_0059: ldc.i4.1 - IL_005a: ldc.i4.2 - IL_005b: box ""int"" - IL_0060: ldtoken ""int"" - IL_0065: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_006a: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" - IL_006f: ldtoken ""object"" - IL_0074: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_0079: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" - IL_007e: stelem.ref - IL_007f: dup - IL_0080: ldc.i4.2 - IL_0081: ldloc.0 - IL_0082: stelem.ref - IL_0083: dup - IL_0084: ldc.i4.3 - IL_0085: ldc.i4.4 - IL_0086: box ""int"" - IL_008b: ldtoken ""int"" - IL_0090: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_0095: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" - IL_009a: ldtoken ""object"" - IL_009f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_00a4: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" - IL_00a9: stelem.ref - IL_00aa: call ""System.Linq.Expressions.NewArrayExpression System.Linq.Expressions.Expression.NewArrayInit(System.Type, params System.Linq.Expressions.Expression[])"" - IL_00af: stelem.ref - IL_00b0: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" - IL_00b5: ldc.i4.1 - IL_00b6: newarr ""System.Linq.Expressions.ParameterExpression"" - IL_00bb: dup - IL_00bc: ldc.i4.0 - IL_00bd: ldloc.0 - IL_00be: stelem.ref - IL_00bf: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" - IL_00c4: pop - IL_00c5: ret -} -"); - - verifier.VerifyIL("Program.Test2", -@" -{ - // Code size 198 (0xc6) - .maxstack 11 - .locals init (System.Linq.Expressions.ParameterExpression V_0) - IL_0000: ldtoken ""string"" - IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_000a: ldstr ""s"" - IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)"" - IL_0014: stloc.0 - IL_0015: ldnull - IL_0016: ldtoken ""System.FormattableString System.Runtime.CompilerServices.FormattableStringFactory.Create(string, params object[])"" - IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" - IL_0020: castclass ""System.Reflection.MethodInfo"" - IL_0025: ldc.i4.2 - IL_0026: newarr ""System.Linq.Expressions.Expression"" - IL_002b: dup - IL_002c: ldc.i4.0 - IL_002d: ldstr ""{0} {1} {2} {3}"" - IL_0032: ldtoken ""string"" - IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" - IL_0041: stelem.ref - IL_0042: dup - IL_0043: ldc.i4.1 - IL_0044: ldtoken ""object"" - IL_0049: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_004e: ldc.i4.4 - IL_004f: newarr ""System.Linq.Expressions.Expression"" - IL_0054: dup - IL_0055: ldc.i4.0 - IL_0056: ldloc.0 - IL_0057: stelem.ref - IL_0058: dup - IL_0059: ldc.i4.1 - IL_005a: ldc.i4.2 - IL_005b: box ""int"" - IL_0060: ldtoken ""int"" - IL_0065: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_006a: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" - IL_006f: ldtoken ""object"" - IL_0074: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_0079: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" - IL_007e: stelem.ref - IL_007f: dup - IL_0080: ldc.i4.2 - IL_0081: ldloc.0 - IL_0082: stelem.ref - IL_0083: dup - IL_0084: ldc.i4.3 - IL_0085: ldc.i4.4 - IL_0086: box ""int"" - IL_008b: ldtoken ""int"" - IL_0090: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_0095: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" - IL_009a: ldtoken ""object"" - IL_009f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" - IL_00a4: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" - IL_00a9: stelem.ref - IL_00aa: call ""System.Linq.Expressions.NewArrayExpression System.Linq.Expressions.Expression.NewArrayInit(System.Type, params System.Linq.Expressions.Expression[])"" - IL_00af: stelem.ref - IL_00b0: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" - IL_00b5: ldc.i4.1 - IL_00b6: newarr ""System.Linq.Expressions.ParameterExpression"" - IL_00bb: dup - IL_00bc: ldc.i4.0 - IL_00bd: ldloc.0 - IL_00be: stelem.ref - IL_00bf: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" - IL_00c4: pop - IL_00c5: ret - -} -"); - - string source2 = """ -class Program -{ - public static string Test1(string s) => $"{s} {2} {s} {4}"; - - public static System.FormattableString Test2(string s) => $"{s} {2} {s} {4}"; -} -"""; - comp = CreateEmptyCompilation([source2, core], options: TestOptions.ReleaseDll.WithAllowUnsafe(true)); - verifier = CompileAndVerify(comp, verify: Verification.Skipped).VerifyDiagnostics( - // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options. - Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1) - ); - - verifier.VerifyIL("Program.Test1", -@" -{ - // Code size 77 (0x4d) - .maxstack 3 - .locals init (<>y__InlineArray4 V_0) - IL_0000: ldstr ""{0} {1} {2} {3}"" - IL_0005: ldloca.s V_0 - IL_0007: initobj ""<>y__InlineArray4"" - IL_000d: ldloca.s V_0 - IL_000f: ldc.i4.0 - IL_0010: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" - IL_0015: ldarg.0 - IL_0016: stind.ref - IL_0017: ldloca.s V_0 - IL_0019: ldc.i4.1 - IL_001a: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" - IL_001f: ldc.i4.2 - IL_0020: box ""int"" - IL_0025: stind.ref - IL_0026: ldloca.s V_0 - IL_0028: ldc.i4.2 - IL_0029: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" - IL_002e: ldarg.0 - IL_002f: stind.ref - IL_0030: ldloca.s V_0 - IL_0032: ldc.i4.3 - IL_0033: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" - IL_0038: ldc.i4.4 - IL_0039: box ""int"" - IL_003e: stind.ref - IL_003f: ldloca.s V_0 - IL_0041: ldc.i4.4 - IL_0042: call ""System.ReadOnlySpan .InlineArrayAsReadOnlySpan<<>y__InlineArray4, object>(in <>y__InlineArray4, int)"" - IL_0047: call ""string string.Format(string, params System.ReadOnlySpan)"" - IL_004c: ret -} -"); - - verifier.VerifyIL("Program.Test2", -@" -{ - // Code size 77 (0x4d) - .maxstack 3 - .locals init (<>y__InlineArray4 V_0) - IL_0000: ldstr ""{0} {1} {2} {3}"" - IL_0005: ldloca.s V_0 - IL_0007: initobj ""<>y__InlineArray4"" - IL_000d: ldloca.s V_0 - IL_000f: ldc.i4.0 - IL_0010: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" - IL_0015: ldarg.0 - IL_0016: stind.ref - IL_0017: ldloca.s V_0 - IL_0019: ldc.i4.1 - IL_001a: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" - IL_001f: ldc.i4.2 - IL_0020: box ""int"" - IL_0025: stind.ref - IL_0026: ldloca.s V_0 - IL_0028: ldc.i4.2 - IL_0029: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" - IL_002e: ldarg.0 - IL_002f: stind.ref - IL_0030: ldloca.s V_0 - IL_0032: ldc.i4.3 - IL_0033: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" - IL_0038: ldc.i4.4 - IL_0039: box ""int"" - IL_003e: stind.ref - IL_003f: ldloca.s V_0 - IL_0041: ldc.i4.4 - IL_0042: call ""System.ReadOnlySpan .InlineArrayAsReadOnlySpan<<>y__InlineArray4, object>(in <>y__InlineArray4, int)"" - IL_0047: call ""System.FormattableString System.Runtime.CompilerServices.FormattableStringFactory.Create(string, params System.ReadOnlySpan)"" - IL_004c: ret -} -"); - } - } -} diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/RefReadonlyParameterTests.cs b/src/Compilers/CSharp/Test/Emit3/RefReadonlyParameterTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Semantics/RefReadonlyParameterTests.cs rename to src/Compilers/CSharp/Test/Emit3/RefReadonlyParameterTests.cs diff --git a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs index 9ff6e678248d2..9eb341f5bb670 100644 --- a/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -41,12 +42,12 @@ void verify(ModuleSymbol m) Assert.True(m.GlobalNamespace.GetMember("I.M").HasUnscopedRefAttribute); } - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 6) ); } @@ -74,12 +75,12 @@ void verify(ModuleSymbol m) Assert.True(m.GlobalNamespace.GetMember("I.M").HasUnscopedRefAttribute); } - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 6) ); } @@ -156,12 +157,12 @@ void verify(ModuleSymbol m) Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 6) ); } @@ -188,12 +189,12 @@ void verify(ModuleSymbol m) Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 6) ); } @@ -273,12 +274,12 @@ void verify(ModuleSymbol m) Assert.True(propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (8,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,10): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(8, 10) ); } @@ -311,12 +312,12 @@ void verify(ModuleSymbol m) Assert.True(propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (8,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,10): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(8, 10) ); } @@ -403,12 +404,12 @@ void verify(ModuleSymbol m) Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 6) ); } @@ -435,12 +436,12 @@ void verify(ModuleSymbol m) Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 6) ); } @@ -521,12 +522,12 @@ void verify(ModuleSymbol m) Assert.True(propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (8,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,10): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(8, 10) ); } @@ -559,12 +560,12 @@ void verify(ModuleSymbol m) Assert.True(propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (8,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,10): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(8, 10) ); } @@ -805,12 +806,12 @@ void verify(ModuleSymbol m) Assert.True(m.GlobalNamespace.GetMember("C.M").HasUnscopedRefAttribute); } - CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (8,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(8, 6) ); } @@ -839,12 +840,12 @@ void verify(ModuleSymbol m) Assert.True(m.GlobalNamespace.GetMember("C.I.M").HasUnscopedRefAttribute); } - CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (8,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(8, 6) ); } @@ -1029,9 +1030,9 @@ public ref int M() "; CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( - // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (100,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(100, 6) ); } @@ -1347,23 +1348,23 @@ void verify(ModuleSymbol m) Assert.Equal(onImplementationGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13); + comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12); if (onImplementationGet) { comp7.VerifyDiagnostics( - // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (200,10): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(200, 10) ); } else { comp7.VerifyDiagnostics( - // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (100,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(100, 6) ); } } @@ -1400,37 +1401,37 @@ void verify(ModuleSymbol m) Assert.Equal(onImplementationGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13); + comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12); if (onImplementationProperty) { if (onImplementationGet) { comp8.VerifyDiagnostics( - // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (100,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6), - // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(100, 6), + // (200,10): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(200, 10) ); } else { comp8.VerifyDiagnostics( - // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (100,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(100, 6) ); } } else { comp8.VerifyDiagnostics( - // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (200,10): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(200, 10) ); } } @@ -1923,23 +1924,23 @@ void verify(ModuleSymbol m) Assert.Equal(onImplementationGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13); + comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12); if (onImplementationGet) { comp7.VerifyDiagnostics( - // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (200,10): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(200, 10) ); } else { comp7.VerifyDiagnostics( - // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (100,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(100, 6) ); } } @@ -1976,37 +1977,37 @@ void verify(ModuleSymbol m) Assert.Equal(onImplementationGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); } - CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13).VerifyDiagnostics(); - comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular13); + comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12); if (onImplementationProperty) { if (onImplementationGet) { comp8.VerifyDiagnostics( - // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (100,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6), - // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(100, 6), + // (200,10): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(200, 10) ); } else { comp8.VerifyDiagnostics( - // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (100,6): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(100, 6) ); } } else { comp8.VerifyDiagnostics( - // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (200,10): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // [UnscopedRef] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "UnscopedRef").WithArguments("ref struct interfaces", "13.0").WithLocation(200, 10) ); } } @@ -4366,6 +4367,9 @@ public class C CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify, verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify, verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped, + emitOptions: EmitOptions.Default.WithEmitMetadataOnly(true)).VerifyDiagnostics(); + void verify(ModuleSymbol m) { var c = m.GlobalNamespace.GetMember("C"); @@ -4388,7 +4392,7 @@ void verify(ModuleSymbol m) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "ref struct").WithArguments("allows ref struct constraint", "13.0").WithLocation(3, 22) ); - comp = CreateCompilation(src, targetFramework: TargetFramework.DesktopLatestExtended, parseOptions: TestOptions.Regular13).VerifyDiagnostics( + comp = CreateCompilation(src, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular13).VerifyDiagnostics( // (3,22): error CS9240: Target runtime doesn't support by-ref-like generics. // where T : allows ref struct Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportByRefLikeGenerics, "ref struct").WithLocation(3, 22) @@ -4438,7 +4442,7 @@ void verify(ModuleSymbol m) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "ref struct").WithArguments("allows ref struct constraint", "13.0").WithLocation(5, 26) ); - CreateCompilation(src, targetFramework: TargetFramework.DesktopLatestExtended, parseOptions: TestOptions.Regular13).VerifyDiagnostics( + CreateCompilation(src, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular13).VerifyDiagnostics( // (5,26): error CS9240: Target runtime doesn't support by-ref-like generics. // where T : allows ref struct Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportByRefLikeGenerics, "ref struct").WithLocation(5, 26) @@ -5856,12 +5860,12 @@ void verify(ModuleSymbol m) Assert.Equal("I1", s1.InterfacesNoUseSiteDiagnostics().Single().ToTestDisplayString()); } - CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.RegularNext).VerifyEmitDiagnostics(); + CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(); - CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular13).VerifyDiagnostics( - // (5,17): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + CreateCompilation(src, targetFramework: TargetFramework.Net70, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (5,17): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // ref struct S1 : I1 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1").WithArguments("ref struct interfaces").WithLocation(5, 17) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "I1").WithArguments("ref struct interfaces", "13.0").WithLocation(5, 17) ); } @@ -5916,6 +5920,11 @@ static void Main() { Test(new S1()); } + + static void Test2(T2 x) where T2 : I1, allows ref struct + { + Test(x); + } static void Test(T x) where T : I1 { @@ -5923,12 +5932,15 @@ static void Test(T x) where T : I1 } } "; - var comp = CreateCompilation(src); + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); comp.VerifyDiagnostics( // (19,9): error CS9244: The type 'S1' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T' in the generic type or method 'C.Test(T)' // Test(new S1()); - Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "Test").WithArguments("C.Test(T)", "T", "S1").WithLocation(19, 9) + Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "Test").WithArguments("C.Test(T)", "T", "S1").WithLocation(19, 9), + // (24,9): error CS9244: The type 'T2' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T' in the generic type or method 'C.Test(T)' + // Test(x); + Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "Test").WithArguments("C.Test(T)", "T", "T2").WithLocation(24, 9) ); } @@ -5994,7 +6006,12 @@ interface I1 void M1(T x); } -ref struct S1 : I1 +interface I2 +{ + T M2(); +} + +ref struct S1 : I1, I2 { public void M1(object x) { @@ -6002,25 +6019,55 @@ public void M1(object x) System.Console.Write("" ""); System.Console.Write(x); } + + public string M2() + { + System.Console.Write(""S1.M2 ""); + return ""z""; + } } class C { static void Main() { - Test(new S1(), ""y""); + Test1(new S1(), ""y""); + System.Console.Write("" - ""); + System.Console.Write(Test2(new S1())); + System.Console.Write("" - ""); + Test3(new S1(), ""y""); + System.Console.Write("" - ""); + System.Console.Write(Test4(new S1())); } - static void Test(T x, string y) where T : I1, allows ref struct + static void Test1(T x, string y) where T : I1, allows ref struct { x.M1(y); } + + static object Test2(T x) where T : I2, allows ref struct + { + return x.M2(); + } + + static void Test3(T x, string y) where T : I1, allows ref struct + { + Test1(x, y); + } + + static object Test4(T x) where T : I2, allows ref struct + { + return Test2(x); + } } "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - var verifier = CompileAndVerify(comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? @"S1.M1 y" : null, verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); - verifier.VerifyIL("C.Test(T, string)", + var verifier = CompileAndVerify( + comp, expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? @"S1.M1 y - S1.M2 z - S1.M1 y - S1.M2 z" : null, + verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); + + verifier.VerifyIL("C.Test1(T, string)", @" { // Code size 15 (0xf) @@ -6031,6 +6078,18 @@ .maxstack 2 IL_0009: callvirt ""void I1.M1(string)"" IL_000e: ret } +"); + + verifier.VerifyIL("C.Test2(T)", +@" +{ + // Code size 14 (0xe) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: constrained. ""T"" + IL_0008: callvirt ""object I2.M2()"" + IL_000d: ret +} "); } @@ -6438,17 +6497,29 @@ interface IOut { T MOut(); } -ref struct S : I, IOut +interface IIn +{ + void MIn(T x); +} + +ref struct S : I, IOut, IIn { public void M(object o) { } public object MOut() => null; + public void MIn(string x) {} } class Program { static void Main() { +#line 19 Test1(new S()); Test2(new S()); + Test3(new S()); + + Test4(new S()); + Test5(new S()); + Test6(new S()); } static void Test1(T x) where T : I, allows ref struct { @@ -6456,6 +6527,22 @@ static void Test1(T x) where T : I, allows ref struct static void Test2(T x) where T : IOut, allows ref struct { } + static void Test3(T x) where T : IIn, allows ref struct + { + } + + static void Test4(T4 x) where T4 : I, allows ref struct + { + Test1(x); + } + static void Test5(T5 x) where T5 : IOut, allows ref struct + { + Test2(x); + } + static void Test6(T6 x) where T6 : IIn, allows ref struct + { + Test3(x); + } } "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); @@ -6466,7 +6553,19 @@ static void Test2(T x) where T : IOut, allows ref struct Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "Test1").WithArguments("Program.Test1(T)", "I", "T", "S").WithLocation(19, 9), // (20,9): error CS0315: The type 'S' cannot be used as type parameter 'T' in the generic type or method 'Program.Test2(T)'. There is no boxing conversion from 'S' to 'IOut'. // Test2(new S()); - Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "Test2").WithArguments("Program.Test2(T)", "IOut", "T", "S").WithLocation(20, 9) + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "Test2").WithArguments("Program.Test2(T)", "IOut", "T", "S").WithLocation(20, 9), + // (21,9): error CS0315: The type 'S' cannot be used as type parameter 'T' in the generic type or method 'Program.Test3(T)'. There is no boxing conversion from 'S' to 'IIn'. + // Test3(new S()); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedValType, "Test3").WithArguments("Program.Test3(T)", "IIn", "T", "S").WithLocation(21, 9), + // (39,9): error CS0314: The type 'T4' cannot be used as type parameter 'T' in the generic type or method 'Program.Test1(T)'. There is no boxing conversion or type parameter conversion from 'T4' to 'I'. + // Test1(x); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "Test1").WithArguments("Program.Test1(T)", "I", "T", "T4").WithLocation(39, 9), + // (43,9): error CS0314: The type 'T5' cannot be used as type parameter 'T' in the generic type or method 'Program.Test2(T)'. There is no boxing conversion or type parameter conversion from 'T5' to 'IOut'. + // Test2(x); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "Test2").WithArguments("Program.Test2(T)", "IOut", "T", "T5").WithLocation(43, 9), + // (47,9): error CS0314: The type 'T6' cannot be used as type parameter 'T' in the generic type or method 'Program.Test3(T)'. There is no boxing conversion or type parameter conversion from 'T6' to 'IIn'. + // Test3(x); + Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar, "Test3").WithArguments("Program.Test3(T)", "IIn", "T", "T6").WithLocation(47, 9) ); } @@ -7220,32 +7319,22 @@ static void Main() "; var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (6,16): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,16): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // using (new S2()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S2()").WithArguments("ref struct interfaces").WithLocation(6, 16), - // (10,16): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "new S2()").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 16), + // (10,16): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // using (var s = new S2()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "var s = new S2()").WithArguments("ref struct interfaces").WithLocation(10, 16) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "var s = new S2()").WithArguments("ref struct interfaces", "13.0").WithLocation(10, 16) ); comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (2,24): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (2,24): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // public ref struct S2 : System.IDisposable - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.IDisposable").WithArguments("ref struct interfaces").WithLocation(2, 24) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "System.IDisposable").WithArguments("ref struct interfaces", "13.0").WithLocation(2, 24) ); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); - comp2.VerifyEmitDiagnostics( - // (6,16): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // using (new S2()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S2()").WithArguments("ref struct interfaces").WithLocation(6, 16), - // (10,16): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // using (var s = new S2()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "var s = new S2()").WithArguments("ref struct interfaces").WithLocation(10, 16) - ); - - comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); comp2.VerifyEmitDiagnostics(); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); @@ -8641,26 +8730,19 @@ static void Main() // Even though semantic analysis didn't produce any errors in C# 12 compiler, an attempt to emit was failing with // "Unable to determine specific cause of the failure" error. comp2.VerifyEmitDiagnostics( - // (6,27): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,27): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // foreach (var i in new S()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S()").WithArguments("ref struct interfaces").WithLocation(6, 27) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "new S()").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 27) ); comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (4,23): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,23): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // public ref struct S : IEnumerable - Diagnostic(ErrorCode.ERR_FeatureInPreview, "IEnumerable").WithArguments("ref struct interfaces").WithLocation(4, 23) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "IEnumerable").WithArguments("ref struct interfaces", "13.0").WithLocation(4, 23) ); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); - comp2.VerifyEmitDiagnostics( - // (6,27): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // foreach (var i in new S()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S()").WithArguments("ref struct interfaces").WithLocation(6, 27) - ); - - comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); comp2.VerifyEmitDiagnostics(); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); @@ -11727,21 +11809,21 @@ static void Main() } } "; - var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (6,9): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // foreach (var i in new S1()) {} - Diagnostic(ErrorCode.ERR_FeatureInPreview, "foreach (var i in new S1()) {}").WithArguments("ref struct interfaces").WithLocation(6, 9) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach (var i in new S1()) {}").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 9) ); - comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); + comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (10,24): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (10,24): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // public ref struct S2 : System.IDisposable - Diagnostic(ErrorCode.ERR_FeatureInPreview, "System.IDisposable").WithArguments("ref struct interfaces").WithLocation(10, 24) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "System.IDisposable").WithArguments("ref struct interfaces", "13.0").WithLocation(10, 24) ); - comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); comp2.VerifyEmitDiagnostics(); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); @@ -13587,7 +13669,7 @@ public class Activator verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); } - [ConditionalFact(typeof(NoUsedAssembliesValidation))] // https://github.com/dotnet/roslyn/issues/73563 + [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/73563")] public void AwaitUsing_LanguageVersion_01() { @@ -13681,25 +13763,25 @@ static async System.Threading.Tasks.Task Main() "; var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (6,22): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,22): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // await using (new S2()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S2()").WithArguments("ref struct interfaces").WithLocation(6, 22), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "new S2()").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 22), // (6,22): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // await using (new S2()) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "new S2()").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 22), // (10,22): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // await using (var s = new S2()) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "var").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(10, 22), - // (10,22): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (10,22): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // await using (var s = new S2()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "var s = new S2()").WithArguments("ref struct interfaces").WithLocation(10, 22) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "var s = new S2()").WithArguments("ref struct interfaces", "13.0").WithLocation(10, 22) ); comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (5,24): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,24): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // public ref struct S2 : IAsyncDisposable - Diagnostic(ErrorCode.ERR_FeatureInPreview, "IAsyncDisposable").WithArguments("ref struct interfaces").WithLocation(5, 24), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "IAsyncDisposable").WithArguments("ref struct interfaces", "13.0").WithLocation(5, 24), // (25,22): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // await using (new S2()) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "new S2()").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(25, 22), @@ -13709,23 +13791,6 @@ static async System.Threading.Tasks.Task Main() ); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); - comp2.VerifyEmitDiagnostics( - // (6,22): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // await using (new S2()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S2()").WithArguments("ref struct interfaces").WithLocation(6, 22), - // (10,22): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // await using (var s = new S2()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "var s = new S2()").WithArguments("ref struct interfaces").WithLocation(10, 22) - ); - - comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); - comp2.VerifyEmitDiagnostics( - // (5,24): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // public ref struct S2 : IAsyncDisposable - Diagnostic(ErrorCode.ERR_FeatureInPreview, "IAsyncDisposable").WithArguments("ref struct interfaces").WithLocation(5, 24) - ); - - comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); comp2.VerifyEmitDiagnostics(); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); @@ -16041,7 +16106,7 @@ .locals init (int V_0, AssertEx.Equal("System.Int32", op.Info.ElementType.ToTestDisplayString()); } - [ConditionalFact(typeof(NoUsedAssembliesValidation))] // https://github.com/dotnet/roslyn/issues/73563 + [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/73563")] public void AwaitForeach_IAsyncEnumerableT_LanguageVersion_01() { @@ -16113,24 +16178,24 @@ static async System.Threading.Tasks.Task Main() } } "; - var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); // Even though semantic analysis didn't produce any errors in C# 12 compiler, an attempt to emit was failing with // "Unable to determine specific cause of the failure" error. comp2.VerifyEmitDiagnostics( - // (6,33): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,33): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // await foreach (var i in new S()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S()").WithArguments("ref struct interfaces").WithLocation(6, 33) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "new S()").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 33) ); - comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); + comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (6,23): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,23): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // public ref struct S : IAsyncEnumerable - Diagnostic(ErrorCode.ERR_FeatureInPreview, "IAsyncEnumerable").WithArguments("ref struct interfaces").WithLocation(6, 23) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "IAsyncEnumerable").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 23) ); - comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); comp2.VerifyEmitDiagnostics(); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); @@ -16308,10 +16373,13 @@ static async Task Main() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (27,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (27,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(27, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + System.Console.Write(i); + }").WithArguments("S2").WithLocation(27, 9) ); } @@ -16357,10 +16425,13 @@ static async Task Main() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (30,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (30,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(30, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + System.Console.Write(i); + }").WithArguments("S2").WithLocation(30, 9) ); } @@ -16415,10 +16486,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (39,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (39,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(39, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(39, 9) ); } @@ -16479,10 +16553,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (45,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (45,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(45, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(45, 9) ); } @@ -16668,10 +16745,13 @@ static async Task Main() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (27,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (27,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(27, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + System.Console.Write(i); + }").WithArguments("S2").WithLocation(27, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -16730,10 +16810,13 @@ static async Task Main() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (27,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (27,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(27, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + System.Console.Write(i); + }").WithArguments("S2").WithLocation(27, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -16792,10 +16875,13 @@ static async Task Main() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (27,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (27,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(27, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + System.Console.Write(i); + }").WithArguments("S2").WithLocation(27, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -16873,10 +16959,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (46,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (46,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(46, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(46, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -16958,10 +17047,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (50,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (50,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(50, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(50, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -17048,10 +17140,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (55,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (55,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(55, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(55, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -17142,10 +17237,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (59,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (59,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(59, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(59, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -17223,10 +17321,13 @@ static async Task Test() "; var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); - comp.VerifyDiagnostics( - // (46,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + comp.VerifyEmitDiagnostics( + // (46,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(46, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in default(TEnumerable)) + { + System.Console.Write(i); + }").WithArguments("TEnumerator").WithLocation(46, 9) ); var tree = comp.SyntaxTrees.Single(); @@ -17289,23 +17390,27 @@ static async Task Main() "; var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (10,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (10,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(10, 15) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(10, 15) ); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); comp2.VerifyEmitDiagnostics( - // (10,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (10,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(10, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + }").WithArguments("S2").WithLocation(10, 9) ); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); comp2.VerifyEmitDiagnostics( - // (10,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (10,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(10, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"await foreach (var i in new S1()) + { + }").WithArguments("S2").WithLocation(10, 9) ); } @@ -17359,38 +17464,38 @@ static async System.Threading.Tasks.Task Main() } } "; - var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (6,9): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,9): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // await foreach (var i in new S1()) {} - Diagnostic(ErrorCode.ERR_FeatureInPreview, "await foreach (var i in new S1()) {}").WithArguments("ref struct interfaces").WithLocation(6, 9), - // (6,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "await foreach (var i in new S1()) {}").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 9), + // (6,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // await foreach (var i in new S1()) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(6, 15) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(6, 15) ); - comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); + comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (14,24): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (14,24): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // public ref struct S2 : IAsyncDisposable - Diagnostic(ErrorCode.ERR_FeatureInPreview, "IAsyncDisposable").WithArguments("ref struct interfaces").WithLocation(14, 24), - // (40,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "IAsyncDisposable").WithArguments("ref struct interfaces", "13.0").WithLocation(14, 24), + // (40,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // await foreach (var i in new S1()) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(40, 15) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(40, 15) ); - comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); comp2.VerifyEmitDiagnostics( - // (6,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (6,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(6, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await foreach (var i in new S1()) {}").WithArguments("S2").WithLocation(6, 9) ); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); comp2.VerifyEmitDiagnostics( - // (6,15): error CS8344: foreach statement cannot operate on enumerators of type 'S2' in async or iterator methods because 'S2' is a ref struct or a type parameter that allows ref struct. + // (6,9): error CS4007: Instance of type 'S2' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in new S1()) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("S2").WithLocation(6, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await foreach (var i in new S1()) {}").WithArguments("S2").WithLocation(6, 9) ); var src3 = @" @@ -17453,23 +17558,23 @@ static async Task Test() // (22,73): error CS9202: Feature 'allows ref struct constraint' is not available in C# 12.0. Please use language version 13.0 or greater. // where TEnumerator : ICustomEnumerator, IAsyncDisposable, allows ref struct Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "ref struct").WithArguments("allows ref struct constraint", "13.0").WithLocation(22, 73), - // (24,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + // (24,15): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // await foreach (var i in default(TEnumerable)) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(24, 15) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(24, 15) ); comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics( - // (24,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + // (24,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(24, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await foreach (var i in default(TEnumerable)) {}").WithArguments("TEnumerator").WithLocation(24, 9) ); comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); comp.VerifyEmitDiagnostics( - // (24,15): error CS8344: foreach statement cannot operate on enumerators of type 'TEnumerator' in async or iterator methods because 'TEnumerator' is a ref struct or a type parameter that allows ref struct. + // (24,9): error CS4007: Instance of type 'TEnumerator' cannot be preserved across 'await' or 'yield' boundary. // await foreach (var i in default(TEnumerable)) {} - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("TEnumerator").WithLocation(24, 15) + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await foreach (var i in default(TEnumerable)) {}").WithArguments("TEnumerator").WithLocation(24, 9) ); } @@ -18835,21 +18940,21 @@ static void Main() } } "; - var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); + var comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (6,27): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,27): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // foreach (var i in new S()) - Diagnostic(ErrorCode.ERR_FeatureInPreview, "new S()").WithArguments("ref struct interfaces").WithLocation(6, 27) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "new S()").WithArguments("ref struct interfaces", "13.0").WithLocation(6, 27) ); - comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); + comp2 = CreateCompilation(src1 + src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular12); comp2.VerifyEmitDiagnostics( - // (4,23): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,23): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // public ref struct S : IEnumerable - Diagnostic(ErrorCode.ERR_FeatureInPreview, "IEnumerable").WithArguments("ref struct interfaces").WithLocation(4, 23) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "IEnumerable").WithArguments("ref struct interfaces", "13.0").WithLocation(4, 23) ); - comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); + comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); comp2.VerifyEmitDiagnostics(); comp2 = CreateCompilation(src2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); @@ -19952,7 +20057,7 @@ static void Main() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "Helper.Test").WithArguments("allows ref struct constraint", "13.0").WithLocation(200, 9) ); - CreateCompilation([src1, src2], targetFramework: TargetFramework.DesktopLatestExtended, options: TestOptions.ReleaseExe).VerifyDiagnostics( + CreateCompilation([src1, src2], targetFramework: TargetFramework.Mscorlib461Extended, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (100,54): error CS9240: Target runtime doesn't support by-ref-like generics. // public static void Test(T x) where T : allows ref struct Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportByRefLikeGenerics, "ref struct").WithLocation(100, 54) @@ -19990,21 +20095,21 @@ static void Main() CreateCompilation(src3, references: [comp1Ref], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(); CreateCompilation(src3, references: [comp1Ref], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); - CreateCompilation([src1, src3], targetFramework: TargetFramework.DesktopLatestExtended, options: TestOptions.ReleaseExe).VerifyDiagnostics( + CreateCompilation([src1, src3], targetFramework: TargetFramework.Mscorlib461Extended, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (100,54): error CS9240: Target runtime doesn't support by-ref-like generics. // public static void Test(T x) where T : allows ref struct Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportByRefLikeGenerics, "ref struct").WithLocation(100, 54) ); - comp1Ref = CreateCompilation(src1, targetFramework: TargetFramework.DesktopLatestExtended).ToMetadataReference(); + comp1Ref = CreateCompilation(src1, targetFramework: TargetFramework.Mscorlib461Extended).ToMetadataReference(); - CreateCompilation(src2, references: [comp1Ref], targetFramework: TargetFramework.DesktopLatestExtended, options: TestOptions.ReleaseExe).VerifyDiagnostics( + CreateCompilation(src2, references: [comp1Ref], targetFramework: TargetFramework.Mscorlib461Extended, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (200,9): error CS9240: Target runtime doesn't support by-ref-like generics. // Helper.Test(new S1()); Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportByRefLikeGenerics, "Helper.Test").WithLocation(200, 9) ); - CreateCompilation(src3, references: [comp1Ref], targetFramework: TargetFramework.DesktopLatestExtended, options: TestOptions.ReleaseExe).VerifyEmitDiagnostics(); + CreateCompilation(src3, references: [comp1Ref], targetFramework: TargetFramework.Mscorlib461Extended, options: TestOptions.ReleaseExe).VerifyEmitDiagnostics(); } [Fact] @@ -20209,7 +20314,7 @@ static void Main() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "S1").WithArguments("allows ref struct constraint", "13.0").WithLocation(200, 16) ); - CreateCompilation([src1, src2], targetFramework: TargetFramework.DesktopLatestExtended, options: TestOptions.ReleaseExe).VerifyDiagnostics( + CreateCompilation([src1, src2], targetFramework: TargetFramework.Mscorlib461Extended, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (100,41): error CS9240: Target runtime doesn't support by-ref-like generics. // public class Helper where T : allows ref struct Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportByRefLikeGenerics, "ref struct").WithLocation(100, 41) @@ -20247,21 +20352,21 @@ static void Main() CreateCompilation(src3, references: [comp1Ref], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(); CreateCompilation(src3, references: [comp1Ref], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics(); - CreateCompilation([src1, src3], targetFramework: TargetFramework.DesktopLatestExtended, options: TestOptions.ReleaseExe).VerifyDiagnostics( + CreateCompilation([src1, src3], targetFramework: TargetFramework.Mscorlib461Extended, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (100,41): error CS9240: Target runtime doesn't support by-ref-like generics. // public class Helper where T : allows ref struct Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportByRefLikeGenerics, "ref struct").WithLocation(100, 41) ); - comp1Ref = CreateCompilation(src1, targetFramework: TargetFramework.DesktopLatestExtended).ToMetadataReference(); + comp1Ref = CreateCompilation(src1, targetFramework: TargetFramework.Mscorlib461Extended).ToMetadataReference(); - CreateCompilation(src2, references: [comp1Ref], targetFramework: TargetFramework.DesktopLatestExtended, options: TestOptions.ReleaseExe).VerifyDiagnostics( + CreateCompilation(src2, references: [comp1Ref], targetFramework: TargetFramework.Mscorlib461Extended, options: TestOptions.ReleaseExe).VerifyDiagnostics( // (200,16): error CS9240: Target runtime doesn't support by-ref-like generics. // Helper.Test(new S1()); Diagnostic(ErrorCode.ERR_RuntimeDoesNotSupportByRefLikeGenerics, "S1").WithLocation(200, 16) ); - CreateCompilation(src3, references: [comp1Ref], targetFramework: TargetFramework.DesktopLatestExtended, options: TestOptions.ReleaseExe).VerifyEmitDiagnostics(); + CreateCompilation(src3, references: [comp1Ref], targetFramework: TargetFramework.Mscorlib461Extended, options: TestOptions.ReleaseExe).VerifyEmitDiagnostics(); } [Fact] @@ -21067,6 +21172,18 @@ static void Test4() var d = void (scoped T u) => {}; d(default); } + + static void Test5() + { + void local5(scoped T u) {}; + local5(default); + } + + static void Test6() + { + void local6(scoped T u) {}; + local6(default); + } } ref struct S @@ -21080,7 +21197,13 @@ ref struct S Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T z").WithLocation(13, 26), // (19,23): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. // var d = void (scoped T u) => {}; - Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T u").WithLocation(19, 23) + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T u").WithLocation(19, 23), + // (25,21): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // void local5(scoped T u) {}; + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T u").WithLocation(25, 21), + // (31,24): error CS9048: The 'scoped' modifier can be used for refs and ref struct values only. + // void local6(scoped T u) {}; + Diagnostic(ErrorCode.ERR_ScopedRefAndRefStructOnly, "scoped T u").WithLocation(31, 24) ); var src2 = @" @@ -21090,9 +21213,44 @@ public static void Test1(scoped T x) where T : allows ref struct { } + + public static void Test2() + where T : allows ref struct + { + var d = void (scoped T u) => {}; + d(default); + + void local5(scoped T u) {}; + local5(default); + } + + static void Test3() + { + void local6(scoped T u) where T : allows ref struct {}; + local6(default); + } } "; var comp2 = CreateCompilation(src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + var tree = comp2.SyntaxTrees.Single(); + var model = comp2.GetSemanticModel(tree); + + var lambda = tree.GetRoot().DescendantNodes().OfType().Single(); + var parameter = model.GetSymbolInfo(lambda).Symbol.GetSymbol().Parameters[0]; + + AssertEx.Equal("scoped T u", parameter.ToTestDisplayString()); + Assert.Equal(ScopedKind.ScopedValue, parameter.EffectiveScope); + + var localFunctions = tree.GetRoot().DescendantNodes().OfType().ToArray(); + Assert.Equal(2, localFunctions.Length); + + foreach (var localFunction in localFunctions) + { + parameter = model.GetDeclaredSymbol(localFunction).GetSymbol().Parameters[0]; + + AssertEx.Equal("scoped T u", parameter.ToTestDisplayString()); + Assert.Equal(ScopedKind.ScopedValue, parameter.EffectiveScope); + } CompileAndVerify( comp2, symbolValidator: validate, sourceSymbolValidator: validate, @@ -21151,6 +21309,80 @@ ref struct S Assert.Equal(ScopedKind.ScopedValue, local.Scope); } + [Fact] + public void ScopedTypeParameter_03() + { + var src = @" +partial class Helper + where T : allows ref struct +{ + partial void M1(scoped T x); + + partial void M1(T x){} + + partial void M2(T x); + + partial void M2(scoped T x){} + + partial void M3(scoped T x); + + partial void M3(scoped T x){} + + partial void M4(T x); + + partial void M4(T x){} +} +"; + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp.VerifyDiagnostics( + // (7,18): error CS8988: The 'scoped' modifier of parameter 'x' doesn't match partial definition. + // partial void M1(T x){} + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M1").WithArguments("x").WithLocation(7, 18), + // (11,18): error CS8988: The 'scoped' modifier of parameter 'x' doesn't match partial definition. + // partial void M2(scoped T x){} + Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfPartial, "M2").WithArguments("x").WithLocation(11, 18) + ); + } + + [Fact] + public void ScopedTypeParameter_04() + { + var src = @" +using System; + +class Helper + where T : allows ref struct +{ + delegate void D1(scoped T x); + delegate void D2(T x); + + static D1 d11 = M1; + static D1 d12 = M2; + static D2 d21 = M1; + static D2 d22 = M2; + + static void M1(scoped T x) {} + static void M2(T x) {} +} + +class Helper +{ + delegate void D1(scoped Span x); + delegate void D2(Span x); + + static D1 d11 = M1; + static D1 d12 = M2; + static D2 d21 = M1; + static D2 d22 = M2; + + static void M1(scoped Span x) {} + static void M2(Span x) {} +} +"; + var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); + comp.VerifyEmitDiagnostics(); + } + [Fact] public void LiftedUnaryOperator_InvalidTypeArgument01() { @@ -21512,14 +21744,7 @@ ref struct S "; var comp = CreateCompilation(sourceA, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); - comp.VerifyDiagnostics( - // (7,30): error CS9244: The type 'T' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T' in the generic type or method 'Activator.CreateInstance()' - // _ = System.Activator.CreateInstance(); - Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "CreateInstance").WithArguments("System.Activator.CreateInstance()", "T", "T").WithLocation(7, 30), - // (12,30): error CS9244: The type 'S' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'T' in the generic type or method 'Activator.CreateInstance()' - // _ = System.Activator.CreateInstance(); - Diagnostic(ErrorCode.ERR_NotRefStructConstraintNotSatisfied, "CreateInstance").WithArguments("System.Activator.CreateInstance()", "T", "S").WithLocation(12, 30) - ); + comp.VerifyDiagnostics(); } [Fact] @@ -22153,7 +22378,7 @@ ref struct S ); } - [Fact(Skip = "https://github.com/dotnet/roslyn/issues/73553")] // Enable once we get support for 'byreflike' in IL. + [ConditionalFact(typeof(CoreClrOnly))] [WorkItem("https://github.com/dotnet/roslyn/issues/73553")] public void RefFieldTypeAllowsRefLike() { @@ -22176,7 +22401,7 @@ .field public !T& F { static void F(ref T r1) where T : allows ref struct { - var r2 = new R2(); + var r2 = new R2(); r2.F = ref r1; } }"; @@ -22184,7 +22409,7 @@ static void F(ref T r1) where T : allows ref struct comp.VerifyEmitDiagnostics( // (6,12): error CS0570: 'R2.F' is not supported by the language // r2.F = ref r1; - Diagnostic(ErrorCode.ERR_BindToBogus, "F").WithArguments("R2.F").WithLocation(6, 12) + Diagnostic(ErrorCode.ERR_BindToBogus, "F").WithArguments("R2.F").WithLocation(6, 12) ); } @@ -22603,6 +22828,408 @@ namespace System ).VerifyDiagnostics(); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_09_ParamsArray() + { + var source = """ + var d = M; + System.Console.WriteLine(d.GetType()); + + void M(params int[] arr) { } + """; + var verifier = CompileAndVerify(source, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0`1[System.Int32]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + Assert.False(m.ContainingType.TypeParameters.Single().AllowsRefLikeType); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_10_ParamsArray() + { + var source = """ + var d = M; + System.Console.WriteLine(d.GetType()); + + void M(string s, params int[] arr) { } + """; + var verifier = CompileAndVerify(source, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0`2[System.String,System.Int32]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(T1 arg1, params T2[] arg2)", m.ToTestDisplayString()); + Assert.Equal([true, false], m.ContainingType.TypeParameters.Select(t => t.AllowsRefLikeType)); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_11_ParamsArray() + { + var source = """ + unsafe + { + var d = M; + System.Console.WriteLine(d.GetType()); + + void M(int* p, params int[] arr) { } + } + """; + var verifier = CompileAndVerify(source, + options: TestOptions.UnsafeReleaseExe, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(System.Int32* arg1, params System.Int32[] arg2)", m.ToTestDisplayString()); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_12_ParamsArray() + { + var source = """ + M(); + unsafe static void M() + { + var d = C.M; + System.Console.WriteLine(d.GetType()); + } + unsafe static class C + { + public static void M(int* p, T x, params int[] arr) { } + } + """; + var verifier = CompileAndVerify(source, + options: TestOptions.UnsafeReleaseExe, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0`1[System.String]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(System.Int32* arg1, T1 arg2, params System.Int32[] arg3)", m.ToTestDisplayString()); + Assert.False(m.ContainingType.TypeParameters.Single().AllowsRefLikeType); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_13_ParamsArray() + { + var source = """ + M(); + unsafe static void M() where T : allows ref struct + { + var d = C.M; + System.Console.WriteLine(d.GetType()); + } + unsafe static class C where T : allows ref struct + { + public static void M(int* p, T x, params int[] arr) { } + } + """; + var verifier = CompileAndVerify(source, + options: TestOptions.UnsafeReleaseExe, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0`1[System.String]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(System.Int32* arg1, T1 arg2, params System.Int32[] arg3)", m.ToTestDisplayString()); + Assert.True(m.ContainingType.TypeParameters.Single().AllowsRefLikeType); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_14_ParamsArray() + { + var source = """ + M(); + unsafe static void M() + { + var d = C.M; + System.Console.WriteLine(d.GetType()); + } + unsafe static class C + { + public static void M(int* p, T x, params T[] arr) { } + } + """; + var verifier = CompileAndVerify(source, + options: TestOptions.UnsafeReleaseExe, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0`1[System.String]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(System.Int32* arg1, T1 arg2, params T1[] arg3)", m.ToTestDisplayString()); + Assert.False(m.ContainingType.TypeParameters.Single().AllowsRefLikeType); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_15_ParamsArray() + { + var source = """ + M(); + unsafe static void M() + { + var d = C.M; + System.Console.WriteLine(d.GetType()); + } + unsafe static class C + { + public static void M(int* p, params T[] arr) { } + } + """; + var verifier = CompileAndVerify(source, + options: TestOptions.UnsafeReleaseExe, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0`1[System.String]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(System.Int32* arg1, params T1[] arg2)", m.ToTestDisplayString()); + Assert.False(m.ContainingType.TypeParameters.Single().AllowsRefLikeType); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_16_ParamsArray() + { + var source = """ + #nullable enable + M(); + unsafe static void M() + { + var d = C.M; + System.Console.WriteLine(d.GetType()); + } + unsafe static class C + { + public static void M(int* p, params T?[] arr) { } + } + """; + var verifier = CompileAndVerify(source, + options: TestOptions.UnsafeReleaseExe, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0`1[System.String]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(System.Int32* arg1, params T1?[] arg2)", m.ToTestDisplayString()); + Assert.False(m.ContainingType.TypeParameters.Single().AllowsRefLikeType); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_17_ParamsArray() + { + var source = """ + M(); + unsafe static void M() where T : struct + { + var d = C.M; + System.Console.WriteLine(d.GetType()); + } + unsafe static class C where T : struct + { + public static void M(int* p, params T?[] arr) { } + } + """; + var verifier = CompileAndVerify(source, + options: TestOptions.UnsafeReleaseExe, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0`1[System.Int16]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(System.Int32* arg1, params T1?[] arg2)", m.ToTestDisplayString()); + Assert.False(m.ContainingType.TypeParameters.Single().AllowsRefLikeType); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_18_ParamsArray() + { + var source = """ + M(); + unsafe static void M() + { + var d = C.M; + System.Console.WriteLine(d.GetType()); + } + unsafe static class C + { + public static void M(int* p, params T[][] arr) { } + } + """; + var verifier = CompileAndVerify(source, + options: TestOptions.UnsafeReleaseExe, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0`1[System.Int16]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(System.Int32* arg1, params T1[][] arg2)", m.ToTestDisplayString()); + Assert.False(m.ContainingType.TypeParameters.Single().AllowsRefLikeType); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_19_ParamsCollection() + { + var source = """ + var d = M; + System.Console.WriteLine(d.GetType()); + + void M(params System.Collections.Generic.IEnumerable e) { } + """; + var verifier = CompileAndVerify(source, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(params System.Collections.Generic.IEnumerable arg)", m.ToTestDisplayString()); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_20() + { + var source = """ + M(); + unsafe static void M() + { + var d = C.M; + System.Console.WriteLine(d.GetType()); + } + unsafe static class C + { + public static void M(int* p, T[] arr) { } + } + """; + var verifier = CompileAndVerify(source, + options: TestOptions.UnsafeReleaseExe, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0`1[System.Int16]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(System.Int32* arg1, T1[] arg2)", m.ToTestDisplayString()); + Assert.False(m.ContainingType.TypeParameters.Single().AllowsRefLikeType); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_21() + { + var source = """ + M(); + unsafe static void M() where T : allows ref struct + { + var d = C.M; + System.Console.WriteLine(d.GetType()); + } + unsafe static class C where T : allows ref struct + { + public static void M(int* p, T t) { } + } + """; + var verifier = CompileAndVerify(source, + options: TestOptions.UnsafeReleaseExe, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>f__AnonymousDelegate0`1[System.Int16]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + AssertEx.Equal("void <>f__AnonymousDelegate0.Invoke(System.Int32* arg1, T1 arg2)", m.ToTestDisplayString()); + Assert.True(m.ContainingType.TypeParameters.Single().AllowsRefLikeType); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74823")] + public void AnonymousDelegateType_22() + { + var source = """ + var d = M; + System.Console.WriteLine(d.GetType()); + + void M(ref short p, int[] arr) { } + """; + var verifier = CompileAndVerify(source, + targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, + symbolValidator: validate, + verify: Verification.FailsPEVerify, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "<>A{00000001}`2[System.Int16,System.Int32[]]" : null); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>A{00000001}.Invoke"); + AssertEx.Equal("void <>A{00000001}.Invoke(ref T1 arg1, T2 arg2)", m.ToTestDisplayString()); + Assert.Equal([true, true], m.ContainingType.TypeParameters.Select(t => t.AllowsRefLikeType)); + } + } + [Fact] public void ExpressionTree_01() { @@ -23673,12 +24300,15 @@ .maxstack 1 "); } - [Fact] - public void IsOperator_05() + [Theory] + [CombinatorialData] + public void IsOperator_05(bool uHasClassConstraint, bool uHasInterfaceConstraint) { + var uConstraint = GetUConstraint(uHasClassConstraint, uHasInterfaceConstraint); + var src1 = @" class Helper1 - where T : allows ref struct + where T : allows ref struct" + uConstraint + @" { public static void Test1(T h1) { @@ -23687,6 +24317,10 @@ public static void Test1(T h1) } } } + +interface I1 +{ +} "; var comp = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); @@ -23697,7 +24331,7 @@ public static void Test1(T h1) ); var src2 = @" -class Helper2 +class Helper2" + uConstraint + @" { public static void Test2(S h2) { @@ -23751,6 +24385,19 @@ .maxstack 1 "); } + private static string GetUConstraint(bool uHasClassConstraint, bool uHasInterfaceConstraint) + { + if (!uHasClassConstraint && !uHasInterfaceConstraint) + { + return ""; + } + + return " where U :" + + (uHasClassConstraint ? " class" : "") + + ((uHasClassConstraint && uHasInterfaceConstraint) ? "," : "") + + (uHasInterfaceConstraint ? " I1" : ""); + } + [Fact] public void IsOperator_06() { @@ -23798,12 +24445,15 @@ interface I1 ); } - [Fact] - public void IsOperator_07() + [Theory] + [CombinatorialData] + public void IsOperator_07(bool uHasClassConstraint, bool uHasInterfaceConstraint) { + var uConstraint = GetUConstraint(uHasClassConstraint, uHasInterfaceConstraint); + var src = @" class Helper1 - where T : allows ref struct + where T : allows ref struct" + uConstraint + @" { public static void Test1(U h1) { @@ -23818,7 +24468,7 @@ public static void Test1(U h1) } } -class Helper2 +class Helper2" + uConstraint + @" { public static void Test2(U h2) { @@ -23852,14 +24502,25 @@ static void Main() Helper1.Test1(new Program()); Helper1.Test1(new Program()); Helper1.Test1(new Program()); - Helper1.Test1(new Program()); - Helper1.Test1(new S1()); + Helper1.Test1(new Program());" + + (uHasClassConstraint ? "" : +@" + Helper1.Test1(new S1());") + +@" Helper1.Test1(new S1()); - Helper1.Test1(new Program()); - Helper1.Test1(new S1()); - Helper1.Test1(new S2()); - Helper1.Test1(new S1()); - Helper1.Test1(new S2()); + Helper1.Test1(new Program());" + + (uHasClassConstraint ? "" : +@" + Helper1.Test1(new S1());") + + (uHasClassConstraint || uHasInterfaceConstraint ? "" : +@" + Helper1.Test1(new S2());") + +@" + Helper1.Test1(new S1());" + + (uHasClassConstraint || uHasInterfaceConstraint ? "" : +@" + Helper1.Test1(new S2());") + +@" Helper2.Test2(new Program()); } } @@ -23867,7 +24528,13 @@ static void Main() var comp = CreateCompilation(src, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify( comp, - expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "211111112214" : null, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? + (uHasClassConstraint ? + "21111124" : + (uHasInterfaceConstraint ? + "2111111124" : + "211111112214")) : + null, verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped). VerifyDiagnostics( // (22,13): warning CS0184: The given expression is never of the provided ('S') type @@ -24480,12 +25147,15 @@ .locals init (S V_0) //s "); } - [Fact] - public void IsPattern_05() + [Theory] + [CombinatorialData] + public void IsPattern_05(bool uHasClassConstraint, bool uHasInterfaceConstraint) { + var uConstraint = GetUConstraint(uHasClassConstraint, uHasInterfaceConstraint); + var src = @" class Helper1 - where T : allows ref struct + where T : allows ref struct" + uConstraint + @" { public static void Test1(T h1) { @@ -24495,7 +25165,7 @@ public static void Test1(T h1) } } -class Helper2 +class Helper2" + uConstraint + @" { public static void Test2(S h2) { @@ -24572,12 +25242,15 @@ interface I1 ); } - [Fact] - public void IsPattern_07() + [Theory] + [CombinatorialData] + public void IsPattern_07(bool uHasClassConstraint, bool uHasInterfaceConstraint) { + var uConstraint = GetUConstraint(uHasClassConstraint, uHasInterfaceConstraint); + var src1 = @" class Helper1 - where T : I2, allows ref struct + where T : I2, allows ref struct" + uConstraint + @" { public static void Test1(U h1) { @@ -24623,14 +25296,25 @@ static void Main() Helper1.Test1(new Program()); Helper1.Test1(new Program()); Helper1.Test1(new Program()); - Helper1.Test1(new Program()); - Helper1.Test1(new S1()); + Helper1.Test1(new Program());" + + (uHasClassConstraint ? "" : +@" + Helper1.Test1(new S1());") + +@" Helper1.Test1(new S1()); - Helper1.Test1(new Program()); - Helper1.Test1(new S1()); - Helper1.Test1(new S2()); - Helper1.Test1(new S1()); - Helper1.Test1(new S2()); + Helper1.Test1(new Program());" + + (uHasClassConstraint ? "" : +@" + Helper1.Test1(new S1());") + + (uHasClassConstraint || uHasInterfaceConstraint ? "" : +@" + Helper1.Test1(new S2());") + +@" + Helper1.Test1(new S1());" + + (uHasClassConstraint || uHasInterfaceConstraint ? "" : +@" + Helper1.Test1(new S2());") + +@" } public void M() => System.Console.Write(3); @@ -24640,7 +25324,13 @@ static void Main() var comp1 = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, options: TestOptions.ReleaseExe); var verifier = CompileAndVerify( comp1, - expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? "23335535224" : null, + expectedOutput: ExecutionConditionUtil.IsMonoOrCoreClr ? + (uHasClassConstraint ? + "2333532" : + (uHasInterfaceConstraint ? + "233355352" : + "23335535224")) : + null, verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); // According to @@ -24673,7 +25363,7 @@ .locals init (T V_0) //t "); var src2 = @" -class Helper2 +class Helper2" + uConstraint + @" { public static void Test2(U h2) { @@ -25091,12 +25781,15 @@ ref struct S ); } - [Fact] - public void AsOperator_05() + [Theory] + [CombinatorialData] + public void AsOperator_05(bool uHasClassConstraint, bool uHasInterfaceConstraint) { + var uConstraint = GetUConstraint(uHasClassConstraint, uHasInterfaceConstraint); + var src1 = @" class Helper1 - where T : allows ref struct + where T : allows ref struct" + uConstraint + @" { public static void Test1(T h1) { @@ -25104,7 +25797,7 @@ public static void Test1(T h1) } } -class Helper2 +class Helper2" + uConstraint + @" { public static void Test2(S h2) { @@ -25122,53 +25815,29 @@ interface I1 "; var comp = CreateCompilation(src1, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); - comp.VerifyDiagnostics( - // (7,13): error CS0413: The type parameter 'U' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint - // _ = h1 as U; - Diagnostic(ErrorCode.ERR_AsWithTypeVar, "h1 as U").WithArguments("U").WithLocation(7, 13), - // (15,13): error CS0413: The type parameter 'U' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint - // _ = h2 as U; - Diagnostic(ErrorCode.ERR_AsWithTypeVar, "h2 as U").WithArguments("U").WithLocation(15, 13) - ); - var src2 = @" -class Helper1 - where T : allows ref struct - where U : class -{ - public static void Test1(T h1) - { - _ = h1 as U; - } -} - -class Helper2 - where U : class -{ - public static void Test2(S h2) - { - _ = h2 as U; - } -} - -ref struct S : I1 -{ -} - -interface I1 -{ -} -"; - - comp = CreateCompilation(src2, targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); - comp.VerifyDiagnostics( - // (8,13): error CS0019: Operator 'as' cannot be applied to operands of type 'T' and 'U' - // _ = h1 as U; - Diagnostic(ErrorCode.ERR_BadBinaryOps, "h1 as U").WithArguments("as", "T", "U").WithLocation(8, 13), - // (17,13): error CS0019: Operator 'as' cannot be applied to operands of type 'S' and 'U' - // _ = h2 as U; - Diagnostic(ErrorCode.ERR_BadBinaryOps, "h2 as U").WithArguments("as", "S", "U").WithLocation(17, 13) - ); + if (!uHasClassConstraint) + { + comp.VerifyDiagnostics( + // (7,13): error CS0413: The type parameter 'U' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint + // _ = h1 as U; + Diagnostic(ErrorCode.ERR_AsWithTypeVar, "h1 as U").WithArguments("U").WithLocation(7, 13), + // (15,13): error CS0413: The type parameter 'U' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint + // _ = h2 as U; + Diagnostic(ErrorCode.ERR_AsWithTypeVar, "h2 as U").WithArguments("U").WithLocation(15, 13) + ); + } + else + { + comp.VerifyDiagnostics( + // (7,13): error CS0019: Operator 'as' cannot be applied to operands of type 'T' and 'U' + // _ = h1 as U; + Diagnostic(ErrorCode.ERR_BadBinaryOps, "h1 as U").WithArguments("as", "T", "U").WithLocation(7, 13), + // (15,13): error CS0019: Operator 'as' cannot be applied to operands of type 'S' and 'U' + // _ = h2 as U; + Diagnostic(ErrorCode.ERR_BadBinaryOps, "h2 as U").WithArguments("as", "S", "U").WithLocation(15, 13) + ); + } } [Fact] @@ -25214,12 +25883,15 @@ interface I1 ); } - [Fact] - public void AsOperator_07() + [Theory] + [CombinatorialData] + public void AsOperator_07(bool uHasClassConstraint, bool uHasInterfaceConstraint) { + var uConstraint = GetUConstraint(uHasClassConstraint, uHasInterfaceConstraint); + var src = @" class Helper1 - where T : allows ref struct + where T : allows ref struct" + uConstraint + @" { static void Test1(U h1) { @@ -25227,7 +25899,7 @@ static void Test1(U h1) } } -class Helper2 +class Helper2" + uConstraint + @" { public static void Test2(U h2) { @@ -28021,9 +28693,9 @@ public class Activator // (5,37): error CS9202: Feature 'allows ref struct constraint' is not available in C# 12.0. Please use language version 13.0 or greater. // where T : I1, new(), allows ref struct Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "ref struct").WithArguments("allows ref struct constraint", "13.0").WithLocation(5, 37), - // (12,39): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (12,39): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // System.Console.Write((new S() { 200, 40, 6 }).P); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "{ 200, 40, 6 }").WithArguments("ref struct interfaces").WithLocation(12, 39), + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "{ 200, 40, 6 }").WithArguments("ref struct interfaces", "13.0").WithLocation(12, 39), // (20,62): error CS9202: Feature 'allows ref struct constraint' is not available in C# 12.0. Please use language version 13.0 or greater. // public static T CreateInstance() where T : allows ref struct => default; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "ref struct").WithArguments("allows ref struct constraint", "13.0").WithLocation(20, 62) @@ -28037,19 +28709,12 @@ public class Activator // (20,62): error CS9202: Feature 'allows ref struct constraint' is not available in C# 12.0. Please use language version 13.0 or greater. // public static T CreateInstance() where T : allows ref struct => default; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "ref struct").WithArguments("allows ref struct constraint", "13.0").WithLocation(20, 62), - // (24,23): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (24,23): error CS9202: Feature 'ref struct interfaces' is not available in C# 12.0. Please use language version 13.0 or greater. // public ref struct S : I1 - Diagnostic(ErrorCode.ERR_FeatureInPreview, "I1").WithArguments("ref struct interfaces").WithLocation(24, 23) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "I1").WithArguments("ref struct interfaces", "13.0").WithLocation(24, 23) ); comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.Regular13); - comp2.VerifyEmitDiagnostics( - // (12,39): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // System.Console.Write((new S() { 200, 40, 6 }).P); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "{ 200, 40, 6 }").WithArguments("ref struct interfaces").WithLocation(12, 39) - ); - - comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics, parseOptions: TestOptions.RegularNext); comp2.VerifyEmitDiagnostics(); comp2 = CreateCompilation(text2, references: [comp1.ToMetadataReference()], targetFramework: s_targetFrameworkSupportingByRefLikeGenerics); @@ -28251,5 +28916,81 @@ interface UsePia5 : ITest29 CompileAndVerify(compilation2, symbolValidator: metadataValidator, verify: Verification.Skipped).VerifyDiagnostics(); } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/74785")] + public void Issue74785() + { + var src = @" +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +#pragma warning disable CS0649 + +[InlineArray(256)] +public struct BufferStruct : IBufferInterface +{ + private byte _data; + + [UnscopedRef] + public ReadOnlySpan Data => this; +} + + +interface IBufferInterface +{ + [UnscopedRef] + public ReadOnlySpan Data { get; } +} + +struct TestStruct + where T : struct, IBufferInterface +{ + T genericBuffer; + BufferStruct directBuffer; + IBufferInterface interfaceBuffer; + + [UnscopedRef] + public ReadOnlySpan GetGenericBuffer1() + { + return genericBuffer.Data; + } + + [UnscopedRef] + public ReadOnlySpan GetDirectBuffer1() + { + return directBuffer.Data; + } + + public ReadOnlySpan GetInterfaceBuffer() + { + return interfaceBuffer.Data; + } + + public ReadOnlySpan GetGenericBuffer2() + { +#line 1000 + return genericBuffer.Data; + } + + public ReadOnlySpan GetDirectBuffer2() + { +#line 2000 + return directBuffer.Data; + } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net90); + + comp.VerifyEmitDiagnostics( + // (1000,16): error CS8170: Struct members cannot return 'this' or other instance members by reference + // return genericBuffer.Data; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "genericBuffer").WithLocation(1000, 16), + // (2000,16): error CS8170: Struct members cannot return 'this' or other instance members by reference + // return directBuffer.Data; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "directBuffer").WithLocation(2000, 16) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs similarity index 92% rename from src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs index 0ce1560a69336..029c55e5c6c29 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs @@ -109,6 +109,10 @@ private static string Concat(string container, string name) """ static partial class CollectionExtensions { + internal static void ReportSpan(this in Span s) + { + Report((ReadOnlySpan)s); + } internal static void Report(this in ReadOnlySpan s) { var builder = new StringBuilder(); @@ -824,11 +828,16 @@ static void Main() { var x = F1([1]); var y = F2([2]); + x.Report(includeType: true); + y.Report(includeType: true); } } """; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( + var expectedOutput = "(System.Collections.Generic.List) [1], (System.Collections.Generic.List) [2], "; + CompileAndVerify([source, s_collectionExtensions], parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput); + CompileAndVerify([source, s_collectionExtensions], parseOptions: TestOptions.RegularPreview, expectedOutput: expectedOutput); + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics( // (10,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(List)' and 'Program.F1(List)' // var x = F1([1]); Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments("Program.F1(System.Collections.Generic.List)", "Program.F1(System.Collections.Generic.List)").WithLocation(10, 17), @@ -1017,18 +1026,44 @@ class Program static void Main() { var x = F([1, null]); + x.Report(includeType: true); int?[] y = [null, 2]; var z = F([..y]); + z.Report(includeType: true); + F([3, ..y]).Report(includeType: true); + F([..y, 4]).Report(includeType: true); + int[] w = [5, 6, 7]; + F([..y, ..w]).Report(includeType: true); + F([..w, ..y]).Report(includeType: true); } } """; - CreateCompilation(source).VerifyEmitDiagnostics( + var expectedOutput = "(System.Nullable[]) [1, null], (System.Nullable[]) [null, 2], (System.Nullable[]) [3, null, 2], " + + "(System.Nullable[]) [null, 2, 4], (System.Nullable[]) [null, 2, 5, 6, 7], (System.Nullable[]) [5, 6, 7, null, 2], "; + + CompileAndVerify([source, s_collectionExtensions], parseOptions: TestOptions.Regular13, + expectedOutput: expectedOutput); + CompileAndVerify([source, s_collectionExtensions], parseOptions: TestOptions.RegularPreview, + expectedOutput: expectedOutput); + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics( // (15,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F(MyCollection)' and 'Program.F(int?[])' // var x = F([1, null]); Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("Program.F(MyCollection)", "Program.F(int?[])").WithLocation(15, 17), - // (17,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F(MyCollection)' and 'Program.F(int?[])' + // (18,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F(MyCollection)' and 'Program.F(int?[])' // var z = F([..y]); - Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("Program.F(MyCollection)", "Program.F(int?[])").WithLocation(17, 17) + Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("Program.F(MyCollection)", "Program.F(int?[])").WithLocation(18, 17), + // (20,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F(MyCollection)' and 'Program.F(int?[])' + // F([3, ..y]).Report(includeType: true); + Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("Program.F(MyCollection)", "Program.F(int?[])").WithLocation(20, 9), + // (21,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F(MyCollection)' and 'Program.F(int?[])' + // F([..y, 4]).Report(includeType: true); + Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("Program.F(MyCollection)", "Program.F(int?[])").WithLocation(21, 9), + // (23,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F(MyCollection)' and 'Program.F(int?[])' + // F([..y, ..w]).Report(includeType: true); + Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("Program.F(MyCollection)", "Program.F(int?[])").WithLocation(23, 9), + // (24,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F(MyCollection)' and 'Program.F(int?[])' + // F([..w, ..y]).Report(includeType: true); + Diagnostic(ErrorCode.ERR_AmbigCall, "F").WithArguments("Program.F(MyCollection)", "Program.F(int?[])").WithLocation(24, 9) ); } @@ -1293,63 +1328,65 @@ public static RefStructConvertibleFromArray Create(scoped ReadOnlySpan """; [Theory] - [InlineData("System.Span", "T[]", "System.Span")] - [InlineData("System.Span", "System.Collections.Generic.IEnumerable", "System.Span")] - [InlineData("System.Span", "System.Collections.Generic.IReadOnlyCollection", "System.Span")] - [InlineData("System.Span", "System.Collections.Generic.IReadOnlyList", "System.Span")] - [InlineData("System.Span", "System.Collections.Generic.ICollection", "System.Span")] - [InlineData("System.Span", "System.Collections.Generic.IList", "System.Span")] - [InlineData("System.ReadOnlySpan", "T[]", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyCollection", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyList", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.ICollection", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IList", "System.ReadOnlySpan")] - [InlineData("System.Span", "System.Collections.Generic.HashSet", null)] // rule requires array or array interface - [InlineData("System.Span", "System.ReadOnlySpan", null)] // cannot convert from object to int - [InlineData("RefStructCollection", "T[]", null, new[] { example_RefStructCollection })] // rule requires span - [InlineData("RefStructCollection", "RefStructCollection", null, new[] { example_RefStructCollection })] // rule requires span - [InlineData("RefStructCollection", "GenericClassCollection", null, new[] { example_RefStructCollection, example_GenericClassCollection })] // rule requires span - [InlineData("RefStructCollection", "GenericClassCollection", null, new[] { example_RefStructCollection, example_GenericClassCollection })] // cannot convert object to int - [InlineData("RefStructCollection", "NonGenericClassCollection", null, new[] { example_RefStructCollection, example_NonGenericClassCollection })] // rule requires span - [InlineData("GenericClassCollection", "T[]", null, new[] { example_GenericClassCollection })] // rule requires span - [InlineData("NonGenericClassCollection", "object[]", null, new[] { example_NonGenericClassCollection })] // rule requires span - [InlineData("System.ReadOnlySpan", "object[]", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "long[]", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "short[]", null)] // cannot convert int to short - [InlineData("System.ReadOnlySpan", "T[]", null)] // cannot convert long to int - [InlineData("System.ReadOnlySpan", "long[]", null)] // cannot convert object to long - [InlineData("System.ReadOnlySpan", "object[]", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "string[]", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Span", null)] - [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", null)] - [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", null)] - [InlineData("System.Span", "System.Span", "System.Span")] - [InlineData("System.Span", "System.Span", null)] - [InlineData("System.Span", "System.Span", null)] - [InlineData("System.Span", "System.Span", "System.Span")] - [InlineData("T[]", "int[]", "System.Int32[]")] - [InlineData("T[]", "object[]", null)] - [InlineData("T[]", "int?[]", null)] - [InlineData("System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection")] - [InlineData("System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection", null)] - [InlineData("System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection", null)] - [InlineData("System.Collections.Generic.ICollection", "System.Collections.Generic.IReadOnlyCollection", null)] - [InlineData("MyCollectionA", "MyCollectionB", "MyCollectionB", new[] { example_GenericClassesWithConversion })] - [InlineData("MyCollectionA", "MyCollectionB", "MyCollectionB", new[] { example_GenericClassesWithConversion })] - [InlineData("MyCollectionA", "MyCollectionB", null, new[] { example_GenericClassesWithConversion })] - [InlineData("MyCollectionA", "MyCollectionB", null, new[] { example_GenericClassesWithConversion })] - [InlineData("MyCollectionB", "MyCollectionB", null, new[] { example_GenericClassesWithConversion })] - [InlineData("RefStructConvertibleFromArray", "T[]", "System.Int32[]", new[] { example_RefStructConvertibleFromArray })] - [InlineData("RefStructConvertibleFromArray", "int[]", "System.Int32[]", new[] { example_RefStructConvertibleFromArray })] - [InlineData("RefStructConvertibleFromArray", "T[]", null, new[] { example_RefStructConvertibleFromArray })] - [InlineData("RefStructConvertibleFromArray", "object[]", null, new[] { example_RefStructConvertibleFromArray })] - public void BetterConversionFromExpression_01A(string type1, string type2, string expectedType, string[] additionalSources = null) + [InlineData("System.Span", "T[]", "System.Span", "System.Span")] + [InlineData("System.Span", "int[]", "System.Span", "System.Span")] + [InlineData("System.Span", "System.Collections.Generic.IEnumerable", "System.Span", "System.Span")] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyCollection", "System.Span", "System.Span")] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyList", "System.Span", "System.Span")] + [InlineData("System.Span", "System.Collections.Generic.ICollection", "System.Span", "System.Span")] + [InlineData("System.Span", "System.Collections.Generic.IList", "System.Span", "System.Span")] + [InlineData("System.ReadOnlySpan", "T[]", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyCollection", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyList", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.ICollection", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IList", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.Span", "System.Collections.Generic.HashSet", null, null)] // rule requires array or array interface + [InlineData("System.Span", "System.ReadOnlySpan", null, "System.Span")] + [InlineData("RefStructCollection", "T[]", null, null, new[] { example_RefStructCollection })] + [InlineData("RefStructCollection", "RefStructCollection", null, "RefStructCollection", new[] { example_RefStructCollection })] + [InlineData("RefStructCollection", "GenericClassCollection", null, "RefStructCollection", new[] { example_RefStructCollection, example_GenericClassCollection })] + [InlineData("RefStructCollection", "GenericClassCollection", null, "GenericClassCollection", new[] { example_RefStructCollection, example_GenericClassCollection })] + [InlineData("RefStructCollection", "NonGenericClassCollection", null, "RefStructCollection", new[] { example_RefStructCollection, example_NonGenericClassCollection })] + [InlineData("GenericClassCollection", "T[]", null, null, new[] { example_GenericClassCollection })] // rule requires span + [InlineData("NonGenericClassCollection", "object[]", null, null, new[] { example_NonGenericClassCollection })] // rule requires span + [InlineData("System.ReadOnlySpan", "object[]", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "long[]", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "short[]", null, "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "int[]", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "T[]", null, "System.Int32[]")] + [InlineData("System.ReadOnlySpan", "long[]", null, "System.Int64[]")] + [InlineData("System.ReadOnlySpan", "object[]", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "string[]", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Span", null, "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", null, "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", null, "System.ReadOnlySpan")] + [InlineData("System.Span", "System.Span", "System.Span", "System.Span")] + [InlineData("System.Span", "System.Span", null, "System.Span")] + [InlineData("System.Span", "System.Span", null, "System.Span")] + [InlineData("System.Span", "System.Span", "System.Span", "System.Span")] + [InlineData("T[]", "int[]", "System.Int32[]", "System.Int32[]")] + [InlineData("T[]", "object[]", null, "System.Int32[]")] + [InlineData("T[]", "int?[]", null, "System.Int32[]")] + [InlineData("System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection")] + [InlineData("System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection", null, "System.Collections.Generic.ICollection")] + [InlineData("System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection", null, "System.Collections.Generic.ICollection")] + [InlineData("System.Collections.Generic.ICollection", "System.Collections.Generic.IReadOnlyCollection", null, null)] + [InlineData("MyCollectionA", "MyCollectionB", "MyCollectionB", "MyCollectionB", new[] { example_GenericClassesWithConversion })] + [InlineData("MyCollectionA", "MyCollectionB", "MyCollectionB", "MyCollectionB", new[] { example_GenericClassesWithConversion })] + [InlineData("MyCollectionA", "MyCollectionB", null, "MyCollectionA", new[] { example_GenericClassesWithConversion })] + [InlineData("MyCollectionA", "MyCollectionB", null, "MyCollectionA", new[] { example_GenericClassesWithConversion })] + [InlineData("MyCollectionB", "MyCollectionB", null, "MyCollectionB", new[] { example_GenericClassesWithConversion })] + [InlineData("RefStructConvertibleFromArray", "T[]", "System.Int32[]", "System.Int32[]", new[] { example_RefStructConvertibleFromArray })] + [InlineData("RefStructConvertibleFromArray", "int[]", "System.Int32[]", "System.Int32[]", new[] { example_RefStructConvertibleFromArray })] + [InlineData("RefStructConvertibleFromArray", "T[]", null, "System.Int32[]", new[] { example_RefStructConvertibleFromArray })] + [InlineData("RefStructConvertibleFromArray", "object[]", null, "RefStructConvertibleFromArray", new[] { example_RefStructConvertibleFromArray })] + public void BetterConversionFromExpression_01A(string type1, string type2, string expectedType12, string expectedType13, string[] additionalSources = null) { string source = $$""" using System; @@ -1368,10 +1405,131 @@ static void Main() } } """; + + verify(TestOptions.Regular12, expectedType12); + verify(TestOptions.Regular13, expectedType13); + verify(TestOptions.RegularPreview, expectedType13); + + static string getTypeParameters(string type) => + type.Contains("T[]") || type.Contains("") ? "" : ""; + + static string generateMethod(string methodName, string parameterType) => + $"static Type {methodName}{getTypeParameters(parameterType)}({parameterType} value) => typeof({parameterType});"; + + static string generateMethodSignature(string methodName, string parameterType) => + $"Program.{methodName}{getTypeParameters(parameterType)}({parameterType})"; + + static string[] getSources(string source, string[] additionalSources) + { + var builder = ArrayBuilder.GetInstance(); + builder.Add(source); + builder.Add(s_collectionExtensions); + if (additionalSources is { }) builder.AddRange(additionalSources); + return builder.ToArrayAndFree(); + } + + void verify(CSharpParseOptions parseOptions, string expectedType) + { + var comp = CreateCompilation( + getSources(source, additionalSources), + targetFramework: TargetFramework.Net80, + parseOptions: parseOptions, + options: TestOptions.ReleaseExe); + if (expectedType is { }) + { + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput($""" + {expectedType} + {expectedType} + """)); + } + else + { + comp.VerifyEmitDiagnostics( + // 0.cs(10,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(ReadOnlySpan)' and 'Program.F1(ReadOnlySpan)' + // var x = F1([1, 2, 3]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments(generateMethodSignature("F1", type1), generateMethodSignature("F1", type2)).WithLocation(10, 17), + // 0.cs(12,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(ReadOnlySpan)' and 'Program.F2(ReadOnlySpan)' + // var y = F2([4, 5]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments(generateMethodSignature("F2", type2), generateMethodSignature("F2", type1)).WithLocation(12, 17)); + } + } + } + + [Theory] + [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Span", null)] + [InlineData("System.ReadOnlySpan", "System.Span", null)] + [InlineData("System.ReadOnlySpan", "System.Span", null)] + [InlineData("System.ReadOnlySpan", "System.Span", null)] // cannot convert object to int + [InlineData("System.ReadOnlySpan", "System.Span", null)] // cannot convert int? to int + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", null)] + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", null)] + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", null)] + [InlineData("System.Span", "System.Span", null)] + [InlineData("System.Span", "System.Span", null)] + [InlineData("System.Span", "System.Span", null)] + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", null)] + [InlineData("System.Span", "int?[]", null)] + [InlineData("System.Span", "System.Collections.Generic.IEnumerable", null)] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyCollection", null)] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyList", null)] + [InlineData("System.Span", "System.Collections.Generic.ICollection", null)] + [InlineData("System.Span", "System.Collections.Generic.IList", null)] + [InlineData("System.Span", "int[]", null)] // cannot convert int? to int + [InlineData("System.Span", "System.Collections.Generic.IEnumerable", null)] // cannot convert int? to int + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyCollection", null)] // cannot convert int? to int + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyList", null)] // cannot convert int? to int + [InlineData("System.Span", "System.Collections.Generic.ICollection", null)] // cannot convert int? to int + [InlineData("System.Span", "System.Collections.Generic.IList", null)] // cannot convert int? to int + [InlineData("System.ReadOnlySpan", "object[]", null)] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", null)] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyCollection", null)] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyList", null)] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.ICollection", null)] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IList", null)] + [InlineData("System.ReadOnlySpan", "int[]", null)] // cannot convert object to int + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", null)] // cannot convert object to int + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyCollection", null)] // cannot convert object to int + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyList", null)] // cannot convert object to int + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.ICollection", null)] // cannot convert object to int + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IList", null)] // cannot convert object to int + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.IEnumerable", "System.Collections.Generic.List")] + [InlineData("int[]", "object[]", null)] // rule requires span + [InlineData("int[]", "System.Collections.Generic.IReadOnlyList", null)] // rule requires span + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.IEnumerable", "System.Collections.Generic.List", null)] + [InlineData("int[]", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.HashSet", "System.Span", null)] + [InlineData("System.Collections.Generic.HashSet", "System.ReadOnlySpan", null)] + [InlineData("System.Collections.Generic.HashSet", "System.Span", null)] + [InlineData("System.Collections.Generic.HashSet", "System.ReadOnlySpan", null)] + public void BetterConversionFromExpression_01B_Empty(string type1, string type2, string expectedType) + { + string source = $$""" + using System; + class Program + { + {{generateMethod("F1", type1)}} + {{generateMethod("F1", type2)}} + {{generateMethod("F2", type2)}} + {{generateMethod("F2", type1)}} + static void Main() + { + var a = F1([]); + Console.WriteLine(a.GetTypeName()); + var b = F2([]); + Console.WriteLine(b.GetTypeName()); + } + } + """; var comp = CreateCompilation( - getSources(source, additionalSources), + new[] { source, s_collectionExtensions }, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + if (expectedType is { }) { CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput($""" @@ -1382,37 +1540,126 @@ static void Main() else { comp.VerifyEmitDiagnostics( - // 0.cs(10,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(ReadOnlySpan)' and 'Program.F1(ReadOnlySpan)' - // var x = F1([1, 2, 3]); + // 0.cs(10,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(int[])' and 'Program.F1(object[])' + // var a = F1(); Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments(generateMethodSignature("F1", type1), generateMethodSignature("F1", type2)).WithLocation(10, 17), - // 0.cs(12,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(ReadOnlySpan)' and 'Program.F2(ReadOnlySpan)' - // var y = F2([4, 5]); + // 0.cs(12,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(object[])' and 'Program.F2(int[])' + // var b = F2(); Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments(generateMethodSignature("F2", type2), generateMethodSignature("F2", type1)).WithLocation(12, 17)); } - static string getTypeParameters(string type) => - type.Contains("T[]") || type.Contains("") ? "" : ""; - static string generateMethod(string methodName, string parameterType) => - $"static Type {methodName}{getTypeParameters(parameterType)}({parameterType} value) => typeof({parameterType});"; + $"static Type {methodName}({parameterType} value) => typeof({parameterType});"; static string generateMethodSignature(string methodName, string parameterType) => - $"Program.{methodName}{getTypeParameters(parameterType)}({parameterType})"; + $"Program.{methodName}({parameterType})"; + } - static string[] getSources(string source, string[] additionalSources) + [Theory] + [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Span", "System.Span")] + [InlineData("System.ReadOnlySpan", "System.Span", "System.Span")] + [InlineData("System.ReadOnlySpan", "System.Span", "System.Span")] + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan>")] + [InlineData("System.Span", "System.Span", "System.Span")] + [InlineData("System.Span", "System.Span", "System.Span")] + [InlineData("System.Span", "System.Span", "System.Span>")] + [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan")] + [InlineData("System.Span", "int?[]", "System.Span")] + [InlineData("System.Span", "System.Collections.Generic.IEnumerable", "System.Span")] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyCollection", "System.Span")] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyList", "System.Span")] + [InlineData("System.Span", "System.Collections.Generic.ICollection", "System.Span")] + [InlineData("System.Span", "System.Collections.Generic.IList", "System.Span")] + [InlineData("System.Span", "int[]", "System.Int32[]")] + [InlineData("System.Span", "System.Collections.Generic.IEnumerable", "System.Collections.Generic.IEnumerable")] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyCollection", "System.Collections.Generic.IReadOnlyCollection")] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyList", "System.Collections.Generic.IReadOnlyList")] + [InlineData("System.Span", "System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection")] + [InlineData("System.Span", "System.Collections.Generic.IList", "System.Collections.Generic.IList")] + [InlineData("System.ReadOnlySpan", "object[]", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyCollection", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyList", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.ICollection", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IList", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "int[]", "System.Int32[]")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", "System.Collections.Generic.IEnumerable")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyCollection", "System.Collections.Generic.IReadOnlyCollection")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyList", "System.Collections.Generic.IReadOnlyList")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IList", "System.Collections.Generic.IList")] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.IEnumerable", "System.Collections.Generic.List")] + [InlineData("int[]", "object[]", "System.Int32[]")] + [InlineData("int[]", "System.Collections.Generic.IReadOnlyList", "System.Int32[]")] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", "System.Collections.Generic.List")] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", "System.Collections.Generic.List>")] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", "System.Collections.Generic.List")] + [InlineData("System.Collections.Generic.IEnumerable", "System.Collections.Generic.List", "System.Collections.Generic.IEnumerable")] + [InlineData("int[]", "System.Collections.Generic.List", "System.Int32[]")] + [InlineData("System.Collections.Generic.HashSet", "System.Span", "System.Collections.Generic.HashSet")] + [InlineData("System.Collections.Generic.HashSet", "System.ReadOnlySpan", "System.Collections.Generic.HashSet")] + [InlineData("System.Collections.Generic.HashSet", "System.Span", "System.Span")] + [InlineData("System.Collections.Generic.HashSet", "System.ReadOnlySpan", "System.ReadOnlySpan")] + public void BetterConversionFromExpression_01B_NotEmpty(string type1, string type2, string expectedType) + { + string source = $$""" + using System; + class Program + { + {{generateMethod("F1", type1)}} + {{generateMethod("F1", type2)}} + {{generateMethod("F2", type2)}} + {{generateMethod("F2", type1)}} + static void Main() + { + var c = F1([1, 2, 3]); + Console.WriteLine(c.GetTypeName()); + var d = F2([4, 5]); + Console.WriteLine(d.GetTypeName()); + } + } + """; + var comp = CreateCompilation( + new[] { source, s_collectionExtensions }, + targetFramework: TargetFramework.Net80, + options: TestOptions.ReleaseExe); + + if (expectedType is { }) { - var builder = ArrayBuilder.GetInstance(); - builder.Add(source); - builder.Add(s_collectionExtensions); - if (additionalSources is { }) builder.AddRange(additionalSources); - return builder.ToArrayAndFree(); + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput($""" + {expectedType} + {expectedType} + """)); + } + else + { + comp.VerifyEmitDiagnostics( + // 0.cs(10,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(int[])' and 'Program.F1(object[])' + // var c = F1(1, 2, 3); + Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments(generateMethodSignature("F1", type1), generateMethodSignature("F1", type2)).WithLocation(10, 17), + // 0.cs(12,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(object[])' and 'Program.F2(int[])' + // var d = F2(4, 5); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments(generateMethodSignature("F2", type2), generateMethodSignature("F2", type1)).WithLocation(12, 17)); } + + static string generateMethod(string methodName, string parameterType) => + $"static Type {methodName}({parameterType} value) => typeof({parameterType});"; + + static string generateMethodSignature(string methodName, string parameterType) => + $"Program.{methodName}({parameterType})"; } [Theory] [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] [InlineData("System.ReadOnlySpan", "System.Span", null)] // cannot convert object to int [InlineData("System.ReadOnlySpan", "System.Span", null)] // cannot convert int? to int [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", null)] @@ -1449,7 +1696,17 @@ static string[] getSources(string source, string[] additionalSources) [InlineData("System.Collections.Generic.List", "System.Collections.Generic.IEnumerable", "System.Collections.Generic.List")] [InlineData("int[]", "object[]", null)] // rule requires span [InlineData("int[]", "System.Collections.Generic.IReadOnlyList", null)] // rule requires span - public void BetterConversionFromExpression_01B(string type1, string type2, string expectedType) + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.IEnumerable", "System.Collections.Generic.List", null)] + [InlineData("int[]", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.HashSet", "System.Span", null)] + [InlineData("System.Collections.Generic.HashSet", "System.ReadOnlySpan", null)] + [InlineData("System.Collections.Generic.HashSet", "System.Span", null)] + [InlineData("System.Collections.Generic.HashSet", "System.ReadOnlySpan", null)] + public void BetterConversionFromExpression_01B_CSharp12(string type1, string type2, string expectedType) { string source = $$""" using System; @@ -1475,6 +1732,7 @@ static void Main() var comp = CreateCompilation( new[] { source, s_collectionExtensions }, targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular12, options: TestOptions.ReleaseExe); if (expectedType is { }) { @@ -1509,6 +1767,104 @@ static string generateMethodSignature(string methodName, string parameterType) = $"Program.{methodName}({parameterType})"; } + [Theory, CombinatorialData] + public void BetterConversionFromExpression_01C( + [CombinatorialValues( + "System.ReadOnlySpan", + "System.Span", + "string[]", + "System.Collections.Generic.IEnumerable", + "System.Collections.Generic.IReadOnlyList", + "System.Collections.Generic.IReadOnlyCollection", + "System.Collections.Generic.IList", + "System.Collections.Generic.ICollection" + )] + string stringType, + [CombinatorialValues( + "System.ReadOnlySpan", + "System.Span", + "CustomHandler[]", + "System.Collections.Generic.IEnumerable", + "System.Collections.Generic.IReadOnlyList", + "System.Collections.Generic.IReadOnlyCollection", + "System.Collections.Generic.IList", + "System.Collections.Generic.ICollection")] + string interpolatedType) + { + var testMethods = $$""" + partial class Program + { + {{generateMethod("F1", stringType)}} + {{generateMethod("F1", interpolatedType)}} + {{generateMethod("F2", interpolatedType)}} + {{generateMethod("F2", stringType)}} + } + """; + + var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: false, includeOneTimeHelpers: false); + + string source1 = $$""" + var a = F1([]); + var b = F2([]); + var c = F1([$"{1}", $"2", $"{3}"]); + var d = F2([$"{1}", $"2", $"{3}"]); + """; + var comp = CreateCompilation( + [source1, testMethods, customHandler, s_collectionExtensions], + targetFramework: TargetFramework.Net80, + options: TestOptions.ReleaseExe); + + string f1InterpolatedSig = generateMethodSignature("F1", interpolatedType); + string f1StringSig = generateMethodSignature("F1", stringType); + string f2InterpolatedSig = generateMethodSignature("F2", interpolatedType); + string f2StringSig = generateMethodSignature("F2", stringType); + comp.VerifyDiagnostics( + // (1,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(IReadOnlyList)' and 'Program.F1(IReadOnlyCollection)' + // var a = F1([]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments(f1StringSig, f1InterpolatedSig).WithLocation(1, 9), + // (2,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(IReadOnlyCollection)' and 'Program.F2(IReadOnlyList)' + // var b = F2([]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments(f2InterpolatedSig, f2StringSig).WithLocation(2, 9), + // (3,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(string[])' and 'Program.F1(CustomHandler[])' + // var c = F1([$"{1}", $"2", $"{3}"]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments(f1StringSig, f1InterpolatedSig).WithLocation(3, 9), + // (4,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(CustomHandler[])' and 'Program.F2(string[])' + // var d = F2([$"{1}", $"2", $"{3}"]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments(f2InterpolatedSig, f2StringSig).WithLocation(4, 9) + ); + + var source2 = $$""" + using System; + var c = F1([$"{1}", $"{2}", $"{3}"]); + Console.WriteLine(c.GetTypeName()); + var d = F2([$"{1}", $"{2}", $"{3}"]); + Console.WriteLine(d.GetTypeName()); + var e = F1([$"1", $"2", $"3"]); + Console.WriteLine(e.GetTypeName()); + var f = F2([$"1", $"2", $"3"]); + Console.WriteLine(f.GetTypeName()); + """; + + comp = CreateCompilation( + [source2, testMethods, customHandler, s_collectionExtensions], + targetFramework: TargetFramework.Net80, + options: TestOptions.ReleaseExe); + + string outputStringType = stringType.Replace("string", "System.String"); + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput($""" + {interpolatedType} + {interpolatedType} + {outputStringType} + {outputStringType} + """)); + + static string generateMethod(string methodName, string parameterType) => + $"static System.Type {methodName}({parameterType} value) => typeof({parameterType});"; + + static string generateMethodSignature(string methodName, string parameterType) => + $"Program.{methodName}({parameterType})"; + } + [Fact] public void BetterConversionFromExpression_02() { @@ -1544,21 +1900,46 @@ static void Main() Generic([string.Empty]); // Span Identical([string.Empty]); // Span SpanDerived([string.Empty]); // Span + ArrayDerived([string.Empty]); // string[] } } """; - var comp = CreateCompilation( - new[] { sourceA, sourceB1 }, - targetFramework: TargetFramework.Net80, - options: TestOptions.ReleaseExe); - CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput(""" + + string expectedOutput = IncludeExpectedOutput(""" T[] string[] string[] Span Span Span - """)); + string[] + """); + + var comp = CreateCompilation( + new[] { sourceA, sourceB1 }, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular13, + options: TestOptions.ReleaseExe); + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: expectedOutput); + + comp = CreateCompilation( + new[] { sourceA, sourceB1 }, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.RegularPreview, + options: TestOptions.ReleaseExe); + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: expectedOutput); + + comp = CreateCompilation( + new[] { sourceA, sourceB1 }, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular12, + options: TestOptions.ReleaseExe); + + comp.VerifyDiagnostics( + // 1.cs(12,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.ArrayDerived(Span)' and 'Program.ArrayDerived(string[])' + // ArrayDerived([string.Empty]); // string[] + Diagnostic(ErrorCode.ERR_AmbigCall, "ArrayDerived").WithArguments("Program.ArrayDerived(System.Span)", "Program.ArrayDerived(string[])").WithLocation(12, 9) + ); string sourceB2 = """ partial class Program @@ -1566,39 +1947,32 @@ partial class Program static void Main() { SpanDerived(new[] { string.Empty }); // ambiguous - ArrayDerived([string.Empty]); // ambiguous } } """; + + // 1.cs(5,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.SpanDerived(Span)' and 'Program.SpanDerived(object[])' + // SpanDerived(new[] { string.Empty }); // ambiguous + var expectedDiagnostic = Diagnostic(ErrorCode.ERR_AmbigCall, "SpanDerived").WithArguments("Program.SpanDerived(System.Span)", "Program.SpanDerived(object[])").WithLocation(5, 9); + comp = CreateCompilation( new[] { sourceA, sourceB2 }, - parseOptions: TestOptions.Regular12, + parseOptions: TestOptions.Regular13, targetFramework: TargetFramework.Net80); - comp.VerifyEmitDiagnostics( - // 1.cs(5,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.SpanDerived(Span)' and 'Program.SpanDerived(object[])' - // SpanDerived(new[] { string.Empty }); // ambiguous - Diagnostic(ErrorCode.ERR_AmbigCall, "SpanDerived").WithArguments("Program.SpanDerived(System.Span)", "Program.SpanDerived(object[])").WithLocation(5, 9), - // 1.cs(6,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.ArrayDerived(Span)' and 'Program.ArrayDerived(string[])' - // ArrayDerived([string.Empty]); // ambiguous - Diagnostic(ErrorCode.ERR_AmbigCall, "ArrayDerived").WithArguments("Program.ArrayDerived(System.Span)", "Program.ArrayDerived(string[])").WithLocation(6, 9)); - - var expectedDiagnostics = new[] - { - // 1.cs(6,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.ArrayDerived(Span)' and 'Program.ArrayDerived(string[])' - // ArrayDerived([string.Empty]); // ambiguous - Diagnostic(ErrorCode.ERR_AmbigCall, "ArrayDerived").WithArguments("Program.ArrayDerived(System.Span)", "Program.ArrayDerived(string[])").WithLocation(6, 9) - }; + comp.VerifyEmitDiagnostics(expectedDiagnostic); comp = CreateCompilation( new[] { sourceA, sourceB2 }, - parseOptions: TestOptions.RegularNext, + parseOptions: TestOptions.RegularPreview, + options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net80); - comp.VerifyEmitDiagnostics(expectedDiagnostics); + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("Span")).VerifyDiagnostics(); comp = CreateCompilation( new[] { sourceA, sourceB2 }, + parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80); - comp.VerifyEmitDiagnostics(expectedDiagnostics); + comp.VerifyEmitDiagnostics(expectedDiagnostic); } [WorkItem("https://github.com/dotnet/roslyn/issues/69634")] @@ -1673,9 +2047,9 @@ public void BetterConversionFromExpression_04() class Program { static void F1(int[] x, int[] y) { throw null; } - static void F1(Span x, ReadOnlySpan y) { x.Report(); y.Report(); } + static void F1(Span x, ReadOnlySpan y) { x.ReportSpan(); y.Report(); } static void F2(object x, string[] y) { throw null; } - static void F2(string x, Span y) { y.Report(); } + static void F2(string x, Span y) { y.ReportSpan(); } static void Main() { F1([1], [2]); @@ -1683,9 +2057,31 @@ static void Main() } } """; + var expectedDiagnostics = new[] { + // 'params' works in this case. + // For 'Inline collection expression' case it fails because: + // - For the first argument, 'int[]' and 'Span' -> `int[]` is better vs. `Span` for 'params' + // - For the second argument, 'int' and 'int' -> 'ReadOnlySpan' is better vs. neither is better for 'params' + // The first parameter is better for the first overload, and the second is better for the second overload, ambiguous. + + // 0.cs(10,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(int[], int[])' and 'Program.F1(Span, ReadOnlySpan)' + // F1([1], [2]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments("Program.F1(int[], int[])", "Program.F1(System.Span, System.ReadOnlySpan)").WithLocation(10, 9), + // 0.cs(11,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(object, string[])' and 'Program.F2(string, Span)' + // F2("3", ["4"]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments("Program.F2(object, string[])", "Program.F2(string, System.Span)").WithLocation(11, 9) + }; + + var comp = CreateCompilation(new[] { source, s_collectionExtensionsWithSpan }, parseOptions: TestOptions.Regular13, targetFramework: TargetFramework.Net80); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(new[] { source, s_collectionExtensionsWithSpan }, parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.Net80); + comp.VerifyDiagnostics(expectedDiagnostics); + CompileAndVerify( new[] { source, s_collectionExtensionsWithSpan }, targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular12, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput("[1], [2], [4], ")); } @@ -1788,10 +2184,10 @@ public void BetterConversionFromExpression_07() using System; class Program { - static void F1(ReadOnlySpan value) { } - static void F1(ReadOnlySpan value) { } - static void F2(Span value) { } - static void F2(Span value) { } + static void F1(ReadOnlySpan value) => Console.WriteLine("ReadOnlySpan"); + static void F1(ReadOnlySpan value) => Console.WriteLine("ReadOnlySpan"); + static void F2(Span value) => Console.WriteLine("Span"); + static void F2(Span value) => Console.WriteLine("Span"); static void Main() { F1([1, 2, 3]); @@ -1799,10 +2195,25 @@ static void Main() } } """; - var comp = CreateCompilation( + var expectedOutput = IncludeExpectedOutput(""" + ReadOnlySpan + Span + """); + CompileAndVerify( source, - targetFramework: TargetFramework.Net80); - comp.VerifyEmitDiagnostics( + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular13, + verify: Verification.Skipped, + expectedOutput: expectedOutput); + + CompileAndVerify( + source, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.RegularPreview, + verify: Verification.Skipped, + expectedOutput: expectedOutput); + + CreateCompilation(source, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyEmitDiagnostics( // (10,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(ReadOnlySpan)' and 'Program.F1(ReadOnlySpan)' // F1([1, 2, 3]); Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments("Program.F1(System.ReadOnlySpan)", "Program.F1(System.ReadOnlySpan)").WithLocation(10, 9), @@ -1815,21 +2226,25 @@ static void Main() public void BetterConversionFromExpression_08A() { string source = """ + using System; class Program { - static void F1(int[] value) { } - static void F1(object[] value) { } + static void F1(int[] value) => Console.WriteLine("int[]"); + static void F1(object[] value) => Console.WriteLine("object[]"); static void Main() { F1([1, 2, 3]); } } """; - var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (7,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(int[])' and 'Program.F1(object[])' + var expectedOutput = "int[]"; + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: expectedOutput).VerifyDiagnostics(); + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyEmitDiagnostics( + // (8,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(int[])' and 'Program.F1(object[])' // F1([1, 2, 3]); - Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments("Program.F1(int[])", "Program.F1(object[])").WithLocation(7, 9)); + Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments("Program.F1(int[])", "Program.F1(object[])").WithLocation(8, 9)); } [Fact] @@ -1850,6 +2265,788 @@ static void Main() CompileAndVerify(source, expectedOutput: "string[]"); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73857")] + public void BetterConversionFromExpression_08C() + { + string source = """ + using System; + class Program + { + static void F2(ReadOnlySpan value) { Console.WriteLine("ReadOnlySpan"); } + static void F2(ReadOnlySpan value) { Console.WriteLine("ReadOnlySpan"); } + static void Main() + { + F2(["a", "b"]); + } + } + """; + CompileAndVerify(source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("ReadOnlySpan")); + } + + [Theory] + [InlineData(LanguageVersion.Preview)] + [InlineData(LanguageVersion.CSharp13)] + [InlineData(LanguageVersion.CSharp12)] + public void BetterConversionFromExpression_09(LanguageVersion version) + { + string source = """ + using System; + using System.Collections.Generic; + class Program + { + static void F2(List value) { Console.WriteLine("List"); } + static void F2(List value) { Console.WriteLine("List"); } + static void Main() + { + F2([1, (byte)2]); + } + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(version)).VerifyDiagnostics( + // (9,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(List)' and 'Program.F2(List)' + // F2([1, (byte)2]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments("Program.F2(System.Collections.Generic.List)", "Program.F2(System.Collections.Generic.List)").WithLocation(9, 9)); + } + + [Fact] + public void BetterConversionFromExpression_10() + { + string source = """ + using System; + using System.Collections.Generic; + class Program + { + static void F2(List value) { Console.WriteLine("List"); } + static void F2(List value) { Console.WriteLine("List"); } + static void Main() + { + F2([(byte)1, (byte)2]); + } + } + """; + + var expectedOutput = "List"; + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: expectedOutput); + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (9,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(List)' and 'Program.F2(List)' + // F2([1, (byte)2]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments("Program.F2(System.Collections.Generic.List)", "Program.F2(System.Collections.Generic.List)").WithLocation(9, 9)); + } + + [Theory] + [InlineData("System.FormattableString")] + [InlineData("System.IFormattable")] + public void BetterConversionFromExpression_11(string formatType) + { + string source = $$""" + using System; + class Program + { + static void F2(ReadOnlySpan value) { Console.WriteLine("ReadOnlySpan"); } + static void F2(ReadOnlySpan<{{formatType}}> value) { Console.WriteLine("ReadOnlySpan<{{formatType}}>"); } + static void Main() + { + F2([$"{1}"]); + } + } + """; + + string expectedOutput = IncludeExpectedOutput("ReadOnlySpan"); + + CompileAndVerify(source, + parseOptions: TestOptions.Regular13, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: expectedOutput); + + CompileAndVerify(source, + parseOptions: TestOptions.RegularPreview, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: expectedOutput); + + CreateCompilation(source, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics( + // (8,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(ReadOnlySpan)' and 'Program.F2(ReadOnlySpan)' + // F2([$"{1}"]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments("Program.F2(System.ReadOnlySpan)", $"Program.F2(System.ReadOnlySpan<{formatType}>)").WithLocation(8, 9) + ); + } + + [Fact] + public void BetterConversionFromExpression_12() + { + string source = """ + using System; + + M1([$"{1}"]); + + partial class Program + { + static void M1(System.ReadOnlySpan x) => Console.WriteLine("ReadOnlySpan"); + static void M1(System.Span x) => Console.WriteLine("Span"); + } + + partial class CustomHandler + { + public static implicit operator CustomHandler(string s) => new CustomHandler(0, 0); + } + """; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: false, includeOneTimeHelpers: false); + + string expectedOutput13 = IncludeExpectedOutput("Span"); + + CompileAndVerify( + new[] { source, handler }, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular13, + verify: Verification.Skipped, + expectedOutput: expectedOutput13); + + CompileAndVerify( + new[] { source, handler }, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.RegularPreview, + verify: Verification.Skipped, + expectedOutput: expectedOutput13); + + CompileAndVerify( + new[] { source, handler }, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular12, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("ReadOnlySpan")); + } + + [Theory] + [CombinatorialData] + public void BetterConversionFromExpression_13(bool dynamicReadOnlySpan) + { + var spanType = dynamicReadOnlySpan ? "Span" : "Span"; + var readOnlySpanType = dynamicReadOnlySpan ? "ReadOnlySpan" : "ReadOnlySpan"; + + var source = $$""" + using System; + using System.Collections.Generic; + + object o = null; + dynamic d = null; + + M1([o, o]); + M1([d, d]); + M1([o, d]); + M1([d, o]); + M2([o, o]); + M2([d, d]); + M2([o, d]); + M2([d, o]); + + IEnumerable x = []; + IEnumerable y = []; + M1([..x]); + M1([..y]); + M1([o, ..x]); + M1([d, ..x]); + M1([..y, o]); + M1([..y, d]); + M1([..x, ..y]); + M1([..y, ..x]); + + partial class Program + { + static void M1({{spanType}} s) => Console.WriteLine("{{spanType}}"); + static void M1({{readOnlySpanType}} s) => Console.WriteLine("{{readOnlySpanType}}"); + static void M2({{readOnlySpanType}} s) => Console.WriteLine("{{readOnlySpanType}}"); + static void M2({{spanType}} s) => Console.WriteLine("{{spanType}}"); + } + """; + + string expectedOutput = IncludeExpectedOutput($""" + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + {readOnlySpanType} + """); + + CompileAndVerify(source, + verify: Verification.Skipped, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular13, + expectedOutput: expectedOutput); + + CompileAndVerify(source, + verify: Verification.Skipped, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.RegularPreview, + expectedOutput: expectedOutput); + + CompileAndVerify(source, + verify: Verification.Skipped, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular12, + expectedOutput: expectedOutput); + } + + [Fact] + public void BetterConversionFromExpression_14() + { + var source = $$""" + using System.Collections.Generic; + + object o = null; + dynamic d = null; + + o.M1([o, o]); + o.M1([d, d]); + o.M1([o, d]); + o.M1([d, o]); + + IEnumerable x = []; + IEnumerable y = []; + o.M1([..x]); + o.M1([..y]); + o.M1([o, ..x]); + o.M1([d, ..x]); + o.M1([..y, o]); + o.M1([..y, d]); + o.M1([..x, ..y]); + o.M1([..y, ..x]); + + static class Ext1 + { + public static void M1(this object o, List d) { } + } + + static class Ext2 + { + public static void M1(this object o, List d) { } + } + """; + + var expectedDiagnostics = new[] { + // (6,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([o, o]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(6, 3), + // (7,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([d, d]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(7, 3), + // (8,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([o, d]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(8, 3), + // (9,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([d, o]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(9, 3), + // (13,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(13, 3), + // (14,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([..y]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(14, 3), + // (15,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([o, ..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(15, 3), + // (16,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([d, ..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(16, 3), + // (17,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([..y, o]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(17, 3), + // (18,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([..y, d]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(18, 3), + // (19,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([..x, ..y]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(19, 3), + // (20,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ext1.M1(object, List)' and 'Ext2.M1(object, List)' + // o.M1([..y, ..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ext1.M1(object, System.Collections.Generic.List)", "Ext2.M1(object, System.Collections.Generic.List)").WithLocation(20, 3) + }; + + CreateCompilation(source, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); + + CreateCompilation(source, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics); + + CreateCompilation(source, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory] + [CombinatorialData] + public void BetterConversionFromExpression_15(bool dynamicList) + { + var ienumerableType = dynamicList ? "IEnumerable" : "IEnumerable"; + var listType = dynamicList ? "List" : "List"; + + var source = $$""" + using System; + using System.Collections.Generic; + + object o = null; + dynamic d = null; + + M1([o, o]); + M1([d, d]); + M1([o, d]); + M1([d, o]); + M2([o, o]); + M2([d, d]); + M2([o, d]); + M2([d, o]); + + IEnumerable x = []; + IEnumerable y = []; + M1([..x]); + M1([..y]); + M1([o, ..x]); + M1([d, ..x]); + M1([..y, o]); + M1([..y, d]); + M1([..x, ..y]); + M1([..y, ..x]); + + partial class Program + { + static void M1({{ienumerableType}} s) => Console.WriteLine("{{ienumerableType}}"); + static void M1({{listType}} s) => Console.WriteLine("{{listType}}"); + static void M2({{listType}} s) => Console.WriteLine("{{listType}}"); + static void M2({{ienumerableType}} s) => Console.WriteLine("{{ienumerableType}}"); + } + """; + + string expectedOutput = IncludeExpectedOutput($""" + {listType} + {listType} + {listType} + {listType} + {listType} + {listType} + {listType} + {listType} + {listType} + {listType} + {listType} + {listType} + {listType} + {listType} + {listType} + {listType} + """); + + CompileAndVerify(source, + verify: Verification.Skipped, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular13, + expectedOutput: expectedOutput); + + CompileAndVerify(source, + verify: Verification.Skipped, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.RegularPreview, + expectedOutput: expectedOutput); + + CompileAndVerify(source, + verify: Verification.Skipped, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular12, + expectedOutput: expectedOutput); + } + + [Theory] + [CombinatorialData] + public void BetterConversionFromExpression_16(bool dynamicList) + { + var hashSetType = dynamicList ? "HashSet" : "HashSet"; + var listType = dynamicList ? "List" : "List"; + + var source = $$""" + using System.Collections.Generic; + + object o = null; + dynamic d = null; + + M1([o, o]); + M1([d, d]); + M1([o, d]); + M1([d, o]); + M2([o, o]); + M2([d, d]); + M2([o, d]); + M2([d, o]); + + IEnumerable x = []; + IEnumerable y = []; + M1([..x]); + M1([..y]); + M1([o, ..x]); + M1([d, ..x]); + M1([..y, o]); + M1([..y, d]); + M1([..x, ..y]); + M1([..y, ..x]); + + partial class Program + { + static void M1({{hashSetType}} s) { } + static void M1({{listType}} s) { } + static void M2({{listType}} s) { } + static void M2({{hashSetType}} s) { } + } + """; + + var expectedDiagnostics = new[] { + // (6,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([o, o]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(6, 1), + // (7,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([d, d]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(7, 1), + // (8,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([o, d]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(8, 1), + // (9,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([d, o]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(9, 1), + // (10,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M2(List)' and 'Program.M2(HashSet)' + // M2([o, o]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments(generateMethodSignature("M2", listType),generateMethodSignature("M2", hashSetType)).WithLocation(10, 1), + // (11,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M2(List)' and 'Program.M2(HashSet)' + // M2([d, d]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments(generateMethodSignature("M2", listType),generateMethodSignature("M2", hashSetType)).WithLocation(11, 1), + // (12,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M2(List)' and 'Program.M2(HashSet)' + // M2([o, d]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments(generateMethodSignature("M2", listType),generateMethodSignature("M2", hashSetType)).WithLocation(12, 1), + // (13,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M2(List)' and 'Program.M2(HashSet)' + // M2([d, o]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M2").WithArguments(generateMethodSignature("M2", listType),generateMethodSignature("M2", hashSetType)).WithLocation(13, 1), + // (17,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(17, 1), + // (18,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([..y]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(18, 1), + // (19,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([o, ..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(19, 1), + // (20,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([d, ..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(20, 1), + // (21,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([..y, o]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(21, 1), + // (22,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([..y, d]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(22, 1), + // (23,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([..x, ..y]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(23, 1), + // (24,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(HashSet)' and 'Program.M1(List)' + // M1([..y, ..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments(generateMethodSignature("M1", hashSetType), generateMethodSignature("M1", listType)).WithLocation(24, 1) + }; + + CreateCompilation(source, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); + + CreateCompilation(source, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics); + + CreateCompilation(source, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + + static string generateMethodSignature(string methodName, string parameterType) => + $"Program.{methodName}(System.Collections.Generic.{parameterType})"; + } + + [Fact] + public void BetterConversionFromExpression_17() + { + var source = $$""" + using System; + using System.Collections.Generic; + + M1([(a: 1, b: 2)]); + M1([(a: 1, d: 2)]); + M1([(c: 1, b: 2)]); + M1([(c: 1, d: 2)]); + M2([(a: 1, b: 2)]); + M2([(a: 1, d: 2)]); + M2([(c: 1, b: 2)]); + M2([(c: 1, d: 2)]); + + IEnumerable<(int a, int b)> x = []; + IEnumerable<(int c, int d)> y = []; + M1([..x]); + M1([..y]); + M1([(a: 1, b: 2), ..x]); + M1([(c: 3, d: 4), ..x]); + M1([..y, (a: 5, b: 6)]); + M1([..y, (c: 7, d: 8)]); + M1([..x, ..y]); + M1([..y, ..x]); + + partial class Program + { + static void M1(Span<(int a, int b)> s) => Console.WriteLine("a, b"); + static void M1(ReadOnlySpan<(int c, int d)> s) => Console.WriteLine("c, d"); + static void M2(ReadOnlySpan<(int c, int d)> s) => Console.WriteLine("c, d"); + static void M2(Span<(int a, int b)> s) => Console.WriteLine("a, b"); + } + """; + + string expectedOutput = IncludeExpectedOutput($""" + c, d + c, d + c, d + c, d + c, d + c, d + c, d + c, d + c, d + c, d + c, d + c, d + c, d + c, d + c, d + c, d + """); + + CompileAndVerify(source, + verify: Verification.Skipped, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular13, + expectedOutput: expectedOutput); + + CompileAndVerify(source, + verify: Verification.Skipped, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.RegularPreview, + expectedOutput: expectedOutput); + + CompileAndVerify(source, + verify: Verification.Skipped, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular12, + expectedOutput: expectedOutput); + } + + [Fact] + public void BetterConversionFromExpression_18() + { + var source = $$""" + using System; + using System.Collections.Generic; + + object o = null; + + o.M1([(a: 1, b: 2)]); + o.M1([(a: 1, d: 2)]); + o.M1([(c: 1, b: 2)]); + o.M1([(c: 1, d: 2)]); + + IEnumerable<(int a, int b)> x = []; + IEnumerable<(int c, int d)> y = []; + o.M1([..x]); + o.M1([..y]); + o.M1([(a: 1, b: 2), ..x]); + o.M1([(c: 3, d: 4), ..x]); + o.M1([..y, (a: 5, b: 6)]); + o.M1([..y, (c: 7, d: 8)]); + o.M1([..x, ..y]); + o.M1([..y, ..x]); + + + static class Ex1 + { + public static void M1(this object o, List<(int a, int b)> s) => Console.WriteLine("a, b"); + } + + static class Ex2 + { + public static void M1(this object o, List<(int c, int d)> s) => Console.WriteLine("c, d"); + } + """; + + var expectedDiagnostics = new[] { + // (6,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([(a: 1, b: 2)]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(6, 3), + // (7,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([(a: 1, d: 2)]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(7, 3), + // (8,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([(c: 1, b: 2)]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(8, 3), + // (9,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([(c: 1, d: 2)]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(9, 3), + // (13,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(13, 3), + // (14,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([..y]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(14, 3), + // (15,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([(a: 1, b: 2), ..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(15, 3), + // (16,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([(c: 3, d: 4), ..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(16, 3), + // (17,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([..y, (a: 5, b: 6)]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(17, 3), + // (18,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([..y, (c: 7, d: 8)]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(18, 3), + // (19,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([..x, ..y]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(19, 3), + // (20,3): error CS0121: The call is ambiguous between the following methods or properties: 'Ex1.M1(object, List<(int a, int b)>)' and 'Ex2.M1(object, List<(int c, int d)>)' + // o.M1([..y, ..x]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("Ex1.M1(object, System.Collections.Generic.List<(int a, int b)>)", "Ex2.M1(object, System.Collections.Generic.List<(int c, int d)>)").WithLocation(20, 3) + }; + + CreateCompilation(source, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); + + CreateCompilation(source, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics); + + CreateCompilation(source, + targetFramework: TargetFramework.Net80, + parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + } + + [Theory] + [CombinatorialData] + public void BetterConversionFromExpression_19( + [CombinatorialValues( + "List", + "List", + "List", + "List", + "List<(int, int)>" + )] string type1, + [CombinatorialValues( + "List", + "List", + "List", + "List", + "List<(int, int)>" + )] string type2) + { + if (type1 == type2) + { + return; + } + + var source = $$""" + using System; + using System.Collections.Generic; + + M1([default]); + M1([new()]); + M1(default, default); + M1(new(), new()); + + partial class Program + { + static void M1(params {{type1}} s) => Console.WriteLine("{{type1}}"); + static void M1(params {{type2}} s) => Console.WriteLine("{{type2}}"); + } + """; + + var comp = CreateCompilation(source); + + string expectedType; + + switch (type1, type2) + { + // (int, int) vs everything but object is ambiguous + case ("List<(int, int)>", not "List"): + case (not "List", "List<(int, int)>"): + comp.VerifyDiagnostics( + // (4,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(params List)' and 'Program.M1(params List<(int, int)>)' + // M1([default]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments($"Program.M1(params System.Collections.Generic.{type1})", $"Program.M1(params System.Collections.Generic.{type2})").WithLocation(4, 1), + // (5,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(params List)' and 'Program.M1(params List<(int, int)>)' + // M1([new()]); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments($"Program.M1(params System.Collections.Generic.{type1})", $"Program.M1(params System.Collections.Generic.{type2})").WithLocation(5, 1), + // (6,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(params List)' and 'Program.M1(params List<(int, int)>)' + // M1(default, default); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments($"Program.M1(params System.Collections.Generic.{type1})", $"Program.M1(params System.Collections.Generic.{type2})").WithLocation(6, 1), + // (7,1): error CS0121: The call is ambiguous between the following methods or properties: 'Program.M1(params List)' and 'Program.M1(params List<(int, int)>)' + // M1(new(), new()); + Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments($"Program.M1(params System.Collections.Generic.{type1})", $"Program.M1(params System.Collections.Generic.{type2})").WithLocation(7, 1) + ); + return; + + // Then byte is always preferred when present + case ("List", _): + case (_, "List"): + expectedType = "List"; + break; + + // Then int + case ("List", _): + case (_, "List"): + expectedType = "List"; + break; + + // Then int? + case ("List", _): + case (_, "List"): + expectedType = "List"; + break; + + // Finally (int, int). It's only non-ambiguous when the other type is object + case ("List", "List<(int, int)>"): + case ("List<(int, int)>", "List"): + expectedType = "List<(int, int)>"; + break; + + // Unreachable + default: + throw ExceptionUtilities.Unreachable(); + } + + CompileAndVerify(comp, expectedOutput: $""" + {expectedType} + {expectedType} + {expectedType} + {expectedType} + """); + } + [Theory] [InlineData("System.ReadOnlySpan")] [InlineData("System.Span")] @@ -9183,15 +10380,29 @@ static void Main() var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, references: new[] { CSharpRef }, options: TestOptions.ReleaseExe, expectedOutput: "[1, 2, 3], "); if (resultType == "List") { + verifier.VerifyIL("Program.F", + """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """); + } + else + { + Assert.Equal("List", resultType); verifier.VerifyIL("Program.F", """ { // Code size 141 (0x8d) .maxstack 9 - .locals init (System.Collections.Generic.List V_0, + .locals init (System.Collections.Generic.List V_0, System.Collections.Generic.List.Enumerator V_1, object V_2) - IL_0000: newobj "System.Collections.Generic.List..ctor()" + IL_0000: newobj "System.Collections.Generic.List..ctor()" IL_0005: stloc.0 IL_0006: ldarg.0 IL_0007: callvirt "System.Collections.Generic.List.Enumerator System.Collections.Generic.List.GetEnumerator()" @@ -9202,76 +10413,7 @@ .locals init (System.Collections.Generic.List V_0, IL_000f: ldloca.s V_1 IL_0011: call "dynamic System.Collections.Generic.List.Enumerator.Current.get" IL_0016: stloc.2 - IL_0017: ldsfld "System.Runtime.CompilerServices.CallSite, dynamic>> Program.<>o__0.<>p__0" - IL_001c: brtrue.s IL_005c - IL_001e: ldc.i4 0x100 - IL_0023: ldstr "Add" - IL_0028: ldnull - IL_0029: ldtoken "Program" - IL_002e: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)" - IL_0033: ldc.i4.2 - IL_0034: newarr "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo" - IL_0039: dup - IL_003a: ldc.i4.0 - IL_003b: ldc.i4.1 - IL_003c: ldnull - IL_003d: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)" - IL_0042: stelem.ref - IL_0043: dup - IL_0044: ldc.i4.1 - IL_0045: ldc.i4.0 - IL_0046: ldnull - IL_0047: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)" - IL_004c: stelem.ref - IL_004d: call "System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Collections.Generic.IEnumerable, System.Type, System.Collections.Generic.IEnumerable)" - IL_0052: call "System.Runtime.CompilerServices.CallSite, dynamic>> System.Runtime.CompilerServices.CallSite, dynamic>>.Create(System.Runtime.CompilerServices.CallSiteBinder)" - IL_0057: stsfld "System.Runtime.CompilerServices.CallSite, dynamic>> Program.<>o__0.<>p__0" - IL_005c: ldsfld "System.Runtime.CompilerServices.CallSite, dynamic>> Program.<>o__0.<>p__0" - IL_0061: ldfld "System.Action, dynamic> System.Runtime.CompilerServices.CallSite, dynamic>>.Target" - IL_0066: ldsfld "System.Runtime.CompilerServices.CallSite, dynamic>> Program.<>o__0.<>p__0" - IL_006b: ldloc.0 - IL_006c: ldloc.2 - IL_006d: callvirt "void System.Action, dynamic>.Invoke(System.Runtime.CompilerServices.CallSite, System.Collections.Generic.List, dynamic)" - IL_0072: ldloca.s V_1 - IL_0074: call "bool System.Collections.Generic.List.Enumerator.MoveNext()" - IL_0079: brtrue.s IL_000f - IL_007b: leave.s IL_008b - } - finally - { - IL_007d: ldloca.s V_1 - IL_007f: constrained. "System.Collections.Generic.List.Enumerator" - IL_0085: callvirt "void System.IDisposable.Dispose()" - IL_008a: endfinally - } - IL_008b: ldloc.0 - IL_008c: ret - } - """); - } - else - { - Assert.Equal("List", resultType); - verifier.VerifyIL("Program.F", - """ - { - // Code size 141 (0x8d) - .maxstack 9 - .locals init (System.Collections.Generic.List V_0, - System.Collections.Generic.List.Enumerator V_1, - object V_2) - IL_0000: newobj "System.Collections.Generic.List..ctor()" - IL_0005: stloc.0 - IL_0006: ldarg.0 - IL_0007: callvirt "System.Collections.Generic.List.Enumerator System.Collections.Generic.List.GetEnumerator()" - IL_000c: stloc.1 - .try - { - IL_000d: br.s IL_0072 - IL_000f: ldloca.s V_1 - IL_0011: call "dynamic System.Collections.Generic.List.Enumerator.Current.get" - IL_0016: stloc.2 - IL_0017: ldsfld "System.Runtime.CompilerServices.CallSite, dynamic>> Program.<>o__0.<>p__0" + IL_0017: ldsfld "System.Runtime.CompilerServices.CallSite, dynamic>> Program.<>o__0.<>p__0" IL_001c: brtrue.s IL_005c IL_001e: ldc.i4 0x100 IL_0023: ldstr "Add" @@ -10131,18 +11273,13 @@ static void Main() } """; - var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], [1, 2, 3],"), targetFramework: TargetFramework.Net80, verify: Verification.Skipped); + var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: "[1, 2, 3], [1, 2, 3],", verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.Main", """ { - // Code size 114 (0x72) - .maxstack 5 - .locals init (object[] V_0, - int V_1, - System.Span V_2, - int V_3, - System.ReadOnlySpan V_4) + // Code size 52 (0x34) + .maxstack 4 IL_0000: ldc.i4.3 IL_0001: newarr "object" IL_0006: dup @@ -10163,39 +11300,10 @@ .locals init (object[] V_0, IL_0021: dup IL_0022: ldc.i4.0 IL_0023: call "void CollectionExtensions.Report(object, bool)" - IL_0028: stloc.0 - IL_0029: ldloc.0 - IL_002a: ldlen - IL_002b: conv.i4 - IL_002c: stloc.1 - IL_002d: ldloc.1 - IL_002e: newobj "System.Collections.Generic.List..ctor(int)" - IL_0033: dup - IL_0034: ldloc.1 - IL_0035: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount(System.Collections.Generic.List, int)" - IL_003a: dup - IL_003b: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)" - IL_0040: stloc.2 - IL_0041: ldc.i4.0 - IL_0042: stloc.3 - IL_0043: ldloca.s V_4 - IL_0045: ldloc.0 - IL_0046: call "System.ReadOnlySpan..ctor(object[])" - IL_004b: ldloca.s V_4 - IL_004d: ldloca.s V_2 - IL_004f: ldloc.3 - IL_0050: ldloca.s V_4 - IL_0052: call "int System.ReadOnlySpan.Length.get" - IL_0057: call "System.Span System.Span.Slice(int, int)" - IL_005c: call "void System.ReadOnlySpan.CopyTo(System.Span)" - IL_0061: ldloc.3 - IL_0062: ldloca.s V_4 - IL_0064: call "int System.ReadOnlySpan.Length.get" - IL_0069: add - IL_006a: stloc.3 - IL_006b: ldc.i4.0 - IL_006c: call "void CollectionExtensions.Report(object, bool)" - IL_0071: ret + IL_0028: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_002d: ldc.i4.0 + IL_002e: call "void CollectionExtensions.Report(object, bool)" + IL_0033: ret } """); } @@ -10337,17 +11445,12 @@ static void Main() } """; - var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], [1, 2, 3],"), targetFramework: TargetFramework.Net80, verify: Verification.Skipped); + var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: "[1, 2, 3], [1, 2, 3],", verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.Main", """ { - // Code size 114 (0x72) - .maxstack 5 - .locals init (object[] V_0, - int V_1, - System.Span V_2, - int V_3, - System.ReadOnlySpan V_4) + // Code size 52 (0x34) + .maxstack 4 IL_0000: ldc.i4.3 IL_0001: newarr "object" IL_0006: dup @@ -10368,39 +11471,10 @@ .locals init (object[] V_0, IL_0021: dup IL_0022: ldc.i4.0 IL_0023: call "void CollectionExtensions.Report(object, bool)" - IL_0028: stloc.0 - IL_0029: ldloc.0 - IL_002a: ldlen - IL_002b: conv.i4 - IL_002c: stloc.1 - IL_002d: ldloc.1 - IL_002e: newobj "System.Collections.Generic.List..ctor(int)" - IL_0033: dup - IL_0034: ldloc.1 - IL_0035: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount(System.Collections.Generic.List, int)" - IL_003a: dup - IL_003b: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)" - IL_0040: stloc.2 - IL_0041: ldc.i4.0 - IL_0042: stloc.3 - IL_0043: ldloca.s V_4 - IL_0045: ldloc.0 - IL_0046: call "System.ReadOnlySpan..ctor(object[])" - IL_004b: ldloca.s V_4 - IL_004d: ldloca.s V_2 - IL_004f: ldloc.3 - IL_0050: ldloca.s V_4 - IL_0052: call "int System.ReadOnlySpan.Length.get" - IL_0057: call "System.Span System.Span.Slice(int, int)" - IL_005c: call "void System.ReadOnlySpan.CopyTo(System.Span)" - IL_0061: ldloc.3 - IL_0062: ldloca.s V_4 - IL_0064: call "int System.ReadOnlySpan.Length.get" - IL_0069: add - IL_006a: stloc.3 - IL_006b: ldc.i4.0 - IL_006c: call "void CollectionExtensions.Report(object, bool)" - IL_0071: ret + IL_0028: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_002d: ldc.i4.0 + IL_002e: call "void CollectionExtensions.Report(object, bool)" + IL_0033: ret } """); } @@ -11200,10 +12274,8 @@ class C [CombinatorialData] [Theory] - public void ArrayEmpty_01([CombinatorialValues(TargetFramework.Mscorlib45Extended, TargetFramework.Net80)] TargetFramework targetFramework) + public void ArrayEmpty_01(bool includeEmptyArray) { - if (!ExecutionConditionUtil.IsCoreClr && targetFramework == TargetFramework.Net80) return; - string source = """ using System.Collections.Generic; class Program @@ -11225,12 +12297,18 @@ static void Main() static IReadOnlyList EmptyIReadOnlyList() => []; } """; + + var comp = CreateCompilation(new[] { source, s_collectionExtensions }, options: TestOptions.ReleaseExe); + if (!includeEmptyArray) + { + comp.MakeMemberMissing(SpecialMember.System_Array__Empty); + } + var verifier = CompileAndVerify( - new[] { source, s_collectionExtensions }, - targetFramework: targetFramework, + comp, expectedOutput: "[], [], [], [], [], [], "); - string expectedIL = (targetFramework == TargetFramework.Mscorlib45Extended) ? + string expectedIL = !includeEmptyArray ? """ { // Code size 7 (0x7) @@ -11268,10 +12346,8 @@ .maxstack 1 [CombinatorialData] [Theory] - public void ArrayEmpty_02([CombinatorialValues(TargetFramework.Mscorlib45Extended, TargetFramework.Net80)] TargetFramework targetFramework) + public void ArrayEmpty_02(bool includeEmptyArray) { - if (!ExecutionConditionUtil.IsCoreClr && targetFramework == TargetFramework.Net80) return; - string source = """ using System.Collections.Generic; class Program @@ -11293,12 +12369,16 @@ static void Main() static IReadOnlyList EmptyIReadOnlyList() => []; } """; + var comp = CreateCompilation(new[] { source, s_collectionExtensions }, options: TestOptions.ReleaseExe); + if (!includeEmptyArray) + { + comp.MakeMemberMissing(SpecialMember.System_Array__Empty); + } var verifier = CompileAndVerify( - new[] { source, s_collectionExtensions }, - targetFramework: targetFramework, + comp, expectedOutput: "[], [], [], [], [], [], "); - string expectedIL = (targetFramework == TargetFramework.Mscorlib45Extended) ? + string expectedIL = !includeEmptyArray ? """ { // Code size 7 (0x7) @@ -12903,6 +13983,64 @@ static void Main() expectedOutput: "(<>z__ReadOnlyArray) [1, 2, 0], (<>z__ReadOnlyArray) [1, 2, null], "); } + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/72539")] + [WorkItem("https://github.com/dotnet/roslyn/issues/74676")] + public void SynthesizedCollections_EnsureCompilerGenerated() + { + string source = """ + using System; + using System.Collections.Generic; + + class Program + { + static void Main() + { + IEnumerable x = [1]; + IEnumerable y = [2, 3]; + IEnumerable z = [.. x]; + + Report(x); + Report(y); + Report(z); + } + + static void Report(IEnumerable e) + { + var type = e.GetType(); + Console.Write("{0}: ", type.Name); + foreach (var a in type.GetCustomAttributes(inherit: false)) + Console.Write("{0}, ", a); + Console.WriteLine(); + } + } + """; + + CompileAndVerify( + source, + symbolValidator: module => + { + var globalNamespace = module.GlobalNamespace; + verifyCompilerGeneratedType(globalNamespace.GetTypeMember("<>z__ReadOnlySingleElementList")); + verifyCompilerGeneratedType(globalNamespace.GetTypeMember("<>z__ReadOnlyArray")); + verifyCompilerGeneratedType(globalNamespace.GetTypeMember("<>z__ReadOnlyList")); + }, + expectedOutput: """ + <>z__ReadOnlySingleElementList`1: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + <>z__ReadOnlyArray`1: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + <>z__ReadOnlyList`1: System.Runtime.CompilerServices.CompilerGeneratedAttribute, + + """); + + static void verifyCompilerGeneratedType(NamedTypeSymbol type) + { + Assert.Collection(type.GetAttributes(), + a => Assert.Equal("System.Runtime.CompilerServices.CompilerGeneratedAttribute", a.AttributeClass?.ToTestDisplayString())); + Assert.DoesNotContain(type.GetMembers(), + m => m.GetAttributes().Any(a => a.AttributeClass?.ToTestDisplayString() == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")); + } + } + [Fact] public void Nullable_01() { @@ -18283,7 +19421,7 @@ static void F(MyCollection c) } } """; - comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Mscorlib45); + comp = CreateCompilation(sourceB, references: new[] { refA }, targetFramework: TargetFramework.Mscorlib461); comp.VerifyEmitDiagnostics( // (6,11): error CS9187: Could not find an accessible 'Create' method with the expected signature: a static method with a single parameter of type 'ReadOnlySpan' and return type 'MyCollection'. // F([]); @@ -19526,7 +20664,7 @@ static void Main() var x = F([1, 2, 3]); x.Report(); } - static List F(T[] items) => [..items]; + static List F(T[] items) => [..items, ..items]; } """; @@ -19543,51 +20681,74 @@ static void Main() var verifier = CompileAndVerify( comp, verify: Verification.FailsPEVerify, - expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); + expectedOutput: IncludeExpectedOutput("[1, 2, 3, 1, 2, 3], ")); if (missingMembers.Length == 0) { verifier.VerifyIL("Program.F(T[])", """ { - // Code size 69 (0x45) + // Code size 122 (0x7a) .maxstack 5 .locals init (T[] V_0, - int V_1, - System.Span V_2, - int V_3, - System.ReadOnlySpan V_4) + T[] V_1, + int V_2, + System.Span V_3, + int V_4, + System.ReadOnlySpan V_5, + System.ReadOnlySpan V_6) IL_0000: ldarg.0 IL_0001: stloc.0 - IL_0002: ldloc.0 - IL_0003: ldlen - IL_0004: conv.i4 - IL_0005: stloc.1 - IL_0006: ldloc.1 - IL_0007: newobj "System.Collections.Generic.List..ctor(int)" - IL_000c: dup - IL_000d: ldloc.1 - IL_000e: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount(System.Collections.Generic.List, int)" - IL_0013: dup - IL_0014: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)" - IL_0019: stloc.2 - IL_001a: ldc.i4.0 - IL_001b: stloc.3 - IL_001c: ldloca.s V_4 - IL_001e: ldloc.0 - IL_001f: call "System.ReadOnlySpan..ctor(T[])" - IL_0024: ldloca.s V_4 - IL_0026: ldloca.s V_2 - IL_0028: ldloc.3 - IL_0029: ldloca.s V_4 - IL_002b: call "int System.ReadOnlySpan.Length.get" - IL_0030: call "System.Span System.Span.Slice(int, int)" - IL_0035: call "void System.ReadOnlySpan.CopyTo(System.Span)" - IL_003a: ldloc.3 - IL_003b: ldloca.s V_4 - IL_003d: call "int System.ReadOnlySpan.Length.get" - IL_0042: add - IL_0043: stloc.3 - IL_0044: ret + IL_0002: ldarg.0 + IL_0003: stloc.1 + IL_0004: ldloc.0 + IL_0005: ldlen + IL_0006: conv.i4 + IL_0007: ldloc.1 + IL_0008: ldlen + IL_0009: conv.i4 + IL_000a: add + IL_000b: stloc.2 + IL_000c: ldloc.2 + IL_000d: newobj "System.Collections.Generic.List..ctor(int)" + IL_0012: dup + IL_0013: ldloc.2 + IL_0014: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount(System.Collections.Generic.List, int)" + IL_0019: dup + IL_001a: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)" + IL_001f: stloc.3 + IL_0020: ldc.i4.0 + IL_0021: stloc.s V_4 + IL_0023: ldloca.s V_5 + IL_0025: ldloc.0 + IL_0026: call "System.ReadOnlySpan..ctor(T[])" + IL_002b: ldloca.s V_5 + IL_002d: ldloca.s V_3 + IL_002f: ldloc.s V_4 + IL_0031: ldloca.s V_5 + IL_0033: call "int System.ReadOnlySpan.Length.get" + IL_0038: call "System.Span System.Span.Slice(int, int)" + IL_003d: call "void System.ReadOnlySpan.CopyTo(System.Span)" + IL_0042: ldloc.s V_4 + IL_0044: ldloca.s V_5 + IL_0046: call "int System.ReadOnlySpan.Length.get" + IL_004b: add + IL_004c: stloc.s V_4 + IL_004e: ldloca.s V_6 + IL_0050: ldloc.1 + IL_0051: call "System.ReadOnlySpan..ctor(T[])" + IL_0056: ldloca.s V_6 + IL_0058: ldloca.s V_3 + IL_005a: ldloc.s V_4 + IL_005c: ldloca.s V_6 + IL_005e: call "int System.ReadOnlySpan.Length.get" + IL_0063: call "System.Span System.Span.Slice(int, int)" + IL_0068: call "void System.ReadOnlySpan.CopyTo(System.Span)" + IL_006d: ldloc.s V_4 + IL_006f: ldloca.s V_6 + IL_0071: call "int System.ReadOnlySpan.Length.get" + IL_0076: add + IL_0077: stloc.s V_4 + IL_0079: ret } """); } @@ -19597,19 +20758,29 @@ .locals init (T[] V_0, // Consider preferring AddRange over CopyTo for collection-expressions of List type verifier.VerifyIL("Program.F(T[])", """ { - // Code size 18 (0x12) + // Code size 31 (0x1f) .maxstack 3 - .locals init (T[] V_0) + .locals init (T[] V_0, + T[] V_1) IL_0000: ldarg.0 IL_0001: stloc.0 - IL_0002: ldloc.0 - IL_0003: ldlen - IL_0004: conv.i4 - IL_0005: newobj "System.Collections.Generic.List..ctor(int)" - IL_000a: dup - IL_000b: ldloc.0 - IL_000c: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" - IL_0011: ret + IL_0002: ldarg.0 + IL_0003: stloc.1 + IL_0004: ldloc.0 + IL_0005: ldlen + IL_0006: conv.i4 + IL_0007: ldloc.1 + IL_0008: ldlen + IL_0009: conv.i4 + IL_000a: add + IL_000b: newobj "System.Collections.Generic.List..ctor(int)" + IL_0010: dup + IL_0011: ldloc.0 + IL_0012: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" + IL_0017: dup + IL_0018: ldloc.1 + IL_0019: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" + IL_001e: ret } """); } @@ -20333,67 +21504,12 @@ static void Main() verifier.VerifyIL("Program.F1", """ { - // Code size 141 (0x8d) - .maxstack 9 - .locals init (System.Collections.Generic.List V_0, - System.Collections.Generic.List.Enumerator V_1, - object V_2) - IL_0000: newobj "System.Collections.Generic.List..ctor()" - IL_0005: stloc.0 - IL_0006: ldarg.0 - IL_0007: callvirt "System.Collections.Generic.List.Enumerator System.Collections.Generic.List.GetEnumerator()" - IL_000c: stloc.1 - .try - { - IL_000d: br.s IL_0072 - IL_000f: ldloca.s V_1 - IL_0011: call "dynamic System.Collections.Generic.List.Enumerator.Current.get" - IL_0016: stloc.2 - IL_0017: ldsfld "System.Runtime.CompilerServices.CallSite, dynamic>> Program.<>o__0.<>p__0" - IL_001c: brtrue.s IL_005c - IL_001e: ldc.i4 0x100 - IL_0023: ldstr "Add" - IL_0028: ldnull - IL_0029: ldtoken "Program" - IL_002e: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)" - IL_0033: ldc.i4.2 - IL_0034: newarr "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo" - IL_0039: dup - IL_003a: ldc.i4.0 - IL_003b: ldc.i4.1 - IL_003c: ldnull - IL_003d: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)" - IL_0042: stelem.ref - IL_0043: dup - IL_0044: ldc.i4.1 - IL_0045: ldc.i4.0 - IL_0046: ldnull - IL_0047: call "Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string)" - IL_004c: stelem.ref - IL_004d: call "System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, System.Collections.Generic.IEnumerable, System.Type, System.Collections.Generic.IEnumerable)" - IL_0052: call "System.Runtime.CompilerServices.CallSite, dynamic>> System.Runtime.CompilerServices.CallSite, dynamic>>.Create(System.Runtime.CompilerServices.CallSiteBinder)" - IL_0057: stsfld "System.Runtime.CompilerServices.CallSite, dynamic>> Program.<>o__0.<>p__0" - IL_005c: ldsfld "System.Runtime.CompilerServices.CallSite, dynamic>> Program.<>o__0.<>p__0" - IL_0061: ldfld "System.Action, dynamic> System.Runtime.CompilerServices.CallSite, dynamic>>.Target" - IL_0066: ldsfld "System.Runtime.CompilerServices.CallSite, dynamic>> Program.<>o__0.<>p__0" - IL_006b: ldloc.0 - IL_006c: ldloc.2 - IL_006d: callvirt "void System.Action, dynamic>.Invoke(System.Runtime.CompilerServices.CallSite, System.Collections.Generic.List, dynamic)" - IL_0072: ldloca.s V_1 - IL_0074: call "bool System.Collections.Generic.List.Enumerator.MoveNext()" - IL_0079: brtrue.s IL_000f - IL_007b: leave.s IL_008b - } - finally - { - IL_007d: ldloca.s V_1 - IL_007f: constrained. "System.Collections.Generic.List.Enumerator" - IL_0085: callvirt "void System.IDisposable.Dispose()" - IL_008a: endfinally - } - IL_008b: ldloc.0 - IL_008c: ret - } + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } """); verifier.VerifyIL("Program.F2", """ @@ -29127,8 +30243,39 @@ .maxstack 6 """); } - [Fact] - public void ImmutableArray_03() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71159")] + public void ImmutableArray_Empty() + { + string sourceA = """ + using System.Collections.Immutable; + + class Program + { + static void Main() + { + ImmutableArray arr = []; + arr.Report(); + } + } + """; + + var verifier = CompileAndVerify([sourceA, s_collectionExtensions], targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput("[],"), verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.Main", """ + { + // Code size 17 (0x11) + .maxstack 2 + IL_0000: ldsfld "System.Collections.Immutable.ImmutableArray System.Collections.Immutable.ImmutableArray.Empty" + IL_0005: box "System.Collections.Immutable.ImmutableArray" + IL_000a: ldc.i4.0 + IL_000b: call "void CollectionExtensions.Report(object, bool)" + IL_0010: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71159")] + public void ImmutableArray_Empty_MissingKnownSingleton() { string sourceA = """ using System.Collections.Immutable; @@ -29143,7 +30290,10 @@ static void Main() } """; - var verifier = CompileAndVerify(new[] { sourceA, s_collectionExtensions }, targetFramework: TargetFramework.Net80, expectedOutput: IncludeExpectedOutput("[],"), verify: Verification.Skipped); + var comp = CreateCompilation([sourceA, s_collectionExtensions], options: TestOptions.ReleaseExe, targetFramework: TargetFramework.Net80); + comp.MakeMemberMissing(WellKnownMember.System_Collections_Immutable_ImmutableArray_T__Empty); + + var verifier = CompileAndVerify(comp, expectedOutput: IncludeExpectedOutput("[],"), verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("Program.Main", """ { @@ -34059,45 +35209,11 @@ .maxstack 1 verifier.VerifyIL("C.M2", """ { - // Code size 69 (0x45) - .maxstack 5 - .locals init (nint[] V_0, - int V_1, - System.Span V_2, - int V_3, - System.ReadOnlySpan V_4) + // Code size 7 (0x7) + .maxstack 1 IL_0000: ldarg.1 - IL_0001: stloc.0 - IL_0002: ldloc.0 - IL_0003: ldlen - IL_0004: conv.i4 - IL_0005: stloc.1 - IL_0006: ldloc.1 - IL_0007: newobj "System.Collections.Generic.List..ctor(int)" - IL_000c: dup - IL_000d: ldloc.1 - IL_000e: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount(System.Collections.Generic.List, int)" - IL_0013: dup - IL_0014: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)" - IL_0019: stloc.2 - IL_001a: ldc.i4.0 - IL_001b: stloc.3 - IL_001c: ldloca.s V_4 - IL_001e: ldloc.0 - IL_001f: call "System.ReadOnlySpan..ctor(nint[])" - IL_0024: ldloca.s V_4 - IL_0026: ldloca.s V_2 - IL_0028: ldloc.3 - IL_0029: ldloca.s V_4 - IL_002b: call "int System.ReadOnlySpan.Length.get" - IL_0030: call "System.Span System.Span.Slice(int, int)" - IL_0035: call "void System.ReadOnlySpan.CopyTo(System.Span)" - IL_003a: ldloc.3 - IL_003b: ldloca.s V_4 - IL_003d: call "int System.ReadOnlySpan.Length.get" - IL_0042: add - IL_0043: stloc.3 - IL_0044: ret + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret } """); @@ -34560,209 +35676,1444 @@ .locals init (int V_0, IL_0090: call "void CollectionExtensions.Report(object, bool)" IL_0095: ret } - """); + """); + } + + [Fact] + public void Spread_ExtensionGetEnumerator_NonGeneric() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + class MyCollection + { + public readonly List Items; + public MyCollection(IEnumerable items) { Items = new(items); } + } + static class Extensions + { + public static IEnumerator GetEnumerator(this MyCollection c) => c.Items.GetEnumerator(); + } + class Program + { + static void Main() + { + MyCollection x = new([1, 2, 3]); + object[] y = Convert(x); + y.Report(); + } + static object[] Convert(MyCollection c) => [..c]; + } + """; + var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.Convert", """ + { + // Code size 63 (0x3f) + .maxstack 2 + .locals init (System.Collections.Generic.List V_0, + System.Collections.IEnumerator V_1, + object V_2, + System.IDisposable V_3) + IL_0000: newobj "System.Collections.Generic.List..ctor()" + IL_0005: stloc.0 + IL_0006: ldarg.0 + IL_0007: call "System.Collections.IEnumerator Extensions.GetEnumerator(MyCollection)" + IL_000c: stloc.1 + .try + { + IL_000d: br.s IL_001d + IL_000f: ldloc.1 + IL_0010: callvirt "object System.Collections.IEnumerator.Current.get" + IL_0015: stloc.2 + IL_0016: ldloc.0 + IL_0017: ldloc.2 + IL_0018: callvirt "void System.Collections.Generic.List.Add(object)" + IL_001d: ldloc.1 + IL_001e: callvirt "bool System.Collections.IEnumerator.MoveNext()" + IL_0023: brtrue.s IL_000f + IL_0025: leave.s IL_0038 + } + finally + { + IL_0027: ldloc.1 + IL_0028: isinst "System.IDisposable" + IL_002d: stloc.3 + IL_002e: ldloc.3 + IL_002f: brfalse.s IL_0037 + IL_0031: ldloc.3 + IL_0032: callvirt "void System.IDisposable.Dispose()" + IL_0037: endfinally + } + IL_0038: ldloc.0 + IL_0039: callvirt "object[] System.Collections.Generic.List.ToArray()" + IL_003e: ret + } + """); + } + + [Fact] + public void Spread_ExtensionGetEnumerator_Generic() + { + var source = """ + using System.Collections.Generic; + class MyCollection + { + public readonly List Items; + public MyCollection(IEnumerable items) { Items = new(items); } + } + static class Extensions + { + public static IEnumerator GetEnumerator(this MyCollection c) => c.Items.GetEnumerator(); + } + class Program + { + static void Main() + { + MyCollection x = new([1, 2, 3]); + int[] y = Convert(x); + y.Report(); + } + static T[] Convert(MyCollection c) => [..c]; + } + """; + var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.Convert", """ + { + // Code size 56 (0x38) + .maxstack 2 + .locals init (System.Collections.Generic.List V_0, + System.Collections.Generic.IEnumerator V_1, + T V_2) + IL_0000: newobj "System.Collections.Generic.List..ctor()" + IL_0005: stloc.0 + IL_0006: ldarg.0 + IL_0007: call "System.Collections.Generic.IEnumerator Extensions.GetEnumerator(MyCollection)" + IL_000c: stloc.1 + .try + { + IL_000d: br.s IL_001d + IL_000f: ldloc.1 + IL_0010: callvirt "T System.Collections.Generic.IEnumerator.Current.get" + IL_0015: stloc.2 + IL_0016: ldloc.0 + IL_0017: ldloc.2 + IL_0018: callvirt "void System.Collections.Generic.List.Add(T)" + IL_001d: ldloc.1 + IL_001e: callvirt "bool System.Collections.IEnumerator.MoveNext()" + IL_0023: brtrue.s IL_000f + IL_0025: leave.s IL_0031 + } + finally + { + IL_0027: ldloc.1 + IL_0028: brfalse.s IL_0030 + IL_002a: ldloc.1 + IL_002b: callvirt "void System.IDisposable.Dispose()" + IL_0030: endfinally + } + IL_0031: ldloc.0 + IL_0032: callvirt "T[] System.Collections.Generic.List.ToArray()" + IL_0037: ret + } + """); + } + + [Fact] + public void Spread_ExtensionGetEnumerator_Pattern() + { + var source = """ + using System.Collections.Generic; + class MyCollection + { + public readonly List Items; + public MyCollection(IEnumerable items) { Items = new(items); } + } + struct MyEnumerator + { + private IEnumerator _enumerator; + public MyEnumerator(IEnumerator enumerator) { _enumerator = enumerator; } + public bool MoveNext() => _enumerator.MoveNext(); + public T Current => _enumerator.Current; + } + static class Extensions + { + public static MyEnumerator GetEnumerator(this MyCollection c) => new(c.Items.GetEnumerator()); + } + class Program + { + static void Main() + { + MyCollection x = new([1, 2, 3]); + int[] y = Convert(x); + y.Report(); + } + static T[] Convert(MyCollection c) => [..c]; + } + """; + var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("Program.Convert", """ + { + // Code size 46 (0x2e) + .maxstack 2 + .locals init (System.Collections.Generic.List V_0, + MyEnumerator V_1, + T V_2) + IL_0000: newobj "System.Collections.Generic.List..ctor()" + IL_0005: stloc.0 + IL_0006: ldarg.0 + IL_0007: call "MyEnumerator Extensions.GetEnumerator(MyCollection)" + IL_000c: stloc.1 + IL_000d: br.s IL_001e + IL_000f: ldloca.s V_1 + IL_0011: call "T MyEnumerator.Current.get" + IL_0016: stloc.2 + IL_0017: ldloc.0 + IL_0018: ldloc.2 + IL_0019: callvirt "void System.Collections.Generic.List.Add(T)" + IL_001e: ldloca.s V_1 + IL_0020: call "bool MyEnumerator.MoveNext()" + IL_0025: brtrue.s IL_000f + IL_0027: ldloc.0 + IL_0028: callvirt "T[] System.Collections.Generic.List.ToArray()" + IL_002d: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_IEnumerable() + { + var source = """ + using System.Collections.Generic; + + class C + { + static void Main() + { + M([1, 2, 3]).Report(); + } + + static List M(IEnumerable e) => [..e]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[1, 2, 3],", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_IEnumerable_Covariant() + { + var source = """ + using System.Collections.Generic; + + class C + { + static void Main() + { + M(["a", "b", "c"]).Report(); + } + + static List M(IEnumerable e) => [..e]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[a, b, c],", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_IEnumerable_ElementConversions_Generics() + { + var source = """ + using System; + using System.Collections.Generic; + + class C + { + static void Main() + { + M1(["a", "b", "c"]).Report(); + M2, int>([1, 2, 3]).Report(); + M3, string>(["a", "b", "c"]).Report(); + M4([1, 2, 3]).Report(); + } + + static List M1(IEnumerable e) where U : T => [..e]; + static List M2(IEnumerable e) where U : struct, T => [..e]; + static List M3(IEnumerable e) where U : class, T => [..e]; + static List M4(IEnumerable e) where T : struct => [..e]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[a, b, c], [1, 2, 3], [a, b, c], [1, 2, 3], ", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + var expectedILWiwthBoxingConversion = """ + { + // Code size 61 (0x3d) + .maxstack 2 + .locals init (System.Collections.Generic.List V_0, + System.Collections.Generic.IEnumerator V_1, + U V_2) + IL_0000: newobj "System.Collections.Generic.List..ctor()" + IL_0005: stloc.0 + IL_0006: ldarg.0 + IL_0007: callvirt "System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator()" + IL_000c: stloc.1 + .try + { + IL_000d: br.s IL_0027 + IL_000f: ldloc.1 + IL_0010: callvirt "U System.Collections.Generic.IEnumerator.Current.get" + IL_0015: stloc.2 + IL_0016: ldloc.0 + IL_0017: ldloc.2 + IL_0018: box "U" + IL_001d: unbox.any "T" + IL_0022: callvirt "void System.Collections.Generic.List.Add(T)" + IL_0027: ldloc.1 + IL_0028: callvirt "bool System.Collections.IEnumerator.MoveNext()" + IL_002d: brtrue.s IL_000f + IL_002f: leave.s IL_003b + } + finally + { + IL_0031: ldloc.1 + IL_0032: brfalse.s IL_003a + IL_0034: ldloc.1 + IL_0035: callvirt "void System.IDisposable.Dispose()" + IL_003a: endfinally + } + IL_003b: ldloc.0 + IL_003c: ret + } + """; + + verifier.VerifyIL("C.M1", expectedILWiwthBoxingConversion); + verifier.VerifyIL("C.M2", expectedILWiwthBoxingConversion); + + verifier.VerifyIL("C.M3", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """); + + verifier.VerifyIL("C.M4", """ + { + // Code size 56 (0x38) + .maxstack 2 + .locals init (System.Collections.Generic.List V_0, + System.Collections.Generic.IEnumerator V_1, + T V_2) + IL_0000: newobj "System.Collections.Generic.List..ctor()" + IL_0005: stloc.0 + IL_0006: ldarg.0 + IL_0007: callvirt "System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator()" + IL_000c: stloc.1 + .try + { + IL_000d: br.s IL_0022 + IL_000f: ldloc.1 + IL_0010: callvirt "T System.Collections.Generic.IEnumerator.Current.get" + IL_0015: stloc.2 + IL_0016: ldloc.0 + IL_0017: ldloc.2 + IL_0018: newobj "T?..ctor(T)" + IL_001d: callvirt "void System.Collections.Generic.List.Add(T?)" + IL_0022: ldloc.1 + IL_0023: callvirt "bool System.Collections.IEnumerator.MoveNext()" + IL_0028: brtrue.s IL_000f + IL_002a: leave.s IL_0036 + } + finally + { + IL_002c: ldloc.1 + IL_002d: brfalse.s IL_0035 + IL_002f: ldloc.1 + IL_0030: callvirt "void System.IDisposable.Dispose()" + IL_0035: endfinally + } + IL_0036: ldloc.0 + IL_0037: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_IEnumerable_ClassConstraint() + { + var source = """ + using System.Collections.Generic; + class C + { + static void Main() + { + M, string>(["a", "b", "c"]).Report(); + } + + static List M(T t) where T : class, IEnumerable => [..t]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[a, b, c],", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_IEnumerable_MissingToList() + { + var source = """ + using System.Collections.Generic; + + class C + { + static void Main() + { + M([1, 2, 3]).Report(); + } + + static List M(IEnumerable e) => [..e]; + } + """; + + var comp = CreateCompilation([source, s_collectionExtensions], options: TestOptions.ReleaseExe); + comp.MakeMemberMissing(WellKnownMember.System_Linq_Enumerable__ToList); + + var verifier = CompileAndVerify(comp, expectedOutput: "[1, 2, 3],", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 13 (0xd) + .maxstack 3 + IL_0000: newobj "System.Collections.Generic.List..ctor()" + IL_0005: dup + IL_0006: ldarg.0 + IL_0007: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" + IL_000c: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_IEnumerable_NonGeneric() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + class C + { + static void Main() + { + M(new[] { "a", "b", "c" }).Report(); + } + + static List M(IEnumerable e) => [..e]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[a, b, c],", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 58 (0x3a) + .maxstack 2 + .locals init (System.Collections.Generic.List V_0, + System.Collections.IEnumerator V_1, + object V_2, + System.IDisposable V_3) + IL_0000: newobj "System.Collections.Generic.List..ctor()" + IL_0005: stloc.0 + IL_0006: ldarg.0 + IL_0007: callvirt "System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()" + IL_000c: stloc.1 + .try + { + IL_000d: br.s IL_001d + IL_000f: ldloc.1 + IL_0010: callvirt "object System.Collections.IEnumerator.Current.get" + IL_0015: stloc.2 + IL_0016: ldloc.0 + IL_0017: ldloc.2 + IL_0018: callvirt "void System.Collections.Generic.List.Add(object)" + IL_001d: ldloc.1 + IL_001e: callvirt "bool System.Collections.IEnumerator.MoveNext()" + IL_0023: brtrue.s IL_000f + IL_0025: leave.s IL_0038 + } + finally + { + IL_0027: ldloc.1 + IL_0028: isinst "System.IDisposable" + IL_002d: stloc.3 + IL_002e: ldloc.3 + IL_002f: brfalse.s IL_0037 + IL_0031: ldloc.3 + IL_0032: callvirt "void System.IDisposable.Dispose()" + IL_0037: endfinally + } + IL_0038: ldloc.0 + IL_0039: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_IEnumerable_PropertyAccess() + { + var source = """ + using System.Collections.Generic; + + class C + { + private IEnumerable E { get; set; } + + static void Main() + { + var c = new C() + { + E = [1, 2, 3] + }; + + M(c).Report(); + } + + static List M(C c) => [.. c.E]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[1, 2, 3],", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 12 (0xc) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: callvirt "System.Collections.Generic.IEnumerable C.E.get" + IL_0006: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_000b: ret + } + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + [InlineData("ICollection")] + [InlineData("IList")] + [InlineData("List")] + [InlineData("HashSet")] + [InlineData("int[]")] + public void List_SingleSpread_ICollectionAndItsDerivatives(string type) + { + var source = $$""" + using System.Collections.Generic; + + class C + { + static void Main() + { + M([1, 2, 3]).Report(); + } + + static List M({{type}} c) => [..c]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[1, 2, 3],", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_ImmutableArray() + { + var source = """ + using System.Collections.Generic; + using System.Collections.Immutable; + + class C + { + static void Main() + { + M([1, 2, 3]).Report(); + } + + static List M(ImmutableArray a) => [..a]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: IncludeExpectedOutput("[1, 2, 3],"), targetFramework: TargetFramework.Net80, verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 74 (0x4a) + .maxstack 5 + .locals init (System.Collections.Immutable.ImmutableArray V_0, + int V_1, + System.Span V_2, + int V_3, + System.ReadOnlySpan V_4) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloca.s V_0 + IL_0004: call "int System.Collections.Immutable.ImmutableArray.Length.get" + IL_0009: stloc.1 + IL_000a: ldloc.1 + IL_000b: newobj "System.Collections.Generic.List..ctor(int)" + IL_0010: dup + IL_0011: ldloc.1 + IL_0012: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount(System.Collections.Generic.List, int)" + IL_0017: dup + IL_0018: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)" + IL_001d: stloc.2 + IL_001e: ldc.i4.0 + IL_001f: stloc.3 + IL_0020: ldloca.s V_0 + IL_0022: call "System.ReadOnlySpan System.Collections.Immutable.ImmutableArray.AsSpan()" + IL_0027: stloc.s V_4 + IL_0029: ldloca.s V_4 + IL_002b: ldloca.s V_2 + IL_002d: ldloc.3 + IL_002e: ldloca.s V_4 + IL_0030: call "int System.ReadOnlySpan.Length.get" + IL_0035: call "System.Span System.Span.Slice(int, int)" + IL_003a: call "void System.ReadOnlySpan.CopyTo(System.Span)" + IL_003f: ldloc.3 + IL_0040: ldloca.s V_4 + IL_0042: call "int System.ReadOnlySpan.Length.get" + IL_0047: add + IL_0048: stloc.3 + IL_0049: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_CustomCollection_NotICollectionAndNoStructEnumerator() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + class MyCollection(List list) : IEnumerable + { + public IEnumerator GetEnumerator() => list.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + + class C + { + static void Main() + { + M(new([1, 2, 3])).Report(); + } + + static List M(MyCollection c) => [..c]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[1, 2, 3],", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_CustomCollection_NotICollectionAndNoStructEnumerator_PublicAndExplicitGetEnumerator() + { + var source = """ + using System; + using System.Collections; + using System.Collections.Generic; + + class MyCollection(List list) : IEnumerable + { + public IEnumerator GetEnumerator() + { + Console.WriteLine("Public"); + return list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + Console.WriteLine("Explicit"); + return list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + + class C + { + static void Main() + { + M(new([1, 2, 3])).Report(); + } + + static List M(MyCollection c) => [..c]; + } + """; + + var expectedOutput = """ + Explicit + [1, 2, 3], + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: expectedOutput, verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_CustomCollection_ICollectionAndNoStructEnumerator() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + class MyCollection(List list) : ICollection + { + public int Count => list.Count; + + public bool IsReadOnly => false; + + public void Add(int item) => list.Add(item); + + public void Clear() => list.Clear(); + + public bool Contains(int item) => list.Contains(item); + + public void CopyTo(int[] array, int arrayIndex) => list.CopyTo(array, arrayIndex); + + public bool Remove(int item) => list.Remove(item); + + public IEnumerator GetEnumerator() => list.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } + + class C + { + static void Main() + { + M(new([1, 2, 3])).Report(); + } + + static List M(MyCollection c) => [..c]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[1, 2, 3],", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74615")] + public void List_SingleSpread_CustomCollection_NotICollectionAndStructEnumerator() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + class MyCollection(List list) : IEnumerable + { + public Enumerator GetEnumerator() => new(list.GetEnumerator()); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public struct Enumerator(List.Enumerator enumerator) : IEnumerator + { + public int Current => enumerator.Current; + + object IEnumerator.Current => Current; + + public bool MoveNext() => enumerator.MoveNext(); + + public void Dispose() => enumerator.Dispose(); + + public void Reset() { } + } + } + + class C + { + static void Main() + { + M(new([1, 2, 3])).Report(); + } + + static List M(MyCollection c) => [..c]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[1, 2, 3],", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 57 (0x39) + .maxstack 2 + .locals init (System.Collections.Generic.List V_0, + MyCollection.Enumerator V_1, + int V_2) + IL_0000: newobj "System.Collections.Generic.List..ctor()" + IL_0005: stloc.0 + IL_0006: ldarg.0 + IL_0007: callvirt "MyCollection.Enumerator MyCollection.GetEnumerator()" + IL_000c: stloc.1 + .try + { + IL_000d: br.s IL_001e + IL_000f: ldloca.s V_1 + IL_0011: call "int MyCollection.Enumerator.Current.get" + IL_0016: stloc.2 + IL_0017: ldloc.0 + IL_0018: ldloc.2 + IL_0019: callvirt "void System.Collections.Generic.List.Add(int)" + IL_001e: ldloca.s V_1 + IL_0020: call "bool MyCollection.Enumerator.MoveNext()" + IL_0025: brtrue.s IL_000f + IL_0027: leave.s IL_0037 + } + finally + { + IL_0029: ldloca.s V_1 + IL_002b: constrained. "MyCollection.Enumerator" + IL_0031: callvirt "void System.IDisposable.Dispose()" + IL_0036: endfinally + } + IL_0037: ldloc.0 + IL_0038: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74615")] + public void List_SingleSpread_CustomCollection_NotICollectionAndStructEnumerator_MissingICollectionOfTType() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + class MyCollection(List list) : IEnumerable + { + public Enumerator GetEnumerator() => new(list.GetEnumerator()); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public struct Enumerator(List.Enumerator enumerator) : IEnumerator + { + public int Current => enumerator.Current; + + object IEnumerator.Current => Current; + + public bool MoveNext() => enumerator.MoveNext(); + + public void Dispose() => enumerator.Dispose(); + + public void Reset() { } + } + } + + class C + { + static void Main() + { + M(new([1, 2, 3])).Report(); + } + + static List M(MyCollection c) => [..c]; + } + """; + + var comp = CreateCompilation([source, s_collectionExtensions], options: TestOptions.ReleaseExe); + comp.MakeTypeMissing(SpecialType.System_Collections_Generic_ICollection_T); + + var verifier = CompileAndVerify(comp, expectedOutput: "[1, 2, 3],", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M", """ + { + // Code size 57 (0x39) + .maxstack 2 + .locals init (System.Collections.Generic.List V_0, + MyCollection.Enumerator V_1, + int V_2) + IL_0000: newobj "System.Collections.Generic.List..ctor()" + IL_0005: stloc.0 + IL_0006: ldarg.0 + IL_0007: callvirt "MyCollection.Enumerator MyCollection.GetEnumerator()" + IL_000c: stloc.1 + .try + { + IL_000d: br.s IL_001e + IL_000f: ldloca.s V_1 + IL_0011: call "int MyCollection.Enumerator.Current.get" + IL_0016: stloc.2 + IL_0017: ldloc.0 + IL_0018: ldloc.2 + IL_0019: callvirt "void System.Collections.Generic.List.Add(int)" + IL_001e: ldloca.s V_1 + IL_0020: call "bool MyCollection.Enumerator.MoveNext()" + IL_0025: brtrue.s IL_000f + IL_0027: leave.s IL_0037 + } + finally + { + IL_0029: ldloca.s V_1 + IL_002b: constrained. "MyCollection.Enumerator" + IL_0031: callvirt "void System.IDisposable.Dispose()" + IL_0036: endfinally + } + IL_0037: ldloc.0 + IL_0038: ret + } + """); } - [Fact] - public void Spread_ExtensionGetEnumerator_NonGeneric() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74615")] + public void List_CustomCollection_NotICollectionAndStructEnumerator_MixedWithOtherAddRangeSpread() { var source = """ using System.Collections; using System.Collections.Generic; - class MyCollection - { - public readonly List Items; - public MyCollection(IEnumerable items) { Items = new(items); } - } - static class Extensions + + class MyCollection(List list) : IEnumerable { - public static IEnumerator GetEnumerator(this MyCollection c) => c.Items.GetEnumerator(); + public Enumerator GetEnumerator() => new(list.GetEnumerator()); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public struct Enumerator(List.Enumerator enumerator) : IEnumerator + { + public int Current => enumerator.Current; + + object IEnumerator.Current => Current; + + public bool MoveNext() => enumerator.MoveNext(); + + public void Dispose() => enumerator.Dispose(); + + public void Reset() { } + } } - class Program + + class C { static void Main() { - MyCollection x = new([1, 2, 3]); - object[] y = Convert(x); - y.Report(); + M(new([1, 2, 3]), [4, 5, 6]).Report(); } - static object[] Convert(MyCollection c) => [..c]; + + static List M(MyCollection c, IEnumerable e) => [..c, ..e]; } """; - var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[1, 2, 3, 4, 5, 6],", verify: Verification.Skipped); verifier.VerifyDiagnostics(); - verifier.VerifyIL("Program.Convert", """ + + verifier.VerifyIL("C.M", """ { - // Code size 63 (0x3f) + // Code size 64 (0x40) .maxstack 2 - .locals init (System.Collections.Generic.List V_0, - System.Collections.IEnumerator V_1, - object V_2, - System.IDisposable V_3) - IL_0000: newobj "System.Collections.Generic.List..ctor()" + .locals init (System.Collections.Generic.List V_0, + MyCollection.Enumerator V_1, + int V_2) + IL_0000: newobj "System.Collections.Generic.List..ctor()" IL_0005: stloc.0 IL_0006: ldarg.0 - IL_0007: call "System.Collections.IEnumerator Extensions.GetEnumerator(MyCollection)" + IL_0007: callvirt "MyCollection.Enumerator MyCollection.GetEnumerator()" IL_000c: stloc.1 .try { - IL_000d: br.s IL_001d - IL_000f: ldloc.1 - IL_0010: callvirt "object System.Collections.IEnumerator.Current.get" - IL_0015: stloc.2 - IL_0016: ldloc.0 - IL_0017: ldloc.2 - IL_0018: callvirt "void System.Collections.Generic.List.Add(object)" - IL_001d: ldloc.1 - IL_001e: callvirt "bool System.Collections.IEnumerator.MoveNext()" - IL_0023: brtrue.s IL_000f - IL_0025: leave.s IL_0038 + IL_000d: br.s IL_001e + IL_000f: ldloca.s V_1 + IL_0011: call "int MyCollection.Enumerator.Current.get" + IL_0016: stloc.2 + IL_0017: ldloc.0 + IL_0018: ldloc.2 + IL_0019: callvirt "void System.Collections.Generic.List.Add(int)" + IL_001e: ldloca.s V_1 + IL_0020: call "bool MyCollection.Enumerator.MoveNext()" + IL_0025: brtrue.s IL_000f + IL_0027: leave.s IL_0037 } finally { - IL_0027: ldloc.1 - IL_0028: isinst "System.IDisposable" - IL_002d: stloc.3 - IL_002e: ldloc.3 - IL_002f: brfalse.s IL_0037 - IL_0031: ldloc.3 - IL_0032: callvirt "void System.IDisposable.Dispose()" - IL_0037: endfinally + IL_0029: ldloca.s V_1 + IL_002b: constrained. "MyCollection.Enumerator" + IL_0031: callvirt "void System.IDisposable.Dispose()" + IL_0036: endfinally } - IL_0038: ldloc.0 - IL_0039: callvirt "object[] System.Collections.Generic.List.ToArray()" - IL_003e: ret + IL_0037: ldloc.0 + IL_0038: ldarg.1 + IL_0039: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" + IL_003e: ldloc.0 + IL_003f: ret } """); } - [Fact] - public void Spread_ExtensionGetEnumerator_Generic() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_CustomCollection_ICollectionAndStructEnumerator() { var source = """ + using System.Collections; using System.Collections.Generic; - class MyCollection + + class MyCollection(List list) : ICollection { - public readonly List Items; - public MyCollection(IEnumerable items) { Items = new(items); } + public int Count => list.Count; + + public bool IsReadOnly => false; + + public void Add(T item) => list.Add(item); + + public void Clear() => list.Clear(); + + public bool Contains(T item) => list.Contains(item); + + public void CopyTo(T[] array, int arrayIndex) => list.CopyTo(array, arrayIndex); + + public bool Remove(T item) => list.Remove(item); + + public Enumerator GetEnumerator() => new(list.GetEnumerator()); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public struct Enumerator(List.Enumerator enumerator) : IEnumerator + { + public T Current => enumerator.Current; + + object IEnumerator.Current => Current; + + public bool MoveNext() => enumerator.MoveNext(); + + public void Dispose() => enumerator.Dispose(); + + public void Reset() { } + } } - static class Extensions + + class C { - public static IEnumerator GetEnumerator(this MyCollection c) => c.Items.GetEnumerator(); + static void Main() + { + M1(new([1, 2, 3])).Report(); + M2(new([1, 2, 3])).Report(); + M3(new([1, 2, 3])).Report(); + } + + static List M1(MyCollection c) => [..c]; + + #nullable enable + static List M2(MyCollection c) => [..c]; + static List M3(MyCollection c) => [..c]; + } + """; + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[1, 2, 3], [1, 2, 3], [1, 2, 3], ", verify: Verification.Skipped); + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("C.M1", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """); + var expectedILForObject = """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """; + verifier.VerifyIL("C.M2", expectedILForObject); + verifier.VerifyIL("C.M3", expectedILForObject); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71217")] + public void List_SingleSpread_Generics_Nullability() + { + var source = """ + using System.Collections.Generic; + interface IMyEnumerable : IEnumerable + { + new MyEnumerator GetEnumerator(); + } + interface IMyCollection : ICollection + { + new MyEnumerator GetEnumerator(); + } + struct MyEnumerator + { + private readonly List _list; + private int _index; + public MyEnumerator(List list) { _list = list; _index = -1; } + public T Current => _list[_index]; + public bool MoveNext() + { + if (_index < _list.Count) _index++; + return _index < _list.Count; + } + } + class MyEnumerable : List, IMyEnumerable + { + MyEnumerator IMyEnumerable.GetEnumerator() => new(this); + } + class MyCollection : List, IMyCollection + { + MyEnumerator IMyCollection.GetEnumerator() => new(this); } class Program { static void Main() { - MyCollection x = new([1, 2, 3]); - int[] y = Convert(x); - y.Report(); + MyEnumerable e = ["a", "b", "c"]; + MyCollection c = ["a", "b", "c"]; + M1, string>(e).Report(); + M2, string>(e).Report(); + M3, string>(c).Report(); + M4, string>(c).Report(); + } + #nullable enable + static List M1(T c) + where T : class, IMyEnumerable + where U : class + { + return [..c]; + } + static List M2(T c) + where T : class, IMyEnumerable + where U : class + { + return [..c]; + } + static List M3(T c) + where T : class, IMyCollection + where U : class + { + return [..c]; + } + static List M4(T c) + where T : class, IMyCollection + where U : class + { + return [..c]; } - static T[] Convert(MyCollection c) => [..c]; } """; - var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); + + var verifier = CompileAndVerify([source, s_collectionExtensions], expectedOutput: "[a, b, c], [a, b, c], [a, b, c], [a, b, c], ", verify: Verification.Skipped); verifier.VerifyDiagnostics(); - verifier.VerifyIL("Program.Convert", """ + + var expectedILForMyEnumerator = """ { - // Code size 56 (0x38) + // Code size 46 (0x2e) .maxstack 2 - .locals init (System.Collections.Generic.List V_0, - System.Collections.Generic.IEnumerator V_1, - T V_2) - IL_0000: newobj "System.Collections.Generic.List..ctor()" + .locals init (System.Collections.Generic.List V_0, + MyEnumerator V_1, + U V_2) + IL_0000: newobj "System.Collections.Generic.List..ctor()" IL_0005: stloc.0 IL_0006: ldarg.0 - IL_0007: call "System.Collections.Generic.IEnumerator Extensions.GetEnumerator(MyCollection)" - IL_000c: stloc.1 - .try - { - IL_000d: br.s IL_001d - IL_000f: ldloc.1 - IL_0010: callvirt "T System.Collections.Generic.IEnumerator.Current.get" - IL_0015: stloc.2 - IL_0016: ldloc.0 - IL_0017: ldloc.2 - IL_0018: callvirt "void System.Collections.Generic.List.Add(T)" - IL_001d: ldloc.1 - IL_001e: callvirt "bool System.Collections.IEnumerator.MoveNext()" - IL_0023: brtrue.s IL_000f - IL_0025: leave.s IL_0031 - } - finally - { - IL_0027: ldloc.1 - IL_0028: brfalse.s IL_0030 - IL_002a: ldloc.1 - IL_002b: callvirt "void System.IDisposable.Dispose()" - IL_0030: endfinally - } - IL_0031: ldloc.0 - IL_0032: callvirt "T[] System.Collections.Generic.List.ToArray()" - IL_0037: ret + IL_0007: box "T" + IL_000c: callvirt "MyEnumerator IMyEnumerable.GetEnumerator()" + IL_0011: stloc.1 + IL_0012: br.s IL_0023 + IL_0014: ldloca.s V_1 + IL_0016: call "U MyEnumerator.Current.get" + IL_001b: stloc.2 + IL_001c: ldloc.0 + IL_001d: ldloc.2 + IL_001e: callvirt "void System.Collections.Generic.List.Add(U)" + IL_0023: ldloca.s V_1 + IL_0025: call "bool MyEnumerator.MoveNext()" + IL_002a: brtrue.s IL_0014 + IL_002c: ldloc.0 + IL_002d: ret } - """); + """; + verifier.VerifyIL("Program.M1", expectedILForMyEnumerator); + verifier.VerifyIL("Program.M2", expectedILForMyEnumerator); + + var expectedILForMyCollection = """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "System.Collections.Generic.List System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)" + IL_0006: ret + } + """; + verifier.VerifyIL("Program.M3", expectedILForMyCollection); + verifier.VerifyIL("Program.M4", expectedILForMyCollection); } - [Fact] - public void Spread_ExtensionGetEnumerator_Pattern() + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74894")] + public void List_Spread_StructEnumerator() { var source = """ using System.Collections.Generic; - class MyCollection + interface IMyEnumerable : IEnumerable { - public readonly List Items; - public MyCollection(IEnumerable items) { Items = new(items); } + new MyEnumerator GetEnumerator(); + } + interface IMyCollection : ICollection + { + new MyEnumerator GetEnumerator(); } struct MyEnumerator { - private IEnumerator _enumerator; - public MyEnumerator(IEnumerator enumerator) { _enumerator = enumerator; } - public bool MoveNext() => _enumerator.MoveNext(); - public T Current => _enumerator.Current; + private readonly List _list; + private int _index; + public MyEnumerator(List list) { _list = list; _index = -1; } + public T Current => _list[_index]; + public bool MoveNext() + { + if (_index < _list.Count) _index++; + return _index < _list.Count; + } } - static class Extensions + class MyEnumerable : List, IMyEnumerable { - public static MyEnumerator GetEnumerator(this MyCollection c) => new(c.Items.GetEnumerator()); + MyEnumerator IMyEnumerable.GetEnumerator() => new(this); + } + class MyCollection : List, IMyCollection + { + MyEnumerator IMyCollection.GetEnumerator() => new(this); } class Program { static void Main() { - MyCollection x = new([1, 2, 3]); - int[] y = Convert(x); - y.Report(); + MyEnumerable x = [1, 2]; + MyCollection y = [1, 2]; + object z = 3; + M1(x, z).Report(); + M2(y, z).Report(); + M3(x, z).Report(); + M4(y, z).Report(); + } + static List M1(IMyEnumerable x, object y) + { + return [..x, y]; + } + static List M2(IMyCollection x, object y) + { + return [..x, y]; + } + #nullable enable + static List M3(T x, U y) + where T : class, IMyEnumerable + where U : class + { + return [..x, y]; + } + static List M4(T x, U y) + where T : class, IMyCollection + where U : class + { + return [..x, y]; } - static T[] Convert(MyCollection c) => [..c]; } """; - var verifier = CompileAndVerify(new[] { source, s_collectionExtensions }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); + var verifier = CompileAndVerify( + [source, s_collectionExtensions], + targetFramework: TargetFramework.Standard, + expectedOutput: "[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], ", + verify: Verification.Skipped); verifier.VerifyDiagnostics(); - verifier.VerifyIL("Program.Convert", """ + verifier.VerifyIL("Program.M1", """ { - // Code size 46 (0x2e) + // Code size 48 (0x30) .maxstack 2 - .locals init (System.Collections.Generic.List V_0, - MyEnumerator V_1, - T V_2) - IL_0000: newobj "System.Collections.Generic.List..ctor()" + .locals init (System.Collections.Generic.List V_0, + MyEnumerator V_1, + object V_2) + IL_0000: newobj "System.Collections.Generic.List..ctor()" IL_0005: stloc.0 IL_0006: ldarg.0 - IL_0007: call "MyEnumerator Extensions.GetEnumerator(MyCollection)" + IL_0007: callvirt "MyEnumerator IMyEnumerable.GetEnumerator()" IL_000c: stloc.1 IL_000d: br.s IL_001e IL_000f: ldloca.s V_1 - IL_0011: call "T MyEnumerator.Current.get" + IL_0011: call "object MyEnumerator.Current.get" IL_0016: stloc.2 IL_0017: ldloc.0 IL_0018: ldloc.2 - IL_0019: callvirt "void System.Collections.Generic.List.Add(T)" + IL_0019: callvirt "void System.Collections.Generic.List.Add(object)" IL_001e: ldloca.s V_1 - IL_0020: call "bool MyEnumerator.MoveNext()" + IL_0020: call "bool MyEnumerator.MoveNext()" IL_0025: brtrue.s IL_000f IL_0027: ldloc.0 - IL_0028: callvirt "T[] System.Collections.Generic.List.ToArray()" - IL_002d: ret + IL_0028: ldarg.1 + IL_0029: callvirt "void System.Collections.Generic.List.Add(object)" + IL_002e: ldloc.0 + IL_002f: ret + } + """); + verifier.VerifyIL("Program.M2", """ + { + // Code size 30 (0x1e) + .maxstack 3 + .locals init (IMyCollection V_0) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldc.i4.1 + IL_0003: ldloc.0 + IL_0004: callvirt "int System.Collections.Generic.ICollection.Count.get" + IL_0009: add + IL_000a: newobj "System.Collections.Generic.List..ctor(int)" + IL_000f: dup + IL_0010: ldloc.0 + IL_0011: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" + IL_0016: dup + IL_0017: ldarg.1 + IL_0018: callvirt "void System.Collections.Generic.List.Add(object)" + IL_001d: ret + } + """); + verifier.VerifyIL("Program.M3(T, U)", """ + { + // Code size 53 (0x35) + .maxstack 2 + .locals init (System.Collections.Generic.List V_0, + MyEnumerator V_1, + U V_2) + IL_0000: newobj "System.Collections.Generic.List..ctor()" + IL_0005: stloc.0 + IL_0006: ldarg.0 + IL_0007: box "T" + IL_000c: callvirt "MyEnumerator IMyEnumerable.GetEnumerator()" + IL_0011: stloc.1 + IL_0012: br.s IL_0023 + IL_0014: ldloca.s V_1 + IL_0016: call "U MyEnumerator.Current.get" + IL_001b: stloc.2 + IL_001c: ldloc.0 + IL_001d: ldloc.2 + IL_001e: callvirt "void System.Collections.Generic.List.Add(U)" + IL_0023: ldloca.s V_1 + IL_0025: call "bool MyEnumerator.MoveNext()" + IL_002a: brtrue.s IL_0014 + IL_002c: ldloc.0 + IL_002d: ldarg.1 + IL_002e: callvirt "void System.Collections.Generic.List.Add(U)" + IL_0033: ldloc.0 + IL_0034: ret + } + """); + verifier.VerifyIL("Program.M4(T, U)", """ + { + // Code size 35 (0x23) + .maxstack 3 + .locals init (T V_0) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldc.i4.1 + IL_0003: ldloc.0 + IL_0004: box "T" + IL_0009: callvirt "int System.Collections.Generic.ICollection.Count.get" + IL_000e: add + IL_000f: newobj "System.Collections.Generic.List..ctor(int)" + IL_0014: dup + IL_0015: ldloc.0 + IL_0016: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" + IL_001b: dup + IL_001c: ldarg.1 + IL_001d: callvirt "void System.Collections.Generic.List.Add(U)" + IL_0022: ret } """); } @@ -34778,20 +37129,20 @@ static void Main() { IEnumerable e = [1, 2, 3]; e.Report(); - List list = [..e]; + List list = [..e, 4]; list.Report(); } } """; - var verifier = CompileAndVerify(new[] { source, s_collectionExtensionsWithSpan }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], [1, 2, 3],"), targetFramework: TargetFramework.Net80, verify: Verification.Skipped); + var verifier = CompileAndVerify(new[] { source, s_collectionExtensionsWithSpan }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], [1, 2, 3, 4],"), targetFramework: TargetFramework.Net80, verify: Verification.Skipped); verifier.VerifyDiagnostics(); // https://github.com/dotnet/roslyn/issues/71273 // It's strange that using a *less* specific type can result in *better* codegen when using a List target type. verifier.VerifyIL("C.Main", """ { - // Code size 49 (0x31) + // Code size 56 (0x38) .maxstack 3 .locals init (System.Collections.Generic.IEnumerable V_0) //e IL_0000: ldc.i4.3 @@ -34808,9 +37159,12 @@ .locals init (System.Collections.Generic.IEnumerable V_0) //e IL_0023: dup IL_0024: ldloc.0 IL_0025: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" - IL_002a: ldc.i4.0 - IL_002b: call "void CollectionExtensions.Report(object, bool)" - IL_0030: ret + IL_002a: dup + IL_002b: ldc.i4.4 + IL_002c: callvirt "void System.Collections.Generic.List.Add(int)" + IL_0031: ldc.i4.0 + IL_0032: call "void CollectionExtensions.Report(object, bool)" + IL_0037: ret } """); } @@ -34826,18 +37180,18 @@ static void Main() { IEnumerable e = ["a", "b", "c"]; e.Report(); - List list = [..e]; + List list = [..e, "d"]; list.Report(); } } """; - var verifier = CompileAndVerify(new[] { source, s_collectionExtensionsWithSpan }, expectedOutput: IncludeExpectedOutput("[a, b, c], [a, b, c],"), targetFramework: TargetFramework.Net80, verify: Verification.Skipped); + var verifier = CompileAndVerify(new[] { source, s_collectionExtensionsWithSpan }, expectedOutput: IncludeExpectedOutput("[a, b, c], [a, b, c, d],"), targetFramework: TargetFramework.Net80, verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.Main", """ { - // Code size 62 (0x3e) + // Code size 73 (0x49) .maxstack 4 .locals init (System.Collections.Generic.IEnumerable V_0) //e IL_0000: ldc.i4.3 @@ -34863,9 +37217,12 @@ .locals init (System.Collections.Generic.IEnumerable V_0) //e IL_0030: dup IL_0031: ldloc.0 IL_0032: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" - IL_0037: ldc.i4.0 - IL_0038: call "void CollectionExtensions.Report(object, bool)" - IL_003d: ret + IL_0037: dup + IL_0038: ldstr "d" + IL_003d: callvirt "void System.Collections.Generic.List.Add(object)" + IL_0042: ldc.i4.0 + IL_0043: call "void CollectionExtensions.Report(object, bool)" + IL_0048: ret } """); } @@ -34957,26 +37314,29 @@ static void Main() static void M(T t) where T : class, IEnumerable { - List list = [..t]; + List list = [..t, ..t]; list.Report(); } } """; - var verifier = CompileAndVerify(new[] { source, s_collectionExtensionsWithSpan }, expectedOutput: IncludeExpectedOutput("[a, b, c], [a, b, c],"), targetFramework: TargetFramework.Net80, verify: Verification.Skipped); + var verifier = CompileAndVerify(new[] { source, s_collectionExtensionsWithSpan }, expectedOutput: IncludeExpectedOutput("[a, b, c], [a, b, c, a, b, c],"), targetFramework: TargetFramework.Net80, verify: Verification.Skipped); verifier.VerifyDiagnostics(); verifier.VerifyIL("C.M", """ { - // Code size 19 (0x13) + // Code size 26 (0x1a) .maxstack 3 IL_0000: newobj "System.Collections.Generic.List..ctor()" IL_0005: dup IL_0006: ldarg.0 IL_0007: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" - IL_000c: ldc.i4.0 - IL_000d: call "void CollectionExtensions.Report(object, bool)" - IL_0012: ret + IL_000c: dup + IL_000d: ldarg.0 + IL_000e: callvirt "void System.Collections.Generic.List.AddRange(System.Collections.Generic.IEnumerable)" + IL_0013: ldc.i4.0 + IL_0014: call "void CollectionExtensions.Report(object, bool)" + IL_0019: ret } """); } @@ -34992,27 +37352,28 @@ static void Main() { ICollection e = [1, 2, 3]; e.Report(); - List list = [..e]; + List list = [..e, 4]; list.Report(); } } """; - var verifier = CompileAndVerify(new[] { source, s_collectionExtensionsWithSpan }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], [1, 2, 3],"), targetFramework: TargetFramework.Net80, verify: Verification.Skipped); + var verifier = CompileAndVerify(new[] { source, s_collectionExtensionsWithSpan }, expectedOutput: IncludeExpectedOutput("[1, 2, 3], [1, 2, 3, 4],"), targetFramework: TargetFramework.Net80, verify: Verification.Skipped); verifier.VerifyDiagnostics(); // https://github.com/dotnet/roslyn/issues/71273 // Ideally we'd like to be able to use *both* something like AddRange, *and* AsSpan/CopyTo/etc. while building the same target collection verifier.VerifyIL("C.Main", """ { - // Code size 167 (0xa7) + // Code size 189 (0xbd) .maxstack 3 .locals init (int V_0, System.Span V_1, int V_2, - System.Collections.Generic.List V_3, - System.Collections.Generic.IEnumerator V_4, - int V_5) + System.Collections.Generic.ICollection V_3, + System.Collections.Generic.List V_4, + System.Collections.Generic.IEnumerator V_5, + int V_6) IL_0000: ldc.i4.3 IL_0001: stloc.0 IL_0002: ldloc.0 @@ -35055,54 +37416,67 @@ .locals init (int V_0, IL_0042: dup IL_0043: ldc.i4.0 IL_0044: call "void CollectionExtensions.Report(object, bool)" - IL_0049: dup - IL_004a: callvirt "int System.Collections.Generic.ICollection.Count.get" - IL_004f: stloc.2 - IL_0050: ldloc.2 - IL_0051: newobj "System.Collections.Generic.List..ctor(int)" - IL_0056: stloc.3 - IL_0057: ldloc.3 - IL_0058: ldloc.2 - IL_0059: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount(System.Collections.Generic.List, int)" - IL_005e: ldloc.3 - IL_005f: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)" - IL_0064: stloc.1 - IL_0065: ldc.i4.0 - IL_0066: stloc.0 - IL_0067: callvirt "System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator()" - IL_006c: stloc.s V_4 + IL_0049: stloc.3 + IL_004a: ldc.i4.1 + IL_004b: ldloc.3 + IL_004c: callvirt "int System.Collections.Generic.ICollection.Count.get" + IL_0051: add + IL_0052: stloc.2 + IL_0053: ldloc.2 + IL_0054: newobj "System.Collections.Generic.List..ctor(int)" + IL_0059: stloc.s V_4 + IL_005b: ldloc.s V_4 + IL_005d: ldloc.2 + IL_005e: call "void System.Runtime.InteropServices.CollectionsMarshal.SetCount(System.Collections.Generic.List, int)" + IL_0063: ldloc.s V_4 + IL_0065: call "System.Span System.Runtime.InteropServices.CollectionsMarshal.AsSpan(System.Collections.Generic.List)" + IL_006a: stloc.1 + IL_006b: ldc.i4.0 + IL_006c: stloc.0 + IL_006d: ldloc.3 + IL_006e: callvirt "System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator()" + IL_0073: stloc.s V_5 .try { - IL_006e: br.s IL_0088 - IL_0070: ldloc.s V_4 - IL_0072: callvirt "int System.Collections.Generic.IEnumerator.Current.get" - IL_0077: stloc.s V_5 - IL_0079: ldloca.s V_1 - IL_007b: ldloc.0 - IL_007c: call "ref int System.Span.this[int].get" - IL_0081: ldloc.s V_5 - IL_0083: stind.i4 - IL_0084: ldloc.0 - IL_0085: ldc.i4.1 - IL_0086: add - IL_0087: stloc.0 - IL_0088: ldloc.s V_4 - IL_008a: callvirt "bool System.Collections.IEnumerator.MoveNext()" - IL_008f: brtrue.s IL_0070 - IL_0091: leave.s IL_009f + IL_0075: br.s IL_008f + IL_0077: ldloc.s V_5 + IL_0079: callvirt "int System.Collections.Generic.IEnumerator.Current.get" + IL_007e: stloc.s V_6 + IL_0080: ldloca.s V_1 + IL_0082: ldloc.0 + IL_0083: call "ref int System.Span.this[int].get" + IL_0088: ldloc.s V_6 + IL_008a: stind.i4 + IL_008b: ldloc.0 + IL_008c: ldc.i4.1 + IL_008d: add + IL_008e: stloc.0 + IL_008f: ldloc.s V_5 + IL_0091: callvirt "bool System.Collections.IEnumerator.MoveNext()" + IL_0096: brtrue.s IL_0077 + IL_0098: leave.s IL_00a6 } finally { - IL_0093: ldloc.s V_4 - IL_0095: brfalse.s IL_009e - IL_0097: ldloc.s V_4 - IL_0099: callvirt "void System.IDisposable.Dispose()" - IL_009e: endfinally + IL_009a: ldloc.s V_5 + IL_009c: brfalse.s IL_00a5 + IL_009e: ldloc.s V_5 + IL_00a0: callvirt "void System.IDisposable.Dispose()" + IL_00a5: endfinally } - IL_009f: ldloc.3 - IL_00a0: ldc.i4.0 - IL_00a1: call "void CollectionExtensions.Report(object, bool)" - IL_00a6: ret + IL_00a6: ldloca.s V_1 + IL_00a8: ldloc.0 + IL_00a9: call "ref int System.Span.this[int].get" + IL_00ae: ldc.i4.4 + IL_00af: stind.i4 + IL_00b0: ldloc.0 + IL_00b1: ldc.i4.1 + IL_00b2: add + IL_00b3: stloc.0 + IL_00b4: ldloc.s V_4 + IL_00b6: ldc.i4.0 + IL_00b7: call "void CollectionExtensions.Report(object, bool)" + IL_00bc: ret } """); } @@ -40179,5 +42553,459 @@ public class Container // (Container, int) x = ([1, 2], 3); Diagnostic(ErrorCode.ERR_CollectionExpressionTargetTypeNotConstructible, "[1, 2]").WithArguments("Container").WithLocation(7, 36)); } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/70708")] + public void InlineArraySpread_01() + { + string source = """ + class Program + { + static int[] Test(MyArray x) => [..x]; + + static void Main() + { + MyArray x = new(); + x[0] = -3; + x[1] = -2; + x[2] = -1; + + var a = Test(x); + foreach (var i in a) + System.Console.Write(i); + + System.Console.Write(a.Length); + } + } + + [System.Runtime.CompilerServices.InlineArray(3)] + struct MyArray + { + T _e0; + } + """; + + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + + var verifier = CompileAndVerify( + comp, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("-3-2-13")); + + verifier.VerifyIL("Program.Test", +@" +{ + // Code size 52 (0x34) + .maxstack 3 + .locals init (MyArray V_0, + int V_1, + int[] V_2, + MyArray& V_3, + int V_4, + int V_5) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldc.i4.0 + IL_0003: stloc.1 + IL_0004: ldc.i4.3 + IL_0005: newarr ""int"" + IL_000a: stloc.2 + IL_000b: ldloca.s V_0 + IL_000d: stloc.3 + IL_000e: ldc.i4.0 + IL_000f: stloc.s V_4 + IL_0011: br.s IL_002d + IL_0013: ldloc.3 + IL_0014: ldloc.s V_4 + IL_0016: call ""ref int .InlineArrayElementRef, int>(ref MyArray, int)"" + IL_001b: ldind.i4 + IL_001c: stloc.s V_5 + IL_001e: ldloc.2 + IL_001f: ldloc.1 + IL_0020: ldloc.s V_5 + IL_0022: stelem.i4 + IL_0023: ldloc.1 + IL_0024: ldc.i4.1 + IL_0025: add + IL_0026: stloc.1 + IL_0027: ldloc.s V_4 + IL_0029: ldc.i4.1 + IL_002a: add + IL_002b: stloc.s V_4 + IL_002d: ldloc.s V_4 + IL_002f: ldc.i4.3 + IL_0030: blt.s IL_0013 + IL_0032: ldloc.2 + IL_0033: ret +} +"); + + comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_Unsafe__Add_T); + comp.VerifyDiagnostics( + // (3,45): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.Unsafe.Add' + // static int[] Test(MyArray x) => [..x]; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.Runtime.CompilerServices.Unsafe", "Add").WithLocation(3, 45) + ); + + comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_Unsafe__As_T); + comp.VerifyDiagnostics( + // (3,45): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.Unsafe.As' + // static int[] Test(MyArray x) => [..x]; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.Runtime.CompilerServices.Unsafe", "As").WithLocation(3, 45), + // (8,9): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.Unsafe.As' + // x[0] = -3; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x[0]").WithArguments("System.Runtime.CompilerServices.Unsafe", "As").WithLocation(8, 9), + // (9,9): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.Unsafe.As' + // x[1] = -2; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x[1]").WithArguments("System.Runtime.CompilerServices.Unsafe", "As").WithLocation(9, 9), + // (10,9): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.Unsafe.As' + // x[2] = -1; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x[2]").WithArguments("System.Runtime.CompilerServices.Unsafe", "As").WithLocation(10, 9) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/70708")] + public void InlineArraySpread_02() + { + string source = """ + class Program + { + static int[] Test(ref readonly MyArray x) => [..x]; + + static void Main() + { + MyArray x = new(); + x[0] = -3; + x[1] = -2; + x[2] = -1; + + var a = Test(in x); + foreach (var i in a) + System.Console.Write(i); + + System.Console.Write(a.Length); + } + } + + [System.Runtime.CompilerServices.InlineArray(3)] + struct MyArray + { + T _e0; + } + """; + + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + + var verifier = CompileAndVerify( + comp, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("-3-2-13")); + + verifier.VerifyIL("Program.Test", +@" +{ + // Code size 57 (0x39) + .maxstack 3 + .locals init (MyArray V_0, + int V_1, + int[] V_2, + MyArray& V_3, + int V_4, + int V_5) + IL_0000: ldarg.0 + IL_0001: ldobj ""MyArray"" + IL_0006: stloc.0 + IL_0007: ldc.i4.0 + IL_0008: stloc.1 + IL_0009: ldc.i4.3 + IL_000a: newarr ""int"" + IL_000f: stloc.2 + IL_0010: ldloca.s V_0 + IL_0012: stloc.3 + IL_0013: ldc.i4.0 + IL_0014: stloc.s V_4 + IL_0016: br.s IL_0032 + IL_0018: ldloc.3 + IL_0019: ldloc.s V_4 + IL_001b: call ""ref readonly int .InlineArrayElementRefReadOnly, int>(in MyArray, int)"" + IL_0020: ldind.i4 + IL_0021: stloc.s V_5 + IL_0023: ldloc.2 + IL_0024: ldloc.1 + IL_0025: ldloc.s V_5 + IL_0027: stelem.i4 + IL_0028: ldloc.1 + IL_0029: ldc.i4.1 + IL_002a: add + IL_002b: stloc.1 + IL_002c: ldloc.s V_4 + IL_002e: ldc.i4.1 + IL_002f: add + IL_0030: stloc.s V_4 + IL_0032: ldloc.s V_4 + IL_0034: ldc.i4.3 + IL_0035: blt.s IL_0018 + IL_0037: ldloc.2 + IL_0038: ret +} +"); + comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_Unsafe__Add_T); + comp.VerifyDiagnostics( + // (3,58): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.Unsafe.Add' + // static int[] Test(ref readonly MyArray x) => [..x]; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.Runtime.CompilerServices.Unsafe", "Add").WithLocation(3, 58) + ); + + comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_Unsafe__As_T); + comp.VerifyDiagnostics( + // (3,58): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.Unsafe.As' + // static int[] Test(ref readonly MyArray x) => [..x]; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.Runtime.CompilerServices.Unsafe", "As").WithLocation(3, 58), + // (8,9): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.Unsafe.As' + // x[0] = -3; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x[0]").WithArguments("System.Runtime.CompilerServices.Unsafe", "As").WithLocation(8, 9), + // (9,9): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.Unsafe.As' + // x[1] = -2; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x[1]").WithArguments("System.Runtime.CompilerServices.Unsafe", "As").WithLocation(9, 9), + // (10,9): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.Unsafe.As' + // x[2] = -1; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x[2]").WithArguments("System.Runtime.CompilerServices.Unsafe", "As").WithLocation(10, 9) + ); + + comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_Unsafe__AsRef_T); + comp.VerifyDiagnostics( + // (3,58): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.Unsafe.AsRef' + // static int[] Test(ref readonly MyArray x) => [..x]; + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "x").WithArguments("System.Runtime.CompilerServices.Unsafe", "AsRef").WithLocation(3, 58) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/70708")] + public void InlineArraySpread_03() + { + string source = """ + class Program + { + static int[] Test() => [..GetVal()]; + + static MyArray GetVal() + { + MyArray x = new(); + x[0] = -3; + x[1] = -2; + x[2] = -1; + + return x; + } + + static void Main() + { + var a = Test(); + foreach (var i in a) + System.Console.Write(i); + + System.Console.Write(a.Length); + } + } + + [System.Runtime.CompilerServices.InlineArray(3)] + struct MyArray + { + T _e0; + } + """; + + var verifier = CompileAndVerify( + source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("-3-2-13")); + + verifier.VerifyIL("Program.Test", +@" +{ + // Code size 56 (0x38) + .maxstack 3 + .locals init (int V_0, + int[] V_1, + MyArray V_2, + MyArray& V_3, + int V_4, + int V_5) + IL_0000: call ""MyArray Program.GetVal()"" + IL_0005: ldc.i4.0 + IL_0006: stloc.0 + IL_0007: ldc.i4.3 + IL_0008: newarr ""int"" + IL_000d: stloc.1 + IL_000e: stloc.2 + IL_000f: ldloca.s V_2 + IL_0011: stloc.3 + IL_0012: ldc.i4.0 + IL_0013: stloc.s V_4 + IL_0015: br.s IL_0031 + IL_0017: ldloc.3 + IL_0018: ldloc.s V_4 + IL_001a: call ""ref readonly int .InlineArrayElementRefReadOnly, int>(in MyArray, int)"" + IL_001f: ldind.i4 + IL_0020: stloc.s V_5 + IL_0022: ldloc.1 + IL_0023: ldloc.0 + IL_0024: ldloc.s V_5 + IL_0026: stelem.i4 + IL_0027: ldloc.0 + IL_0028: ldc.i4.1 + IL_0029: add + IL_002a: stloc.0 + IL_002b: ldloc.s V_4 + IL_002d: ldc.i4.1 + IL_002e: add + IL_002f: stloc.s V_4 + IL_0031: ldloc.s V_4 + IL_0033: ldc.i4.3 + IL_0034: blt.s IL_0017 + IL_0036: ldloc.1 + IL_0037: ret +} +"); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/70708")] + public void InlineArraySpread_04() + { + string source = """ + class Program + { + static int[] Test(MyArray x) => [..x]; + + static void Main() + { + MyArray x = new(); + x[0] = -3; + x[1] = -2; + x[2] = -1; + + var a = Test(x); + foreach (var i in a) + System.Console.Write(i); + + System.Console.Write(a.Length); + } + } + + [System.Runtime.CompilerServices.InlineArray(3)] + struct MyArray + { + T _e0; + + public int Length => throw null; + public int Count => throw null; + } + """; + + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseExe); + + var verifier = CompileAndVerify( + comp, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("-3-2-13")); + + verifier.VerifyIL("Program.Test", +@" +{ + // Code size 52 (0x34) + .maxstack 3 + .locals init (MyArray V_0, + int V_1, + int[] V_2, + MyArray& V_3, + int V_4, + int V_5) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldc.i4.0 + IL_0003: stloc.1 + IL_0004: ldc.i4.3 + IL_0005: newarr ""int"" + IL_000a: stloc.2 + IL_000b: ldloca.s V_0 + IL_000d: stloc.3 + IL_000e: ldc.i4.0 + IL_000f: stloc.s V_4 + IL_0011: br.s IL_002d + IL_0013: ldloc.3 + IL_0014: ldloc.s V_4 + IL_0016: call ""ref int .InlineArrayElementRef, int>(ref MyArray, int)"" + IL_001b: ldind.i4 + IL_001c: stloc.s V_5 + IL_001e: ldloc.2 + IL_001f: ldloc.1 + IL_0020: ldloc.s V_5 + IL_0022: stelem.i4 + IL_0023: ldloc.1 + IL_0024: ldc.i4.1 + IL_0025: add + IL_0026: stloc.1 + IL_0027: ldloc.s V_4 + IL_0029: ldc.i4.1 + IL_002a: add + IL_002b: stloc.s V_4 + IL_002d: ldloc.s V_4 + IL_002f: ldc.i4.3 + IL_0030: blt.s IL_0013 + IL_0032: ldloc.2 + IL_0033: ret +} +"); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75194")] + public void LinqSpread() + { + string source = """ + using System; + using System.Runtime.CompilerServices; + using System.Collections.Generic; + + CustomizedCollection c = [.. from element in returnArray() select element / 9]; + + foreach (var i in c.Array) + { + System.Console.Write(i); + } + + + static int[] returnArray() => null; + + [CollectionBuilder(typeof(CustomizedCollection), nameof(Create))] + struct CustomizedCollection + { + public void Add(int variable) => throw null; + public IEnumerator GetEnumerator() => throw null; + public static CustomizedCollection Create(ReadOnlySpan values) => new CustomizedCollection { Array = values.ToArray() }; + + public int[] Array; + } + + static class Extensions + { + public static ReadOnlySpan Select(this T[] array, Func selector) + => (TResult[])[(TResult)(object)1, (TResult)(object)2, (TResult)(object)3]; + } + """; + + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + + CompileAndVerify(comp, expectedOutput: IncludeExpectedOutput("123"), verify: Verification.Skipped).VerifyDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/ExperimentalAttributeTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExperimentalAttributeTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Semantics/ExperimentalAttributeTests.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/ExperimentalAttributeTests.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/InlineArrayTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/InlineArrayTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Semantics/InlineArrayTests.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/InlineArrayTests.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/LockTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/LockTests.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Semantics/LockTests.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/LockTests.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/OutVarTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/OutVarTests.cs similarity index 96% rename from src/Compilers/CSharp/Test/Emit2/Semantics/OutVarTests.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/OutVarTests.cs index 323eaba897a20..9ee3226572928 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/OutVarTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/OutVarTests.cs @@ -16,7 +16,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Microsoft.CodeAnalysis.Diagnostics; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; using ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer; namespace Microsoft.CodeAnalysis.CSharp.UnitTests @@ -1965,7 +1965,7 @@ class Test : System.Attribute public bool p2 {get; set;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (8,15): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [Test(p = TakeOutParam(out int x3) && x3 > 0)] @@ -2075,7 +2075,7 @@ public Test(bool p) {} public Test(bool p1, bool p2) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (8,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [Test(TakeOutParam(out int x3) && x3 > 0)] @@ -2186,7 +2186,7 @@ class Test : System.Attribute public bool p2 {get; set;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (8,15): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [Test(p = TakeOutParam(out var x3) && x3 > 0)] @@ -2296,7 +2296,7 @@ public Test(bool p) {} public Test(bool p1, bool p2) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (8,11): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [Test(TakeOutParam(out var x3) && x3 > 0)] @@ -2385,7 +2385,7 @@ class Test : System.Attribute public Test(out int p) { p = 100; } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_1); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_1); compilation.VerifyDiagnostics( // (4,11): error CS1041: Identifier expected; 'out' is a keyword // [Test(out var x3)] @@ -2606,7 +2606,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (25,42): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // catch when (TakeOutParam(out var x4) && x4 > 0) @@ -2823,7 +2823,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (25,42): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // catch when (TakeOutParam(out int x4) && x4 > 0) @@ -2941,7 +2941,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"System.InvalidOperationException System.InvalidOperationException"); @@ -2987,7 +2987,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"System.InvalidOperationException System.InvalidOperationException"); @@ -3031,7 +3031,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"System.InvalidOperationException System.InvalidOperationException @@ -3078,7 +3078,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"System.InvalidOperationException System.InvalidOperationException @@ -3125,7 +3125,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"System.InvalidOperationException System.InvalidOperationException @@ -3179,7 +3179,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,16): error CS0841: Cannot use local variable 'x4' before it is declared // : this(x4 && TakeOutParam(4, out int x4)) @@ -3281,7 +3281,7 @@ public class Y public Y(params object[] x) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,16): error CS0841: Cannot use local variable 'x4' before it is declared // : base(x4 && TakeOutParam(4, out int x4)) @@ -3362,7 +3362,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"False 1 @@ -3414,7 +3414,7 @@ class C public C(bool b) { Console.WriteLine(b); } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"False 1 @@ -3453,7 +3453,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); ArgumentListSyntax arguments = SyntaxFactory.ParseArgumentList(@"(TakeOutParam(o, out int x1) && x1 >= 5)"); var initializer = SyntaxFactory.ConstructorInitializer(SyntaxKind.ThisConstructorInitializer, arguments); @@ -3494,7 +3494,7 @@ class C public C(bool b) { Console.WriteLine(b); } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); ArgumentListSyntax arguments = SyntaxFactory.ParseArgumentList(@"(TakeOutParam(o, out int x1) && x1 >= 5)"); var initializer = SyntaxFactory.ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, arguments); @@ -3612,7 +3612,7 @@ public Y(params object[] x) {} public Y(out int x, int y) { x = y; } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (9,40): error CS0136: A local or parameter named 'x3' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // : base(TakeOutParam(3, out var x3)) @@ -3803,7 +3803,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (97,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -3951,7 +3951,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (18,9): error CS0103: The name 'x1' does not exist in the current context // x1++; @@ -3992,7 +3992,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -4044,7 +4044,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 2 3"); @@ -4090,7 +4090,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"2"); var tree = compilation.SyntaxTrees.Single(); @@ -4139,7 +4139,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 3"); @@ -4195,7 +4195,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 2 3 @@ -4251,7 +4251,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (10,29): error CS0841: Cannot use local variable 'x4' before it is declared // bool Test4(object o) => x4 && TakeOutParam(o, out int x4); @@ -4333,7 +4333,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 True"); } @@ -4365,7 +4365,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 True"); } @@ -4455,7 +4455,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (18,30): error CS0841: Cannot use local variable 'x4' before it is declared // bool f (object o) => x4 && TakeOutParam(o, out int x4); @@ -4471,7 +4471,7 @@ static bool TakeOutParam(object y, out int x) Diagnostic(ErrorCode.ERR_NameNotInContext, "x7").WithArguments("x7").WithLocation(43, 15) ); - compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_3); + compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_3); compilation.VerifyDiagnostics( // (18,30): error CS0841: Cannot use local variable 'x4' before it is declared // bool f (object o) => x4 && TakeOutParam(o, out int x4); @@ -4575,7 +4575,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 True"); } @@ -4611,7 +4611,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 True"); } @@ -4653,7 +4653,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (10,19): error CS0841: Cannot use local variable 'x4' before it is declared // bool Test4 => x4 && TakeOutParam(4, out int x4); @@ -4738,7 +4738,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"2 True 1 @@ -4775,7 +4775,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"2 True 1 @@ -4881,7 +4881,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (14,46): error CS0136: A local or parameter named 'x1' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -5054,7 +5054,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (15,9): error CS0103: The name 'x1' does not exist in the current context @@ -5098,7 +5098,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -5155,7 +5155,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (10,18): error CS0841: Cannot use local variable 'x4' before it is declared // bool Test4 = x4 && TakeOutParam(4, out int x4); @@ -5250,7 +5250,7 @@ public static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (6,13): error CS0841: Cannot use local variable 'x4' before it is declared // Test4 = x4 && TakeOutParam(4, out int x4) ? 1 : 0, @@ -5374,7 +5374,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (8,24): error CS0133: The expression being assigned to 'X.Test3' must be constant // const bool Test3 = TakeOutParam(3, out int x3) && x3 > 0; @@ -5484,7 +5484,7 @@ class Y public Y(object y) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (8,43): error CS0165: Use of unassigned local variable 'x3' // bool Test3 = TakeOutParam(out int x3, x3); @@ -5563,11 +5563,11 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 True"); - CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( // (9,45): error CS8320: Feature 'declaration of expression variables in member initializers and queries' is not available in C# 7.2. Please use language version 7.3 or greater. // static bool Test1 = TakeOutParam(1, out int x1) && Dummy(x1); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "int x1").WithArguments("declaration of expression variables in member initializers and queries", "7.3").WithLocation(9, 45) @@ -5641,7 +5641,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 True"); } @@ -5674,7 +5674,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 True"); } @@ -5698,7 +5698,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (8,54): error CS0165: Use of unassigned local variable 'x1' // bool Test1 = a && TakeOutParam(3, out int x1) || x1 > 0; @@ -5741,7 +5741,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"2 3"); @@ -5872,7 +5872,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (87,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -6022,7 +6022,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (14,59): error CS0128: A local variable named 'x1' is already defined in this scope // Dummy(TakeOutParam(true, out var x1) && x1)) @@ -6105,7 +6105,7 @@ static bool TakeOutParam(string y, out string x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); CompileAndVerify(compilation, verify: Verification.Fails, expectedOutput: @"fixed fixed"); @@ -6139,7 +6139,7 @@ static bool TakeOutParam(string y, out string x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); CompileAndVerify(compilation, verify: Verification.Fails, expectedOutput: @"fixed fixed"); @@ -6287,7 +6287,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (109,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -6525,7 +6525,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (109,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -6760,7 +6760,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (109,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -7024,7 +7024,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (109,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -7262,7 +7262,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (109,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -7506,7 +7506,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,47): error CS0128: A local variable or function named 'x1' is already defined in this scope // Dummy(TakeOutParam(true, out var x1) && x1) @@ -7760,7 +7760,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,20): error CS0841: Cannot use local variable 'x1' before it is declared // Dummy(x1), @@ -7820,7 +7820,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"10 1 @@ -7882,7 +7882,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"10 1 @@ -7948,7 +7948,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"10 20 @@ -8011,7 +8011,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"10 20 @@ -8076,7 +8076,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"10 20 @@ -8142,7 +8142,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"20 30 @@ -8197,7 +8197,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"10 20 @@ -8347,7 +8347,7 @@ static bool TakeOutParam(bool y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (87,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -8479,7 +8479,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"3 3"); @@ -8619,7 +8619,7 @@ static bool TakeOutParam(bool y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (101,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -8751,7 +8751,7 @@ static bool TakeOutParam(bool y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (20,9): error CS0103: The name 'x1' does not exist in the current context // x1++; @@ -8792,7 +8792,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -8855,7 +8855,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 true @@ -8911,7 +8911,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 3"); @@ -9030,7 +9030,7 @@ static bool TakeOutParam(bool y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (12,27): error CS1002: ; expected // return (o) => let x1 = o; @@ -9088,7 +9088,7 @@ static bool TakeOutParam(bool y, out bool x) Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x12").WithArguments("x12").WithLocation(82, 15) ); - compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_3); + compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_3); compilation.VerifyDiagnostics( // (12,27): error CS1002: ; expected // return (o) => let x1 = o; @@ -9256,7 +9256,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 True"); @@ -9318,7 +9318,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (19,50): error CS0128: A local variable named 'x4' is already defined in this scope // var d = Dummy(TakeOutParam(true, out var x4), x4); @@ -9411,7 +9411,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (19,53): error CS0128: A local variable named 'x4' is already defined in this scope // object d = Dummy(TakeOutParam(true, out var x4), x4); @@ -9488,7 +9488,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,51): error CS0128: A local variable named 'x1' is already defined in this scope // Dummy(TakeOutParam(true, out var x1), x1); @@ -9567,7 +9567,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,16): error CS0128: A local variable named 'x1' is already defined in this scope // x1 = Dummy(x1); @@ -9631,7 +9631,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -9680,7 +9680,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (11,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var d =TakeOutParam(true, out var x1) && x1 != null; @@ -9747,7 +9747,7 @@ public override string ToString() } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"b d @@ -9808,7 +9808,7 @@ public override string ToString() } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"b"); @@ -9873,7 +9873,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (19,51): error CS0128: A local variable named 'x4' is already defined in this scope @@ -9968,7 +9968,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (19,61): error CS0128: A local variable named 'x4' is already defined in this scope @@ -10047,7 +10047,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,51): error CS0128: A local variable named 'x1' is already defined in this scope @@ -10128,7 +10128,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (12,67): error CS0128: A local variable named 'x1' is already defined in this scope @@ -10198,7 +10198,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); @@ -10249,7 +10249,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,9): error CS0103: The name 'x1' does not exist in the current context @@ -10315,7 +10315,7 @@ public override string ToString() } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"b @@ -10378,7 +10378,7 @@ public override string ToString() } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"b"); @@ -10442,7 +10442,7 @@ public override string ToString() } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"b @@ -10526,7 +10526,7 @@ public override string ToString() } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"b @@ -10683,7 +10683,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (87,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -10807,7 +10807,7 @@ static object TakeOutParam(bool y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (17,9): error CS0103: The name 'x1' does not exist in the current context // x1++; @@ -10848,7 +10848,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -10899,7 +10899,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"lock lock @@ -10950,7 +10950,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 3"); @@ -11010,7 +11010,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (8,25): error CS1736: Default parameter value for 'p' must be a compile-time constant // void Test3(bool p = TakeOutParam(3, out int x3) && x3 > 0) @@ -11147,7 +11147,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (8,25): error CS1736: Default parameter value for 'p' must be a compile-time constant // void Test3(bool p = TakeOutParam(3, out var x3) && x3 > 0) @@ -11246,7 +11246,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (10,25): error CS0841: Cannot use local variable 'x4' before it is declared // bool Test4 {get;} = x4 && TakeOutParam(4, out int x4); @@ -11322,11 +11322,11 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 True"); - CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( // (9,52): error CS8320: Feature 'declaration of expression variables in member initializers and queries' is not available in C# 7.2. Please use language version 7.3 or greater. // static bool Test1 {get;} = TakeOutParam(1, out int x1) && Dummy(x1); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "int x1").WithArguments("declaration of expression variables in member initializers and queries", "7.3").WithLocation(9, 52) @@ -11393,7 +11393,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 True"); } @@ -11417,7 +11417,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (8,63): error CS0165: Use of unassigned local variable 'x1' // bool Test1 { get; } = a && TakeOutParam(3, out int x1) || x1 > 0; @@ -11460,7 +11460,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"2 3"); @@ -11615,7 +11615,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (25,26): error CS0103: The name 'z2' does not exist in the current context // z2; @@ -11929,7 +11929,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (18,35): error CS0103: The name 'v4' does not exist in the current context // v4 @@ -12071,7 +12071,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (16,62): error CS0128: A local variable or function named 'y1' is already defined in this scope // var res = from x1 in new[] { TakeOutParam(1, out var y1) ? y1 : 0} @@ -12081,7 +12081,7 @@ static bool TakeOutParam(T y, out T x) Diagnostic(ErrorCode.ERR_LocalDuplicate, "y3").WithArguments("y3").WithLocation(18, 62) ); - compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_3); + compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_3); compilation.VerifyDiagnostics( // (16,62): error CS0128: A local variable or function named 'y1' is already defined in this scope // var res = from x1 in new[] { TakeOutParam(1, out var y1) ? y1 : 0} @@ -12221,7 +12221,7 @@ static bool TakeOutParam(out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (26,62): error CS0128: A local variable or function named 'y1' is already defined in this scope // from x1 in new[] { TakeOutParam(1, out var y1) ? y1 : 0} @@ -12231,7 +12231,7 @@ static bool TakeOutParam(out int x) Diagnostic(ErrorCode.ERR_LocalDuplicate, "y3").WithArguments("y3").WithLocation(28, 62) ); - compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_3); + compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_3); compilation.VerifyDiagnostics( // (26,62): error CS0128: A local variable or function named 'y1' is already defined in this scope // from x1 in new[] { TakeOutParam(1, out var y1) ? y1 : 0} @@ -12341,7 +12341,7 @@ static bool TakeOutParam(out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (18,62): error CS0128: A local variable named 'y3' is already defined in this scope // join x3 in new[] { TakeOutParam(3, out var y3) ? y3 : 0} @@ -12401,7 +12401,7 @@ static bool TakeOutParam(out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (19,24): error CS1931: The range variable 'y1' conflicts with a previous declaration of 'y1' // from y1 in new[] { 1 } @@ -12474,7 +12474,7 @@ static bool TakeOutParam(out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (14,24): error CS1931: The range variable 'y1' conflicts with a previous declaration of 'y1' // var res = from y1 in new[] { 0 } @@ -12619,7 +12619,7 @@ static bool TakeOutParam(out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); // error CS0412 is misleading and reported due to preexisting bug https://github.com/dotnet/roslyn/issues/12052 compilation.VerifyDiagnostics( @@ -12746,7 +12746,7 @@ static bool TakeOutParam(out int x, int y) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (26,60): error CS0128: A local variable or function named 'y2' is already defined in this scope // TakeOutParam(x1 + 1, out var y2)) @@ -12759,7 +12759,7 @@ static bool TakeOutParam(out int x, int y) Diagnostic(ErrorCode.ERR_ImplicitlyTypedOutVariableUsedInTheSameArgumentList, "y4").WithArguments("y4").WithLocation(40, 50) ); - compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_3); + compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_3); compilation.VerifyDiagnostics( // (17,62): error CS0136: A local or parameter named 'y1' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // where TakeOutParam(x1, out var y1) @@ -12844,7 +12844,7 @@ static bool Print(object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics(); CompileAndVerify(compilation, expectedOutput: @@ -12911,7 +12911,7 @@ static bool Print(object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 @@ -12951,7 +12951,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,62): error CS0165: Use of unassigned local variable 'x1' @@ -13009,7 +13009,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"2 @@ -13049,7 +13049,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,46): error CS8198: An expression tree may not contain an out argument variable declaration. @@ -13157,7 +13157,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (14,53): error CS0136: A local or parameter named 'x1' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -13284,7 +13284,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (15,9): error CS0103: The name 'x1' does not exist in the current context @@ -13328,7 +13328,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -13379,7 +13379,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"return"); var tree = compilation.SyntaxTrees.Single(); @@ -13431,7 +13431,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"return 1 return 2"); @@ -13574,7 +13574,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (27,41): error CS0128: A local variable named 'x4' is already defined in this scope // switch (TakeOutParam(4, out var x4) ? x4 : 0) @@ -13686,7 +13686,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (19,15): error CS0103: The name 'x1' does not exist in the current context // Dummy(x1, 1); @@ -13727,7 +13727,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -13786,7 +13786,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"Test1 case 0 Test1 {0} @@ -13838,7 +13838,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 3"); @@ -14068,7 +14068,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (30,31): error CS0841: Cannot use local variable 'x2' before it is declared @@ -14249,7 +14249,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"123").VerifyDiagnostics(); @@ -14296,7 +14296,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"123").VerifyDiagnostics(); @@ -14345,7 +14345,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"123").VerifyDiagnostics(); @@ -14387,7 +14387,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"123").VerifyDiagnostics(); @@ -14429,7 +14429,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"123").VerifyDiagnostics(); @@ -14474,7 +14474,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"123").VerifyDiagnostics(); @@ -14516,7 +14516,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"123").VerifyDiagnostics(); @@ -14559,7 +14559,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"123 @@ -14606,7 +14606,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"123").VerifyDiagnostics( // (14,1): warning CS0164: This label has not been referenced @@ -14660,7 +14660,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"123").VerifyDiagnostics( // (15,17): warning CS0162: Unreachable code detected @@ -14719,7 +14719,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"123").VerifyDiagnostics( // (17,21): warning CS0162: Unreachable code detected @@ -14767,7 +14767,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @@ -14817,7 +14817,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @@ -14913,7 +14913,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (15,64): error CS0128: A local variable named 'x8' is already defined in this scope @@ -15081,7 +15081,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (14,52): error CS0136: A local or parameter named 'x1' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -15204,7 +15204,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (15,9): error CS0103: The name 'x1' does not exist in the current context @@ -15248,7 +15248,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -15305,7 +15305,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"throw"); var tree = compilation.SyntaxTrees.Single(); @@ -15361,7 +15361,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"throw 1 throw 2"); @@ -15493,7 +15493,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (87,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -15706,7 +15706,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (87,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -15919,7 +15919,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (87,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -16052,7 +16052,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (12,58): error CS0128: A local variable named 'x1' is already defined in this scope // using (var x1 = Dummy(TakeOutParam(true, out var x1), x1)) @@ -16142,7 +16142,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,35): error CS0128: A local variable named 'x1' is already defined in this scope // x1 = Dummy(x1)) @@ -16234,7 +16234,7 @@ public override string ToString() } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"a b @@ -16362,7 +16362,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (87,13): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -16485,7 +16485,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (18,9): error CS0103: The name 'x1' does not exist in the current context // x1++; @@ -16526,7 +16526,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -16578,7 +16578,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 1 @@ -16632,7 +16632,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 2 @@ -16689,7 +16689,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 2 @@ -16748,7 +16748,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 2 @@ -16809,7 +16809,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 2 @@ -16924,7 +16924,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (16,59): error CS0136: A local or parameter named 'x1' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -17040,7 +17040,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (15,9): error CS0103: The name 'x1' does not exist in the current context @@ -17085,7 +17085,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -17139,7 +17139,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"yield1 yield2 @@ -17194,7 +17194,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"yield1 yield2"); @@ -17309,7 +17309,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (14,46): error CS0136: A local or parameter named 'x1' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -17471,7 +17471,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (13,1): error CS1023: Embedded statement cannot be a declaration or labeled statement @@ -17521,7 +17521,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -19619,7 +19619,7 @@ static void Test2(object x, System.ArgIterator y) } }"; var compilation = CreateCompilation(text, - targetFramework: TargetFramework.Mscorlib45, + targetFramework: TargetFramework.Mscorlib461, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular12); @@ -19641,7 +19641,7 @@ static void Test2(object x, System.ArgIterator y) Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Test").WithLocation(6, 16) ); - compilation = CreateCompilation(text, targetFramework: TargetFramework.Mscorlib45); + compilation = CreateCompilation(text, targetFramework: TargetFramework.Mscorlib461); compilation.VerifyDiagnostics( // (12,25): error CS1601: Cannot make reference to variable of type 'ArgIterator' @@ -20893,7 +20893,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.WRN_UnreferencedVar @@ -21003,7 +21003,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.WRN_UnreferencedVar @@ -21103,7 +21103,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.WRN_UnreferencedVar, @@ -21200,7 +21200,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.ERR_UnexpectedToken, @@ -21284,7 +21284,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -21336,7 +21336,7 @@ static bool TakeOutParam(object y, out object x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.WRN_UnreferencedVar @@ -21402,7 +21402,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -21561,7 +21561,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.ERR_UnexpectedToken, @@ -21726,7 +21726,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.ERR_UnexpectedToken, @@ -21916,7 +21916,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.ERR_UnexpectedToken, @@ -22068,7 +22068,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.WRN_UnreferencedVar, @@ -22163,7 +22163,7 @@ static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.ERR_UnexpectedToken, @@ -22331,7 +22331,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.ERR_UnexpectedToken, @@ -22497,7 +22497,7 @@ static bool TakeOutParam(object y, out bool x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, (int)ErrorCode.ERR_SyntaxError, (int)ErrorCode.ERR_UnexpectedToken, @@ -22595,7 +22595,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_CStyleArray, (int)ErrorCode.ERR_ArraySizeInDeclaration, (int)ErrorCode.WRN_UnreferencedField @@ -22708,7 +22708,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_CStyleArray, (int)ErrorCode.ERR_ArraySizeInDeclaration, (int)ErrorCode.WRN_UnreferencedField, @@ -22801,7 +22801,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_CStyleArray, (int)ErrorCode.ERR_ArraySizeInDeclaration }; @@ -22883,7 +22883,7 @@ static bool TakeOutParam(object y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_CStyleArray, (int)ErrorCode.ERR_ArraySizeInDeclaration, (int)ErrorCode.ERR_EventNotDelegate, @@ -22947,7 +22947,7 @@ public static void Main() fixed bool d[2], Test3 (out var x3); } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); int[] exclude = new int[] { (int)ErrorCode.ERR_BadVarDecl, }; @@ -22985,7 +22985,7 @@ public static void Main() fixed bool Test3[out var x3]; } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe.WithAllowUnsafe(true), parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (8,22): error CS1003: Syntax error, ',' expected @@ -23133,7 +23133,7 @@ static bool TakeOutParam(object y, out int x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (20,13): error CS0841: Cannot use local variable 'x6' before it is declared // catch when (x6 && TakeOutParam(out var x6)) @@ -23217,7 +23217,7 @@ static bool TakeOutParam(object y, out int x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (14,34): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -23337,7 +23337,7 @@ static bool TakeOutParam(T y, out T x) return true; } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"System.InvalidOperationException System.InvalidOperationException"); @@ -23382,7 +23382,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (15,9): error CS0103: The name 'x3' does not exist in the current context @@ -23409,7 +23409,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (7,8): warning CS0168: The variable 'x2' is declared but never used @@ -23468,7 +23468,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1 @@ -23584,7 +23584,7 @@ static bool TakeOutParam(object y, out bool x) "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (74,5): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -23678,7 +23678,7 @@ static bool TakeOutParam(object y, out bool x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (20,42): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -23804,7 +23804,7 @@ static bool TakeOutParam(int y, out int x) return true; } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"10 1 @@ -23922,7 +23922,7 @@ public static bool TakeOutParam(bool y, out bool x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (52,5): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -24022,7 +24022,7 @@ public static bool TakeOutParam(bool y, out bool x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (15,52): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -24150,7 +24150,7 @@ static bool TakeOutParam(int y, out int x) return true; } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"3 3"); @@ -24221,7 +24221,7 @@ static bool TakeOutParam(bool y, out bool x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,41): error CS0841: Cannot use local variable 'x4' before it is declared // Dummy((System.Func) (o => x4 && TakeOutParam(o, out var x4))); @@ -24311,7 +24311,7 @@ static bool TakeOutParam(bool y, out bool x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,41): error CS0841: Cannot use local variable 'x4' before it is declared @@ -24438,7 +24438,7 @@ static bool TakeOutParam(int y, out int x) return true; } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1 True"); @@ -24469,7 +24469,7 @@ static bool TakeOutParam(int y, out int x) return true; } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1 True"); @@ -24584,7 +24584,7 @@ static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (14,21): error CS0103: The name 'z2' does not exist in the current context // z2; @@ -24836,7 +24836,7 @@ static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (14,21): error CS0103: The name 'z2' does not exist in the current context @@ -25119,7 +25119,7 @@ static bool Print(object x) return true; } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1 @@ -25207,7 +25207,7 @@ static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (52,5): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -25302,7 +25302,7 @@ static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (15,41): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -25448,7 +25448,7 @@ public override string ToString() } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"a b @@ -25493,7 +25493,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,27): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -25540,7 +25540,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,27): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -25618,7 +25618,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,27): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -25665,7 +25665,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,27): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -25734,7 +25734,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -25798,7 +25798,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,31): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -25852,7 +25852,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,31): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -25955,7 +25955,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,31): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -26009,7 +26009,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,31): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -26095,7 +26095,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -26143,7 +26143,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -26196,7 +26196,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,40): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -26255,7 +26255,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): error CS1624: The body of '' cannot be an iterator block because 'void' is not an iterator interface type @@ -26338,7 +26338,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,40): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -26398,7 +26398,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): error CS1624: The body of '' cannot be an iterator block because 'void' is not an iterator interface type @@ -26479,7 +26479,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,34): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -26529,7 +26529,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,8): error CS0029: Cannot implicitly convert type 'bool' to 'int' @@ -26623,7 +26623,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,34): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -26673,7 +26673,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,8): error CS0029: Cannot implicitly convert type 'bool' to 'int' @@ -26763,7 +26763,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -26814,7 +26814,7 @@ public static System.Exception TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,33): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -26864,7 +26864,7 @@ public static System.Exception TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,1): warning CS0162: Unreachable code detected @@ -26944,7 +26944,7 @@ public static System.Exception TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,33): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -26995,7 +26995,7 @@ public static System.Exception TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,1): warning CS0162: Unreachable code detected @@ -27084,7 +27084,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,35): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -27138,7 +27138,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,35): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -27237,7 +27237,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,35): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -27291,7 +27291,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,35): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -27376,7 +27376,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -27434,7 +27434,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -27498,7 +27498,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -27611,7 +27611,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -27675,7 +27675,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -27769,7 +27769,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1").VerifyDiagnostics(); @@ -27824,7 +27824,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -27888,7 +27888,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -28002,7 +28002,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -28066,7 +28066,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -28167,7 +28167,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1 @@ -28226,7 +28226,7 @@ public static object TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,33): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -28280,7 +28280,7 @@ public static object TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,33): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -28377,7 +28377,7 @@ public static object TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,33): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -28431,7 +28431,7 @@ public static object TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,33): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -28514,7 +28514,7 @@ public static object TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -28562,7 +28562,7 @@ public static object TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -28617,7 +28617,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( @@ -28687,7 +28687,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( @@ -28786,7 +28786,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,30): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -28845,7 +28845,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): warning CS0164: This label has not been referenced @@ -28937,7 +28937,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,30): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -28996,7 +28996,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): warning CS0164: This label has not been referenced @@ -29077,7 +29077,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -29141,7 +29141,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,36): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -29208,7 +29208,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): warning CS0164: This label has not been referenced @@ -29317,7 +29317,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,36): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -29384,7 +29384,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): warning CS0164: This label has not been referenced @@ -29479,7 +29479,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -29529,7 +29529,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); CompileAndVerify(compilation, expectedOutput: @"1").VerifyDiagnostics( @@ -29591,7 +29591,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( @@ -29676,7 +29676,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( @@ -29792,7 +29792,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( @@ -29877,7 +29877,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( @@ -29980,7 +29980,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @@ -30048,7 +30048,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,36): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -30115,7 +30115,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (7,36): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -30220,7 +30220,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,36): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -30287,7 +30287,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (7,36): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -30374,7 +30374,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -30427,7 +30427,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"InitA 0 @@ -30468,7 +30468,7 @@ public static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -30512,7 +30512,7 @@ public static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -30557,7 +30557,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 0 @@ -30615,7 +30615,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,45): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -30672,7 +30672,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,6): error CS0116: A namespace cannot directly contain members such as fields or methods @@ -30786,7 +30786,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,45): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -30843,7 +30843,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,6): error CS0116: A namespace cannot directly contain members such as fields or methods @@ -30942,7 +30942,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -30995,7 +30995,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"InitA 0 @@ -31036,7 +31036,7 @@ public static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -31080,7 +31080,7 @@ public static bool TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -31140,7 +31140,7 @@ public static System.Action TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,51): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -31207,7 +31207,7 @@ public static System.Action TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); int[] exclude = new int[] { (int)ErrorCode.ERR_NamespaceUnexpected }; compilation.GetDiagnostics().Where(d => !exclude.Contains(d.Code)).Verify( @@ -31313,7 +31313,7 @@ public static System.Action TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,51): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -31380,7 +31380,7 @@ public static System.Action TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); int[] exclude = new int[] { (int)ErrorCode.ERR_NamespaceUnexpected }; compilation.GetDiagnostics().Where(d => !exclude.Contains(d.Code)).Verify( @@ -31470,7 +31470,7 @@ public static System.Action TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -31523,7 +31523,7 @@ public static System.Action TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"InitA 0 @@ -31564,7 +31564,7 @@ public static System.Action TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -31608,7 +31608,7 @@ public static System.Action TakeOutParam(T y, out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -31653,7 +31653,7 @@ public static System.Action TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 0 @@ -31697,7 +31697,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,10): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) @@ -31725,7 +31725,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,10): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) @@ -31784,7 +31784,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,10): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) @@ -31812,7 +31812,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,10): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) @@ -31877,7 +31877,7 @@ public static bool TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,25): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) @@ -31902,7 +31902,7 @@ public static bool TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,25): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) @@ -31963,7 +31963,7 @@ public static int TakeOutParam(T y, out T x) } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( @@ -31992,7 +31992,7 @@ public static int TakeOutParam(T y, out T x) } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,12): error CS0116: A namespace cannot directly contain members such as fields or methods @@ -32052,7 +32052,7 @@ public static void TakeOutParam(out System.ArgIterator x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.GetDeclarationDiagnostics().Verify( // (9,37): error CS1601: Cannot make reference to variable of type 'ArgIterator' @@ -32096,7 +32096,7 @@ public static void TakeOutParam(out StaticType x) static class StaticType{} "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.GetDeclarationDiagnostics().Verify( // (5,31): error CS0723: Cannot declare a variable of static type 'StaticType' @@ -32136,7 +32136,7 @@ public static void TakeOutParam(out int x, long y) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.GetDeclarationDiagnostics().Verify( // (3,24): error CS7019: Type of 'x1' cannot be inferred since its initializer directly or indirectly refers to the definition. @@ -32176,7 +32176,7 @@ public static int TakeOutParam(out int x, long y) "; // `skipUsesIsNullable: true` is necessary to avoid visiting symbols eagerly in CreateCompilation, // which would result in `ERR_RecursivelyTypedVariable` reported on the other local (field). - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -32216,7 +32216,7 @@ public static int TakeOutParam(out int x, long y) "; // `skipUsesIsNullable: true` is necessary to avoid visiting symbols eagerly in CreateCompilation, // which would result in `ERR_RecursivelyTypedVariable` reported on the other local (field). - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -32256,7 +32256,7 @@ public static int TakeOutParam(out int x, long y) "; // `skipUsesIsNullable: true` is necessary to avoid visiting symbols eagerly in CreateCompilation, // which would result in `ERR_RecursivelyTypedVariable` reported on the other local (field). - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -32275,7 +32275,7 @@ public static int TakeOutParam(out int x, long y) var x1 = (IFieldSymbol)model.GetDeclaredSymbol(x1Decl.VariableDesignation()); Assert.Equal("System.Int32", x1.Type.ToTestDisplayString()); - compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); + compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); tree = compilation.SyntaxTrees.Single(); model = compilation.GetSemanticModel(tree); x1Decl = GetOutVarDeclarations(tree, "x1").Single(); @@ -32311,7 +32311,7 @@ public static int TakeOutParam(out int x, long y) "; // `skipUsesIsNullable: true` is necessary to avoid visiting symbols eagerly in CreateCompilation, // which would result in `ERR_RecursivelyTypedVariable` reported on the other local (field). - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -32328,7 +32328,7 @@ public static int TakeOutParam(out int x, long y) Diagnostic(ErrorCode.ERR_RecursivelyTypedVariable, "x1").WithArguments("x1").WithLocation(3, 32) ); - compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); + compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script, skipUsesIsNullable: true); tree = compilation.SyntaxTrees.Single(); model = compilation.GetSemanticModel(tree); @@ -32365,7 +32365,7 @@ public static int TakeOutParam(out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (2,24): error CS8197: Cannot infer the type of implicitly-typed out variable 'x1'. @@ -32405,7 +32405,7 @@ class H public static void M(object a) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (2,10): error CS7019: Type of 'x1' cannot be inferred since its initializer directly or indirectly refers to the definition. // H.M((var x1, int x2)); @@ -32493,7 +32493,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -32521,7 +32521,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -32549,7 +32549,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -32575,7 +32575,7 @@ public static bool TakeOutParam(T y, out T x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -32607,7 +32607,7 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); // The point of this test is that it should not crash. compilation.VerifyDiagnostics( // (8,18): error CS9135: A constant value of type 'bool' is expected @@ -32640,7 +32640,7 @@ static void Main(string[] args) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); // The point of this test is that it should not crash. compilation.VerifyDiagnostics( // (8,19): error CS0103: The name 'TakeOutParam' does not exist in the current context @@ -32781,7 +32781,7 @@ static void TakeOutParam(out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"System.Int32 System.Int64"); @@ -32805,7 +32805,7 @@ static void TakeOutParam(out T x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (6,9): error CS0411: The type arguments for method 'X.TakeOutParam(out T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // TakeOutParam(out var a); @@ -32834,7 +32834,7 @@ static void TakeOutParam(out T x, T y) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (7,9): error CS0411: The type arguments for method 'X.TakeOutParam(out T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. // TakeOutParam(out int b, a); @@ -32867,7 +32867,7 @@ static void TakeOutParam(out T x, T y) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"System.Int32 System.Int32"); @@ -33425,7 +33425,7 @@ public static class S { public static void M2(this A self, out B x) { x = null; } }"; - var comp = CreateCompilationWithMscorlib40(source, options: TestOptions.DebugDll, references: new[] { Net40.SystemCore }); + var comp = CreateCompilationWithMscorlib40(source, options: TestOptions.DebugDll, references: new[] { Net40.References.SystemCore }); comp.VerifyDiagnostics( // (7,18): error CS1503: Argument 2: cannot convert from 'out A' to 'out B' // a.M2(out A x); @@ -33482,7 +33482,7 @@ public static void Main(string[] args) static int M(out int z) => z = 1; static int M(int a, int b) => a+b; }"; - var comp = CreateCompilationWithMscorlib45(text); + var comp = CreateCompilationWithMscorlib461(text); comp.VerifyDiagnostics( // (10,29): error CS0128: A local variable or function named 'x1' is already defined in this scope // M(M(out int x1), x1); @@ -33524,7 +33524,7 @@ public static void Main(int arg) "; // the scope of an expression variable introduced in the default expression // of a local function parameter is that default expression. - var compilation = CreateCompilationWithMscorlib45(text); + var compilation = CreateCompilationWithMscorlib461(text); compilation.VerifyDiagnostics( // (6,75): error CS0103: The name 'z1' does not exist in the current context // void Local2(bool b = M(M(out int z1), z1), int s2 = z1) { var t = z1; } @@ -33601,7 +33601,7 @@ public static void Main(int arg) "; // the scope of an expression variable introduced in the default expression // of a lambda parameter is that default expression. - var compilation = CreateCompilationWithMscorlib45(text); + var compilation = CreateCompilationWithMscorlib461(text); compilation.GetDiagnostics().Verify( // (7,56): error CS1065: Default values are not valid in this context. // bool b = M(M(out int z1), z1), @@ -33709,7 +33709,7 @@ class Test : System.Attribute public bool p2 {get; set;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); compilation.GetDiagnostics().Where(d => d.Code != (int)ErrorCode.ERR_BadAttributeArgument).Verify( // (18,19): error CS0103: The name 'x7' does not exist in the current context // Dummy(x7, p1); @@ -33807,7 +33807,7 @@ public Test(bool p) {} public Test(bool p1, bool p2) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); compilation.GetDiagnostics().Where(d => d.Code != (int)ErrorCode.ERR_BadAttributeArgument).Verify( // (18,19): error CS0103: The name 'x7' does not exist in the current context // Dummy(x7, p1); @@ -33906,7 +33906,7 @@ class Test : System.Attribute public bool p2 {get; set;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); compilation.GetDiagnostics().Where(d => d.Code != (int)ErrorCode.ERR_BadAttributeArgument).Verify( // (18,19): error CS0103: The name 'x7' does not exist in the current context // Dummy(x7, p1); @@ -34004,7 +34004,7 @@ public Test(bool p) {} public Test(bool p1, bool p2) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); compilation.GetDiagnostics().Where(d => d.Code != (int)ErrorCode.ERR_BadAttributeArgument).Verify( // (18,19): error CS0103: The name 'x7' does not exist in the current context // Dummy(x7, p1); @@ -34089,7 +34089,7 @@ class Test : System.Attribute public bool p {get; set;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); compilation.GetDiagnostics().Where(d => d.Code != (int)ErrorCode.ERR_BadAttributeArgument).Verify( // (10,44): error CS0136: A local or parameter named 'x2' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // [Test(p = TakeOutParam(out int x2) && x1 > 0 && x2 > 0)] @@ -34145,7 +34145,7 @@ class Test : System.Attribute public Test(bool p) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); compilation.GetDiagnostics().Where(d => d.Code != (int)ErrorCode.ERR_BadAttributeArgument).Verify( // (10,40): error CS0136: A local or parameter named 'x2' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // [Test(TakeOutParam(out int x2) && x1 > 0 && x2 > 0)] @@ -34698,7 +34698,7 @@ public static void Main() static int M2(int a, int b) => 2; } "; - var compilation = CreateCompilationWithMscorlib45(text); + var compilation = CreateCompilationWithMscorlib461(text); compilation.VerifyDiagnostics( // (6,24): error CS8081: Expression does not have a name. // var x = nameof(M2(M1(out var x1), x1)).ToString(); @@ -34735,7 +34735,7 @@ public static void Main(int arg) "; // the scope of an expression variable introduced in the default expression // of a local function parameter is that default expression. - var compilation = CreateCompilationWithMscorlib45(text); + var compilation = CreateCompilationWithMscorlib461(text); compilation.VerifyDiagnostics( // (6,83): error CS0103: The name 'z1' does not exist in the current context // void Local2(bool b = M(nameof(M(out int z1)), z1), int s2 = z1) { var t = z1; } @@ -34814,7 +34814,7 @@ class MyAttribute: System.Attribute public MyAttribute(bool x, int y) {} } "; - var compilation = CreateCompilationWithMscorlib45(text); + var compilation = CreateCompilationWithMscorlib461(text); compilation.VerifyDiagnostics( // (2,16): error CS8081: Expression does not have a name. // [My(C.M(nameof(C.M(out int z1)), z1), z1)] @@ -34868,7 +34868,7 @@ class MyAttribute: System.Attribute public MyAttribute(bool x, int y) {} } "; - var compilation = CreateCompilationWithMscorlib45(new[] { text1, text2 }); + var compilation = CreateCompilationWithMscorlib461(new[] { text1, text2 }); compilation.VerifyDiagnostics( // (2,26): error CS8081: Expression does not have a name. // [assembly: My(C.M(nameof(C.M(out int z1)), z1), z1)] @@ -34926,7 +34926,7 @@ public static void Main(string[] args) public static bool M(object a, int b) => b == 0; } "; - var compilation = CreateCompilationWithMscorlib45(text); + var compilation = CreateCompilationWithMscorlib461(text); compilation.VerifyDiagnostics( // (8,28): error CS8081: Expression does not have a name. // case !M(nameof(M(out int z1)), z1): @@ -34976,7 +34976,7 @@ class C public static bool M(object a, int b) => b == 0; } "; - var compilation = CreateCompilationWithMscorlib45(text); + var compilation = CreateCompilationWithMscorlib461(text); compilation.VerifyDiagnostics( // (5,29): error CS8081: Expression does not have a name. // const bool b = M(nameof(M(out var z2)), z2); @@ -35030,7 +35030,7 @@ public static void Main(string[] args) public static bool M(object a, int b) => b == 0; } "; - var compilation = CreateCompilationWithMscorlib45(text); + var compilation = CreateCompilationWithMscorlib461(text); compilation.VerifyDiagnostics( // (6,33): error CS8081: Expression does not have a name. // const bool a = M(nameof(M(out int z1)), z1); @@ -35082,7 +35082,7 @@ public static void Main(string[] args) public static bool M(object a, int b) => b == 0; } "; - var compilation = CreateCompilationWithMscorlib45(text); + var compilation = CreateCompilationWithMscorlib461(text); compilation.VerifyDiagnostics( // (6,27): error CS8081: Expression does not have a name. // string s = nameof((System.Action)(() => M(M(out var z1), z1))).ToString(); @@ -35898,11 +35898,11 @@ static bool TakeOutParam(int y, out int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); CompileAndVerify(compilation, expectedOutput: @"1 True"); - CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( // (9,76): error CS8320: Feature 'declaration of expression variables in member initializers and queries' is not available in C# 7.2. Please use language version 7.3 or greater. // static event System.Func Test1 = GetDelegate(TakeOutParam(1, out int x1) && Dummy(x1)); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "int x1").WithArguments("declaration of expression variables in member initializers and queries", "7.3").WithLocation(9, 76) diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/ParamsCollectionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ParamsCollectionTests.cs similarity index 90% rename from src/Compilers/CSharp/Test/Emit2/Semantics/ParamsCollectionTests.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/ParamsCollectionTests.cs index f5ae6ed8879c7..c90bf7d92467c 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/ParamsCollectionTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ParamsCollectionTests.cs @@ -3084,6 +3084,48 @@ .locals init (<>y__InlineArray2 V_0, "); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74733")] + public void InterpolatedString() + { + var source = """ + using System; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + + C.M("xyz"); + + [InterpolatedStringHandler] + public class C + { + public C(int literalLength, int formattedCount) + { + Console.WriteLine($"literal:{literalLength}, formatted:{formattedCount}"); + } + + public void AppendLiteral(params List s) + { + Console.WriteLine($"append:'{(string.Join(",", s))}'"); + } + + public void AppendFormatted(string s) + { + Console.WriteLine($"formatted:'{s}'"); + } + + public static void M(string s) + { + C c = $"abc {s} def"; + } + } + """; + CompileAndVerify([source, InterpolatedStringHandlerAttribute], expectedOutput: """ + literal:8, formatted:1 + append:'abc ' + formatted:'xyz' + append:' def' + """).VerifyDiagnostics(); + } + [Fact] public void OrderOfEvaluation_01_NamedArguments() { @@ -5066,8 +5108,8 @@ static string[] getSources(string source, string[] additionalSources) [Theory] [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "System.Span", null)] + [InlineData("System.ReadOnlySpan", "System.Span", null)] [InlineData("System.ReadOnlySpan", "System.Span", null)] // cannot convert object to int [InlineData("System.ReadOnlySpan", "System.Span", null)] // cannot convert int? to int [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", null)] @@ -5077,24 +5119,24 @@ static string[] getSources(string source, string[] additionalSources) [InlineData("System.Span", "System.Span", null)] [InlineData("System.Span", "System.Span", null)] [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", null)] - [InlineData("System.Span", "int?[]", "System.Span")] - [InlineData("System.Span", "System.Collections.Generic.IEnumerable", "System.Span")] - [InlineData("System.Span", "System.Collections.Generic.IReadOnlyCollection", "System.Span")] - [InlineData("System.Span", "System.Collections.Generic.IReadOnlyList", "System.Span")] - [InlineData("System.Span", "System.Collections.Generic.ICollection", "System.Span")] - [InlineData("System.Span", "System.Collections.Generic.IList", "System.Span")] + [InlineData("System.Span", "int?[]", null)] + [InlineData("System.Span", "System.Collections.Generic.IEnumerable", null)] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyCollection", null)] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyList", null)] + [InlineData("System.Span", "System.Collections.Generic.ICollection", null)] + [InlineData("System.Span", "System.Collections.Generic.IList", null)] [InlineData("System.Span", "int[]", null)] // cannot convert int? to int [InlineData("System.Span", "System.Collections.Generic.IEnumerable", null)] // cannot convert int? to int [InlineData("System.Span", "System.Collections.Generic.IReadOnlyCollection", null)] // cannot convert int? to int [InlineData("System.Span", "System.Collections.Generic.IReadOnlyList", null)] // cannot convert int? to int [InlineData("System.Span", "System.Collections.Generic.ICollection", null)] // cannot convert int? to int [InlineData("System.Span", "System.Collections.Generic.IList", null)] // cannot convert int? to int - [InlineData("System.ReadOnlySpan", "object[]", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyCollection", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyList", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.ICollection", "System.ReadOnlySpan")] - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IList", "System.ReadOnlySpan")] + [InlineData("System.ReadOnlySpan", "object[]", null)] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", null)] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyCollection", null)] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyList", null)] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.ICollection", null)] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IList", null)] [InlineData("System.ReadOnlySpan", "int[]", null)] // cannot convert object to int [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", null)] // cannot convert object to int [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyCollection", null)] // cannot convert object to int @@ -5104,6 +5146,16 @@ static string[] getSources(string source, string[] additionalSources) [InlineData("System.Collections.Generic.List", "System.Collections.Generic.IEnumerable", "System.Collections.Generic.List")] [InlineData("int[]", "object[]", null)] // rule requires span [InlineData("int[]", "System.Collections.Generic.IReadOnlyList", null)] // rule requires span + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.IEnumerable", "System.Collections.Generic.List", null)] + [InlineData("int[]", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.HashSet", "System.Span", null)] + [InlineData("System.Collections.Generic.HashSet", "System.ReadOnlySpan", null)] + [InlineData("System.Collections.Generic.HashSet", "System.Span", null)] + [InlineData("System.Collections.Generic.HashSet", "System.ReadOnlySpan", null)] public void BetterConversionFromExpression_01B_Empty(string type1, string type2, string expectedType) // This is a clone of a unit-test from CollectionExpressionTests.cs { string source = $$""" @@ -5156,24 +5208,14 @@ static string generateMethodSignature(string methodName, string parameterType) = [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] [InlineData("System.ReadOnlySpan", "System.Span", "System.ReadOnlySpan")] - - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'object' in params case - [InlineData("System.ReadOnlySpan", "System.Span", "System.Span")] // cannot convert object to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'int?' in params case - [InlineData("System.ReadOnlySpan", "System.Span", "System.Span")] // cannot convert int? to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'object' in params case + [InlineData("System.ReadOnlySpan", "System.Span", "System.Span")] + [InlineData("System.ReadOnlySpan", "System.Span", "System.Span")] [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan")] - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'int?' in params case [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan")] - // Ambiguous for inline collection expression, but 'int?' is a better conversion target than 'object' in params case [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan>")] - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'object' in params case [InlineData("System.Span", "System.Span", "System.Span")] - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'int?' in params case [InlineData("System.Span", "System.Span", "System.Span")] - // Ambiguous for inline collection expression, but 'int?' is a better conversion target than 'object' in params case [InlineData("System.Span", "System.Span", "System.Span>")] - // Ambiguous for inline collection expression, but 'long' is a better conversion target than 'object' in params case [InlineData("System.ReadOnlySpan", "System.ReadOnlySpan", "System.ReadOnlySpan")] [InlineData("System.Span", "int?[]", "System.Span")] @@ -5183,18 +5225,12 @@ static string generateMethodSignature(string methodName, string parameterType) = [InlineData("System.Span", "System.Collections.Generic.ICollection", "System.Span")] [InlineData("System.Span", "System.Collections.Generic.IList", "System.Span")] - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'int?' in params case [InlineData("System.Span", "int[]", "System.Int32[]")] // cannot convert int? to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'int?' in params case - [InlineData("System.Span", "System.Collections.Generic.IEnumerable", "System.Collections.Generic.IEnumerable")] // cannot convert int? to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'int?' in params case - [InlineData("System.Span", "System.Collections.Generic.IReadOnlyCollection", "System.Collections.Generic.IReadOnlyCollection")] // cannot convert int? to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'int?' in params case - [InlineData("System.Span", "System.Collections.Generic.IReadOnlyList", "System.Collections.Generic.IReadOnlyList")] // cannot convert int? to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'int?' in params case - [InlineData("System.Span", "System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection")] // cannot convert int? to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'int?' in params case - [InlineData("System.Span", "System.Collections.Generic.IList", "System.Collections.Generic.IList")] // cannot convert int? to int + [InlineData("System.Span", "System.Collections.Generic.IEnumerable", "System.Collections.Generic.IEnumerable")] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyCollection", "System.Collections.Generic.IReadOnlyCollection")] + [InlineData("System.Span", "System.Collections.Generic.IReadOnlyList", "System.Collections.Generic.IReadOnlyList")] + [InlineData("System.Span", "System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection")] + [InlineData("System.Span", "System.Collections.Generic.IList", "System.Collections.Generic.IList")] [InlineData("System.ReadOnlySpan", "object[]", "System.ReadOnlySpan")] [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", "System.ReadOnlySpan")] @@ -5203,25 +5239,28 @@ static string generateMethodSignature(string methodName, string parameterType) = [InlineData("System.ReadOnlySpan", "System.Collections.Generic.ICollection", "System.ReadOnlySpan")] [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IList", "System.ReadOnlySpan")] - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'object' in params case - [InlineData("System.ReadOnlySpan", "int[]", "System.Int32[]")] // cannot convert object to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'object' in params case - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", "System.Collections.Generic.IEnumerable")] // cannot convert object to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'object' in params case - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyCollection", "System.Collections.Generic.IReadOnlyCollection")] // cannot convert object to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'object' in params case - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyList", "System.Collections.Generic.IReadOnlyList")] // cannot convert object to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'object' in params case - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection")] // cannot convert object to int - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'object' in params case - [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IList", "System.Collections.Generic.IList")] // cannot convert object to int + [InlineData("System.ReadOnlySpan", "int[]", "System.Int32[]")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IEnumerable", "System.Collections.Generic.IEnumerable")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyCollection", "System.Collections.Generic.IReadOnlyCollection")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IReadOnlyList", "System.Collections.Generic.IReadOnlyList")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.ICollection", "System.Collections.Generic.ICollection")] + [InlineData("System.ReadOnlySpan", "System.Collections.Generic.IList", "System.Collections.Generic.IList")] [InlineData("System.Collections.Generic.List", "System.Collections.Generic.IEnumerable", "System.Collections.Generic.List")] - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'object' in params case - [InlineData("int[]", "object[]", "System.Int32[]")] // rule requires span - // Ambiguous for inline collection expression, but 'int' is a better conversion target than 'object' in params case - [InlineData("int[]", "System.Collections.Generic.IReadOnlyList", "System.Int32[]")] // rule requires span + [InlineData("int[]", "object[]", "System.Int32[]")] + [InlineData("int[]", "System.Collections.Generic.IReadOnlyList", "System.Int32[]")] + + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", "System.Collections.Generic.List")] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", null)] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", "System.Collections.Generic.List>")] + [InlineData("System.Collections.Generic.List", "System.Collections.Generic.List", "System.Collections.Generic.List")] + [InlineData("System.Collections.Generic.IEnumerable", "System.Collections.Generic.List", "System.Collections.Generic.IEnumerable")] + [InlineData("int[]", "System.Collections.Generic.List", "System.Int32[]")] + [InlineData("System.Collections.Generic.HashSet", "System.Span", "System.Collections.Generic.HashSet")] + [InlineData("System.Collections.Generic.HashSet", "System.ReadOnlySpan", "System.Collections.Generic.HashSet")] + [InlineData("System.Collections.Generic.HashSet", "System.Span", "System.Span")] + [InlineData("System.Collections.Generic.HashSet", "System.ReadOnlySpan", "System.ReadOnlySpan")] public void BetterConversionFromExpression_01B_NotEmpty(string type1, string type2, string expectedType) // This is a clone of a unit-test from CollectionExpressionTests.cs { string source = $$""" @@ -5270,6 +5309,104 @@ static string generateMethodSignature(string methodName, string parameterType) = $"Program.{methodName}(params {parameterType})"; } + [Theory, CombinatorialData] + public void BetterConversionFromExpression_01C( + [CombinatorialValues( + "System.ReadOnlySpan", + "System.Span", + "string[]", + "System.Collections.Generic.IEnumerable", + "System.Collections.Generic.IReadOnlyList", + "System.Collections.Generic.IReadOnlyCollection", + "System.Collections.Generic.IList", + "System.Collections.Generic.ICollection" + )] + string stringType, + [CombinatorialValues( + "System.ReadOnlySpan", + "System.Span", + "CustomHandler[]", + "System.Collections.Generic.IEnumerable", + "System.Collections.Generic.IReadOnlyList", + "System.Collections.Generic.IReadOnlyCollection", + "System.Collections.Generic.IList", + "System.Collections.Generic.ICollection")] + string interpolatedType) // This is a clone of a unit-test from CollectionExpressionTests.cs + { + var testMethods = $$""" + partial class Program + { + {{generateMethod("F1", stringType)}} + {{generateMethod("F1", interpolatedType)}} + {{generateMethod("F2", interpolatedType)}} + {{generateMethod("F2", stringType)}} + } + """; + + var customHandler = GetInterpolatedStringCustomHandlerType("CustomHandler", "class", useBoolReturns: false, includeOneTimeHelpers: false); + + string source1 = $$""" + var a = F1(); + var b = F2(); + var c = F1($"{1}", $"2", $"{3}"); + var d = F2($"{1}", $"2", $"{3}"); + """; + var comp = CreateCompilation( + [source1, testMethods, customHandler, CollectionExpressionTests.s_collectionExtensions], + targetFramework: TargetFramework.Net80, + options: TestOptions.ReleaseExe); + + string f1InterpolatedSig = generateMethodSignature("F1", interpolatedType); + string f1StringSig = generateMethodSignature("F1", stringType); + string f2InterpolatedSig = generateMethodSignature("F2", interpolatedType); + string f2StringSig = generateMethodSignature("F2", stringType); + comp.VerifyDiagnostics( + // (1,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(IReadOnlyList)' and 'Program.F1(IReadOnlyCollection)' + // var a = F1(); + Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments(f1StringSig, f1InterpolatedSig).WithLocation(1, 9), + // (2,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(IReadOnlyCollection)' and 'Program.F2(IReadOnlyList)' + // var b = F2(); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments(f2InterpolatedSig, f2StringSig).WithLocation(2, 9), + // (3,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(string[])' and 'Program.F1(CustomHandler[])' + // var c = F1($"{1}", $"2", $"{3}"); + Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments(f1StringSig, f1InterpolatedSig).WithLocation(3, 9), + // (4,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(CustomHandler[])' and 'Program.F2(string[])' + // var d = F2($"{1}", $"2", $"{3}"); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments(f2InterpolatedSig, f2StringSig).WithLocation(4, 9) + ); + + var source2 = $$""" + using System; + var c = F1($"{1}", $"{2}", $"{3}"); + Console.WriteLine(c.GetTypeName()); + var d = F2($"{1}", $"{2}", $"{3}"); + Console.WriteLine(d.GetTypeName()); + var e = F1([$"1", $"2", $"3"]); + Console.WriteLine(e.GetTypeName()); + var f = F2([$"1", $"2", $"3"]); + Console.WriteLine(f.GetTypeName()); + """; + + comp = CreateCompilation( + [source2, testMethods, customHandler, CollectionExpressionTests.s_collectionExtensions], + targetFramework: TargetFramework.Net80, + options: TestOptions.ReleaseExe); + + string outputStringType = stringType.Replace("string", "System.String"); + CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: ExpectedOutput($""" + {interpolatedType} + {interpolatedType} + {outputStringType} + {outputStringType} + """)); + + static string generateMethod(string methodName, string parameterType) => + $"static System.Type {methodName}(params {parameterType} value) => typeof({parameterType});"; + + static string generateMethodSignature(string methodName, string parameterType) => + $"Program.{methodName}(params {parameterType})"; + } + [Fact] public void BetterConversionFromExpression_02() // This is a clone of a unit-test from CollectionExpressionTests.cs { @@ -5409,25 +5546,11 @@ static void Main() } } """; + + // Both calls are ambiguous for collection expressions due to different betterness among arguments. CreateCompilation( new[] { source, CollectionExpressionTests.s_collectionExtensionsWithSpan }, targetFramework: TargetFramework.Net80).VerifyDiagnostics( - // Inline collection expression works in this case. - // For 'params' case it fails because: - // - For the first argument, 'int[]' and 'Span' -> neither is better - // - For the second argument, 'int' and 'int' -> neither is better vs. 'int[]' and 'ReadOnlySpan' -> ReadOnlySpan for a collection expression - // Parameters type sequences are different, tie-breaking rules do not apply. - - // 0.cs(10,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(int[], params int[])' and 'Program.F1(Span, params ReadOnlySpan)' - // F1([1], 2); - Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments("Program.F1(int[], params int[])", "Program.F1(System.Span, params System.ReadOnlySpan)").WithLocation(10, 9), - - // Inline collection expression works in this case. - // For 'params' case it fails because: - // - For the first argument, 'object' and 'string' -> string - // - For the second argument, 'string' and 'object' -> string (different direction) vs. 'string[]' and 'Span' -> neither is better for a collection expression - // Parameters type sequences are different, tie-breaking rules do not apply. - // 0.cs(11,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(object, params string[])' and 'Program.F2(string, params Span)' // F2("3", "4"); Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments("Program.F2(object, params string[])", "Program.F2(string, params System.Span)").WithLocation(11, 9) @@ -5600,6 +5723,95 @@ static void Main() CompileAndVerify(source, expectedOutput: "string[]"); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73857")] + public void BetterConversionFromExpression_08C() // This is a clone of a unit-test from CollectionExpressionTests.cs + { + string source = """ + using System; + class Program + { + static void F2(params ReadOnlySpan value) { Console.WriteLine("ReadOnlySpan"); } + static void F2(params ReadOnlySpan value) { Console.WriteLine("ReadOnlySpan"); } + static void Main() + { + F2("a", "b"); + } + } + """; + CompileAndVerify(source, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: ExpectedOutput("ReadOnlySpan")); + } + + [Fact] + public void BetterConversionFromExpression_09() // This is a clone of a unit-test from CollectionExpressionTests.cs + { + string source = """ + using System; + using System.Collections.Generic; + class Program + { + static void F2(params List value) { Console.WriteLine("List"); } + static void F2(params List value) { Console.WriteLine("List"); } + static void Main() + { + F2(1, (byte)2); + } + } + """; + + CreateCompilation(source).VerifyDiagnostics( + // (9,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(List)' and 'Program.F2(List)' + // F2([1, (byte)2]); + Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments("Program.F2(params System.Collections.Generic.List)", "Program.F2(params System.Collections.Generic.List)").WithLocation(9, 9)); + } + + [Fact] + public void BetterConversionFromExpression_10() // This is a clone of a unit-test from CollectionExpressionTests.cs + { + string source = """ + using System; + using System.Collections.Generic; + class Program + { + static void F2(params List value) { Console.WriteLine("List"); } + static void F2(params List value) { Console.WriteLine("List"); } + static void Main() + { + F2((byte)1, (byte)2); + } + } + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: "List"); + } + + [Theory] + [InlineData("System.FormattableString")] + [InlineData("System.IFormattable")] + public void BetterConversionFromExpression_11(string formatType) // This is a clone of a unit-test from CollectionExpressionTests.cs + { + string source = $$""" + using System; + class Program + { + static void F2(params ReadOnlySpan value) { Console.WriteLine("ReadOnlySpan"); } + static void F2(params ReadOnlySpan<{{formatType}}> value) { Console.WriteLine("ReadOnlySpan<{{formatType}}>"); } + static void Main() + { + F2($"{1}"); + } + } + """; + + CompileAndVerify(source, + parseOptions: TestOptions.Regular13, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: ExpectedOutput("ReadOnlySpan")); + } + [Theory] [InlineData("System.ReadOnlySpan")] [InlineData("System.Span")] @@ -14319,6 +14531,520 @@ static void Test(params CollectionBuilderAttribute a) ); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_16() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + public class Base : IEnumerable + { + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + } + + public class MyCollection1 : Base + { + public void Add(params MyCollection1 c) {} + } + + public class C + { + /**/ + MyCollection1 M() => [1]; + /**/ + } + """; + var comp = CreateCompilation(source).VerifyEmitDiagnostics( + // (18,27): error CS9222: Collection initializer results in an infinite chain of instantiations of collection 'MyCollection1'. + // MyCollection1 M() => [1]; + Diagnostic(ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls, "1").WithArguments("MyCollection1").WithLocation(18, 27)); + + VerifyFlowGraphForTest(comp, """ + Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Block[B1] - Block + Predecessors: [B0] + Statements (0) + Next (Return) Block[B2] + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: MyCollection1, IsInvalid, IsImplicit) (Syntax: '[1]') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + (CollectionExpression) + Operand: + ICollectionExpressionOperation (1 elements, ConstructMethod: MyCollection1..ctor()) (OperationKind.CollectionExpression, Type: MyCollection1, IsInvalid) (Syntax: '[1]') + Elements(1): + IInvocationOperation ( void MyCollection1.Add(params MyCollection1 c)) (OperationKind.Invocation, Type: System.Void, IsInvalid, IsImplicit) (Syntax: '1') + Instance Receiver: + IInvalidOperation (OperationKind.Invalid, Type: MyCollection1, IsInvalid, IsImplicit) (Syntax: '1') + Children(0) + Arguments(1): + IArgumentOperation (ArgumentKind.ParamCollection, Matching Parameter: c) (OperationKind.Argument, Type: null, IsInvalid, IsImplicit) (Syntax: '1') + ICollectionExpressionOperation (1 elements, ConstructMethod: null) (OperationKind.CollectionExpression, Type: MyCollection1, IsInvalid, IsImplicit) (Syntax: '1') + Elements(1): + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Block[B2] - Exit + Predecessors: [B1] + Statements (0) + """); + + VerifyOperationTreeForTest(comp, """ + IMethodBodyOperation (OperationKind.MethodBody, Type: null, IsInvalid) (Syntax: 'MyCollectio ... M() => [1];') + BlockBody: + null + ExpressionBody: + IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '=> [1]') + IReturnOperation (OperationKind.Return, Type: null, IsInvalid, IsImplicit) (Syntax: '[1]') + ReturnedValue: + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: MyCollection1, IsInvalid, IsImplicit) (Syntax: '[1]') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ICollectionExpressionOperation (1 elements, ConstructMethod: MyCollection1..ctor()) (OperationKind.CollectionExpression, Type: MyCollection1, IsInvalid) (Syntax: '[1]') + Elements(1): + IInvocationOperation ( void MyCollection1.Add(params MyCollection1 c)) (OperationKind.Invocation, Type: System.Void, IsInvalid, IsImplicit) (Syntax: '1') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: MyCollection1, IsInvalid, IsImplicit) (Syntax: '1') + Arguments(1): + IArgumentOperation (ArgumentKind.ParamCollection, Matching Parameter: c) (OperationKind.Argument, Type: null, IsInvalid, IsImplicit) (Syntax: '1') + ICollectionExpressionOperation (1 elements, ConstructMethod: null) (OperationKind.CollectionExpression, Type: MyCollection1, IsInvalid, IsImplicit) (Syntax: '1') + Elements(1): + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_17() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + public class Base : IEnumerable + { + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + } + + public class MyCollection1 : Base + { + public void Add(params MyCollection2 c) {} + } + + public class MyCollection2 : Base + { + public void Add(params MyCollection1 c) { } + } + + public class C + { + /**/ + MyCollection1 M() => [1]; + /**/ + } + """; + var comp = CreateCompilation(source).VerifyEmitDiagnostics( + // (23,27): error CS9222: Collection initializer results in an infinite chain of instantiations of collection 'MyCollection2'. + // MyCollection1 M() => [1]; + Diagnostic(ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls, "1").WithArguments("MyCollection2").WithLocation(23, 27)); + + VerifyFlowGraphForTest(comp, """ + Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Block[B1] - Block + Predecessors: [B0] + Statements (0) + Next (Return) Block[B2] + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: MyCollection1, IsInvalid, IsImplicit) (Syntax: '[1]') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + (CollectionExpression) + Operand: + ICollectionExpressionOperation (1 elements, ConstructMethod: MyCollection1..ctor()) (OperationKind.CollectionExpression, Type: MyCollection1, IsInvalid) (Syntax: '[1]') + Elements(1): + IInvocationOperation ( void MyCollection2.Add(params MyCollection1 c)) (OperationKind.Invocation, Type: System.Void, IsInvalid, IsImplicit) (Syntax: '1') + Instance Receiver: + IInvalidOperation (OperationKind.Invalid, Type: MyCollection2, IsInvalid, IsImplicit) (Syntax: '1') + Children(0) + Arguments(1): + IArgumentOperation (ArgumentKind.ParamCollection, Matching Parameter: c) (OperationKind.Argument, Type: null, IsInvalid, IsImplicit) (Syntax: '1') + ICollectionExpressionOperation (1 elements, ConstructMethod: MyCollection1..ctor()) (OperationKind.CollectionExpression, Type: MyCollection1, IsInvalid, IsImplicit) (Syntax: '1') + Elements(1): + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Block[B2] - Exit + Predecessors: [B1] + Statements (0) + """); + + VerifyOperationTreeForTest(comp, """ + IMethodBodyOperation (OperationKind.MethodBody, Type: null, IsInvalid) (Syntax: 'MyCollectio ... M() => [1];') + BlockBody: + null + ExpressionBody: + IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsInvalid) (Syntax: '=> [1]') + IReturnOperation (OperationKind.Return, Type: null, IsInvalid, IsImplicit) (Syntax: '[1]') + ReturnedValue: + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: MyCollection1, IsInvalid, IsImplicit) (Syntax: '[1]') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ICollectionExpressionOperation (1 elements, ConstructMethod: MyCollection1..ctor()) (OperationKind.CollectionExpression, Type: MyCollection1, IsInvalid) (Syntax: '[1]') + Elements(1): + IInvocationOperation ( void MyCollection2.Add(params MyCollection1 c)) (OperationKind.Invocation, Type: System.Void, IsInvalid, IsImplicit) (Syntax: '1') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: MyCollection2, IsInvalid, IsImplicit) (Syntax: '1') + Arguments(1): + IArgumentOperation (ArgumentKind.ParamCollection, Matching Parameter: c) (OperationKind.Argument, Type: null, IsInvalid, IsImplicit) (Syntax: '1') + ICollectionExpressionOperation (1 elements, ConstructMethod: MyCollection1..ctor()) (OperationKind.CollectionExpression, Type: MyCollection1, IsInvalid, IsImplicit) (Syntax: '1') + Elements(1): + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1, IsInvalid) (Syntax: '1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_18() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + public class Base : IEnumerable + { + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + } + + public class MyCollection1 : Base + { + public void Add(params MyCollection1 c) {} + } + + public class C + { + MyCollection1 M() => new() { 1 }; + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (17,34): error CS9222: Collection initializer results in an infinite chain of instantiations of collection 'MyCollection1'. + // MyCollection1 M() => new() { 1 }; + Diagnostic(ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls, "1").WithArguments("MyCollection1").WithLocation(17, 34)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_19() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + public class Base : IEnumerable + { + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + } + + public class MyCollection1 : Base + { + public void Add(params MyCollection2 c) {} + } + + public class MyCollection2 : Base + { + public void Add(params int[] c) { } + } + + public class C + { + /**/ + MyCollection1 M() => new() { 1 }; + /**/ + } + """; + var comp = CreateCompilation(source).VerifyEmitDiagnostics(); + + VerifyFlowGraphForTest(comp, """ + Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Entering: {R1} + .locals {R1} + { + CaptureIds: [0] + Block[B1] - Block + Predecessors: [B0] + Statements (2) + IFlowCaptureOperation: 0 (OperationKind.FlowCapture, Type: null, IsImplicit) (Syntax: 'new() { 1 }') + Value: + IObjectCreationOperation (Constructor: MyCollection1..ctor()) (OperationKind.ObjectCreation, Type: MyCollection1) (Syntax: 'new() { 1 }') + Arguments(0) + Initializer: + null + IInvocationOperation ( void MyCollection1.Add(params MyCollection2 c)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '1') + Instance Receiver: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: MyCollection1, IsImplicit) (Syntax: 'new() { 1 }') + Arguments(1): + IArgumentOperation (ArgumentKind.ParamCollection, Matching Parameter: c) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '1') + ICollectionExpressionOperation (1 elements, ConstructMethod: MyCollection2..ctor()) (OperationKind.CollectionExpression, Type: MyCollection2, IsImplicit) (Syntax: '1') + Elements(1): + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Next (Return) Block[B2] + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: MyCollection1, IsImplicit) (Syntax: 'new() { 1 }') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + (ObjectCreation) + Operand: + IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: MyCollection1, IsImplicit) (Syntax: 'new() { 1 }') + Leaving: {R1} + } + Block[B2] - Exit + Predecessors: [B1] + Statements (0) + """); + + VerifyOperationTreeForTest(comp, """ + IMethodBodyOperation (OperationKind.MethodBody, Type: null) (Syntax: 'MyCollectio ... ew() { 1 };') + BlockBody: + null + ExpressionBody: + IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '=> new() { 1 }') + IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'new() { 1 }') + ReturnedValue: + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: MyCollection1, IsImplicit) (Syntax: 'new() { 1 }') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + IObjectCreationOperation (Constructor: MyCollection1..ctor()) (OperationKind.ObjectCreation, Type: MyCollection1) (Syntax: 'new() { 1 }') + Arguments(0) + Initializer: + IObjectOrCollectionInitializerOperation (OperationKind.ObjectOrCollectionInitializer, Type: MyCollection1) (Syntax: '{ 1 }') + Initializers(1): + IInvocationOperation ( void MyCollection1.Add(params MyCollection2 c)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: '1') + Instance Receiver: + IInstanceReferenceOperation (ReferenceKind: ImplicitReceiver) (OperationKind.InstanceReference, Type: MyCollection1, IsImplicit) (Syntax: 'new() { 1 }') + Arguments(1): + IArgumentOperation (ArgumentKind.ParamCollection, Matching Parameter: c) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: '1') + ICollectionExpressionOperation (1 elements, ConstructMethod: MyCollection2..ctor()) (OperationKind.CollectionExpression, Type: MyCollection2, IsImplicit) (Syntax: '1') + Elements(1): + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_20() + { + var source = """ + using System.Collections.Generic; + List> l; + l = [[], [2, 3]]; + """; + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_21() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + public class MyCollection1 : IEnumerable + { + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + public void Add(params MyCollection1 c) {} + } + + public class C + { + MyCollection1 M() => [1]; + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (13,35): error CS9222: Collection initializer results in an infinite chain of instantiations of collection 'MyCollection1'. + // MyCollection1 M() => [1]; + Diagnostic(ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls, "1").WithArguments("MyCollection1").WithLocation(13, 35)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_22() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + public class MyCollection1 : IEnumerable + { + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + public void Add(params MyCollection1 c) {} + } + + public class C + { + MyCollection1 M() => [1]; + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (13,35): error CS9222: Collection initializer results in an infinite chain of instantiations of collection 'MyCollection1'. + // MyCollection1 M() => [1]; + Diagnostic(ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls, "1").WithArguments("MyCollection1").WithLocation(13, 35)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_23() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + public class MyCollection1 : IEnumerable + { + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + public void Add(T x) {} + public void Add(params MyCollection1 c) {} + } + + public class C + { + MyCollection1 M() => [1]; + } + """; + CreateCompilation(source).VerifyEmitDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_24() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + public class MyCollection1 : IEnumerable + { + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + public void Add(params MyCollection1 c) {} + } + + public class C + { + MyCollection1 M() => [1]; + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (13,35): error CS9222: Collection initializer results in an infinite chain of instantiations of collection 'MyCollection1'. + // MyCollection1 M() => [1]; + Diagnostic(ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls, "1").WithArguments("MyCollection1").WithLocation(13, 35)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_25() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + public class MyCollection1 : IEnumerable + { + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + public void Add(params MyCollection1 c) {} + } + + public class C + { + public void M() + { + MyCollection1 c = new() { 1 }; + c.Add(2); + } + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (15,40): error CS9222: Collection initializer results in an infinite chain of instantiations of collection 'MyCollection1'. + // MyCollection1 c = new() { 1 }; + Diagnostic(ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls, "1").WithArguments("MyCollection1").WithLocation(15, 40), + // (16,15): error CS9222: Collection initializer results in an infinite chain of instantiations of collection 'MyCollection1'. + // c.Add(2); + Diagnostic(ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls, "2").WithArguments("MyCollection1").WithLocation(16, 15)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_26() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + public class MyCollection1 : IEnumerable + { + public MyCollection1(params MyCollection2 c) {} + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + public void Add(params MyCollection2 c) {} + } + + public class MyCollection2 : IEnumerable + { + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + public void Add(params MyCollection1 c) {} + } + + public class C + { + MyCollection1 M() => new() { 1 }; + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (21,34): error CS9222: Collection initializer results in an infinite chain of instantiations of collection 'MyCollection2'. + // MyCollection1 M() => new() { 1 }; + Diagnostic(ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls, "1").WithArguments("MyCollection2").WithLocation(21, 34)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74734")] + public void Cycle_27() + { + var source = """ + using System.Collections; + using System.Collections.Generic; + + public class MyCollection1 : IEnumerable + { + public MyCollection1(params MyCollection2 c) {} + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + public void Add(params MyCollection2 c) {} + } + + public class MyCollection2 : IEnumerable + { + public IEnumerator GetEnumerator() => throw null; + IEnumerator IEnumerable.GetEnumerator() => throw null; + public void Add(params MyCollection1 c) {} + } + + public class C + { + MyCollection1 M() => [1]; + } + """; + CreateCompilation(source).VerifyEmitDiagnostics( + // (21,27): error CS9222: Collection initializer results in an infinite chain of instantiations of collection 'MyCollection2'. + // MyCollection1 M() => [1]; + Diagnostic(ErrorCode.ERR_CollectionInitializerInfiniteChainOfAddCalls, "1").WithArguments("MyCollection2").WithLocation(21, 27)); + } + [Fact] public void InvalidParamsTypeInPartialMethod() { @@ -15803,5 +16529,536 @@ void verify9(ModuleSymbol module) Assert.Empty(module.GlobalNamespace.GetMembers("System")); } } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/73743")] + public void ParamsSpanInExpression_01() + { + string source = """ +class Program +{ + public static void Test() + { + System.Linq.Expressions.Expression> e = (s) => M(s, s, s); + } + + static void M(params string[] p) {} + static void M(params System.Span p) {} +} +"""; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); + + comp.VerifyEmitDiagnostics( + // (5,78): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'Span'. + // System.Linq.Expressions.Expression> e = (s) => M(s, s, s); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "M(s, s, s)").WithArguments("Span").WithLocation(5, 78), + // (5,78): error CS9226: An expression tree may not contain an expanded form of non-array params collection parameter. + // System.Linq.Expressions.Expression> e = (s) => M(s, s, s); + Diagnostic(ErrorCode.ERR_ParamsCollectionExpressionTree, "M(s, s, s)").WithLocation(5, 78) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/73743")] + public void ParamsSpanInExpression_02() + { + string source = """ +class Program +{ + public static void Test() + { + System.Linq.Expressions.Expression> e = (s) => M(s, s, s); + } + + static void M(params System.Span p) {} +} +"""; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80, options: TestOptions.ReleaseDll); + + comp.VerifyEmitDiagnostics( + // (5,78): error CS8640: Expression tree cannot contain value of ref struct or restricted type 'Span'. + // System.Linq.Expressions.Expression> e = (s) => M(s, s, s); + Diagnostic(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, "M(s, s, s)").WithArguments("Span").WithLocation(5, 78), + // (5,78): error CS9226: An expression tree may not contain an expanded form of non-array params collection parameter. + // System.Linq.Expressions.Expression> e = (s) => M(s, s, s); + Diagnostic(ErrorCode.ERR_ParamsCollectionExpressionTree, "M(s, s, s)").WithLocation(5, 78) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/74163")] + public void StringInterpolation_01() + { + string source1 = """ +class Program +{ + public static void Test1() + { + System.Linq.Expressions.Expression> e = (s) => $"{s} {2} {s} {4}"; + } + + public static void Test2() + { + System.Linq.Expressions.Expression> e = (s) => $"{s} {2} {s} {4}"; + } +} +"""; + string core = """ +namespace System +{ + public class Object {} + + public class ValueType {} + public abstract partial class Enum {} + + public struct Void {} + public struct Boolean {} + public struct Byte {} + public struct Int16 {} + public struct Int32 {} + public struct Int64 {} + public struct IntPtr {} + + public partial class Exception {} + + public class String + { + public static string Format(string format, params object[] args) => null; + public static string Format(string format, params ReadOnlySpan args) => null; + } + + public abstract class FormattableString {} + + public abstract partial class Attribute {} + public sealed class ParamArrayAttribute : Attribute {} + + public enum AttributeTargets + { + Assembly = 1, + Module = 2, + Class = 4, + Struct = 8, + Enum = 16, + Constructor = 32, + Method = 64, + Property = 128, + Field = 256, + Event = 512, + Interface = 1024, + Parameter = 2048, + Delegate = 4096, + ReturnValue = 8192, + GenericParameter = 16384, + All = 32767 + } + + public sealed class AttributeUsageAttribute : Attribute + { + public AttributeUsageAttribute(AttributeTargets validOn) + { + } + + internal AttributeUsageAttribute(AttributeTargets validOn, bool allowMultiple, bool inherited) + { + } + + public AttributeTargets ValidOn {get; set;} + + public bool AllowMultiple {get; set;} + + public bool Inherited {get; set;} + } + + public abstract partial class Delegate {} + public abstract partial class MulticastDelegate : Delegate {} + + public delegate TResult Func(T arg); + + public interface IDisposable + { + void Dispose(); + } + + public partial struct Nullable where T : struct {} + + public unsafe partial struct RuntimeTypeHandle {} + public unsafe partial struct RuntimeMethodHandle {} + public abstract partial class Type + { + public static Type GetTypeFromHandle(RuntimeTypeHandle handle) => null; + } + + public ref struct ReadOnlySpan + { + public ReadOnlySpan(T[] array) + { + } + + public ReadOnlySpan(T[] array, int start, int length) + { + } + + public unsafe ReadOnlySpan(void* pointer, int length) + { + } + } +} + +namespace System.Collections +{ + public interface IEnumerator + { + object Current { get; } + bool MoveNext(); + void Reset(); + } + + public interface IEnumerable + { + IEnumerator GetEnumerator(); + } +} + +namespace System.Collections.Generic +{ + public interface IEnumerator : IEnumerator, IDisposable + { + new T Current { get; } + } + + public interface IEnumerable : IEnumerable + { + new IEnumerator GetEnumerator(); + } +} + +namespace System.Reflection +{ + public abstract unsafe partial class MethodBase + { + public static MethodBase GetMethodFromHandle(RuntimeMethodHandle handle) => null; + public static MethodBase GetMethodFromHandle(RuntimeMethodHandle handle, RuntimeTypeHandle declaringType) => null; + } + + public abstract partial class MethodInfo : MethodBase {} + + public abstract partial class ConstructorInfo : MethodBase {} +} + +namespace System.Linq.Expressions +{ + using System.Collections.Generic; + using System.Reflection; + + public partial class Expression + { + public static ParameterExpression Parameter(Type type) => null; + public static ParameterExpression Parameter(Type type, string name) => null; + public static ConstantExpression Constant(object value) => null; + public static ConstantExpression Constant(object value, Type type) => null; + + public static Expression Lambda(Expression body, params ParameterExpression[] parameters) => null; + public static NewArrayExpression NewArrayInit(Type type, params Expression[] initializers) => null; + public static NewExpression New(ConstructorInfo constructor, IEnumerable arguments) => null; + public static MethodCallExpression Call(Expression instance, MethodInfo method, params Expression[] arguments) => null; + public static UnaryExpression Convert(Expression expression, Type type) => null; + } + + public abstract class LambdaExpression : Expression {} + + public class Expression : LambdaExpression {} + + public class ParameterExpression : Expression {} + public class ConstantExpression : Expression {} + public class NewArrayExpression : Expression {} + public class NewExpression : Expression {} + public class MethodCallExpression : Expression {} + public class UnaryExpression : Expression {} +} + +namespace System.Runtime.CompilerServices +{ + public sealed class InlineArrayAttribute : Attribute + { + public InlineArrayAttribute(int length) + { + } + } + + public sealed class IsReadOnlyAttribute : Attribute + {} + + public static class FormattableStringFactory + { + public static FormattableString Create(string format, params object[] arguments) => null; + public static FormattableString Create(string format, params ReadOnlySpan arguments) => null; + } + + public static unsafe partial class Unsafe + { + public static ref TTo As(ref TFrom source) => throw null; + public static ref T AsRef(scoped ref readonly T source) => throw null; + public static ref T Add(ref T source, int elementOffset) => throw null; + } +} + +namespace System.Runtime.InteropServices +{ + public static partial class MemoryMarshal + { + public static ReadOnlySpan CreateReadOnlySpan(ref readonly T reference, int length) => default; + } +} +"""; + + var comp = CreateEmptyCompilation([source1, core], options: TestOptions.ReleaseDll.WithAllowUnsafe(true)); + var verifier = CompileAndVerify(comp, verify: Verification.Skipped).VerifyDiagnostics( + // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options. + Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1) + ); + + verifier.VerifyIL("Program.Test1", +@" +{ + // Code size 198 (0xc6) + .maxstack 11 + .locals init (System.Linq.Expressions.ParameterExpression V_0) + IL_0000: ldtoken ""string"" + IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000a: ldstr ""s"" + IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)"" + IL_0014: stloc.0 + IL_0015: ldnull + IL_0016: ldtoken ""string string.Format(string, params object[])"" + IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_0020: castclass ""System.Reflection.MethodInfo"" + IL_0025: ldc.i4.2 + IL_0026: newarr ""System.Linq.Expressions.Expression"" + IL_002b: dup + IL_002c: ldc.i4.0 + IL_002d: ldstr ""{0} {1} {2} {3}"" + IL_0032: ldtoken ""string"" + IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0041: stelem.ref + IL_0042: dup + IL_0043: ldc.i4.1 + IL_0044: ldtoken ""object"" + IL_0049: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_004e: ldc.i4.4 + IL_004f: newarr ""System.Linq.Expressions.Expression"" + IL_0054: dup + IL_0055: ldc.i4.0 + IL_0056: ldloc.0 + IL_0057: stelem.ref + IL_0058: dup + IL_0059: ldc.i4.1 + IL_005a: ldc.i4.2 + IL_005b: box ""int"" + IL_0060: ldtoken ""int"" + IL_0065: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_006a: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_006f: ldtoken ""object"" + IL_0074: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0079: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" + IL_007e: stelem.ref + IL_007f: dup + IL_0080: ldc.i4.2 + IL_0081: ldloc.0 + IL_0082: stelem.ref + IL_0083: dup + IL_0084: ldc.i4.3 + IL_0085: ldc.i4.4 + IL_0086: box ""int"" + IL_008b: ldtoken ""int"" + IL_0090: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0095: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_009a: ldtoken ""object"" + IL_009f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00a4: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" + IL_00a9: stelem.ref + IL_00aa: call ""System.Linq.Expressions.NewArrayExpression System.Linq.Expressions.Expression.NewArrayInit(System.Type, params System.Linq.Expressions.Expression[])"" + IL_00af: stelem.ref + IL_00b0: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" + IL_00b5: ldc.i4.1 + IL_00b6: newarr ""System.Linq.Expressions.ParameterExpression"" + IL_00bb: dup + IL_00bc: ldc.i4.0 + IL_00bd: ldloc.0 + IL_00be: stelem.ref + IL_00bf: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" + IL_00c4: pop + IL_00c5: ret +} +"); + + verifier.VerifyIL("Program.Test2", +@" +{ + // Code size 198 (0xc6) + .maxstack 11 + .locals init (System.Linq.Expressions.ParameterExpression V_0) + IL_0000: ldtoken ""string"" + IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000a: ldstr ""s"" + IL_000f: call ""System.Linq.Expressions.ParameterExpression System.Linq.Expressions.Expression.Parameter(System.Type, string)"" + IL_0014: stloc.0 + IL_0015: ldnull + IL_0016: ldtoken ""System.FormattableString System.Runtime.CompilerServices.FormattableStringFactory.Create(string, params object[])"" + IL_001b: call ""System.Reflection.MethodBase System.Reflection.MethodBase.GetMethodFromHandle(System.RuntimeMethodHandle)"" + IL_0020: castclass ""System.Reflection.MethodInfo"" + IL_0025: ldc.i4.2 + IL_0026: newarr ""System.Linq.Expressions.Expression"" + IL_002b: dup + IL_002c: ldc.i4.0 + IL_002d: ldstr ""{0} {1} {2} {3}"" + IL_0032: ldtoken ""string"" + IL_0037: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_003c: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_0041: stelem.ref + IL_0042: dup + IL_0043: ldc.i4.1 + IL_0044: ldtoken ""object"" + IL_0049: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_004e: ldc.i4.4 + IL_004f: newarr ""System.Linq.Expressions.Expression"" + IL_0054: dup + IL_0055: ldc.i4.0 + IL_0056: ldloc.0 + IL_0057: stelem.ref + IL_0058: dup + IL_0059: ldc.i4.1 + IL_005a: ldc.i4.2 + IL_005b: box ""int"" + IL_0060: ldtoken ""int"" + IL_0065: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_006a: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_006f: ldtoken ""object"" + IL_0074: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0079: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" + IL_007e: stelem.ref + IL_007f: dup + IL_0080: ldc.i4.2 + IL_0081: ldloc.0 + IL_0082: stelem.ref + IL_0083: dup + IL_0084: ldc.i4.3 + IL_0085: ldc.i4.4 + IL_0086: box ""int"" + IL_008b: ldtoken ""int"" + IL_0090: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_0095: call ""System.Linq.Expressions.ConstantExpression System.Linq.Expressions.Expression.Constant(object, System.Type)"" + IL_009a: ldtoken ""object"" + IL_009f: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_00a4: call ""System.Linq.Expressions.UnaryExpression System.Linq.Expressions.Expression.Convert(System.Linq.Expressions.Expression, System.Type)"" + IL_00a9: stelem.ref + IL_00aa: call ""System.Linq.Expressions.NewArrayExpression System.Linq.Expressions.Expression.NewArrayInit(System.Type, params System.Linq.Expressions.Expression[])"" + IL_00af: stelem.ref + IL_00b0: call ""System.Linq.Expressions.MethodCallExpression System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, params System.Linq.Expressions.Expression[])"" + IL_00b5: ldc.i4.1 + IL_00b6: newarr ""System.Linq.Expressions.ParameterExpression"" + IL_00bb: dup + IL_00bc: ldc.i4.0 + IL_00bd: ldloc.0 + IL_00be: stelem.ref + IL_00bf: call ""System.Linq.Expressions.Expression> System.Linq.Expressions.Expression.Lambda>(System.Linq.Expressions.Expression, params System.Linq.Expressions.ParameterExpression[])"" + IL_00c4: pop + IL_00c5: ret + +} +"); + + string source2 = """ +class Program +{ + public static string Test1(string s) => $"{s} {2} {s} {4}"; + + public static System.FormattableString Test2(string s) => $"{s} {2} {s} {4}"; +} +"""; + comp = CreateEmptyCompilation([source2, core], options: TestOptions.ReleaseDll.WithAllowUnsafe(true)); + verifier = CompileAndVerify(comp, verify: Verification.Skipped).VerifyDiagnostics( + // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options. + Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1) + ); + + verifier.VerifyIL("Program.Test1", +@" +{ + // Code size 77 (0x4d) + .maxstack 3 + .locals init (<>y__InlineArray4 V_0) + IL_0000: ldstr ""{0} {1} {2} {3}"" + IL_0005: ldloca.s V_0 + IL_0007: initobj ""<>y__InlineArray4"" + IL_000d: ldloca.s V_0 + IL_000f: ldc.i4.0 + IL_0010: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" + IL_0015: ldarg.0 + IL_0016: stind.ref + IL_0017: ldloca.s V_0 + IL_0019: ldc.i4.1 + IL_001a: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" + IL_001f: ldc.i4.2 + IL_0020: box ""int"" + IL_0025: stind.ref + IL_0026: ldloca.s V_0 + IL_0028: ldc.i4.2 + IL_0029: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" + IL_002e: ldarg.0 + IL_002f: stind.ref + IL_0030: ldloca.s V_0 + IL_0032: ldc.i4.3 + IL_0033: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" + IL_0038: ldc.i4.4 + IL_0039: box ""int"" + IL_003e: stind.ref + IL_003f: ldloca.s V_0 + IL_0041: ldc.i4.4 + IL_0042: call ""System.ReadOnlySpan .InlineArrayAsReadOnlySpan<<>y__InlineArray4, object>(in <>y__InlineArray4, int)"" + IL_0047: call ""string string.Format(string, params System.ReadOnlySpan)"" + IL_004c: ret +} +"); + + verifier.VerifyIL("Program.Test2", +@" +{ + // Code size 77 (0x4d) + .maxstack 3 + .locals init (<>y__InlineArray4 V_0) + IL_0000: ldstr ""{0} {1} {2} {3}"" + IL_0005: ldloca.s V_0 + IL_0007: initobj ""<>y__InlineArray4"" + IL_000d: ldloca.s V_0 + IL_000f: ldc.i4.0 + IL_0010: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" + IL_0015: ldarg.0 + IL_0016: stind.ref + IL_0017: ldloca.s V_0 + IL_0019: ldc.i4.1 + IL_001a: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" + IL_001f: ldc.i4.2 + IL_0020: box ""int"" + IL_0025: stind.ref + IL_0026: ldloca.s V_0 + IL_0028: ldc.i4.2 + IL_0029: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" + IL_002e: ldarg.0 + IL_002f: stind.ref + IL_0030: ldloca.s V_0 + IL_0032: ldc.i4.3 + IL_0033: call ""ref object .InlineArrayElementRef<<>y__InlineArray4, object>(ref <>y__InlineArray4, int)"" + IL_0038: ldc.i4.4 + IL_0039: box ""int"" + IL_003e: stind.ref + IL_003f: ldloca.s V_0 + IL_0041: ldc.i4.4 + IL_0042: call ""System.ReadOnlySpan .InlineArrayAsReadOnlySpan<<>y__InlineArray4, object>(in <>y__InlineArray4, int)"" + IL_0047: call ""System.FormattableString System.Runtime.CompilerServices.FormattableStringFactory.Create(string, params System.ReadOnlySpan)"" + IL_004c: ret +} +"); + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTestBase.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTestBase.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTestBase.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTestBase.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests.cs index 514fafa67a90b..9b892c7ea73c6 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests.cs @@ -249,7 +249,7 @@ public D(object o) : this(o is int x && x >= 5) {} public D(bool b) { Console.WriteLine(b); } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); compilation.VerifyDiagnostics( ); var expectedOutput = @@ -972,11 +972,11 @@ static bool Dummy(int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); CompileAndVerify(compilation, expectedOutput: @"1 True"); - CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( // (9,34): error CS8320: Feature 'declaration of expression variables in member initializers and queries' is not available in C# 7.2. Please use language version 7.3 or greater. // static bool Test1 = 1 is int x1 && Dummy(x1); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "x1").WithArguments("declaration of expression variables in member initializers and queries", "7.3").WithLocation(9, 34) @@ -1010,7 +1010,7 @@ static bool Dummy(System.Func x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); CompileAndVerify(compilation, expectedOutput: @"1 True 2 @@ -1065,11 +1065,11 @@ static bool Dummy(int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); CompileAndVerify(compilation, expectedOutput: @"1 True"); - CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( // (9,41): error CS8320: Feature 'declaration of expression variables in member initializers and queries' is not available in C# 7.2. Please use language version 7.3 or greater. // static bool Test1 {get;} = 1 is int x1 && Dummy(x1); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "x1").WithArguments("declaration of expression variables in member initializers and queries", "7.3").WithLocation(9, 41) @@ -1142,7 +1142,7 @@ public C(object b) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); CompileAndVerify(compilation, expectedOutput: @"1 2 @@ -1160,7 +1160,7 @@ public C(object b) Assert.Equal("System.Int32", ((ILocalSymbol)compilation.GetSemanticModel(tree).GetDeclaredSymbol(x1Decl[0])).Type.ToTestDisplayString()); - CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( // (12,40): error CS8320: Feature 'declaration of expression variables in member initializers and queries' is not available in C# 7.2. Please use language version 7.3 or greater. // public D(object o) : base(2 is var x1 && Dummy(x1)) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "x1").WithArguments("declaration of expression variables in member initializers and queries", "7.3").WithLocation(12, 40), @@ -6600,11 +6600,11 @@ static bool Dummy(int x) } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); CompileAndVerify(compilation, expectedOutput: @"1 True"); - CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular7_2).VerifyDiagnostics( // (9,65): error CS8320: Feature 'declaration of expression variables in member initializers and queries' is not available in C# 7.2. Please use language version 7.3 or greater. // static event System.Func Test1 = GetDelegate(1 is int x1 && Dummy(x1)); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "x1").WithArguments("declaration of expression variables in member initializers and queries", "7.3").WithLocation(9, 65) diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests2.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests2.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests2.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests2.cs index 3cf79e3499614..317415652d324 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests2.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests2.cs @@ -118,7 +118,7 @@ public static void Deconstruct(this Point p, out int X, out int Y) } "; // We use a compilation profile that provides System.Runtime.CompilerServices.ExtensionAttribute needed for this test - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularWithRecursivePatterns); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularWithRecursivePatterns); compilation.VerifyDiagnostics( ); var comp = CompileAndVerify(compilation, expectedOutput: ""); @@ -1149,7 +1149,7 @@ public static void M(object o) } } "; - var compilation = CreateCompilationWithMscorlib45(source); // doesn't have ITuple + var compilation = CreateCompilationWithMscorlib461(source); // doesn't have ITuple // Two errors below instead of one due to https://github.com/dotnet/roslyn/issues/25533 compilation.VerifyDiagnostics( // (8,18): error CS1061: 'object' does not contain a definition for 'Deconstruct' and no accessible extension method 'Deconstruct' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?) diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests3.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests3.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests3.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests3.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests4.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests4.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests4.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests4.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests5.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests5.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests5.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests5.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_Global.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_Global.cs similarity index 96% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_Global.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_Global.cs index 5b618a7570145..59b1da413af61 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_Global.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_Global.cs @@ -50,7 +50,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,18): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -97,7 +97,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,18): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -172,7 +172,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,18): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -219,7 +219,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,18): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -283,7 +283,7 @@ public static void Dummy(params object[] x) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -342,7 +342,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,15): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -396,7 +396,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,15): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -494,7 +494,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,15): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -548,7 +548,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,15): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -629,7 +629,7 @@ class H } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -671,7 +671,7 @@ public static void Dummy(object x, object y) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -719,7 +719,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,24): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -778,7 +778,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): error CS1624: The body of '' cannot be an iterator block because 'void' is not an iterator interface type @@ -856,7 +856,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,24): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -916,7 +916,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): error CS1624: The body of '' cannot be an iterator block because 'void' is not an iterator interface type @@ -992,7 +992,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,18): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -1042,7 +1042,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,9): error CS0029: Cannot implicitly convert type 'bool' to 'int' @@ -1124,7 +1124,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,18): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -1174,7 +1174,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,9): error CS0029: Cannot implicitly convert type 'bool' to 'int' @@ -1252,7 +1252,7 @@ public static bool Dummy(object x, object y) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -1298,7 +1298,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,24): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -1348,7 +1348,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,1): warning CS0162: Unreachable code detected @@ -1423,7 +1423,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,24): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -1474,7 +1474,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,1): warning CS0162: Unreachable code detected @@ -1558,7 +1558,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,19): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -1612,7 +1612,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,19): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -1706,7 +1706,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,19): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -1760,7 +1760,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,19): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -1840,7 +1840,7 @@ class H } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -1895,7 +1895,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -1959,7 +1959,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -2066,7 +2066,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -2130,7 +2130,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -2217,7 +2217,7 @@ class H } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1").VerifyDiagnostics(); @@ -2269,7 +2269,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -2333,7 +2333,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -2441,7 +2441,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -2505,7 +2505,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,9): error CS0103: The name 'x1' does not exist in the current context @@ -2599,7 +2599,7 @@ class H } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1 @@ -2653,7 +2653,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,24): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -2707,7 +2707,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,24): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -2799,7 +2799,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,24): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -2853,7 +2853,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,24): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -2931,7 +2931,7 @@ class H } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -2977,7 +2977,7 @@ public static object Dummy(object x) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -3029,7 +3029,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( @@ -3097,7 +3097,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( @@ -3189,7 +3189,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,21): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -3248,7 +3248,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): warning CS0164: This label has not been referenced @@ -3335,7 +3335,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,21): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -3394,7 +3394,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): warning CS0164: This label has not been referenced @@ -3470,7 +3470,7 @@ public static void Dummy(params object[] x) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -3529,7 +3529,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,20): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -3596,7 +3596,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): warning CS0164: This label has not been referenced @@ -3700,7 +3700,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,20): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -3767,7 +3767,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): warning CS0164: This label has not been referenced @@ -3853,7 +3853,7 @@ void Test() } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -3912,7 +3912,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( @@ -3997,7 +3997,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( @@ -4110,7 +4110,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( @@ -4195,7 +4195,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( @@ -4291,7 +4291,7 @@ void Test() } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }, options: TestOptions.DebugExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @@ -4354,7 +4354,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,20): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -4421,7 +4421,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (7,20): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -4521,7 +4521,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,20): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -4588,7 +4588,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (7,20): error CS0128: A local variable or function named 'x2' is already defined in this scope @@ -4666,7 +4666,7 @@ void Test() } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -4710,7 +4710,7 @@ static object InitB() } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"InitA 0 @@ -4746,7 +4746,7 @@ class H public static bool Dummy(params object[] x) {return true;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -4785,7 +4785,7 @@ class H public static bool Dummy(params object[] x) {return true;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -4821,7 +4821,7 @@ bool Test() } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 0 @@ -4874,7 +4874,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,29): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -4931,7 +4931,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,6): error CS0116: A namespace cannot directly contain members such as fields or methods @@ -5040,7 +5040,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,29): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -5097,7 +5097,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,6): error CS0116: A namespace cannot directly contain members such as fields or methods @@ -5187,7 +5187,7 @@ void Test() } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -5231,7 +5231,7 @@ static object InitB() } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"InitA 0 @@ -5267,7 +5267,7 @@ class H public static bool Dummy(params object[] x) {return true;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -5306,7 +5306,7 @@ class H public static bool Dummy(params object[] x) {return true;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -5361,7 +5361,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,42): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -5428,7 +5428,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,21): error CS0116: A namespace cannot directly contain members such as fields or methods @@ -5546,7 +5546,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (7,42): error CS0102: The type 'Script' already contains a definition for 'x2' @@ -5613,7 +5613,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,21): error CS0116: A namespace cannot directly contain members such as fields or methods @@ -5716,7 +5716,7 @@ class H } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 @@ -5765,7 +5765,7 @@ class H } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"InitA 0 @@ -5801,7 +5801,7 @@ class H public static System.Action Dummy(params object[] x) {return null;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -5840,7 +5840,7 @@ class H public static System.Action Dummy(params object[] x) {return null;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,16): error CS0120: An object reference is required for the non-static field, method, or property 'x1' @@ -5881,7 +5881,7 @@ class H } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"0 0 @@ -5920,7 +5920,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,10): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) @@ -5946,7 +5946,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,6): warning CS0168: The variable 'a' is declared but never used @@ -6005,7 +6005,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,10): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) @@ -6033,7 +6033,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (2,1): warning CS0164: This label has not been referenced @@ -6092,7 +6092,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (3,25): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) @@ -6118,7 +6118,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,25): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) @@ -6174,7 +6174,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( @@ -6204,7 +6204,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (3,12): error CS0116: A namespace cannot directly contain members such as fields or methods @@ -6257,7 +6257,7 @@ class H public static void Dummy(params object[] x) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.GetDeclarationDiagnostics().Verify( // (3,17): error CS0610: Field or property cannot be of type 'ArgIterator' @@ -6286,7 +6286,7 @@ public static void Dummy(params object[] x) {} static class StaticType{} "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.GetDeclarationDiagnostics().Verify( // (2,28): error CS0723: Cannot declare a variable of static type 'StaticType' @@ -6314,7 +6314,7 @@ public static void Dummy(params object[] x) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -6338,7 +6338,7 @@ public static void Dummy(params object[] x) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,14): error CS8508: The syntax 'var' for a pattern is not permitted to refer to a type, but 'var' is in scope here. // H.Dummy(1 is var x1); @@ -6367,7 +6367,7 @@ public static void Dummy(params object[] x) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -6390,7 +6390,7 @@ public static void Dummy(params object[] x) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -6484,7 +6484,7 @@ public void GlobalCode_Catch_01() } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (20,13): error CS0841: Cannot use local variable 'x6' before it is declared // catch when (x6 && 123 is var x6) @@ -6568,7 +6568,7 @@ public void GlobalCode_Catch_01() } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (14,24): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -6676,7 +6676,7 @@ static bool Dummy(object y, object z) return true; } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"System.InvalidOperationException System.InvalidOperationException"); @@ -6716,7 +6716,7 @@ class H } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (15,9): error CS0103: The name 'x3' does not exist in the current context @@ -6743,7 +6743,7 @@ class H } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (7,8): warning CS0168: The variable 'x2' is declared but never used @@ -6793,7 +6793,7 @@ void Test() } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1 @@ -6903,7 +6903,7 @@ public void GlobalCode_For_01() "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (74,5): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -6997,7 +6997,7 @@ public void GlobalCode_For_01() } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (20,27): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -7117,7 +7117,7 @@ static bool Dummy(bool x, object y, object z) return x; } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"10 1 @@ -7220,7 +7220,7 @@ public void GlobalCode_Foreach_01() } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (52,5): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -7320,7 +7320,7 @@ public void GlobalCode_Foreach_01() } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (15,37): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -7442,7 +7442,7 @@ static System.Collections.IEnumerable Dummy(object y, object z) return ""a""; } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"3 3"); @@ -7501,7 +7501,7 @@ o2 is var x5 && Dummy(x12); "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (6,39): error CS0841: Cannot use local variable 'x4' before it is declared // Dummy((System.Func) (o => x4 && o is var x4)); @@ -7591,7 +7591,7 @@ o2 is var x5 && } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (6,39): error CS0841: Cannot use local variable 'x4' before it is declared @@ -7700,7 +7700,7 @@ static bool Dummy(int x) return true; } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1 True"); @@ -7725,7 +7725,7 @@ static bool Dummy(int x) return true; } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1 True"); @@ -7834,7 +7834,7 @@ from y10 in new[] { 1 } select x1 + y11; "; { - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (14,21): error CS0103: The name 'z2' does not exist in the current context // z2; @@ -8086,7 +8086,7 @@ from y10 in new[] { 1 } } { - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (14,21): error CS0103: The name 'z2' does not exist in the current context @@ -8363,7 +8363,7 @@ static bool Print(object x) return true; } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"1 @@ -8445,7 +8445,7 @@ public void GlobalCode_Using_01() } "; { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (52,5): error CS1023: Embedded statement cannot be a declaration or labeled statement // var y12 = 12; @@ -8540,7 +8540,7 @@ public void GlobalCode_Using_01() } { - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (15,26): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter @@ -8680,7 +8680,7 @@ public override string ToString() } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script); CompileAndVerify(compilation, expectedOutput: @"a b diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_ListPatterns.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_ListPatterns.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_ListPatterns.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_ListPatterns.cs index 0dcfda3f30f71..1ac3077040c01 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_ListPatterns.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_ListPatterns.cs @@ -8867,6 +8867,55 @@ public void ListPattern_AbstractFlowPass_isBoolTest() ); } + [Fact, WorkItem(58738, "https://github.com/dotnet/roslyn/issues/58738")] + public void ListPattern_AbstractFlowPass_isBoolTest_Multiple() + { + var source = @" +var b = new[] { true }; + +if ((b is [var x] and x or x) is [true]) +{ +} + +if ((b is [var z] and z and z) is [true]) +{ +} +"; + var comp = CreateCompilationWithIndexAndRangeAndSpan(new[] { source, TestSources.GetSubArray }); + comp.VerifyEmitDiagnostics( + // 0.cs(4,16): error CS8780: A variable may not be declared within a 'not' or 'or' pattern. + // if ((b is [var x] and x or x) is [true]) + Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "x").WithLocation(4, 16), + // 0.cs(4,23): error CS0029: Cannot implicitly convert type 'bool' to 'bool[]' + // if ((b is [var x] and x or x) is [true]) + Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("bool", "bool[]").WithLocation(4, 23), + // 0.cs(4,23): error CS0165: Use of unassigned local variable 'x' + // if ((b is [var x] and x or x) is [true]) + Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(4, 23), + // 0.cs(4,28): error CS0029: Cannot implicitly convert type 'bool' to 'bool[]' + // if ((b is [var x] and x or x) is [true]) + Diagnostic(ErrorCode.ERR_NoImplicitConv, "x").WithArguments("bool", "bool[]").WithLocation(4, 28), + // 0.cs(4,34): error CS8985: List patterns may not be used for a value of type 'bool'. No suitable 'Length' or 'Count' property was found. + // if ((b is [var x] and x or x) is [true]) + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[true]").WithArguments("bool").WithLocation(4, 34), + // 0.cs(4,34): error CS0021: Cannot apply indexing with [] to an expression of type 'bool' + // if ((b is [var x] and x or x) is [true]) + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[true]").WithArguments("bool").WithLocation(4, 34), + // 0.cs(8,23): error CS0029: Cannot implicitly convert type 'bool' to 'bool[]' + // if ((b is [var z] and z and z) is [true]) + Diagnostic(ErrorCode.ERR_NoImplicitConv, "z").WithArguments("bool", "bool[]").WithLocation(8, 23), + // 0.cs(8,29): error CS0029: Cannot implicitly convert type 'bool' to 'bool[]' + // if ((b is [var z] and z and z) is [true]) + Diagnostic(ErrorCode.ERR_NoImplicitConv, "z").WithArguments("bool", "bool[]").WithLocation(8, 29), + // 0.cs(8,35): error CS8985: List patterns may not be used for a value of type 'bool'. No suitable 'Length' or 'Count' property was found. + // if ((b is [var z] and z and z) is [true]) + Diagnostic(ErrorCode.ERR_ListPatternRequiresLength, "[true]").WithArguments("bool").WithLocation(8, 35), + // 0.cs(8,35): error CS0021: Cannot apply indexing with [] to an expression of type 'bool' + // if ((b is [var z] and z and z) is [true]) + Diagnostic(ErrorCode.ERR_BadIndexLHS, "[true]").WithArguments("bool").WithLocation(8, 35) + ); + } + [Fact, WorkItem(58738, "https://github.com/dotnet/roslyn/issues/58738")] public void ListPattern_AbstractFlowPass_patternMatchesNull() { diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_NullableTypes.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_NullableTypes.cs similarity index 100% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_NullableTypes.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_NullableTypes.cs diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_Scope.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_Scope.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_Scope.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_Scope.cs index 91a7947e41648..3f5a3e860c02c 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternMatchingTests_Scope.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests_Scope.cs @@ -4204,7 +4204,7 @@ public class Y public Y(params object[] x) {} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); compilation.VerifyDiagnostics( // (9,25): error CS0136: A local or parameter named 'x3' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // : base(3 is int x3) diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternSwitchTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternSwitchTests.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PatternSwitchTests.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PatternSwitchTests.cs index f503bdb21b172..8524ef1dff7c2 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/PatternSwitchTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternSwitchTests.cs @@ -2442,7 +2442,7 @@ static async Task GetTask(string val) } "; // Use a compilation profile that supports Task. - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); compilation.VerifyDiagnostics(); var comp = CompileAndVerify(compilation, expectedOutput: @"case 1: 1 @@ -2507,7 +2507,7 @@ static async Task GetTask(string val) } "; // Use a compilation profile that supports Task. - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); compilation.VerifyDiagnostics(); var comp = CompileAndVerify(compilation, expectedOutput: @"case 1: 1 @@ -2567,7 +2567,7 @@ static async Task Test() } "; // Use a compilation profile that supports Task. - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); compilation.VerifyDiagnostics(); var comp = CompileAndVerify(compilation, expectedOutput: @"case 1: 1 @@ -2623,7 +2623,7 @@ static async Task GetTask(string val) } "; // Use a compilation profile that supports Task. - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); compilation.VerifyDiagnostics(); var comp = CompileAndVerify(compilation, expectedOutput: @"case: 3 @@ -2660,7 +2660,7 @@ public static async Task SendMessageAsync(object response) } "; // Use a compilation profile that supports Task. - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); compilation.VerifyDiagnostics( // (12,38): warning 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. // public static async Task SendMessageAsync(object response) @@ -3202,7 +3202,7 @@ public static async Task SwitchWithAwaitInPatternFails(Task self, T defaul } "; // Use a compilation profile that supports Task. - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( source, options: TestOptions.ReleaseDll.WithOptimizationLevel(OptimizationLevel.Release), references: new[] { SystemCoreRef, CSharpRef }); compilation.VerifyDiagnostics(); var comp = CompileAndVerify(compilation); diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/PrimaryConstructorTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PrimaryConstructorTests.cs similarity index 98% rename from src/Compilers/CSharp/Test/Emit2/Semantics/PrimaryConstructorTests.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/PrimaryConstructorTests.cs index c9e40b28b64ba..d7afdee79cad9 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/PrimaryConstructorTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PrimaryConstructorTests.cs @@ -19774,6 +19774,142 @@ class C(int p) AssertEx.Equal("System.Int32 C.this[System.Int32 i] { get; }", info.Symbol.ToTestDisplayString()); } + [WorkItem("https://github.com/dotnet/roslyn/issues/75002")] + [Fact] + public void PartialMembers_01() + { + var source1 = """ + C c = null; + c.M(); + _ = c.P; + """; + var source2 = """ + #pragma warning disable 9113 // parameter is unread + partial class C(int p) + { + public partial void M() { } + public partial void M(); + public partial object P { get; } + public partial object P { get => null; } + } + """; + var comp = CreateCompilation([source1, source2]); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + // https://github.com/dotnet/roslyn/issues/75002: SemanticModel.GetDiagnostics() does not merge partial members. + model.GetDiagnostics().Verify( + // (2,3): error CS0121: The call is ambiguous between the following methods or properties: 'C.M()' and 'C.M()' + // c.M(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M()", "C.M()").WithLocation(2, 3), + // (3,7): error CS0229: Ambiguity between 'C.P' and 'C.P' + // _ = c.P; + Diagnostic(ErrorCode.ERR_AmbigMember, "P").WithArguments("C.P", "C.P").WithLocation(3, 7)); + } + + [Fact] + public void NullableAttributes_01() + { + var source1 = """ + #nullable enable + C c = null!; + object o; + o = c.M(); + o = c.P; + """; + var source2 = """ + #pragma warning disable 9113 // parameter is unread + #nullable enable + using System.Diagnostics.CodeAnalysis; + class C(int p) + { + [return: MaybeNull] public object M() => new(); + [MaybeNull] public object P { get => new(); } + } + """; + var comp = CreateCompilation([source1, source2], targetFramework: TargetFramework.Net80); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + model.GetDiagnostics().Verify( + // (4,5): warning CS8600: Converting null literal or possible null value to non-nullable type. + // o = c.M(); + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "c.M()").WithLocation(4, 5), + // (5,5): warning CS8600: Converting null literal or possible null value to non-nullable type. + // o = c.P; + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "c.P").WithLocation(5, 5)); + } + + [WorkItem("https://github.com/dotnet/roslyn/issues/75002")] + [Fact] + public void NullableAttributes_PartialMembers_01() + { + var source1 = """ + #nullable enable + C c = null!; + object o; + o = c.M(); + o = c.P; + """; + var source2 = """ + #pragma warning disable 9113 // parameter is unread + #nullable enable + using System.Diagnostics.CodeAnalysis; + partial class C(int p) + { + public partial object M() => new(); + [return: MaybeNull] public partial object M(); + [MaybeNull] public partial object P { get; } + public partial object P { get => new(); } + } + """; + var comp = CreateCompilation([source1, source2], targetFramework: TargetFramework.Net80); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + // https://github.com/dotnet/roslyn/issues/75002: SemanticModel.GetDiagnostics() does not merge partial members. + model.GetDiagnostics().Verify( + // (4,7): error CS0121: The call is ambiguous between the following methods or properties: 'C.M()' and 'C.M()' + // o = c.M(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M()", "C.M()").WithLocation(4, 7), + // (5,7): error CS0229: Ambiguity between 'C.P' and 'C.P' + // o = c.P; + Diagnostic(ErrorCode.ERR_AmbigMember, "P").WithArguments("C.P", "C.P").WithLocation(5, 7)); + } + + [WorkItem("https://github.com/dotnet/roslyn/issues/75002")] + [Fact] + public void NullableAttributes_PartialMembers_02() + { + var source1 = """ + #nullable enable + C c = null!; + object o; + o = c.M(); + o = c.P; + """; + var source2 = """ + #pragma warning disable 9113 // parameter is unread + #nullable enable + using System.Diagnostics.CodeAnalysis; + partial class C(int p) + { + [return: MaybeNull] public partial object M() => new(); + public partial object M(); + public partial object P { get; } + [MaybeNull] public partial object P { get => new(); } + } + """; + var comp = CreateCompilation([source1, source2], targetFramework: TargetFramework.Net80); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + // https://github.com/dotnet/roslyn/issues/75002: SemanticModel.GetDiagnostics() does not merge partial members. + model.GetDiagnostics().Verify( + // (4,7): error CS0121: The call is ambiguous between the following methods or properties: 'C.M()' and 'C.M()' + // o = c.M(); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M()", "C.M()").WithLocation(4, 7), + // (5,7): error CS0229: Ambiguity between 'C.P' and 'C.P' + // o = c.P; + Diagnostic(ErrorCode.ERR_AmbigMember, "P").WithArguments("C.P", "C.P").WithLocation(5, 7)); + } + [Fact] public void IllegalCapturingInStruct_01() { @@ -20407,7 +20543,7 @@ void M() { } "; - var comp = CreateCompilation(src1, targetFramework: TargetFramework.DesktopLatestExtended); + var comp = CreateCompilation(src1, targetFramework: TargetFramework.Mscorlib461Extended); comp.VerifyDiagnostics( // (7,13): error CS9136: Cannot use primary constructor parameter of type 'ArgIterator' inside an instance member // _ = a; @@ -22119,5 +22255,95 @@ public event EventHandler OnClosed var comp = CreateCompilation(source, options: TestOptions.ReleaseDll); comp.VerifyEmitDiagnostics(); } + + [Theory] + [InlineData("class")] + [InlineData("struct")] + [WorkItem("https://github.com/dotnet/roslyn/issues/74726")] + public void PrimaryCtorNullableFieldWarning(string typeKind) + { + var source = $$""" + #nullable enable + + public {{typeKind}} C() + { + public string Text { get; set; } // 1 + public C(bool ignored) : this() { } + } + + public {{typeKind}} C2 + { + public string Text { get; set; } + public C2() { } // 2 + } + + public {{typeKind}} C3() + { + public string Text { get; set; } = "a"; + public C3(bool ignored) : this() { } + } + + public {{typeKind}} C4 + { + public string Text { get; set; } + public C4() { Text = "a"; } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,19): warning CS8618: Non-nullable property 'Text' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public string Text { get; set; } // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Text").WithArguments("property", "Text").WithLocation(5, 19), + // (12,12): warning CS8618: Non-nullable property 'Text' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public C2() { } // 2 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C2").WithArguments("property", "Text").WithLocation(12, 12) + ); + } + + [Theory] + [InlineData("class")] + [InlineData("struct")] + [WorkItem("https://github.com/dotnet/roslyn/issues/74726")] + public void RecordPrimaryCtorNullableFieldWarning(string typeKind) + { + var source = $$""" + #nullable enable + + public record {{typeKind}} C() + { + public string Text { get; set; } // 1 + public C(bool ignored) : this() { } + } + + public record {{typeKind}} C2 + { + public string Text { get; set; } + public C2() { } // 2 + } + + public record {{typeKind}} C3() + { + public string Text { get; set; } = "a"; + public C3(bool ignored) : this() { } + } + + public record {{typeKind}} C4 + { + public string Text { get; set; } + public C4() { Text = "a"; } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (5,19): warning CS8618: Non-nullable property 'Text' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public string Text { get; set; } // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Text").WithArguments("property", "Text").WithLocation(5, 19), + // (12,12): warning CS8618: Non-nullable property 'Text' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public C2() { } // 2 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C2").WithArguments("property", "Text").WithLocation(12, 12) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/RecordTests.cs similarity index 99% rename from src/Compilers/CSharp/Test/Emit2/Semantics/RecordTests.cs rename to src/Compilers/CSharp/Test/Emit3/Semantics/RecordTests.cs index d2d97b296fbfd..98c3c648efbaa 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/RecordTests.cs @@ -30441,7 +30441,7 @@ public static ClassWithManyConstructorParameters Create() var comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.NetCoreApp); CompileAndVerify(comp, verify: Verification.Skipped).VerifyDiagnostics(); - comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.DesktopLatestExtended); + comp = CreateCompilation(new[] { src, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Mscorlib461Extended); CompileAndVerify(comp, verify: Verification.Skipped).VerifyDiagnostics(); } } diff --git a/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs b/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs index 64cc4a4f131e7..81186331e0965 100644 --- a/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs +++ b/src/Compilers/CSharp/Test/EndToEnd/EndToEndTests.cs @@ -19,6 +19,8 @@ using System.Diagnostics; using Roslyn.Test.Utilities.TestGenerators; using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.FlowAnalysis; +using Microsoft.CodeAnalysis.Operations; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.EndToEnd { @@ -60,7 +62,7 @@ private static void RunInThread(Action action, TimeSpan? timeout = null) if (exception is object) { - throw exception; + Assert.False(true, exception.ToString()); } } @@ -411,9 +413,9 @@ public void NestedIfStatements() int nestingLevel = (IntPtr.Size, ExecutionConditionUtil.Configuration) switch { (4, ExecutionConfiguration.Debug) => 310, - (4, ExecutionConfiguration.Release) => 1650, + (4, ExecutionConfiguration.Release) => 1419, (8, ExecutionConfiguration.Debug) => 200, - (8, ExecutionConfiguration.Release) => 780, + (8, ExecutionConfiguration.Release) => 474, _ => throw new Exception($"Unexpected configuration {IntPtr.Size * 8}-bit {ExecutionConditionUtil.Configuration}") }; @@ -450,6 +452,95 @@ static void Main() } } + [WorkItem("https://github.com/dotnet/roslyn/issues/72393")] + [ConditionalTheory(typeof(NoIOperationValidation))] + [InlineData(2)] +#if DEBUG + [InlineData(2000)] +#else + [InlineData(5000)] +#endif + public void NestedIfElse(int n) + { + var builder = new System.Text.StringBuilder(); + builder.AppendLine(""" + #nullable enable + class Program + { + static void F(int i) + { + if (i == 0) { } + """); + for (int i = 0; i < n; i++) + { + builder.AppendLine($$""" + else if (i == {{i}}) { } + """); + } + builder.AppendLine(""" + } + } + """); + + var source = builder.ToString(); + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var node = tree.GetRoot().DescendantNodes().OfType().Single(); + + // Avoid using ControlFlowGraphVerifier.GetControlFlowGraph() since that calls + // TestOperationVisitor.VerifySubTree() which has quadratic behavior using + // MemberSemanticModel.GetEnclosingBinderInternalWithinRoot(). + var operation = (Microsoft.CodeAnalysis.Operations.IMethodBodyOperation)model.GetOperation(node); + var graph = Microsoft.CodeAnalysis.FlowAnalysis.ControlFlowGraph.Create(operation); + + if (n == 2) + { + var symbol = model.GetDeclaredSymbol(node); + ControlFlowGraphVerifier.VerifyGraph(comp, """ + Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Block[B1] - Block + Predecessors: [B0] + Statements (0) + Jump if False (Regular) to Block[B2] + IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean) (Syntax: 'i == 0') + Left: + IParameterReferenceOperation: i (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') + Next (Regular) Block[B4] + Block[B2] - Block + Predecessors: [B1] + Statements (0) + Jump if False (Regular) to Block[B3] + IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean) (Syntax: 'i == 0') + Left: + IParameterReferenceOperation: i (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0) (Syntax: '0') + Next (Regular) Block[B4] + Block[B3] - Block + Predecessors: [B2] + Statements (0) + Jump if False (Regular) to Block[B4] + IBinaryOperation (BinaryOperatorKind.Equals) (OperationKind.Binary, Type: System.Boolean) (Syntax: 'i == 1') + Left: + IParameterReferenceOperation: i (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'i') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') + Next (Regular) Block[B4] + Block[B4] - Exit + Predecessors: [B1] [B2] [B3*2] + Statements (0) + """, + graph, symbol); + } + } + [WorkItem(42361, "https://github.com/dotnet/roslyn/issues/42361")] [ConditionalFact(typeof(WindowsOrLinuxOnly))] public void Constraints() @@ -583,7 +674,7 @@ public static void M() """, $"C{i}.cs")); } - var verifier = CompileAndVerify(files.ToArrayAndFree(), parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "global"), expectedOutput: makeExpectedOutput()); + var verifier = CompileAndVerify(files.ToArrayAndFree(), parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "global"), expectedOutput: makeExpectedOutput()); verifier.VerifyDiagnostics(); string makeExpectedOutput() @@ -723,5 +814,59 @@ class XAttribute : System.Attribute { } Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C1" })); } + + [Theory] + [InlineData("or", "1")] + [InlineData("and not", "0")] + public void ManyBinaryPatterns(string pattern, string expectedOutput) + { + const string preamble = $""" + int i = 2; + + System.Console.Write(i is + """; + string append = $""" + + {pattern} + """; + const string postscript = """ + + ? 1 : 0); + """; + + const int numBinaryExpressions = 5_000; + + var builder = new StringBuilder(preamble.Length + postscript.Length + append.Length * numBinaryExpressions + 5 /* Max num digit characters */ * numBinaryExpressions); + + builder.AppendLine(preamble); + + builder.Append(0); + + for (int i = 1; i < numBinaryExpressions; i++) + { + builder.Append(append); + // Make sure the emitter has to handle lots of nodes + builder.Append(i * 2); + } + + builder.AppendLine(postscript); + + var source = builder.ToString(); + RunInThread(() => + { + var comp = CreateCompilation(source, options: TestOptions.DebugExe.WithConcurrentBuild(false)); + CompileAndVerify(comp, expectedOutput: expectedOutput); + + var tree = comp.SyntaxTrees[0]; + var isPattern = tree.GetRoot().DescendantNodes().OfType().Single(); + var model = comp.GetSemanticModel(tree); + var operation = model.GetOperation(isPattern); + Assert.NotNull(operation); + + for (; operation.Parent is not null; operation = operation.Parent) { } + + Assert.NotNull(ControlFlowGraph.Create((IMethodBodyOperation)operation)); + }); + } } } diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IArgument.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IArgument.cs index ba7ac48026861..e459d596ecee0 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IArgument.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IArgument.cs @@ -1415,7 +1415,7 @@ void M() "; var expectedDiagnostics = DiagnosticDescription.None; - VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, TargetFramework.Mscorlib45, expectedDiagnostics); + VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, TargetFramework.Mscorlib461, expectedDiagnostics); } /// @@ -2588,6 +2588,9 @@ void M1() // (6,37): error CS0518: Predefined type 'System.Int32' is not defined or imported // public int this[int x, int? y = 5] Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "5").WithArguments("System.Int32").WithLocation(6, 37), + // (6,16): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor' + // public int this[int x, int? y = 5] + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(6, 16), // (5,27): error CS0518: Predefined type 'System.Int32' is not defined or imported // private int _number = 0; Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "0").WithArguments("System.Int32").WithLocation(5, 27), @@ -2766,6 +2769,9 @@ void M1() // (5,12): error CS0518: Predefined type 'System.Int32' is not defined or imported // public int this[int x, int? y = null] Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "int").WithArguments("System.Int32").WithLocation(5, 12), + // (5,16): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor' + // public int this[int x, int? y = null] + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(5, 16), // (5,21): error CS0518: Predefined type 'System.Int32' is not defined or imported // public int this[int x, int? y = null] Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "int").WithArguments("System.Int32").WithLocation(5, 21), @@ -3829,6 +3835,9 @@ P M1() // (5,37): error CS0518: Predefined type 'System.Int32' is not defined or imported // public int this[int x, int? y = 0] Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "0").WithArguments("System.Int32").WithLocation(5, 37), + // (5,16): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor' + // public int this[int x, int? y = 0] + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(5, 16), // (4,27): error CS0518: Predefined type 'System.Int32' is not defined or imported // private int _number = 0; Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "0").WithArguments("System.Int32").WithLocation(4, 27), @@ -3903,6 +3912,9 @@ P M1() // (5,12): error CS0518: Predefined type 'System.Int32' is not defined or imported // public int this[int x, int? y = null] Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "int").WithArguments("System.Int32").WithLocation(5, 12), + // (5,16): error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor' + // public int this[int x, int? y = null] + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "this").WithArguments("System.Reflection.DefaultMemberAttribute", ".ctor").WithLocation(5, 16), // (5,21): error CS0518: Predefined type 'System.Int32' is not defined or imported // public int this[int x, int? y = null] Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "int").WithArguments("System.Int32").WithLocation(5, 21), diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICoalesceOperation.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICoalesceOperation.cs index bb1cf870e1ede..c45d6f766d94e 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICoalesceOperation.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICoalesceOperation.cs @@ -1524,7 +1524,7 @@ void M1(int? i, int j, int result) }/**/ } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); string expectedGraph = @" diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.cs index 30aed853dde18..1dbd3094d2f23 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.cs @@ -41,7 +41,7 @@ static void M() "; var syntaxTree = Parse(source); - var compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }); + var compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }); (IOperation operation, _) = GetOperationAndSyntaxForTest(compilation); var compoundAssignment = (ICompoundAssignmentOperation)operation; @@ -77,7 +77,7 @@ public static implicit operator int(C c) "; var syntaxTree = Parse(source); - var compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }); + var compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }); (IOperation operation, SyntaxNode node) = GetOperationAndSyntaxForTest(compilation); var compoundAssignment = (ICompoundAssignmentOperation)operation; diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IConditionalAccessExpression.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IConditionalAccessExpression.cs index 98d7282b163d8..b88f5668d9c04 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IConditionalAccessExpression.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IConditionalAccessExpression.cs @@ -1188,7 +1188,7 @@ void M1(P? input, int? result) public int Length { get; } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); string expectedGraph = @" diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs index a515cc28f9774..30dea08887385 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs @@ -3702,5 +3702,154 @@ void M(dynamic a, bool result) VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, expectedDiagnostics); } + + [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] + [Fact] + public void IfFlow_25() + { + string source = @" +class P +{ + void M(bool a, bool b) +/**/{ + if (a) + { + a = false; + } + else if (b) + { + b = false; + } + }/**/ +} +"; + string expectedFlowGraph = @" +Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] +Block[B1] - Block + Predecessors: [B0] + Statements (0) + Jump if False (Regular) to Block[B3] + IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a') + Next (Regular) Block[B2] +Block[B2] - Block + Predecessors: [B1] + Statements (1) + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = false;') + Expression: + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = false') + Left: + IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false') + Next (Regular) Block[B5] +Block[B3] - Block + Predecessors: [B1] + Statements (0) + Jump if False (Regular) to Block[B5] + IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b') + Next (Regular) Block[B4] +Block[B4] - Block + Predecessors: [B3] + Statements (1) + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = false;') + Expression: + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = false') + Left: + IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false') + Next (Regular) Block[B5] +Block[B5] - Exit + Predecessors: [B2] [B3] [B4] + Statements (0) +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, expectedDiagnostics); + } + + [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] + [Fact] + public void IfFlow_26() + { + string source = @" +class P +{ + void M(bool a, bool b, bool c) +/**/{ + if (a) + { + a = false; + } + else if (b) + { + b = false; + } + else + { + c = false; + } + }/**/ +} +"; + string expectedFlowGraph = @" +Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] +Block[B1] - Block + Predecessors: [B0] + Statements (0) + Jump if False (Regular) to Block[B3] + IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a') + Next (Regular) Block[B2] +Block[B2] - Block + Predecessors: [B1] + Statements (1) + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'a = false;') + Expression: + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'a = false') + Left: + IParameterReferenceOperation: a (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'a') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false') + Next (Regular) Block[B6] +Block[B3] - Block + Predecessors: [B1] + Statements (0) + Jump if False (Regular) to Block[B5] + IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b') + Next (Regular) Block[B4] +Block[B4] - Block + Predecessors: [B3] + Statements (1) + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'b = false;') + Expression: + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'b = false') + Left: + IParameterReferenceOperation: b (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'b') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false') + Next (Regular) Block[B6] +Block[B5] - Block + Predecessors: [B3] + Statements (1) + IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'c = false;') + Expression: + ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean) (Syntax: 'c = false') + Left: + IParameterReferenceOperation: c (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'c') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: False) (Syntax: 'false') + Next (Regular) Block[B6] +Block[B6] - Exit + Predecessors: [B2] [B4] [B5] + Statements (0) +"; + var expectedDiagnostics = DiagnosticDescription.None; + + VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, expectedDiagnostics); + } } } diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ILockStatement.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ILockStatement.cs index 4843bb085fcf0..ba3037a381450 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ILockStatement.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ILockStatement.cs @@ -1009,7 +1009,7 @@ void M(P input, bool b) }/**/ } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(WellKnownMember.System_Threading_Monitor__Enter); compilation.MakeMemberMissing(WellKnownMember.System_Threading_Monitor__Enter2); @@ -1098,7 +1098,7 @@ void M(P input, bool b) }/**/ } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(WellKnownMember.System_Threading_Monitor__Exit); string expectedGraph = @" diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IUsingStatement.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IUsingStatement.cs index f83a8e79a35bb..c16115810563f 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IUsingStatement.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IUsingStatement.cs @@ -4146,7 +4146,7 @@ void M(System.IDisposable input, object o) }/**/ } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_IDisposable__Dispose); string expectedGraph = @" diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/AwaitExpressionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/AwaitExpressionTests.cs index 0cdb4221d7784..c47850beca419 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/AwaitExpressionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/AwaitExpressionTests.cs @@ -152,7 +152,7 @@ public void DefaultAwaitExpressionInfo() private AwaitExpressionInfo GetAwaitExpressionInfo(string text, out CSharpCompilation compilation, params DiagnosticDescription[] diagnostics) { var tree = Parse(text, options: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp5)); - var comp = CreateCompilationWithMscorlib45(new SyntaxTree[] { tree }, new MetadataReference[] { SystemRef }); + var comp = CreateCompilationWithMscorlib461(new SyntaxTree[] { tree }, new MetadataReference[] { SystemRef }); comp.VerifyDiagnostics(diagnostics); compilation = comp; var syntaxNode = (AwaitExpressionSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.AwaitExpression).AsNode(); @@ -211,7 +211,7 @@ static int Main() } } "; - var comp = CreateCompilationWithMscorlib45(text, options: TestOptions.ReleaseDll); + var comp = CreateCompilationWithMscorlib461(text, options: TestOptions.ReleaseDll); comp.VerifyEmitDiagnostics( // (16,62): warning 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. // dynamic f = (await GetVal((Func>)(async () => 1)))(); @@ -239,7 +239,7 @@ static async Task Goo() Console.WriteLine(new TypedReference().Equals(await Task.FromResult(0))); } }"; - var comp = CreateCompilationWithMscorlib45(text, options: TestOptions.ReleaseDll); + var comp = CreateCompilationWithMscorlib461(text, options: TestOptions.ReleaseDll); comp.VerifyEmitDiagnostics( // (8,27): error CS4007: Instance of type 'System.TypedReference' cannot be preserved across 'await' or 'yield' boundary. // Console.WriteLine(new TypedReference().Equals(await Task.FromResult(0))); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs index 04501a17c50f2..8197779582e60 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeMoreTests.cs @@ -103,7 +103,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); var verifier = CompileAndVerify(compilation, expectedOutput: "3"); verifier.VerifyDiagnostics(); var testData = verifier.TestData; @@ -230,7 +230,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyEmitDiagnostics( // (6,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Create' // static async MyTask F() { await Task.Delay(0); } @@ -319,7 +319,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyEmitDiagnostics( // (6,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilderFactory.Task' // static async MyTask F() { await Task.Delay(0); } @@ -376,7 +376,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyEmitDiagnostics( // (6,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.Task' // static async MyTask F() { await (Task)null; } @@ -428,7 +428,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); var verifier = CompileAndVerify(compilation); verifier.VerifyDiagnostics(); var testData = verifier.TestData; @@ -509,7 +509,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); var verifier = CompileAndVerify(compilation); verifier.VerifyDiagnostics(); var testData = verifier.TestData; @@ -588,7 +588,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); var verifier = CompileAndVerify(compilation); verifier.VerifyDiagnostics(); var testData = verifier.TestData; @@ -646,7 +646,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }); + var compilation = CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }); var verifier = CompileAndVerify( compilation, expectedSignatures: new[] @@ -697,7 +697,7 @@ internal void GetResult() { } namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyEmitDiagnostics( // (8,26): error CS0656: Missing compiler required member 'string.Task' // async MyTask F() { }; @@ -737,7 +737,7 @@ public void OnCompleted(Action a) { } namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyEmitDiagnostics( // (8,35): error CS0656: Missing compiler required member 'IEquatable.Task' // async MyTask F(T t) => t; @@ -777,7 +777,7 @@ internal void GetResult() { } namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyEmitDiagnostics( // (8,22): error CS1983: The return type of an async method must be void, Task or Task // async MyTask F() { }; @@ -805,7 +805,7 @@ static void Main() { } namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t, int i) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyEmitDiagnostics( // (8,2): error CS7036: There is no argument given that corresponds to the required parameter 'i' of 'AsyncMethodBuilderAttribute.AsyncMethodBuilderAttribute(Type, int)' // [AsyncMethodBuilder(typeof(B2))] class T2 { } @@ -835,7 +835,7 @@ static void Main() { } namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(int i) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyEmitDiagnostics( // (9,13): error CS1983: The return type of an async method must be void, Task or Task // async T f() => await Task.Delay(1); @@ -913,7 +913,7 @@ public void AwaitOnCompleted(ref TAwaiter awaiter, ref public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { } public MyTask Task => default(MyTask); }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); compilation.VerifyEmitDiagnostics( // (13,29): error CS0656: Missing compiler required member 'MyTaskMethodBuilder.SetStateMachine' // static async MyTask F() { await Task.Delay(0); } @@ -1002,7 +1002,7 @@ public void AwaitOnCompleted(ref TAwaiter awaiter, ref public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { } public MyTask Task => default(MyTask); }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); compilation.VerifyEmitDiagnostics( // (17,9): error CS0311: The type 'MyTask.Awaiter' cannot be used as type parameter 'TAwaiter' in the generic type or method 'MyTaskMethodBuilder.AwaitOnCompleted(ref TAwaiter, ref TStateMachine)'. There is no implicit reference conversion from 'MyTask.Awaiter' to 'System.Runtime.CompilerServices.IAsyncStateMachine'. // await F(); @@ -1087,7 +1087,7 @@ public void AwaitOnCompleted(ref TAwaiter awaiter, ref public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine, ICriticalNotifyCompletion { } public MyTask Task => default(MyTask); }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugDll); compilation.VerifyEmitDiagnostics( // (14,40): error CS0311: The type 'C.d__1' cannot be used as type parameter 'TStateMachine' in the generic type or method 'MyTaskMethodBuilder.AwaitUnsafeOnCompleted(ref TAwaiter, ref TStateMachine)'. There is no implicit reference conversion from 'C.d__1' to 'System.Runtime.CompilerServices.ICriticalNotifyCompletion'. // static async MyTask G(T t) { await Task.Delay(0); return t; } @@ -1114,7 +1114,7 @@ static void Main() } } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeDebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.UnsafeDebugExe); compilation.VerifyEmitDiagnostics(); } @@ -1164,7 +1164,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter } public MyTask Task => new MyTask(); }"; - var compilation0 = CreateCompilationWithMscorlib45(source0); + var compilation0 = CreateCompilationWithMscorlib461(source0); var ref0 = compilation0.EmitToImageReference(); var source = @"class Program @@ -1179,7 +1179,7 @@ static void Main() t.GetAwaiter().GetResult(); } }"; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ref0 }); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ref0 }); compilation.VerifyEmitDiagnostics( // (5,9): error CS4027: 'MyTask.Awaiter' does not implement 'INotifyCompletion' // await new MyTask(); @@ -1327,7 +1327,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter } public MyTask Task => new MyTask(); }"; - var compilation0 = CreateCompilationWithMscorlib45(source0); + var compilation0 = CreateCompilationWithMscorlib461(source0); var ref0 = compilation0.EmitToImageReference(); var source = @"class Program @@ -1342,7 +1342,7 @@ static void Main() t.GetAwaiter().GetResult(); } }"; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ref0 }); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ref0 }); compilation.VerifyEmitDiagnostics( // (4,5): error CS0315: The type 'Program.d__0' cannot be used as type parameter 'TStateMachine' in the generic type or method 'MyTaskMethodBuilder.Start(ref TStateMachine)'. There is no boxing conversion from 'Program.d__0' to 'IMyStateMachine'. // { @@ -1401,7 +1401,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter } public MyTask Task => new MyTask(); }"; - var compilation0 = CreateCompilationWithMscorlib45(source0); + var compilation0 = CreateCompilationWithMscorlib461(source0); var ref0 = compilation0.EmitToImageReference(); var source = @"class Program @@ -1416,7 +1416,7 @@ static void Main() t.GetAwaiter().GetResult(); } }"; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ref0 }); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ref0 }); compilation.VerifyEmitDiagnostics( // (5,9): error CS0310: 'MyTask.Awaiter' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TAwaiter' in the generic type or method 'MyTaskMethodBuilder.AwaitOnCompleted(ref TAwaiter, ref TStateMachine)' // await new MyTask(); @@ -1475,7 +1475,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter } public MyTask Task => new MyTask(); }"; - var compilation0 = CreateCompilationWithMscorlib45(source0); + var compilation0 = CreateCompilationWithMscorlib461(source0); var ref0 = compilation0.EmitToImageReference(); var source = @"class Program @@ -1490,7 +1490,7 @@ static void Main() t.GetAwaiter().GetResult(); } }"; - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { ref0 }); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { ref0 }); compilation.VerifyEmitDiagnostics( // (5,9): error CS0311: The type 'MyTask.Awaiter' cannot be used as type parameter 'TAwaiter' in the generic type or method 'MyTaskMethodBuilder.AwaitUnsafeOnCompleted(ref TAwaiter, ref TStateMachine)'. There is no implicit reference conversion from 'MyTask.Awaiter' to 'IMyAwaiter'. // await new MyTask(); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeTests.cs index d29a03008826f..d34a087079884 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTasklikeTests.cs @@ -31,7 +31,7 @@ struct ValueTask { } namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); var methodf = compilation.GetMember("C.f"); var methodg = compilation.GetMember("C.g"); Assert.True(methodf.IsAsync); @@ -92,7 +92,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (15,9): error CS0118: 'GetAwaiter' is a field but is used like a method // await new Unawaitable(); // error: GetAwaiter must be a field not a delegate Diagnostic(ErrorCode.ERR_BadSKknown, "await new Unawaitable()").WithArguments("GetAwaiter", "field", "method").WithLocation(15, 9) @@ -184,7 +184,7 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : source = source.Replace("<>", implicitConversionToTask ? "public static implicit operator Task(ValueTask t) => Task.FromResult(t._result);" : ""); if (isError) { - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); var diagnostics = compilation.GetDiagnostics(); Assert.True(diagnostics.Length == 1); Assert.True(diagnostics.First().Code == (int)ErrorCode.ERR_AmbigCall); @@ -197,7 +197,7 @@ namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : } [Fact] - public bool TasklikeA3() => VerifyTaskOverloads("f(async () => 3)", + public void TasklikeA3() => VerifyTaskOverloads("f(async () => 3)", "f(Func> lambda)", null); @@ -306,7 +306,7 @@ class ValueTaskMethodBuilder {} namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); var methodf = compilation.GetMember("C.f"); var methodg = compilation.GetMember("C.g"); Assert.True(methodf.IsAsync); @@ -325,7 +325,7 @@ static void Main() { } } public class MyTask { } "; - CreateCompilationWithMscorlib45(source1).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source1).VerifyDiagnostics( // (6,18): error CS1983: The return type of an async method must be void, Task or Task // async MyTask f() { await (Task)null; } Diagnostic(ErrorCode.ERR_BadAsyncReturn, "f").WithLocation(6, 18), @@ -343,7 +343,7 @@ static void Main() { } } public class MyTask { } "; - CreateCompilationWithMscorlib45(source2).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source2).VerifyDiagnostics( // (6,18): error CS1983: The return type of an async method must be void, Task or Task // async MyTask f() { await (Task)null; } Diagnostic(ErrorCode.ERR_BadAsyncReturn, "f").WithLocation(6, 18), @@ -369,7 +369,7 @@ public class MyTaskBuilder namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - CreateCompilationWithMscorlib45(source3).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source3).VerifyDiagnostics(); } [Fact] @@ -421,7 +421,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (8,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.h(Func)' and 'C.h(Func)' // h(async () => { await (Task)null; }); Diagnostic(ErrorCode.ERR_AmbigCall, "h").WithArguments("C.h(System.Func)", "C.h(System.Func)").WithLocation(8, 9) @@ -443,7 +443,7 @@ class Mismatch2MethodBuilder {} namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyEmitDiagnostics( // (5,30): error CS1983: The return type of an async method must be void, Task or Task // async Mismatch2 g() { await Task.Delay(0); return 1; } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs index c67dbbdde2610..dd17c9c7c4dcd 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAsyncTests.cs @@ -30,7 +30,7 @@ async void M(Task t) await t; } }"; - var compilation = CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); var method = (SourceMemberMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("M").Single(); Assert.True(method.IsAsync); } @@ -51,7 +51,7 @@ public static void Main() } }"; var tree = SyntaxFactory.ParseSyntaxTree(source); - var compilation = CreateCompilationWithMscorlib45(new SyntaxTree[] { tree }).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(new SyntaxTree[] { tree }).VerifyDiagnostics(); var model = compilation.GetSemanticModel(tree); @@ -80,7 +80,7 @@ public static void Main() } }"; var tree = SyntaxFactory.ParseSyntaxTree(source); - var compilation = CreateCompilationWithMscorlib45(new SyntaxTree[] { tree }).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(new SyntaxTree[] { tree }).VerifyDiagnostics(); var model = compilation.GetSemanticModel(tree); @@ -95,7 +95,7 @@ public void BadAsyncConstructor() class C { async public C() { } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("async")); } @@ -107,7 +107,7 @@ class C { async extern ~C(); }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("async"), Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "C").WithArguments("C.~C()")); } @@ -126,7 +126,7 @@ public C() { async event MyDelegate MyEvent; }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadMemberFlag, "MyEvent").WithArguments("async")); } @@ -143,7 +143,7 @@ public C(int i) async int i; }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadMemberFlag, "i").WithArguments("async")); } @@ -154,7 +154,7 @@ public void BadAsyncClass() public async class C { }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("async")); } @@ -165,7 +165,7 @@ public void BadAsyncStruct() internal async struct S { }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadMemberFlag, "S").WithArguments("async")); } @@ -176,7 +176,7 @@ public void BadAsyncInterface() internal async interface I { }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadMemberFlag, "I").WithArguments("async")); } @@ -186,7 +186,7 @@ public void BadAsyncDelegate() var source = @" public async delegate void MyDelegate(); "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadMemberFlag, "MyDelegate").WithArguments("async")); } @@ -196,7 +196,7 @@ public void BadAsyncProperty() var source = @" public async delegate void MyDelegate(); "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadMemberFlag, "MyDelegate").WithArguments("async")); } @@ -206,7 +206,7 @@ public void BadAsyncPropertyAccessor() var source = @" public async delegate void MyDelegate(); "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_BadMemberFlag, "MyDelegate").WithArguments("async")); } @@ -236,7 +236,7 @@ static void Main() InferTaskOrTaskT(async () => { return await Task.Factory.StartNew(() => 1); }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (14,9): error CS1997: Since 'C.F1()' is an async method that returns 'System.Threading.Tasks.Task', a return keyword must not be followed by an object expression // return await Task.Factory.StartNew(() => 1); Diagnostic(ErrorCode.ERR_TaskRetNoObjectRequired, "return").WithArguments("C.F1()", "System.Threading.Tasks.Task").WithLocation(14, 9), @@ -283,7 +283,7 @@ async T F4() where T : Task await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (17,18): error CS1983: The return type of an async method must be void, Task or Task // async MyTask F2() Diagnostic(ErrorCode.ERR_BadAsyncReturn, "F2"), @@ -325,7 +325,7 @@ static void Main() Func f2 = async () => { return await Task.Factory.StartNew(() => 1); }; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (9,33): error CS4010: Cannot convert async lambda expression to delegate type 'Func'. An async lambda expression may return void, Task or Task, none of which are convertible to 'Func'. // Func f1 = async () => await Task.Factory.StartNew(() => 1); Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "=>").WithArguments("lambda expression", "System.Func").WithLocation(9, 33), @@ -355,7 +355,7 @@ static void Main() InferTask_T(async () => { return await Task.Factory.StartNew(() => new Task(() => 1)); }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (11,42): error CS4016: Since this is an async method, the return expression must be of type 'int' rather than 'Task' // Func> f1 = async () => await Task.Factory.StartNew(() => new Task(null)); Diagnostic(ErrorCode.ERR_BadAsyncReturnExpression, "await Task.Factory.StartNew(() => new Task(null))").WithArguments("int", "System.Threading.Tasks.Task").WithLocation(11, 42), @@ -409,7 +409,7 @@ static void Main() Infer_T(async () => { return await Task.Factory.StartNew(() => { }); }); } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics( // (13,33): error CS8029: Anonymous function converted to a void returning delegate cannot return a value // InferVoid(async () => { return await Task.Factory.StartNew(() => { }); }); Diagnostic(ErrorCode.ERR_RetNoObjectRequiredLambda, "return").WithLocation(13, 33), @@ -446,7 +446,7 @@ static void Main() InferTask_T(async () => { return await Task.Factory.StartNew(() => 1); }); } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics(); } [Fact] @@ -476,7 +476,7 @@ static void Main() }); } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics( // (19,17): error CS0126: An object of a type convertible to 'int' is required // return; Diagnostic(ErrorCode.ERR_RetObjectRequired, "return").WithArguments("int")); @@ -509,7 +509,7 @@ static void Main() }); } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics( // (16,17): error CS8029: Anonymous function converted to a void returning delegate cannot return a value // return 1; Diagnostic(ErrorCode.ERR_RetNoObjectRequiredLambda, "return").WithLocation(16, 17) @@ -543,7 +543,7 @@ static void Main() }); } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics( // (16,17): error CS8030: Async lambda expression converted to a 'System.Threading.Tasks.Task' returning delegate cannot return a value // return 1; Diagnostic(ErrorCode.ERR_TaskRetNoObjectRequiredLambda, "return").WithArguments("System.Threading.Tasks.Task").WithLocation(16, 17) @@ -577,7 +577,7 @@ static void Main() }); } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, new MetadataReference[] { LinqAssemblyRef, SystemRef }).VerifyDiagnostics( // (19,17): error CS0126: An object of a type convertible to 'int' is required // return; Diagnostic(ErrorCode.ERR_RetObjectRequired, "return").WithArguments("int")); @@ -595,7 +595,7 @@ async static Task F() { } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,23): warning 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. // async static Task F() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "F")); @@ -622,7 +622,7 @@ static void Main() Func> f2 = async () => { return await Task.Factory.StartNew(() => { return null; }); }; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -638,7 +638,7 @@ async static Task M1(__arglist) await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,23): error CS4006: __arglist is not allowed in the parameter list of async methods // async static Task M1(__arglist) Diagnostic(ErrorCode.ERR_VarargsAsync, "M1")); @@ -658,7 +658,7 @@ async static Task M1(__arglist) return; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,23): error CS0224: A method with vararg cannot be generic, be in a generic type, or have a params parameter // async static Task M1(__arglist) Diagnostic(ErrorCode.ERR_BadVarargs, "M1")); @@ -678,7 +678,7 @@ async static Task M1(__arglist) return; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,23): error CS0224: A method with vararg cannot be generic, be in a generic type, or have a params parameter // async static Task M1(__arglist) Diagnostic(ErrorCode.ERR_BadVarargs, "M1")); @@ -694,7 +694,7 @@ class Test { unsafe async static Task M1(int* i) { } }"; - CreateCompilationWithMscorlib45(source, null, TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, null, TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (6,38): error CS4005: Async methods cannot have pointer type parameters // unsafe async static Task M1(int* i) Diagnostic(ErrorCode.ERR_UnsafeAsyncArgType, "i"), @@ -713,7 +713,7 @@ class Test { unsafe async static Task M1(delegate* i) { } }"; - CreateCompilationWithMscorlib45(source, null, TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, null, TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (6,49): error CS4005: Async methods cannot have pointer type parameters // unsafe async static Task M1(delegate* i) { } Diagnostic(ErrorCode.ERR_UnsafeAsyncArgType, "i").WithLocation(6, 49), @@ -736,7 +736,7 @@ class Test async static Task M3(int*[] i) { await Task.Yield(); } // 3 async static Task M4(delegate*[] i) { await Task.Yield(); } // 4 }"; - CreateCompilationWithMscorlib45(source, null, TestOptions.UnsafeReleaseDll) + CreateCompilationWithMscorlib461(source, null, TestOptions.UnsafeReleaseDll) .VerifyDiagnostics( // (6,45): error CS4004: Cannot await in an unsafe context // unsafe async static Task M1(int*[] i) { await Task.Yield(); } // 1 @@ -763,7 +763,7 @@ class Test { unsafe async static Task M1(ref int* i) { } }"; - CreateCompilationWithMscorlib45(source, null, TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, null, TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (6,42): error CS1988: Async methods cannot have ref, in or out parameters // unsafe async static Task M1(ref int* i) Diagnostic(ErrorCode.ERR_BadAsyncArgType, "i"), @@ -785,7 +785,7 @@ async static Task M1(ref int i) await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,42): error CS1988: Async methods cannot have ref, in or out parameters // unsafe async static Task M1(ref int* i) { } Diagnostic(ErrorCode.ERR_BadAsyncArgType, "i")); @@ -804,7 +804,7 @@ async static Task M1(out int i) await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,34): error CS1988: Async methods cannot have ref, in or out parameters // async static Task M1(out int i) { } Diagnostic(ErrorCode.ERR_BadAsyncArgType, "i")); @@ -823,7 +823,7 @@ async static Task M1(in int i) await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,33): error CS1988: Async methods cannot have ref, in or out parameters // async static Task M1(in int i) Diagnostic(ErrorCode.ERR_BadAsyncArgType, "i").WithLocation(6, 33) @@ -848,7 +848,7 @@ class C int i = await t; }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (9,14): error CS1992: The 'await' operator can only be used when contained within a method or lambda expression marked with the 'async' modifier // [MyAttribute(await C.t)] Diagnostic(ErrorCode.ERR_BadAwaitWithoutAsync, "await C.t"), @@ -873,7 +873,7 @@ public static void Main() Action f3 = () => { await Task.Factory.StartNew(() => { }); }; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (9,34): error CS4034: The 'await' operator can only be used within an async anonymous method. Consider marking this anonymous method with the 'async' modifier. // Action f1 = delegate() { await Task.Factory.StartNew(() => { }); }; Diagnostic(ErrorCode.ERR_BadAwaitWithoutAsyncLambda, "await Task.Factory.StartNew(() => { })").WithArguments("anonymous method"), @@ -903,7 +903,7 @@ public static int G() return await Task.Factory.StartNew(() => 1); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (8,9): error CS4033: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. // await Task.Factory.StartNew(() => { }); Diagnostic(ErrorCode.ERR_BadAwaitWithoutVoidAsyncMethod, "await Task.Factory.StartNew(() => { })"), @@ -935,7 +935,7 @@ static int Main() } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,32): error CS4032: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. // static int Goo(int[] arr = await t) Diagnostic(ErrorCode.ERR_BadAwaitWithoutAsyncMethod, "await t").WithArguments("int").WithLocation(10, 32) @@ -982,7 +982,7 @@ async static Task M1() { } } }"; - CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp5)).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp5)).VerifyDiagnostics( // (20,17): error CS1984: Cannot await in the body of a finally clause // await Task.Factory.StartNew(() => { }); Diagnostic(ErrorCode.ERR_BadAwaitInFinally, "await Task.Factory.StartNew(() => { })").WithLocation(20, 17), @@ -990,7 +990,7 @@ async static Task M1() { // await Task.Factory.StartNew(() => { }); Diagnostic(ErrorCode.ERR_BadAwaitInFinally, "await Task.Factory.StartNew(() => { })").WithLocation(30, 17) ); - CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6)).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6)).VerifyDiagnostics(); } [Fact] @@ -1014,12 +1014,12 @@ async static Task M1() { } } }"; - CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp5)).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp5)).VerifyDiagnostics( // (12,13): error CS1985: Cannot await in a catch clause // await Task.Factory.StartNew(() => { }); Diagnostic(ErrorCode.ERR_BadAwaitInCatch, "await Task.Factory.StartNew(() => { })").WithLocation(12, 13) ); - CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6)).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6)).VerifyDiagnostics(); } [Fact] @@ -1043,7 +1043,7 @@ async static Task M1() } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (11,19): error CS7094: Cannot await in the filter expression of a catch clause // catch when (await Task.Factory.StartNew(() => false)) Diagnostic(ErrorCode.ERR_BadAwaitInCatchFilter, "await Task.Factory.StartNew(() => false)").WithLocation(11, 21) @@ -1096,7 +1096,7 @@ async static Task M1() { } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,13): error CS1996: Cannot await in the body of a lock statement // await Task.Factory.StartNew(() => { }); Diagnostic(ErrorCode.ERR_BadAwaitInLock, "await Task.Factory.StartNew(() => { })"), @@ -1136,7 +1136,7 @@ async Task M() return await M(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (9,19): error CS1996: Cannot await in the body of a lock statement // lock (await M()) // error, in body of outer lock Diagnostic(ErrorCode.ERR_BadAwaitInLock, "await M()"), @@ -1164,7 +1164,7 @@ public static async void F() static void Main() { } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [WorkItem(611150, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/611150")] @@ -1186,7 +1186,7 @@ static void Main() } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -1211,7 +1211,7 @@ async static Task M2() } } }"; - CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (7,9): error CS4004: Cannot await in an unsafe context // await Task.Factory.StartNew(() => { }); // not OK Diagnostic(ErrorCode.ERR_AwaitInUnsafeContext, "await Task.Factory.StartNew(() => { })"), @@ -1250,7 +1250,7 @@ static Task M2() } } }"; - CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (8,9): error CS4032: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. // await Task.Factory.StartNew(() => { }); Diagnostic(ErrorCode.ERR_BadAwaitWithoutAsyncMethod, "await Task.Factory.StartNew(() => { })").WithArguments("System.Threading.Tasks.Task").WithLocation(8, 9), @@ -1294,7 +1294,7 @@ static void Main() } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -1305,7 +1305,7 @@ interface IInterface { async void F(); }"; - CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular7).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular7).VerifyDiagnostics( // (4,16): error CS8503: The modifier 'async' is not valid for this item in C# 7. Please use language version 'preview' or greater. // async void F(); Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "F").WithArguments("async", "7.0", "8.0").WithLocation(4, 16), @@ -1339,7 +1339,7 @@ async static void F2() var xs = from l in await F1() where l > 1 select l; } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics(); } [Fact] @@ -1368,7 +1368,7 @@ join l2 in await F1() on l equals l2 where l > 1 select l; } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics(); } [Fact] @@ -1396,7 +1396,7 @@ async static void F2() where l > 1 select await F1(); } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics( // (20,37): error CS1995: The 'await' operator may only be used in a query expression within the first collection expression of the initial 'from' clause or within the collection expression of a 'join' clause // where l > 1 select await F1(); Diagnostic(ErrorCode.ERR_BadAwaitInQuery, "await F1()")); @@ -1428,7 +1428,7 @@ where l > 1 select (from l2 in await F1() where l2 > 1 select l2); } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics( // (21,37): error CS1995: The 'await' operator may only be used in a query expression within the first collection expression of the initial 'from' clause or within the collection expression of a 'join' clause // select (from l2 in await F1() where l2 > 1 select l2); Diagnostic(ErrorCode.ERR_BadAwaitInQuery, "await F1()")); @@ -1463,7 +1463,7 @@ where l2 > 1 select l2); } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics( // (22,37): error CS1995: The 'await' operator may only be used in a query expression within the first collection expression of the initial 'from' clause or within the collection expression of a 'join' clause // join l3 in await F1() on l2 equals l3 Diagnostic(ErrorCode.ERR_BadAwaitInQuery, "await F1()")); @@ -1499,7 +1499,7 @@ where l2 > 1 } } }"; - var c = CreateCompilationWithMscorlib45( + var c = CreateCompilationWithMscorlib461( source, new MetadataReference[] { SystemRef, LinqAssemblyRef }, TestOptions.UnsafeReleaseDll); @@ -1540,7 +1540,7 @@ where l2 > 1 select l2); } }"; - CreateCompilationWithMscorlib45( + CreateCompilationWithMscorlib461( source, new MetadataReference[] { SystemRef, LinqAssemblyRef }, TestOptions.ReleaseDll).VerifyDiagnostics( @@ -1574,7 +1574,7 @@ where l > 1 select l; } }"; - CreateCompilationWithMscorlib45(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, new MetadataReference[] { SystemRef, LinqAssemblyRef }).VerifyDiagnostics( // (17,28): error CS4033: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. // var xs = from l in await F1() Diagnostic(ErrorCode.ERR_BadAwaitWithoutVoidAsyncMethod, "await F1()")); @@ -1602,7 +1602,7 @@ static void Main() Func> f5 = async delegate () { return 1; }; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (7,23): warning 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. // async static Task M() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(7, 23), @@ -1650,7 +1650,7 @@ static void Main() F2(false); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (13): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // for (F1(); truth; F1()) ; Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "F1()"), @@ -1699,7 +1699,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (16,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Goo(); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Goo()")); @@ -1739,7 +1739,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( // (19,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Goo(); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Goo()"), @@ -1793,7 +1793,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (21,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Goo(); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Goo()"), @@ -1848,7 +1848,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (19,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // i.MethExt(); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "i.MethExt()").WithLocation(19, 9), @@ -1899,7 +1899,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( // (20,32): warning 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 Meth1() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Meth1"), @@ -1954,7 +1954,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( // (22,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Goo(); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Goo()"), @@ -2025,7 +2025,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (30,13): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Meth(1); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Meth(1)"), @@ -2149,7 +2149,7 @@ static int Main() return Driver.Result; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (55,13): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Meth(x); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Meth(x)"), @@ -2208,7 +2208,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (28,13): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Meth(1); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Meth(1)"), @@ -2274,7 +2274,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (33,13): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // i.Meth(1); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "i.Meth(1)"), @@ -2340,7 +2340,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( // (30,13): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Meth(1); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Meth(1)"), @@ -2388,7 +2388,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (19,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Meth("", null); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, @"Meth("""", null)").WithLocation(19, 9), @@ -2446,7 +2446,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (16,13): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Meth(await Meth(int.MaxValue) + 1); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Meth(await Meth(int.MaxValue) + 1)"), @@ -2478,7 +2478,7 @@ static async Task Goo() } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -2529,7 +2529,7 @@ static int Main() } }"; - CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( // (41,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Meth(1); //warning CS4014 Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Meth(1)"), @@ -2580,7 +2580,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (27,14): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // for (Meth(""); await Meth(false); Meth((float?)null)) Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, @"Meth("""")"), @@ -2646,7 +2646,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (33,14): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // for (testB.Meth2(); await testB.Meth(false); testB.Meth((float?)null)) Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "testB.Meth2()"), @@ -2687,7 +2687,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (15,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Goo(); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Goo()")); @@ -2722,7 +2722,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (29,14): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // s.ExMeth(); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "s.ExMeth()")); @@ -2760,7 +2760,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (18,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Goo(); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Goo()"), @@ -2810,7 +2810,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (21,13): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Goo(); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Goo()")); @@ -2852,7 +2852,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -2887,7 +2887,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, references: new MetadataReference[] { CSharpRef, SystemCoreRef }).VerifyDiagnostics( // (27,17): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // del(y); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "del(y)")); @@ -2929,7 +2929,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -2972,7 +2972,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -3006,7 +3006,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -3043,7 +3043,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (14,34): warning 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. // return Task.Run(async () => { return i; }); Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "=>").WithLocation(14, 34), @@ -3091,7 +3091,7 @@ static int Main() return 0; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (17,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Goo(); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Goo()")); @@ -3125,7 +3125,7 @@ static int Main() } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (22,9): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Goo(); Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "Goo()"), @@ -3141,7 +3141,7 @@ public void UnobservedAwaitableExpression_Script() @"using System.Threading.Tasks; Task.FromResult(1); Task.FromResult(2);"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (2,1): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Task.FromResult(1); @@ -3181,7 +3181,7 @@ static class Test { static async Task M1(); }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,23): error CS1994: The 'async' modifier can only be used in methods that have a body // static async Task M1(); Diagnostic(ErrorCode.ERR_BadAsyncLacksBody, "M1")); @@ -3197,7 +3197,7 @@ static class Test { static async Task M1(__arglist); }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,23): error CS1994: The 'async' modifier can only be used in methods that have a body // static async Task M1(__arglist); Diagnostic(ErrorCode.ERR_BadAsyncLacksBody, "M1")); @@ -3217,7 +3217,7 @@ async Task M1(TypedReference tr) await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (7,34): error CS4012: Parameters of type 'System.TypedReference' cannot be declared in async methods or async lambda expressions // async Task M1(TypedReference tr) Diagnostic(ErrorCode.ERR_BadSpecialByRefParameter, "tr").WithArguments("System.TypedReference")); @@ -3238,7 +3238,7 @@ async Task M1() await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyEmitDiagnostics( // (9,24): warning CS0168: The variable 'tr' is declared but never used // TypedReference tr; Diagnostic(ErrorCode.WRN_UnreferencedVar, "tr").WithArguments("tr")); @@ -3274,7 +3274,7 @@ async Task M3() var tr2 = tr; } }"; - CreateCompilationWithMscorlib45(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyEmitDiagnostics( // (9,13): warning CS0219: The variable 'tr' is assigned but its value is never used // var tr = new TypedReference(); // 1 Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "tr").WithArguments("tr").WithLocation(9, 13), @@ -3296,7 +3296,7 @@ unsafe async public static void F() fixed (TypedReference tr) { } } }"; - CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (8,31): error CS0209: The type of a local declared in a fixed statement must be a pointer type // fixed (TypedReference tr) { } Diagnostic(ErrorCode.ERR_BadFixedInitType, "tr"), @@ -3323,7 +3323,7 @@ public async void M() await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (8,23): error CS4031: Async methods are not allowed in an Interface, Class, or Structure which has the 'SecurityCritical' or 'SecuritySafeCritical' attribute. // public async void M() Diagnostic(ErrorCode.ERR_SecurityCriticalOrSecuritySafeCriticalOnAsyncInClassOrStruct, "M")); @@ -3344,7 +3344,7 @@ public async void M() await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (8,23): error CS4031: Async methods are not allowed in an Interface, Class, or Structure which has the 'SecurityCritical' or 'SecuritySafeCritical' attribute. // public async void M() Diagnostic(ErrorCode.ERR_SecurityCriticalOrSecuritySafeCriticalOnAsyncInClassOrStruct, "M")); @@ -3366,7 +3366,7 @@ public async void M() await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (9,23): error CS4031: Async methods are not allowed in an Interface, Class, or Structure which has the 'SecurityCritical' or 'SecuritySafeCritical' attribute. // public async void M() Diagnostic(ErrorCode.ERR_SecurityCriticalOrSecuritySafeCriticalOnAsyncInClassOrStruct, "M")); @@ -3392,7 +3392,7 @@ public async void M() } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (12,27): error CS4031: Async methods are not allowed in an Interface, Class, or Structure which has the 'SecurityCritical' or 'SecuritySafeCritical' attribute. // public async void M() Diagnostic(ErrorCode.ERR_SecurityCriticalOrSecuritySafeCriticalOnAsyncInClassOrStruct, "M")); @@ -3413,7 +3413,7 @@ public async void M() await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (7,6): error CS4030: Security attribute 'SecurityCritical' cannot be applied to an Async method. // [SecurityCritical] Diagnostic(ErrorCode.ERR_SecurityCriticalOrSecuritySafeCriticalOnAsync, "SecurityCritical").WithArguments("SecurityCritical")); @@ -3434,7 +3434,7 @@ public async void M() await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (7,6): error CS4030: Security attribute 'SecuritySafeCritical' cannot be applied to an Async method. // [SecuritySafeCritical] Diagnostic(ErrorCode.ERR_SecurityCriticalOrSecuritySafeCriticalOnAsync, "SecuritySafeCritical").WithArguments("SecuritySafeCritical")); @@ -3456,7 +3456,7 @@ public async void M() await Task.Factory.StartNew(() => { }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (7,6): error CS4030: Security attribute 'SecurityCritical' cannot be applied to an Async method. // [SecurityCritical] Diagnostic(ErrorCode.ERR_SecurityCriticalOrSecuritySafeCriticalOnAsync, "SecurityCritical").WithArguments("SecurityCritical"), @@ -3475,7 +3475,7 @@ async void Meth() { } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,16): warning 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. // async void Meth() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Meth")); @@ -3497,7 +3497,7 @@ public static int Main() return 1; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,32): error CS1994: The 'async' modifier can only be used in methods that have a body. // public async abstract void M1(); Diagnostic(ErrorCode.ERR_BadAsyncLacksBody, "M1")); @@ -3514,7 +3514,7 @@ async public static Task Main() { } }"; - CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics( // (5,30): warning 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. // async public static Task Main() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Main").WithLocation(5, 30)); @@ -3531,7 +3531,7 @@ async public static Task Main() { } }"; - var comp = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); + var comp = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7)); comp.VerifyDiagnostics( // (5,30): warning 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. // async public static Task Main() @@ -3558,7 +3558,7 @@ static int Main() public async void Goo(ref int x) { } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (9,35): error CS1988: Async methods cannot have ref, in or out parameters // public async void Goo(ref int x) Diagnostic(ErrorCode.ERR_BadAsyncArgType, "x"), @@ -3582,7 +3582,7 @@ async Task F1() return await Task.Factory.StartNew(() => 1); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (9,21): error CS4015: 'MethodImplOptions.Synchronized' cannot be applied to an Async method. // async Task F1() Diagnostic(ErrorCode.ERR_SynchronizedAsyncMethod, "F1")); @@ -3606,7 +3606,7 @@ void M() }; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (9,81): error CS4015: 'MethodImplOptions.Synchronized' cannot be applied to an async method // var a = [MethodImpl(MethodImplOptions.Synchronized)] async Task () => Diagnostic(ErrorCode.ERR_SynchronizedAsyncMethod, "=>").WithLocation(9, 81)); @@ -3630,7 +3630,7 @@ async Task local() } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,25): error CS4015: 'MethodImplOptions.Synchronized' cannot be applied to an async method // async Task local() Diagnostic(ErrorCode.ERR_SynchronizedAsyncMethod, "local").WithLocation(10, 25), @@ -3656,7 +3656,7 @@ async int F1() return await Task.Factory.StartNew(() => 1); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,15): error CS1983: The return type of an async method must be void, Task or Task // async int F1() Diagnostic(ErrorCode.ERR_BadAsyncReturn, "F1"), @@ -3707,7 +3707,7 @@ public static void Main(string[] args) } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -3723,7 +3723,7 @@ static void Main() Func x = async delegate { throw null; }; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,29): error CS4010: Cannot convert async anonymous method to delegate type 'Func'. An async anonymous method may return void, Task or Task, none of which are convertible to 'Func'. // Func x = async delegate { throw null; }; Diagnostic(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, "delegate").WithArguments("anonymous method", "System.Func"), @@ -3748,7 +3748,7 @@ async void Goo() await Task.Delay(1); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (8,26): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression // Action x = (await) => { }; // should be a syntax error Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(8, 26) @@ -3774,7 +3774,7 @@ public async Task F(C x) } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (12,17): error CS0118: 'GetAwaiter' is a field but is used like a method Diagnostic(ErrorCode.ERR_BadSKknown, "await x").WithArguments("GetAwaiter", "field", "method")); } @@ -3798,7 +3798,7 @@ public async Task F(C x) } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (12,16): error CS0118: 'GetAwaiter' is a property but is used like a method Diagnostic(ErrorCode.ERR_BadSKknown, "await x").WithArguments("GetAwaiter", "property", "method")); } @@ -3818,7 +3818,7 @@ static async Task Goo() return 1; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (9,16): error CS0029: Cannot implicitly convert type 'int' to 'T' // return 1; Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "T") @@ -3850,7 +3850,7 @@ static void Main() Console.WriteLine(x); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (11,38): error CS1988: Async methods cannot have ref, in or out parameters // D d = async delegate(ref int i) Diagnostic(ErrorCode.ERR_BadAsyncArgType, "i") @@ -3892,7 +3892,7 @@ Task YAsync() }"; // The rules for when we give a warning may seem quirky, but we aim to precisely replicate // the diagnostics produced by the native compiler. - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (12,27): warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. // Action x1 = () => XAsync(); // warn Diagnostic(ErrorCode.WRN_UnobservedAwaitableExpression, "XAsync()"), @@ -3945,7 +3945,7 @@ static void M() } }"; var reference = CompileIL(ilSource); - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { reference }); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { reference }); compilation.VerifyEmitDiagnostics(); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAwaitTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAwaitTests.cs index 4a5de7c40f8a2..eb4b6f91c7492 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAwaitTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingAwaitTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics { @@ -44,7 +45,7 @@ static async void f() await goo; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (8,15): error CS0103: The name 'goo' does not exist in the current context // await goo; Diagnostic(ErrorCode.ERR_NameNotInContext, "goo").WithArguments("goo")); @@ -67,7 +68,7 @@ static async void f() class A { }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (8,9): error CS1061: 'A' does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type 'A' could be found (are you missing a using directive or an assembly reference?) // await new A(); Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "await new A()").WithArguments("A", "GetAwaiter") @@ -121,7 +122,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return true; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0122: 'A.GetAwaiter()' is inaccessible due to its protection level // await new A(); Diagnostic(ErrorCode.ERR_BadAccess, "await new A()").WithArguments("A.GetAwaiter()"), @@ -169,7 +170,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return true; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (11,9): error CS1986: 'await' requires that the type B have a suitable GetAwaiter method // await new B(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new B()").WithArguments("B") @@ -216,7 +217,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return true; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS1955: Non-invocable member 'A.GetAwaiter' cannot be used like a method. // await new A(); Diagnostic(ErrorCode.ERR_NonInvocableMemberCalled, "await new A()").WithArguments("A.GetAwaiter"), @@ -253,7 +254,7 @@ static async void F() await new A(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (22,9): error CS1986: 'await' requires that the type A have a suitable GetAwaiter method // await new A(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new A()").WithArguments("A")); @@ -279,7 +280,7 @@ class A { public void GetAwaiter() { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS1986: 'await' requires that the type A have a suitable GetAwaiter method // await new A(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new A()").WithArguments("A")); @@ -335,7 +336,7 @@ public static Awaiter GetAwaiter(this C a) return new Awaiter(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,15): error CS1929: 'A' does not contain a definition for 'GetAwaiter' and the best extension method overload 'MyExtensions.GetAwaiter(C)' requires a receiver of type 'C' // await new A(); Diagnostic(ErrorCode.ERR_BadInstanceArgType, "new A()").WithArguments("A", "GetAwaiter", "MyExtensions.GetAwaiter(C)", "C"), @@ -391,7 +392,7 @@ public void OnCompleted(System.Action x) { } public bool IsCompleted { get { return true; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (14,9): error CS0121: The call is ambiguous between the following methods or properties: 'Test.GetAwaiter(A)' and 'E.GetAwaiter(A)' // new A().GetAwaiter(); Diagnostic(ErrorCode.ERR_AmbigCall, "GetAwaiter").WithArguments("Test.GetAwaiter(A)", "E.GetAwaiter(A)"), @@ -452,7 +453,7 @@ static void Main() public static Awaiter GetAwaiter(this I2 a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (31,9): error CS0121: The call is ambiguous between the following methods or properties: 'E.GetAwaiter(I1)' and 'E.GetAwaiter(I2)' // await new A(); Diagnostic(ErrorCode.ERR_AmbigCall, "await new A()").WithArguments("E.GetAwaiter(I1)", "E.GetAwaiter(I2)") @@ -497,7 +498,7 @@ static void Main() public static Awaiter GetAwaiter(this A a, object o = null) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (19,9): error CS1986: 'await' requires that the type A have a suitable GetAwaiter method // await new A(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new A()").WithArguments("A")); @@ -541,7 +542,7 @@ static void Main() public static Awaiter GetAwaiter(this I1 a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (19,9): error CS1986: 'await' requires that the type A have a suitable GetAwaiter method // await new A(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new A()").WithArguments("A")); @@ -578,7 +579,7 @@ public static class E { public static Awaiter GetAwaiter(this A a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -612,7 +613,7 @@ public static class E { public static Awaiter GetAwaiter(this A a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (19,9): error CS0121: The call is ambiguous between the following methods or properties: 'Test.GetAwaiter(A)' and 'E.GetAwaiter(A)' // await new A(); Diagnostic(ErrorCode.ERR_AmbigCall, "await new A()").WithArguments("Test.GetAwaiter(A)", "E.GetAwaiter(A)")); @@ -651,7 +652,7 @@ public static class E { public static Awaiter GetAwaiter(this A a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -686,7 +687,7 @@ public static class E { public static void GetAwaiter(this object a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (24,9): error CS1986: 'await' requires that the type A have a suitable GetAwaiter method // await new A(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new A()").WithArguments("A")); @@ -732,7 +733,7 @@ public static class E2 { public static Awaiter GetAwaiter(this A a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (20,9): error CS0121: The call is ambiguous between the following methods or properties: 'E1.GetAwaiter(A)' and 'E2.GetAwaiter(A)' // await new A(); Diagnostic(ErrorCode.ERR_AmbigCall, "await new A()").WithArguments("E1.GetAwaiter(A)", "E2.GetAwaiter(A)") @@ -779,7 +780,7 @@ public static class E2 { public static void GetAwaiter(this A a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (20,9): error CS0121: The call is ambiguous between the following methods or properties: 'E1.GetAwaiter(A)' and 'E2.GetAwaiter(A)' // await new A(); Diagnostic(ErrorCode.ERR_AmbigCall, "await new A()").WithArguments("E1.GetAwaiter(A)", "E2.GetAwaiter(A)") @@ -817,7 +818,7 @@ public static class E { public static Awaiter GetAwaiter(this A a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -856,7 +857,7 @@ public static class EE { public static void GetAwaiter(this object a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (24,9): error CS0121: The call is ambiguous between the following methods or properties: 'Test.GetAwaiter(object)' and 'EE.GetAwaiter(object)' // await new A(); Diagnostic(ErrorCode.ERR_AmbigCall, "await new A()").WithArguments("Test.GetAwaiter(object)", "EE.GetAwaiter(object)") @@ -899,7 +900,7 @@ public static class EE { public static Awaiter GetAwaiter(this object a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (24,9): error CS0121: The call is ambiguous between the following methods or properties: 'Test.GetAwaiter(object)' and 'EE.GetAwaiter(object)' // await new A(); Diagnostic(ErrorCode.ERR_AmbigCall, "await new A()").WithArguments("Test.GetAwaiter(object)", "EE.GetAwaiter(object)") @@ -943,7 +944,7 @@ public static class E public static Awaiter GetAwaiter(this A a) { throw new Exception(); } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (24,17): error CS1986: 'await' requires that the type A have a suitable GetAwaiter method // await new A(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new A()").WithArguments("A")); @@ -988,7 +989,7 @@ public static class E public static Awaiter GetAwaiter(this A a) { throw new Exception(); } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -1033,7 +1034,7 @@ public static class EE public static Awaiter GetAwaiter(this A a) { throw new Exception(); } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (11,9): error CS1986: 'await' requires that the type A have a suitable GetAwaiter method // await new A(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new A()").WithArguments("A")); @@ -1081,7 +1082,7 @@ public static class EE public static Awaiter GetAwaiter(this A a) { throw new Exception(); } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (11,9): error CS1986: 'await' requires that the type A have a suitable GetAwaiter method // await new A(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new A()").WithArguments("A")); @@ -1131,7 +1132,7 @@ public static class E2 { public static Awaiter GetAwaiter(this A a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (23,13): error CS0121: The call is ambiguous between the following methods or properties: 'E1.GetAwaiter(A)' and 'E2.GetAwaiter(A)' // await new A(); Diagnostic(ErrorCode.ERR_AmbigCall, "await new A()").WithArguments("E1.GetAwaiter(A)", "E2.GetAwaiter(A)") @@ -1182,7 +1183,7 @@ public static class E2 { public static void GetAwaiter(this A a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (23,13): error CS0121: The call is ambiguous between the following methods or properties: 'E1.GetAwaiter(A)' and 'E2.GetAwaiter(A)' // await new A(); Diagnostic(ErrorCode.ERR_AmbigCall, "await new A()").WithArguments("E1.GetAwaiter(A)", "E2.GetAwaiter(A)") @@ -1240,7 +1241,7 @@ public static class E2 public static Awaiter GetAwaiter(this A a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -1298,7 +1299,7 @@ public static class E2 public static Awaiter GetAwaiter(this A a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -1356,7 +1357,7 @@ public static class E2 public static Awaiter GetAwaiter(this A a) { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (11,9): error CS1986: 'await' requires that the type A have a suitable GetAwaiter method // await new A(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new A()").WithArguments("A")); @@ -1399,7 +1400,7 @@ public static Awaiter GetAwaiter(this A a) return new Awaiter(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -1439,7 +1440,7 @@ public static Awaiter GetAwaiter(this A a) return new Awaiter(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS1986: 'await' requires that the type A have a suitable GetAwaiter method // await new A(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new A()").WithArguments("A")); @@ -1510,7 +1511,7 @@ public static Awaiter GetAwaiter(this D a, object o) return new Awaiter(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS1986: 'await' requires that the type A have a suitable GetAwaiter method // await new A(); Diagnostic(ErrorCode.ERR_BadAwaitArg, "await new A()").WithArguments("A").WithLocation(10, 9), @@ -1568,7 +1569,7 @@ public static Awaiter GetAwaiter(this B a) return null; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0411: The type arguments for method 'A.GetAwaiter()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // await new A(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "await new A()").WithArguments("A.GetAwaiter()"), @@ -1659,7 +1660,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return true; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (13,9): error CS4027: 'Awaiter4' does not implement 'System.Runtime.CompilerServices.INotifyCompletion' // await new D(); Diagnostic(ErrorCode.ERR_DoesntImplementAwaitInterface, "await new D()").WithArguments("Awaiter4", "System.Runtime.CompilerServices.INotifyCompletion")); @@ -1718,7 +1719,7 @@ static async void F() await new Awaitable(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (37,9): error CS4027: 'T1' does not implement 'System.Runtime.CompilerServices.INotifyCompletion' // await new Awaitable(); Diagnostic(ErrorCode.ERR_DoesntImplementAwaitInterface, "await new Awaitable()").WithArguments("T1", "System.Runtime.CompilerServices.INotifyCompletion").WithLocation(37, 9), @@ -1786,7 +1787,7 @@ internal override async void F() await new Awaitable(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (31,9): error CS4027: 'U' does not implement 'System.Runtime.CompilerServices.INotifyCompletion' // await new Awaitable(); Diagnostic(ErrorCode.ERR_DoesntImplementAwaitInterface, "await new Awaitable()").WithArguments("U", "System.Runtime.CompilerServices.INotifyCompletion").WithLocation(31, 9), @@ -1838,7 +1839,7 @@ async void F() await new Awaitable>(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (34,9): error CS4027: 'B' does not implement 'System.Runtime.CompilerServices.INotifyCompletion' // await new Awaitable(); Diagnostic(ErrorCode.ERR_DoesntImplementAwaitInterface, "await new Awaitable()").WithArguments("B", "System.Runtime.CompilerServices.INotifyCompletion").WithLocation(34, 9), @@ -1892,7 +1893,7 @@ static async void F() await new Awaitable(); } }"; - var compilation = CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); var verifier = CompileAndVerify(compilation); var actualIL = verifier.VisualizeIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()"); var calls = actualIL.Split(new[] { '\n', '\r' }, System.StringSplitOptions.RemoveEmptyEntries).Where(s => s.Contains("OnCompleted")).ToArray(); @@ -1949,7 +1950,7 @@ public static Awaiter GetAwaiter(this B a) return null; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (28,17): error CS0629: Conditional member 'Awaiter.OnCompleted(System.Action)' cannot implement interface member 'System.Runtime.CompilerServices.INotifyCompletion.OnCompleted(System.Action)' in type 'Awaiter' // public void OnCompleted(Action x) { } Diagnostic(ErrorCode.ERR_InterfaceImplementedByConditional, "OnCompleted").WithArguments("Awaiter.OnCompleted(System.Action)", "System.Runtime.CompilerServices.INotifyCompletion.OnCompleted(System.Action)", "Awaiter")); @@ -1982,7 +1983,7 @@ public void OnCompleted(Action x) { } public bool GetResult() { throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0117: 'Awaiter' does not contain a definition for 'IsCompleted' // await new A(); Diagnostic(ErrorCode.ERR_NoSuchMember, "await new A()").WithArguments("Awaiter", "IsCompleted")); @@ -2017,7 +2018,7 @@ public void OnCompleted(Action x) { } bool IsCompleted { get { return false; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0117: 'Awaiter' does not contain a definition for 'IsCompleted' // await new A(); Diagnostic(ErrorCode.ERR_NoSuchMember, "await new A()").WithArguments("Awaiter", "IsCompleted")); @@ -2052,7 +2053,7 @@ public void OnCompleted(Action x) { } public static bool IsCompleted { get { return false; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0176: Member 'Awaiter.IsCompleted' cannot be accessed with an instance reference; qualify it with a type name instead // await new A(); Diagnostic(ErrorCode.ERR_ObjectProhibited, "await new A()").WithArguments("Awaiter.IsCompleted") @@ -2088,7 +2089,7 @@ public void OnCompleted(Action x) { } public static bool IsCompleted { set { } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0176: Member 'Awaiter.IsCompleted' cannot be accessed with an instance reference; qualify it with a type name instead // await new A(); Diagnostic(ErrorCode.ERR_ObjectProhibited, "await new A()").WithArguments("Awaiter.IsCompleted") @@ -2124,7 +2125,7 @@ public void OnCompleted(Action x) { } public static bool IsCompleted { } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (25,24): error CS0548: 'Awaiter.IsCompleted': property or indexer must have at least one accessor // public static bool IsCompleted { } Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "IsCompleted").WithArguments("Awaiter.IsCompleted"), @@ -2163,7 +2164,7 @@ public void OnCompleted(Action x) { } public int IsCompleted { get { return -1; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS4011: 'await' requires that the return type 'Awaiter' of 'A.GetAwaiter()' have suitable IsCompleted, OnCompleted, and GetResult members, and implement INotifyCompletion or ICriticalNotifyCompletion // await new A(); Diagnostic(ErrorCode.ERR_BadAwaiterPattern, "await new A()").WithArguments("Awaiter", "A")); @@ -2198,7 +2199,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { set { } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0117: 'A' does not contain a definition for 'IsCompleted' // await new A(); Diagnostic(ErrorCode.ERR_PropertyLacksGet, "await new A()").WithArguments("Awaiter.IsCompleted")); @@ -2233,7 +2234,7 @@ public void OnCompleted(Action x) { } public int IsCompleted { set { } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0117: 'A' does not contain a definition for 'IsCompleted' // await new A(); Diagnostic(ErrorCode.ERR_PropertyLacksGet, "await new A()").WithArguments("Awaiter.IsCompleted")); @@ -2266,7 +2267,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return false; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0117: 'Awaiter' does not contain a definition for 'GetResult' // await new A(); Diagnostic(ErrorCode.ERR_NoSuchMember, "await new A()").WithArguments("Awaiter", "GetResult")); @@ -2301,7 +2302,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return false; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0122: 'Awaiter.GetResult()' is inaccessible due to its protection level // await new A(); Diagnostic(ErrorCode.ERR_BadAccess, "await new A()").WithArguments("Awaiter.GetResult()") @@ -2337,7 +2338,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return false; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0176: Member 'Awaiter.GetResult()' cannot be accessed with an instance reference; qualify it with a type name instead // await new A(); Diagnostic(ErrorCode.ERR_ObjectProhibited, "await new A()").WithArguments("Awaiter.GetResult()")); @@ -2378,7 +2379,7 @@ public static bool GetResult(this Awaiter a) throw new Exception(); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0117: 'Awaiter' does not contain a definition for 'GetResult' // await new A(); Diagnostic(ErrorCode.ERR_NoSuchMember, "await new A()").WithArguments("Awaiter", "GetResult")); @@ -2413,7 +2414,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return false; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS4011: 'await' requires that the return type 'Awaiter' of 'A.GetAwaiter()' have suitable IsCompleted, OnCompleted, and GetResult members, and implement INotifyCompletion or ICriticalNotifyCompletion // await new A(); Diagnostic(ErrorCode.ERR_BadAwaiterPattern, "await new A()").WithArguments("Awaiter", "A")); @@ -2448,7 +2449,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return false; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS0411: The type arguments for method 'Awaiter.GetResult()' cannot be inferred from the usage. Try specifying the type arguments explicitly. // await new A(); Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "await new A()").WithArguments("Awaiter.GetResult()") @@ -2482,7 +2483,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return true; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (15,9): error CS4011: 'await' requires that the return type 'Awaiter' of 'A.GetAwaiter()' have suitable IsCompleted, OnCompleted, and GetResult members, and implement INotifyCompletion or ICriticalNotifyCompletion // await new A(); Diagnostic(ErrorCode.ERR_BadAwaiterPattern, "await new A()").WithArguments("Awaiter", "A")); @@ -2515,7 +2516,7 @@ class Awaiter //: System.Runtime.CompilerServices.INotifyCompletion //public bool IsCompleted { get { return true; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (8,9): error CS0117: 'Awaiter' does not contain a definition for 'IsCompleted' // await new A(); Diagnostic(ErrorCode.ERR_NoSuchMember, "await new A()").WithArguments("Awaiter", "IsCompleted")); @@ -2548,7 +2549,7 @@ class Awaiter //: System.Runtime.CompilerServices.INotifyCompletion public bool IsCompleted { get { return true; } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (8,9): error CS4027: 'Awaiter' does not implement 'System.Runtime.CompilerServices.INotifyCompletion' // await new A(); Diagnostic(ErrorCode.ERR_DoesntImplementAwaitInterface, "await new A()").WithArguments("Awaiter", "System.Runtime.CompilerServices.INotifyCompletion")); @@ -2592,7 +2593,7 @@ async void M() } } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,22): error CS0103: The name 'goo' does not exist in the current context // using (await goo()) Diagnostic(ErrorCode.ERR_NameNotInContext, "goo").WithArguments("goo")); @@ -2628,7 +2629,7 @@ public async void awaitLambda() public static void Main() { } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (8,9): error CS4008: Cannot await 'void' // await goo(); Diagnostic(ErrorCode.ERR_BadAwaitArgVoidCall, "await goo()"), @@ -2663,7 +2664,7 @@ public async void bar() public static void Main() { } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,9): error CS4008: Cannot await 'void' // await goo(); Diagnostic(ErrorCode.ERR_BadAwaitArgVoidCall, "await goo()")); @@ -2683,7 +2684,7 @@ public IVsTask ResolveReferenceAsync() }); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,12): error CS0246: The type or namespace name 'IVsTask' could not be found (are you missing a using directive or an assembly reference?) // public IVsTask ResolveReferenceAsync() Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "IVsTask").WithArguments("IVsTask").WithLocation(4, 12), @@ -2722,7 +2723,7 @@ class D { Action a = async x => await x; }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (23,31): error CS0118: 'GetResult' is a property but is used like a method // Action a = async x => await x; Diagnostic(ErrorCode.ERR_BadSKknown, "await x").WithArguments("GetResult", "property", "method") @@ -2758,7 +2759,7 @@ static void Main() } }"; - var comp = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef, CSharpRef }, TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef, CSharpRef }, TestOptions.ReleaseExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "42"); @@ -2830,7 +2831,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib45(source, new[] { TestMetadata.Net40.SystemCore, TestMetadata.Net40.MicrosoftCSharp }, TestOptions.ReleaseExe); + var comp = CreateCompilationWithMscorlib461(source, new[] { Net40.References.SystemCore, Net40.References.MicrosoftCSharp }, TestOptions.ReleaseExe); comp.VerifyDiagnostics( // warning CS1685: The predefined type 'ExtensionAttribute' is defined in multiple assemblies in the global alias; using definition from 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' Diagnostic(ErrorCode.WRN_MultiplePredefTypes).WithArguments("System.Runtime.CompilerServices.ExtensionAttribute", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089").WithLocation(1, 1)); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs index 141b23ed071f5..0d5e3f4c706bc 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs @@ -12,6 +12,7 @@ using Roslyn.Test.Utilities; using Xunit; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics { @@ -1583,7 +1584,7 @@ public void UseSiteErrorViaImplementedInterfaceMember_1() public struct ImageMoniker { }"; - CSharpCompilation comp1 = CreateCompilationWithMscorlib45(source1, assemblyName: "Pia948674_1"); + CSharpCompilation comp1 = CreateCompilationWithMscorlib461(source1, assemblyName: "Pia948674_1"); var source2 = @" public interface IBar @@ -1591,7 +1592,7 @@ public interface IBar ImageMoniker? Moniker { get; } }"; - CSharpCompilation comp2 = CreateCompilationWithMscorlib45(source2, new MetadataReference[] { new CSharpCompilationReference(comp1, embedInteropTypes: true) }, assemblyName: "Bar948674_1"); + CSharpCompilation comp2 = CreateCompilationWithMscorlib461(source2, new MetadataReference[] { new CSharpCompilationReference(comp1, embedInteropTypes: true) }, assemblyName: "Bar948674_1"); var source3 = @" public class BarImpl : IBar @@ -1602,7 +1603,7 @@ public ImageMoniker? Moniker } }"; - CSharpCompilation comp3 = CreateCompilationWithMscorlib45(source3, new MetadataReference[] { new CSharpCompilationReference(comp2), new CSharpCompilationReference(comp1, embedInteropTypes: true) }); + CSharpCompilation comp3 = CreateCompilationWithMscorlib461(source3, new MetadataReference[] { new CSharpCompilationReference(comp2), new CSharpCompilationReference(comp1, embedInteropTypes: true) }); comp3.VerifyDiagnostics( // (2,24): error CS1769: Type 'ImageMoniker?' from assembly 'Bar948674_1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' cannot be used across assembly boundaries because it has a generic type argument that is an embedded interop type. @@ -1610,7 +1611,7 @@ public ImageMoniker? Moniker Diagnostic(ErrorCode.ERR_GenericsUsedAcrossAssemblies, "IBar").WithArguments("ImageMoniker?", "Bar948674_1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(2, 24) ); - comp3 = CreateCompilationWithMscorlib45(source3, new MetadataReference[] { comp2.EmitToImageReference(), comp1.EmitToImageReference().WithEmbedInteropTypes(true) }); + comp3 = CreateCompilationWithMscorlib461(source3, new MetadataReference[] { comp2.EmitToImageReference(), comp1.EmitToImageReference().WithEmbedInteropTypes(true) }); comp3.VerifyDiagnostics( // (2,24): error CS1769: Type 'ImageMoniker?' from assembly 'Bar948674_1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' cannot be used across assembly boundaries because it has a generic type argument that is an embedded interop type. @@ -1636,7 +1637,7 @@ public void UseSiteErrorViaImplementedInterfaceMember_2() public struct ImageMoniker { }"; - CSharpCompilation comp1 = CreateCompilationWithMscorlib45(source1, assemblyName: "Pia948674_2"); + CSharpCompilation comp1 = CreateCompilationWithMscorlib461(source1, assemblyName: "Pia948674_2"); var source2 = @" public interface IBar @@ -1644,7 +1645,7 @@ public interface IBar ImageMoniker? Moniker { get; } }"; - CSharpCompilation comp2 = CreateCompilationWithMscorlib45(source2, new MetadataReference[] { new CSharpCompilationReference(comp1, embedInteropTypes: true) }, assemblyName: "Bar948674_2"); + CSharpCompilation comp2 = CreateCompilationWithMscorlib461(source2, new MetadataReference[] { new CSharpCompilationReference(comp1, embedInteropTypes: true) }, assemblyName: "Bar948674_2"); var source3 = @" public class BarImpl : IBar @@ -1655,7 +1656,7 @@ public class BarImpl : IBar } }"; - CSharpCompilation comp3 = CreateCompilationWithMscorlib45(source3, new MetadataReference[] { new CSharpCompilationReference(comp2), new CSharpCompilationReference(comp1, embedInteropTypes: true) }); + CSharpCompilation comp3 = CreateCompilationWithMscorlib461(source3, new MetadataReference[] { new CSharpCompilationReference(comp2), new CSharpCompilationReference(comp1, embedInteropTypes: true) }); comp3.VerifyDiagnostics( // (4,24): error CS0539: 'BarImpl.Moniker' in explicit interface declaration is not a member of interface @@ -1666,7 +1667,7 @@ public class BarImpl : IBar Diagnostic(ErrorCode.ERR_GenericsUsedAcrossAssemblies, "IBar").WithArguments("ImageMoniker?", "Bar948674_2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(2, 24) ); - comp3 = CreateCompilationWithMscorlib45(source3, new MetadataReference[] { comp2.EmitToImageReference(), comp1.EmitToImageReference().WithEmbedInteropTypes(true) }); + comp3 = CreateCompilationWithMscorlib461(source3, new MetadataReference[] { comp2.EmitToImageReference(), comp1.EmitToImageReference().WithEmbedInteropTypes(true) }); comp3.VerifyDiagnostics( // (4,24): error CS0539: 'BarImpl.Moniker' in explicit interface declaration is not a member of interface @@ -1692,7 +1693,7 @@ public void UseSiteErrorViaImplementedInterfaceMember_3() public struct ImageMoniker { }"; - CSharpCompilation comp1 = CreateCompilationWithMscorlib45(source1, assemblyName: "Pia948674_3"); + CSharpCompilation comp1 = CreateCompilationWithMscorlib461(source1, assemblyName: "Pia948674_3"); var source2 = @" public interface IBar @@ -1700,7 +1701,7 @@ public interface IBar void SetMoniker(ImageMoniker? moniker); }"; - CSharpCompilation comp2 = CreateCompilationWithMscorlib45(source2, new MetadataReference[] { new CSharpCompilationReference(comp1, embedInteropTypes: true) }, assemblyName: "Bar948674_3"); + CSharpCompilation comp2 = CreateCompilationWithMscorlib461(source2, new MetadataReference[] { new CSharpCompilationReference(comp1, embedInteropTypes: true) }, assemblyName: "Bar948674_3"); var source3 = @" public class BarImpl : IBar @@ -1709,7 +1710,7 @@ public void SetMoniker(ImageMoniker? moniker) {} }"; - CSharpCompilation comp3 = CreateCompilationWithMscorlib45(source3, new MetadataReference[] { new CSharpCompilationReference(comp2), new CSharpCompilationReference(comp1, embedInteropTypes: true) }); + CSharpCompilation comp3 = CreateCompilationWithMscorlib461(source3, new MetadataReference[] { new CSharpCompilationReference(comp2), new CSharpCompilationReference(comp1, embedInteropTypes: true) }); comp3.VerifyDiagnostics( // (2,24): error CS1769: Type 'ImageMoniker?' from assembly 'Bar948674_3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' cannot be used across assembly boundaries because it has a generic type argument that is an embedded interop type. @@ -1717,7 +1718,7 @@ public void SetMoniker(ImageMoniker? moniker) Diagnostic(ErrorCode.ERR_GenericsUsedAcrossAssemblies, "IBar").WithArguments("ImageMoniker?", "Bar948674_3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(2, 24) ); - comp3 = CreateCompilationWithMscorlib45(source3, new MetadataReference[] { comp2.EmitToImageReference(), comp1.EmitToImageReference().WithEmbedInteropTypes(true) }); + comp3 = CreateCompilationWithMscorlib461(source3, new MetadataReference[] { comp2.EmitToImageReference(), comp1.EmitToImageReference().WithEmbedInteropTypes(true) }); comp3.VerifyDiagnostics( // (2,24): error CS1769: Type 'ImageMoniker?' from assembly 'Bar948674_3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' cannot be used across assembly boundaries because it has a generic type argument that is an embedded interop type. @@ -1740,7 +1741,7 @@ public void UseSiteErrorViaImplementedInterfaceMember_4() public struct ImageMoniker { }"; - CSharpCompilation comp1 = CreateCompilationWithMscorlib45(source1, assemblyName: "Pia948674_4"); + CSharpCompilation comp1 = CreateCompilationWithMscorlib461(source1, assemblyName: "Pia948674_4"); var source2 = @" public interface IBar @@ -1748,7 +1749,7 @@ public interface IBar void SetMoniker(ImageMoniker? moniker); }"; - CSharpCompilation comp2 = CreateCompilationWithMscorlib45(source2, new MetadataReference[] { new CSharpCompilationReference(comp1, embedInteropTypes: true) }, assemblyName: "Bar948674_4"); + CSharpCompilation comp2 = CreateCompilationWithMscorlib461(source2, new MetadataReference[] { new CSharpCompilationReference(comp1, embedInteropTypes: true) }, assemblyName: "Bar948674_4"); var source3 = @" public class BarImpl : IBar @@ -1757,7 +1758,7 @@ void IBar.SetMoniker(ImageMoniker? moniker) {} }"; - CSharpCompilation comp3 = CreateCompilationWithMscorlib45(source3, new MetadataReference[] { new CSharpCompilationReference(comp2), new CSharpCompilationReference(comp1, embedInteropTypes: true) }); + CSharpCompilation comp3 = CreateCompilationWithMscorlib461(source3, new MetadataReference[] { new CSharpCompilationReference(comp2), new CSharpCompilationReference(comp1, embedInteropTypes: true) }); comp3.VerifyDiagnostics( // (4,15): error CS0539: 'BarImpl.SetMoniker(ImageMoniker?)' in explicit interface declaration is not a member of interface @@ -1768,7 +1769,7 @@ void IBar.SetMoniker(ImageMoniker? moniker) Diagnostic(ErrorCode.ERR_GenericsUsedAcrossAssemblies, "IBar").WithArguments("ImageMoniker?", "Bar948674_4, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(2, 24) ); - comp3 = CreateCompilationWithMscorlib45(source3, new MetadataReference[] { comp2.EmitToImageReference(), comp1.EmitToImageReference().WithEmbedInteropTypes(true) }); + comp3 = CreateCompilationWithMscorlib461(source3, new MetadataReference[] { comp2.EmitToImageReference(), comp1.EmitToImageReference().WithEmbedInteropTypes(true) }); comp3.VerifyDiagnostics( // (4,15): error CS0539: 'BarImpl.SetMoniker(ImageMoniker?)' in explicit interface declaration is not a member of interface @@ -2410,7 +2411,7 @@ void Test() } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(text).VerifyDiagnostics(); } [Fact] @@ -2435,12 +2436,12 @@ void Test() } "; - CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (15,15): error CS8189: Ref mismatch between 'C.M()' and delegate 'D' // new D(M)(); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "M").WithArguments("C.M()", "D").WithLocation(15, 15) ); - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (15,15): error CS8189: Ref mismatch between 'C.M()' and delegate 'D' // new D(M)(); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "M").WithArguments("C.M()", "D").WithLocation(15, 15) @@ -2473,7 +2474,7 @@ void Test() } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(text).VerifyDiagnostics(); } [Fact] @@ -2502,12 +2503,12 @@ void Test() } "; - CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (19,11): error CS8189: Ref mismatch between 'C.M()' and delegate 'D' // M(M); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "M").WithArguments("C.M()", "D").WithLocation(19, 11) ); - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (19,11): error CS8189: Ref mismatch between 'C.M()' and delegate 'D' // M(M); Diagnostic(ErrorCode.ERR_DelegateRefMismatch, "M").WithArguments("C.M()", "D").WithLocation(19, 11) @@ -2871,7 +2872,7 @@ public static string LazyToString(this T obj) where T : class .Select(x => x.GetValue(obj)) } }"; - var compilation = CreateCompilationWithMscorlib40(sourceText, new[] { TestMetadata.Net40.SystemCore }, options: TestOptions.DebugDll); + var compilation = CreateCompilationWithMscorlib40(sourceText, new[] { Net40.References.SystemCore }, options: TestOptions.DebugDll); compilation.VerifyDiagnostics( // (12,42): error CS1002: ; expected // .Select(x => x.GetValue(obj)) @@ -3022,7 +3023,7 @@ void M(IApplicationBuilder app) } } "; - var comp = CreateCompilationWithMscorlib40(source, new[] { TestMetadata.Net40.SystemCore }); + var comp = CreateCompilationWithMscorlib40(source, new[] { Net40.References.SystemCore }); comp.VerifyDiagnostics( // (41,38): error CS7036: There is no argument given that corresponds to the required parameter 'authenticationScheme' of 'AuthenticationManager.AuthenticateAsync(string)' @@ -3102,7 +3103,7 @@ void M(IApplicationBuilder app) } } "; - var comp = CreateCompilationWithMscorlib40(source, new[] { TestMetadata.Net40.SystemCore }); + var comp = CreateCompilationWithMscorlib40(source, new[] { Net40.References.SystemCore }); comp.VerifyDiagnostics( // (41,38): error CS7036: There is no argument given that corresponds to the required parameter 'authenticationScheme' of 'AuthenticationManager.AuthenticateAsync(string)' @@ -3260,7 +3261,7 @@ void M(IApplicationBuilder app) } } "; - var comp = CreateCompilationWithMscorlib40(source, new[] { TestMetadata.Net40.SystemCore }); + var comp = CreateCompilationWithMscorlib40(source, new[] { Net40.References.SystemCore }); comp.VerifyDiagnostics( // (41,38): error CS7036: There is no argument given that corresponds to the required parameter 'authenticationScheme' of 'AuthenticationManager.AuthenticateAsync(string)' @@ -3359,7 +3360,7 @@ public static int MathMax3(this int a, int b) } } "; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics( // (16,9): error CS0103: The name 'MathMin' does not exist in the current context @@ -3421,7 +3422,7 @@ internal enum AnyEnum } } "; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. @@ -3453,7 +3454,7 @@ internal enum AnyEnum } } "; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. @@ -3486,7 +3487,7 @@ internal class AnyEnum } } "; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. @@ -3521,7 +3522,7 @@ internal class AnyEnum } } "; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. @@ -3553,7 +3554,7 @@ internal struct AnyEnum } } "; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. @@ -3585,7 +3586,7 @@ internal interface AnyEnum } } "; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. @@ -3615,7 +3616,7 @@ internal class AnyClass : AnyBaseClass internal delegate void AnyEnum(); } "; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. @@ -3638,7 +3639,7 @@ public void UsingStaticGenericConstraint() public static class Test where T : struct { } "; - CreateCompilationWithMscorlib45(code).VerifyDiagnostics( + CreateCompilationWithMscorlib461(code).VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. // using static Test; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static Test;").WithLocation(2, 1), @@ -3658,7 +3659,7 @@ class A where T : class internal static class B { } } "; - CreateCompilationWithMscorlib45(code).VerifyDiagnostics( + CreateCompilationWithMscorlib461(code).VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. // using static A[]>.B; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static A[]>.B;").WithLocation(2, 1), @@ -3674,7 +3675,7 @@ public void UsingStaticMultipleGenericConstraints() using static A; static class A where T : class where U : struct { } "; - CreateCompilationWithMscorlib45(code).VerifyDiagnostics( + CreateCompilationWithMscorlib461(code).VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. // using static A; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using static A;").WithLocation(2, 1), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ColorColorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ColorColorTests.cs index 0a193882d3374..3b759fc18bcf9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ColorColorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ColorColorTests.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -1835,7 +1836,7 @@ private void CheckExpressionAndParent( { var tree = Parse(text); - var comp = CreateCompilationWithMscorlib40(new[] { tree }, new[] { TestMetadata.Net40.SystemCore }); + var comp = CreateCompilationWithMscorlib40(new[] { tree }, new[] { Net40.References.SystemCore }); comp.VerifyDiagnostics(expectedDiagnostics); var model = comp.GetSemanticModel(tree); @@ -2081,7 +2082,7 @@ public enum Color { Red } var refLib = CreateEmptyCompilation( sourceRefLib, assemblyName: "RefLib", - references: new[] { TestMetadata.Net20.mscorlib }); + references: new[] { Net20.References.mscorlib }); refLib.VerifyEmitDiagnostics(); @@ -2102,7 +2103,7 @@ void F() references: new MetadataReference[] { new CSharpCompilationReference(refLib), - TestMetadata.Net451.mscorlib + NetFramework.mscorlib }); var unifyReferenceWarning = @@ -2126,7 +2127,7 @@ public class Base { } var refLib = CreateEmptyCompilation( sourceRefLib, assemblyName: "RefLib", - references: new[] { TestMetadata.Net20.mscorlib }); + references: new[] { Net20.References.mscorlib }); refLib.VerifyEmitDiagnostics(); @@ -2145,7 +2146,7 @@ void M(Derived d) references: new MetadataReference[] { new CSharpCompilationReference(refLib), - TestMetadata.Net451.mscorlib + NetFramework.mscorlib }); var unifyReferenceWarning = diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 50b94c22b0db0..212a1e79b9163 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -1087,8 +1087,6 @@ static void Main() public static IEnumerable GetBaseAndDerivedTypesData() { yield return getData("internal void F(object x) { }", "internal static new void F(object x) { }", "F", "F", null, "System.Action"); // instance and static - // https://github.com/dotnet/roslyn/issues/52701: Assert failure: Unexpected value 'LessDerived' of type 'Microsoft.CodeAnalysis.CSharp.MemberResolutionKind' -#if !DEBUG yield return getData("internal void F(object x) { }", "internal static new void F(object x) { }", "this.F", "F", new[] { @@ -1096,7 +1094,6 @@ static void Main() // System.Delegate d = this.F; Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.F").WithArguments("B.F(object)").WithLocation(5, 29) }); // instance and static -#endif yield return getData("internal void F(object x) { }", "internal static new void F(object x) { }", "base.F", "F", null, "System.Action"); // instance and static yield return getData("internal static void F(object x) { }", "internal new void F(object x) { }", "F", "F", null, "System.Action"); // static and instance yield return getData("internal static void F(object x) { }", "internal new void F(object x) { }", "this.F", "F", null, "System.Action"); // static and instance @@ -1124,9 +1121,9 @@ static void Main() yield return getData("internal virtual object F() => throw null;", "internal override object F() => throw null;", "F", "F", null, "System.Func"); // override yield return getData("internal object F() => throw null;", "internal object F() => throw null;", "F", "F", null, "System.Func"); // hiding yield return getData("internal object F() => throw null;", "internal new object F() => throw null;", "F", "F", null, "System.Func"); // hiding - yield return getData("internal string F() => throw null;", "internal new object F() => throw null;", "F", "F"); // different return type - yield return getData("internal object F() => throw null;", "internal new ref object F() => throw null;", "F", "F"); // different return ref kind - yield return getData("internal ref object F() => throw null;", "internal new object F() => throw null;", "F", "F"); // different return ref kind + yield return getData("internal string F() => throw null;", "internal new object F() => throw null;", "F", "F", null, "System.Func"); // different return type + yield return getData("internal object F() => throw null;", "internal new ref object F() => throw null;", "F", "F", null, "<>F{00000001}"); // different return ref kind + yield return getData("internal ref object F() => throw null;", "internal new object F() => throw null;", "F", "F", null, "System.Func"); // different return ref kind yield return getData("internal void F(object x) { }", "internal new void F(dynamic x) { }", "F", "F", null, "System.Action"); // object/dynamic yield return getData("internal dynamic F() => throw null;", "internal new object F() => throw null;", "F", "F", null, "System.Func"); // object/dynamic yield return getData("internal void F((object, int) x) { }", "internal new void F((object a, int b) x) { }", "F", "F", null, "System.Action>"); // tuple names @@ -1150,8 +1147,6 @@ static void Main() yield return getData("internal void F(T t) { }", "internal new void F(T t) where T : class { }", "F", "F", null, "System.Action"); // different type parameter constraints yield return getData("internal void F(T t) { }", "internal new void F(T t) where T : class { }", "base.F", "F", null, "System.Action"); // different type parameter constraints yield return getData("internal void F(T t) where T : class { }", "internal new void F(T t) where T : struct { }", "F", "F", null, "System.Action"); // different type parameter constraints - // https://github.com/dotnet/roslyn/issues/52701: Assert failure: Unexpected value 'LessDerived' of type 'Microsoft.CodeAnalysis.CSharp.MemberResolutionKind' -#if !DEBUG yield return getData("internal void F(T t) where T : class { }", "internal new void F(T t) where T : struct { }", "F", "F", new[] { @@ -1159,7 +1154,6 @@ static void Main() // System.Delegate d = F; Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "F").WithArguments("B.F(T)", "T", "object").WithLocation(5, 29) }); // different type parameter constraints -#endif static object?[] getData(string methodA, string methodB, string methodGroupExpression, string methodGroupOnly, DiagnosticDescription[]? expectedDiagnostics = null, string? expectedType = null) { @@ -1384,7 +1378,7 @@ static class B // https://github.com/dotnet/roslyn/issues/52870: GetSymbolInfo() should return resolved method from method group. Assert.Null(symbolInfo.Symbol); - Assert.Equal(["void System.Object.F(System.Object y)", "void System.Object.F(T y)"], + AssertEx.Equal(["void System.Object.F(System.Object y)", "void System.Object.F(T y)"], model.GetMemberGroup(expr).ToTestDisplayStrings()); } @@ -1427,7 +1421,7 @@ static class B // https://github.com/dotnet/roslyn/issues/52870: GetSymbolInfo() should return resolved method from method group. Assert.Null(symbolInfo.Symbol); - Assert.Equal(["void System.Object.F()", "void System.Object.F()"], + AssertEx.Equal(["void System.Object.F()", "void System.Object.F()"], model.GetMemberGroup(expr).ToTestDisplayStrings()); } @@ -2090,7 +2084,7 @@ public static void M(this C c, object o) Assert.Null(typeInfo.Type); Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void C.M()", "void C.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()", "void C.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2155,7 +2149,7 @@ public static void M(this C c, object o) { } // ignored Assert.Null(typeInfo.Type); Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); - Assert.Equal(["void C.M()", "void C.M()", "void C.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()", "void C.M()", "void C.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2218,7 +2212,7 @@ public static void M(this C c, object o) { } // ignored Assert.True(typeInfo.ConvertedType!.IsErrorType()); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); - Assert.Equal(["void C.M()", "void C.M(System.Object o)", "void C.M(System.Object o)"], + AssertEx.Equal(["void C.M()", "void C.M(System.Object o)", "void C.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } @@ -2276,7 +2270,7 @@ public static void M(this C c, object o) { } // ignored Assert.Null(typeInfo.Type); Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void C.M()", "void C.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()", "void C.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2325,7 +2319,7 @@ public static void M(this C c) Assert.Null(typeInfo.Type); Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2365,7 +2359,7 @@ public static void M(this C c) Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); // https://github.com/dotnet/roslyn/issues/52870: GetSymbolInfo() should return resolved method from method group. Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); - Assert.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2408,7 +2402,7 @@ public static void M(this C c) Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); // https://github.com/dotnet/roslyn/issues/52870: GetSymbolInfo() should return resolved method from method group. Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); - Assert.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2459,7 +2453,7 @@ public static void M(this C c) { } Assert.Null(typeInfo.Type); Assert.True(typeInfo.ConvertedType!.IsErrorType()); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); - Assert.Equal(["void C.M(C c)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M(C c)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2500,7 +2494,7 @@ public static void M(this C c) Assert.Null(typeInfo.Type); Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void C.M()", "void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()", "void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2548,7 +2542,7 @@ public static class E2 Assert.Null(typeInfo.Type); Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void C.M()", "void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()", "void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2600,7 +2594,7 @@ public static class E2 Assert.Null(typeInfo.Type); Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void C.M()", "void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()", "void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2646,7 +2640,7 @@ public static void M(this C c) Assert.Null(typeInfo.Type); Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); - Assert.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2694,7 +2688,7 @@ public static void M(this C c) Assert.Null(typeInfo.Type); Assert.Equal("System.Action", typeInfo.ConvertedType!.ToTestDisplayString()); Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2741,7 +2735,7 @@ public static class E Assert.Null(typeInfo.Type); Assert.True(typeInfo.ConvertedType!.IsErrorType()); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); - Assert.Equal(["void C.M()", "void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()", "void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2785,7 +2779,7 @@ public static class DExt var memberAccess = GetSyntax(tree, "c.M"); // https://github.com/dotnet/roslyn/issues/52870: GetSymbolInfo() should return resolved method from method group. Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); - Assert.Equal(["void C.M()", "void C.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()", "void C.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact, WorkItem("https://github.com/dotnet/csharplang/issues/7364")] @@ -2835,7 +2829,7 @@ public static void M(this T t) var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax(tree, "new object().M"); Assert.Equal("void System.Object.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void System.Object.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void System.Object.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69222")] @@ -2865,7 +2859,7 @@ public static void M(this C t) Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void C.M()"], + AssertEx.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } @@ -2894,7 +2888,7 @@ public static void M(this C c) { } var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax(tree, "new C().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); - Assert.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69222")] @@ -2923,7 +2917,7 @@ public void M(object o) where T : class { } var memberAccess = GetSyntax(tree, "new C().M"); Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void C.M()", "void C.M(System.Object o)"], + AssertEx.Equal(["void C.M()", "void C.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } @@ -2954,7 +2948,7 @@ public void M(object o) where T : class { } var memberAccess = GetSyntax(tree, "new C().M"); Assert.Null(model.GetSymbolInfo(memberAccess).Symbol); - Assert.Equal(["void C.M()", "void C.M(System.Object o)"], + AssertEx.Equal(["void C.M()", "void C.M(System.Object o)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } @@ -2986,7 +2980,7 @@ public void M() where T : class var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax(tree, "new C().M"); Assert.Equal("void C.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void C.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69222")] @@ -3017,7 +3011,7 @@ public static void M(this T t, object ignored) where T : struct { } var model = comp.GetSemanticModel(tree); var memberAccess = GetSyntax(tree, "new object().M"); Assert.Equal("void System.Object.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void System.Object.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); + AssertEx.Equal(["void System.Object.M()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69222")] @@ -3049,7 +3043,7 @@ public static void M(this T t, object ignored) where T : struct { } var memberAccess = GetSyntax(tree, "new object().M"); Assert.Equal("void System.Object.M()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void System.Object.M()", "void System.Object.M(System.Object ignored)"], + AssertEx.Equal(["void System.Object.M()", "void System.Object.M(System.Object ignored)"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } @@ -3084,7 +3078,7 @@ static class A var memberAccess = GetSyntax(tree, "new object().F"); Assert.Equal("void System.Object.F()", model.GetSymbolInfo(memberAccess).Symbol.ToTestDisplayString()); - Assert.Equal(["void System.Object.F()", "void System.Object.F()"], + AssertEx.Equal(["void System.Object.F()", "void System.Object.F()"], model.GetMemberGroup(memberAccess).ToTestDisplayStrings()); } @@ -6461,6 +6455,935 @@ static void Main() CompileAndVerify(source, expectedOutput: "1").VerifyDiagnostics(); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71333")] + public void OverloadResolution_CandidateOrdering_ParamsArray() + { + var source = """ + using System; + + class Program + { + static void Main() + { + var x1 = new Program().Test1; + var x2 = new Program().Test2; + + x1(); + x2(); + } + } + + static class E + { + static public void Test1(this Program p, long[] a) => Console.Write(a.Length); + static public void Test1(this object p, params long[] a) => Console.Write(a.Length); + + static public void Test2(this object p, params long[] a) => Console.Write(a.Length); + static public void Test2(this Program p, long[] a) => Console.Write(a.Length); + } + """; + foreach (var languageVersion in new[] { CSharp.LanguageVersion.Preview, CSharp.LanguageVersion.CSharp13, CSharp.LanguageVersion.CSharp12 }) + { + CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( + // (7,18): error CS8917: The delegate type could not be inferred. + // var x1 = new Program().Test1; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new Program().Test1").WithLocation(7, 18), + // (8,18): error CS8917: The delegate type could not be inferred. + // var x2 = new Program().Test2; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new Program().Test2").WithLocation(8, 18)); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71333")] + public void OverloadResolution_CandidateOrdering_ParamsArray_NotLastParameter() + { + var source = """ + using System; + + class Program + { + static void Main() + { + var x1 = new Program().Test1; + var x2 = new Program().Test2; + + x1(); + x2(); + } + } + + static class E + { + static public void Test1(this Program p, long[] a, long[] b) => Console.Write(a.Length); + static public void Test1(this object p, params long[] a, long[] b) => Console.Write(a.Length); + + static public void Test2(this object p, params long[] a, long[] b) => Console.Write(a.Length); + static public void Test2(this Program p, long[] a, long[] b) => Console.Write(a.Length); + } + """; + foreach (var languageVersion in new[] { CSharp.LanguageVersion.Preview, CSharp.LanguageVersion.CSharp13, CSharp.LanguageVersion.CSharp12 }) + { + CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( + // (10,9): error CS7036: There is no argument given that corresponds to the required parameter 'arg1' of 'Action' + // x1(); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "x1").WithArguments("arg1", "System.Action").WithLocation(10, 9), + // (11,9): error CS7036: There is no argument given that corresponds to the required parameter 'arg1' of 'Action' + // x2(); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "x2").WithArguments("arg1", "System.Action").WithLocation(11, 9), + // (18,45): error CS0231: A params parameter must be the last parameter in a parameter list + // static public void Test1(this object p, params long[] a, long[] b) => Console.Write(a.Length); + Diagnostic(ErrorCode.ERR_ParamsLast, "params long[] a").WithLocation(18, 45), + // (20,45): error CS0231: A params parameter must be the last parameter in a parameter list + // static public void Test2(this object p, params long[] a, long[] b) => Console.Write(a.Length); + Diagnostic(ErrorCode.ERR_ParamsLast, "params long[] a").WithLocation(20, 45)); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71333")] + public void OverloadResolution_CandidateOrdering_ParamsArray_NotLastParameter_02() + { + var source = """ + using System; + + class Program + { + static void Main() + { + var x1 = new Program().Test1; + var x2 = new Program().Test2; + + x1(); + x2(); + } + } + + static class E + { + static public void Test1(this Program p, long[] a, params long[] b) => Console.Write(a.Length); + static public void Test1(this object p, params long[] a, long[] b) => Console.Write(a.Length); + + static public void Test2(this object p, params long[] a, long[] b) => Console.Write(a.Length); + static public void Test2(this Program p, long[] a, params long[] b) => Console.Write(a.Length); + } + """; + foreach (var languageVersion in new[] { CSharp.LanguageVersion.Preview, CSharp.LanguageVersion.CSharp13, CSharp.LanguageVersion.CSharp12 }) + { + CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( + // (7,18): error CS8917: The delegate type could not be inferred. + // var x1 = new Program().Test1; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new Program().Test1").WithLocation(7, 18), + // (8,18): error CS8917: The delegate type could not be inferred. + // var x2 = new Program().Test2; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new Program().Test2").WithLocation(8, 18), + // (18,45): error CS0231: A params parameter must be the last parameter in a parameter list + // static public void Test1(this object p, params long[] a, long[] b) => Console.Write(a.Length); + Diagnostic(ErrorCode.ERR_ParamsLast, "params long[] a").WithLocation(18, 45), + // (20,45): error CS0231: A params parameter must be the last parameter in a parameter list + // static public void Test2(this object p, params long[] a, long[] b) => Console.Write(a.Length); + Diagnostic(ErrorCode.ERR_ParamsLast, "params long[] a").WithLocation(20, 45)); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71333")] + public void OverloadResolution_CandidateOrdering_ParamsArray_NotArray_01() + { + var source = """ + using System; + + class Program + { + static void Main() + { + var x1 = new Program().Test1; + var x2 = new Program().Test2; + + x1(); + x2(); + } + } + + static class E + { + static public void Test1(this Program p, long a) => Console.Write(a); + static public void Test1(this object p, params long a) => Console.Write(a); + + static public void Test2(this object p, params long a) => Console.Write(a); + static public void Test2(this Program p, long a) => Console.Write(a); + } + """; + foreach (var languageVersion in new[] { CSharp.LanguageVersion.Preview, CSharp.LanguageVersion.CSharp13, CSharp.LanguageVersion.CSharp12 }) + { + CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( + // (10,9): error CS7036: There is no argument given that corresponds to the required parameter 'obj' of 'Action' + // x1(); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "x1").WithArguments("obj", "System.Action").WithLocation(10, 9), + // (11,9): error CS7036: There is no argument given that corresponds to the required parameter 'obj' of 'Action' + // x2(); + Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "x2").WithArguments("obj", "System.Action").WithLocation(11, 9), + // (18,45): error CS0225: The params parameter must have a valid collection type + // static public void Test1(this object p, params long a) => Console.Write(a); + Diagnostic(ErrorCode.ERR_ParamsMustBeCollection, "params").WithLocation(18, 45), + // (20,45): error CS0225: The params parameter must have a valid collection type + // static public void Test2(this object p, params long a) => Console.Write(a); + Diagnostic(ErrorCode.ERR_ParamsMustBeCollection, "params").WithLocation(20, 45)); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71333")] + public void OverloadResolution_CandidateOrdering_ParamsArray_NotArray_02() + { + var source = """ + using System; + + class Program + { + static void Main() + { + var x1 = new Program().Test1; + var x2 = new Program().Test2; + + x1(); + x2(); + } + } + + static class E + { + static public void Test1(this Program p, params long[] a) => Console.Write(a); + static public void Test1(this object p, params long a) => Console.Write(a); + + static public void Test2(this object p, params long a) => Console.Write(a); + static public void Test2(this Program p, params long[] a) => Console.Write(a); + } + """; + foreach (var languageVersion in new[] { CSharp.LanguageVersion.Preview, CSharp.LanguageVersion.CSharp13, CSharp.LanguageVersion.CSharp12 }) + { + CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( + // (7,18): error CS8917: The delegate type could not be inferred. + // var x1 = new Program().Test1; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new Program().Test1").WithLocation(7, 18), + // (8,18): error CS8917: The delegate type could not be inferred. + // var x2 = new Program().Test2; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new Program().Test2").WithLocation(8, 18), + // (18,45): error CS0225: The params parameter must have a valid collection type + // static public void Test1(this object p, params long a) => Console.Write(a); + Diagnostic(ErrorCode.ERR_ParamsMustBeCollection, "params").WithLocation(18, 45), + // (20,45): error CS0225: The params parameter must have a valid collection type + // static public void Test2(this object p, params long a) => Console.Write(a); + Diagnostic(ErrorCode.ERR_ParamsMustBeCollection, "params").WithLocation(20, 45)); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71333")] + public void OverloadResolution_CandidateOrdering_DefaultValue() + { + var source = """ + using System; + + class Program + { + static void Main() + { + var x1 = new Program().Test1; + var x2 = new Program().Test2; + + x1(); + x2(); + } + } + + static class E + { + static public void Test1(this Program p, long a) => Console.Write(a); + static public void Test1(this object p, long a = 1) => Console.Write(a); + + static public void Test2(this object p, long a = 2) => Console.Write(a); + static public void Test2(this Program p, long a) => Console.Write(a); + } + """; + foreach (var languageVersion in new[] { CSharp.LanguageVersion.Preview, CSharp.LanguageVersion.CSharp13, CSharp.LanguageVersion.CSharp12 }) + { + CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( + // (7,18): error CS8917: The delegate type could not be inferred. + // var x1 = new Program().Test1; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new Program().Test1").WithLocation(7, 18), + // (8,18): error CS8917: The delegate type could not be inferred. + // var x2 = new Program().Test2; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new Program().Test2").WithLocation(8, 18)); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71333")] + public void OverloadResolution_CandidateOrdering_DefaultValue_DifferentValues() + { + var source = """ + using System; + + class Program + { + static void Main() + { + var x1 = new Program().Test1; + var x2 = new Program().Test2; + + x1(); + x2(); + } + } + + static class E + { + static public void Test1(this Program p, long a = 1) => Console.Write(a); + static public void Test1(this object p, long a = 2) => Console.Write(a); + + static public void Test2(this object p, long a = 3) => Console.Write(a); + static public void Test2(this Program p, long a = 4) => Console.Write(a); + } + """; + foreach (var languageVersion in new[] { CSharp.LanguageVersion.Preview, CSharp.LanguageVersion.CSharp13, CSharp.LanguageVersion.CSharp12 }) + { + CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)).VerifyDiagnostics( + // (7,18): error CS8917: The delegate type could not be inferred. + // var x1 = new Program().Test1; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new Program().Test1").WithLocation(7, 18), + // (8,18): error CS8917: The delegate type could not be inferred. + // var x2 = new Program().Test2; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new Program().Test2").WithLocation(8, 18)); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71333")] + public void OverloadResolution_CandidateOrdering_DefaultValue_SameValues() + { + var source = """ + using System; + + class Program + { + static void Main() + { + var x1 = new Program().Test1; + var x2 = new Program().Test2; + + x1(); + x2(); + } + } + + static class E + { + static public void Test1(this Program p, long a = 1) => Console.Write(a); + static public void Test1(this object p, long a = 1) => Console.Write(a); + + static public void Test2(this object p, long a = 2) => Console.Write(a); + static public void Test2(this Program p, long a = 2) => Console.Write(a); + } + """; + foreach (var languageVersion in new[] { CSharp.LanguageVersion.Preview, CSharp.LanguageVersion.CSharp13, CSharp.LanguageVersion.CSharp12 }) + { + CompileAndVerify(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion), + expectedOutput: "12").VerifyDiagnostics(); + } + } + + [Fact] + public void OverloadResolution_DefaultValue_01() + { + var source1 = """ + public class Y : X + { + public void M(T x = default) { } + public override void M(int x = 2) => System.Console.WriteLine(x); + } + + public abstract class X + { + public abstract void M(int x = 1); + } + """; + + var source2 = """ + var d1 = new Y().M; + System.Console.WriteLine(d1.GetType()); + d1(); + """; + + var expectedDiagnostics = new[] + { + // (1,10): error CS8917: The delegate type could not be inferred. + // var d1 = new Y().M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new Y().M").WithLocation(1, 10) + }; + + CreateCompilation([source1, source2], parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source1, source2], parseOptions: TestOptions.Regular13).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation([source1, source2]).VerifyDiagnostics(expectedDiagnostics); + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + 1 + """; + + var source3 = """ + var d2 = ((X)new Y()).M; + System.Console.WriteLine(d2.GetType()); + d2(); + """; + + CompileAndVerify([source1, source3], parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify([source1, source3], parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify([source1, source3], symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke([T1 arg = 1])", m.ToTestDisplayString()); + } + } + + [Fact] + public void OverloadResolution_DefaultValue_02() + { + var source = """ + var d = new Z().M; + System.Console.WriteLine(d.GetType()); + d(); + + public class Z : Y + { + public new void M(int x = 3) => System.Console.Write(x); + } + + public abstract class Y : X + { + public virtual void M(T x = default) { } + public override void M(int x = 2) { } + } + + public abstract class X + { + public abstract void M(int x = 1); + } + """; + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + 3 + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke([T1 arg = 3])", m.ToTestDisplayString()); + } + } + + [Fact] + public void OverloadResolution_DefaultValue_03() + { + var source = """ + new B().M(); + + partial class B + { + internal void M() + { + System.Delegate d = F; + System.Console.WriteLine(d.GetType()); + d.DynamicInvoke(3); + } + } + abstract class A + { + internal void F(int x = 1) => System.Console.WriteLine("A" + x); + } + partial class B : A + { + internal static new void F(int x = 2) => System.Console.WriteLine("B" + x); + } + """; + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + B3 + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke([T1 arg = 2])", m.ToTestDisplayString()); + } + } + + [Fact] + public void OverloadResolution_DefaultValue_04() + { + var source = """ + new B().M(); + + partial class B + { + internal void M() + { + var d = F; + System.Console.WriteLine(d.GetType()); + d(3); + } + } + abstract class A + { + internal void F(int x = 1) => System.Console.WriteLine("A" + x); + } + partial class B : A + { + internal static new void F(int x = 2) => System.Console.WriteLine("B" + x); + } + """; + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + B3 + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke([T1 arg = 2])", m.ToTestDisplayString()); + } + } + + [Fact] + public void Params_ExtensionScopes_01() + { + var source = """ + using System; + + static class E1 + { + public static void M(this N.C c, int[] x) => Console.Write(3); + } + + namespace N + { + static class E2 + { + public static void M(this C c, params int[] x) => Console.Write(2); + } + + class C + { + public void M(params int[] x) => Console.Write(1); + public static void Main() + { + var d = new C().M; + Console.WriteLine(d.GetType()); + d(); + } + } + } + """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (20,21): error CS8917: The delegate type could not be inferred. + // var d = new C().M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new C().M").WithLocation(20, 21)); + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + 1 + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void Params_ExtensionScopes_02() + { + var source = """ + using System; + + static class E1 + { + public static void M(this N.C c, params int[] x) => Console.Write(3); + } + + namespace N + { + static class E2 + { + public static void M(this C c, params int[] x) => Console.Write(2); + } + + class C + { + public void M(params int[] x) => Console.Write(1); + public static void Main() + { + var d = new C().M; + Console.WriteLine(d.GetType()); + d(); + } + } + } + """; + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + 1 + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void Params_ExtensionScopes_03() + { + var source = """ + using System; + + static class E1 + { + public static void M(this N.C c, int[] x) => Console.Write(3); + } + + namespace N + { + static class E2 + { + public static void M(this C c, int[] x) => Console.Write(2); + } + + class C + { + public void M(int[] x) => Console.Write(1); + public static void Main() + { + var d = new C().M; + Console.WriteLine(d.GetType()); + d(default); + } + } + } + """; + + var expectedOutput = """ + System.Action`1[System.Int32[]] + 1 + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void Params_ExtensionScopes_04() + { + var source = """ + using System; + + static class E1 + { + public static void M(this N.C c, params int[] x) => Console.Write(3); + } + + namespace N + { + static class E2 + { + public static void M(this C c, int[] x) => Console.Write(2); + } + + class C + { + public void M(int[] x) => Console.Write(1); + public static void Main() + { + var d = new C().M; + Console.WriteLine(d.GetType()); + d(default); + } + } + } + """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (20,21): error CS8917: The delegate type could not be inferred. + // var d = new C().M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new C().M").WithLocation(20, 21)); + + var expectedOutput = """ + System.Action`1[System.Int32[]] + 1 + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void Params_ExtensionScopes_05() + { + var source = """ + using System; + + static class E + { + public static void M(this C c, params int[] x) => Console.Write(2); + } + + class C + { + public void M(int[] x) => Console.Write(1); + public static void Main() + { + var d = new C().M; + Console.WriteLine(d.GetType()); + d(default); + } + } + """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (13,17): error CS8917: The delegate type could not be inferred. + // var d = new C().M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new C().M").WithLocation(13, 17)); + + var expectedOutput = """ + System.Action`1[System.Int32[]] + 1 + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void Params_ExtensionScopes_06() + { + var source = """ + using System; + + static class E + { + public static void M(this C c, int[] x) => Console.Write(2); + } + + class C + { + public void M(params int[] x) => Console.Write(1); + public static void Main() + { + var d = new C().M; + Console.WriteLine(d.GetType()); + d(); + } + } + """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (13,17): error CS8917: The delegate type could not be inferred. + // var d = new C().M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new C().M").WithLocation(13, 17)); + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + 1 + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void Params_ExtensionScopes_07() + { + var source = """ + using System; + + static class E1 + { + public static void M(this N.C c, params int[] x) => Console.Write(1); + } + + namespace N + { + static class E2 + { + public static void M(this C c, int[] x) => Console.Write(2); + } + + class C + { + public static void Main() + { + var d = new C().M; + Console.WriteLine(d.GetType()); + d(default); + } + } + } + """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (19,21): error CS8917: The delegate type could not be inferred. + // var d = new C().M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new C().M").WithLocation(19, 21)); + + var expectedOutput = """ + System.Action`1[System.Int32[]] + 2 + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void Params_ExtensionScopes_08() + { + var source = """ + using System; + + static class E1 + { + public static void M(this N.C c, int[] x) => Console.Write(1); + } + + namespace N + { + static class E2 + { + public static void M(this C c, params int[] x) => Console.Write(2); + } + + class C + { + public static void Main() + { + var d = new C().M; + Console.WriteLine(d.GetType()); + d(); + } + } + } + """; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (19,21): error CS8917: The delegate type could not be inferred. + // var d = new C().M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new C().M").WithLocation(19, 21)); + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + 2 + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void Params_ReducedExtensionMethod_ErrorSource() + { + var source = """ + static class E + { + public static void M(this T x, params T y) + { + } + } + class C + { + void M(System.Collections.Generic.List col) + { + var d = col.M; + d(1, 2, 3); + } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (3,39): error CS0225: The params parameter must have a valid collection type + // public static void M(this T x, params T y) + Diagnostic(ErrorCode.ERR_ParamsMustBeCollection, "params").WithLocation(3, 39), + // (12,9): error CS1593: Delegate 'Action>' does not take 3 arguments + // d(1, 2, 3); + Diagnostic(ErrorCode.ERR_BadDelArgCount, "d").WithArguments("System.Action>", "3").WithLocation(12, 9)); + } + + [Fact] + public void Params_ReducedExtensionMethod_Metadata() + { + /* + public static class E + { + public static void M(this T x, params T y) + { + } + } + */ + var ilSource = """ + .class public auto ansi abstract sealed beforefieldinit E extends System.Object + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (01 00 00 00) + .method public hidebysig static void M(!!T x, !!T y) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (01 00 00 00) + .param [2] .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = (01 00 00 00) + .maxstack 8 + ret + } + } + """; + var source = """ + class C + { + void M(int[] arr) + { + var d = arr.M; + d(1, 2, 3); + } + } + """; + CreateCompilationWithIL(source, ilSource).VerifyDiagnostics( + // (6,9): error CS1593: Delegate 'Action' does not take 3 arguments + // d(1, 2, 3); + Diagnostic(ErrorCode.ERR_BadDelArgCount, "d").WithArguments("System.Action", "3").WithLocation(6, 9)); + } + [Fact] public void BestCommonType_01() { @@ -12483,6 +13406,88 @@ public void SynthesizedDelegateTypes_DefaultParameterValues_StringUnification() """).VerifyDiagnostics(); } + [Fact] + public void SynthesizedDelegateTypes_DefaultParameterValues_LeastOverriddenMethod() + { + var source = """ + var c = ((C)new D()).M; + System.Console.WriteLine(c.GetType()); + var d = new D().M; + System.Console.WriteLine(d.GetType()); + + public class D : C + { + public override void M(int x) { } + } + + public abstract class C + { + public abstract void M(int x = 42); + } + """; + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + System.Action`1[System.Int32] + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + var verifier = CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + var cm = verifier.Compilation.GetMember("C.M"); + Assert.Equal(42, cm.Parameters.Single().ExplicitDefaultValue); + var dm = verifier.Compilation.GetMember("D.M"); + Assert.False(dm.Parameters.Single().HasExplicitDefaultValue); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke([T1 arg = 42])", m.ToTestDisplayString()); + } + } + + [Fact] + public void SynthesizedDelegateTypes_DefaultParameterValues_MostOverriddenMethod() + { + var source = """ + var c = ((C)new D()).M; + System.Console.WriteLine(c.GetType()); + var d = new D().M; + System.Console.WriteLine(d.GetType()); + + public class D : C + { + public override void M(int x = 42) { } + } + + public abstract class C + { + public abstract void M(int x); + } + """; + + var expectedOutput = """ + System.Action`1[System.Int32] + <>f__AnonymousDelegate0`1[System.Int32] + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + var verifier = CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + var cm = verifier.Compilation.GetMember("C.M"); + Assert.False(cm.Parameters.Single().HasExplicitDefaultValue); + var dm = verifier.Compilation.GetMember("D.M"); + Assert.Equal(42, dm.Parameters.Single().ExplicitDefaultValue); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke([T1 arg = 42])", m.ToTestDisplayString()); + } + } + [Fact] public void SynthesizedDelegateTypes_ParamsArray_DifferentElementTypes() { @@ -12494,10 +13499,494 @@ public void SynthesizedDelegateTypes_ParamsArray_DifferentElementTypes() var lam2 = (params string[] ys) => { }; Report(lam2); """; - CompileAndVerify(source, expectedOutput: $""" + + var expectedOutput = """ <>f__AnonymousDelegate0`1[System.Int32] <>f__AnonymousDelegate0`1[System.String] + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact] + public void SynthesizedDelegateTypes_ParamsArray_LeastOverriddenMethod() + { + var source = """ + var c = ((C)new D()).M; + System.Console.WriteLine(c.GetType()); + var d = new D().M; + System.Console.WriteLine(d.GetType()); + + public class D : C + { + public override void M(int[] xs) { } + } + + public abstract class C + { + public abstract void M(params int[] xs); + } + """; + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + <>f__AnonymousDelegate0`1[System.Int32] + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + var verifier = CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + var cm = verifier.Compilation.GetMember("C.M"); + Assert.True(cm.Parameters.Single().IsParams); + var dm = verifier.Compilation.GetMember("D.M"); + Assert.True(dm.Parameters.Single().IsParams); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void SynthesizedDelegateTypes_ParamsArray_LeastOverriddenMethod_Different() + { + var source1a = """ + public abstract class C + { + public abstract void M(int[] xs); + } + """; + var comp1a = CreateCompilation(source1a, assemblyName: "Lib1").VerifyDiagnostics(); + var comp1aRef = comp1a.EmitToImageReference(); + + var source2 = """ + public class D : C + { + public override void M(int[] xs) { } + } + """; + var comp2 = CreateCompilation(source2, [comp1aRef]).VerifyDiagnostics(); + var comp2Ref = comp2.EmitToImageReference(); + + var source3 = """ + var c = ((C)new D()).M; + System.Console.WriteLine(c.GetType()); + var d = new D().M; + System.Console.WriteLine(d.GetType()); + """; + var verifier = CompileAndVerify(source3, [comp2Ref, comp1aRef], + expectedOutput: """ + System.Action`1[System.Int32[]] + System.Action`1[System.Int32[]] """).VerifyDiagnostics(); + + var cm = verifier.Compilation.GetMember("C.M"); + Assert.False(cm.Parameters.Single().IsParams); + var dm = verifier.Compilation.GetMember("D.M"); + Assert.False(dm.Parameters.Single().IsParams); + + var source1b = """ + public abstract class C + { + public abstract void M(params int[] xs); + } + """; + var comp1b = CreateCompilation(source1b, assemblyName: "Lib1").VerifyDiagnostics(); + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + <>f__AnonymousDelegate0`1[System.Int32] + """; + + CompileAndVerify(source3, [comp2Ref, comp1b.EmitToImageReference()], parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source3, [comp2Ref, comp1b.EmitToImageReference()], parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + verifier = CompileAndVerify(source3, [comp2Ref, comp1b.EmitToImageReference()], symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + cm = verifier.Compilation.GetMember("C.M"); + Assert.True(cm.Parameters.Single().IsParams); + dm = verifier.Compilation.GetMember("D.M"); + Assert.False(dm.Parameters.Single().IsParams); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void SynthesizedDelegateTypes_ParamsArray_LeastOverriddenMethod_Generic_01() + { + var source = """ + var c = ((C)new D()).M; + System.Console.WriteLine(c.GetType()); + c(null); + var m = new D().M; + System.Console.WriteLine(m.GetType()); + m(null); + + abstract class C + { + public abstract void M(params T[] xs); + } + + class D : C + { + public override void M(long[] xs) => System.Console.WriteLine("A"); + public void M(T[] xs) => System.Console.WriteLine("B"); + } + """; + + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,9): error CS8917: The delegate type could not be inferred. + // var m = new D().M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new D().M").WithLocation(4, 9)); + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int64] + A + <>f__AnonymousDelegate0`1[System.Int64] + B + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + var verifier = CompileAndVerify(source, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + var cm = verifier.Compilation.GetMember("C.M"); + Assert.True(cm.Parameters.Single().IsParams); + var dm = verifier.Compilation.GetMembers("D.M").Single(m => m.OverriddenMethod is not null); + Assert.True(dm.Parameters.Single().IsParams); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void SynthesizedDelegateTypes_ParamsArray_LeastOverriddenMethod_Different_Generic_01() + { + var source1a = """ + public abstract class C + { + public abstract void M(T[] xs); + } + """; + var comp1a = CreateCompilation(source1a, assemblyName: "Lib1").VerifyDiagnostics(); + var comp1aRef = comp1a.EmitToImageReference(); + + var source2 = """ + public class D : C + { + public override void M(long[] xs) => System.Console.WriteLine("A"); + public void M(T[] xs) => System.Console.WriteLine("B"); + } + """; + var comp2 = CreateCompilation(source2, [comp1aRef]).VerifyDiagnostics(); + var comp2Ref = comp2.EmitToImageReference(); + + var source1b = """ + public abstract class C + { + public abstract void M(params T[] xs); + } + """; + var comp1b = CreateCompilation(source1b, assemblyName: "Lib1").VerifyDiagnostics(); + var comp1bRef = comp1b.EmitToImageReference(); + + var source3 = """ + var c = ((C)new D()).M; + System.Console.WriteLine(c.GetType()); + c(null); + var d = new D().M; + System.Console.WriteLine(d.GetType()); + d(null); + """; + + CreateCompilation(source3, [comp2Ref, comp1bRef], parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (4,9): error CS8917: The delegate type could not be inferred. + // var d = new D().M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new D().M").WithLocation(4, 9)); + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int64] + A + <>f__AnonymousDelegate0`1[System.Int64] + B + """; + + CompileAndVerify(source3, [comp2Ref, comp1bRef], parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + var verifier = CompileAndVerify(source3, [comp2Ref, comp1bRef], symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + var cm = verifier.Compilation.GetMember("C.M"); + Assert.True(cm.Parameters.Single().IsParams); + var dm = verifier.Compilation.GetMembers("D.M").Single(m => m.OverriddenMethod is not null); + Assert.False(dm.Parameters.Single().IsParams); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void SynthesizedDelegateTypes_ParamsArray_LeastOverriddenMethod_Generic_02() + { + var source1 = """ + abstract class C + { + public abstract void M(params T[] xs); + } + + class D : C + { + public override void M(T[] xs) => System.Console.WriteLine("A"); + public void M(T2[] xs) => System.Console.WriteLine("B"); + } + """; + + var source2 = """ + var d = new D().M; + System.Console.WriteLine(d.GetType()); + d(null); + """; + + var expectedDiagnostics = new[] + { + // (1,9): error CS8917: The delegate type could not be inferred. + // var d = new D().M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new D().M").WithLocation(1, 9) + }; + + CreateCompilation([source1, source2], parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + + var expectedOutput = """ + System.Action`1[System.Int64[]] + B + """; + + CompileAndVerify([source1, source2], parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify([source1, source2], expectedOutput: expectedOutput).VerifyDiagnostics(); + + var source3 = """ + var c = ((C)new D()).M; + System.Console.WriteLine(c.GetType()); + c(null); + """; + + expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int64] + A + """; + + CompileAndVerify([source1, source3], parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify([source1, source3], parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + var verifier = CompileAndVerify([source1, source3], symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + var cm = verifier.Compilation.GetMember("C.M"); + Assert.True(cm.Parameters.Single().IsParams); + var dm = verifier.Compilation.GetMembers("D.M").Single(m => m.OverriddenMethod is not null); + Assert.True(dm.Parameters.Single().IsParams); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void SynthesizedDelegateTypes_ParamsArray_LeastOverriddenMethod_Different_Generic_02() + { + var source1a = """ + public abstract class C + { + public abstract void M(T[] xs); + } + """; + var comp1a = CreateCompilation(source1a, assemblyName: "Lib1").VerifyDiagnostics(); + var comp1aRef = comp1a.EmitToImageReference(); + + var source2 = """ + public class D : C + { + public override void M(T[] xs) => System.Console.WriteLine("A"); + public void M(T2[] xs) => System.Console.WriteLine("B"); + } + """; + var comp2 = CreateCompilation(source2, [comp1aRef]).VerifyDiagnostics(); + var comp2Ref = comp2.EmitToImageReference(); + + var source1b = """ + public abstract class C + { + public abstract void M(params T[] xs); + } + """; + var comp1b = CreateCompilation(source1b, assemblyName: "Lib1").VerifyDiagnostics(); + var comp1bRef = comp1b.EmitToImageReference(); + + var source3 = """ + var d = new D().M; + System.Console.WriteLine(d.GetType()); + d(null); + """; + + var expectedDiagnostics = new[] + { + // (1,9): error CS8917: The delegate type could not be inferred. + // var d = new D().M; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "new D().M").WithLocation(1, 9) + }; + + CreateCompilation(source3, [comp2Ref, comp1bRef], parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + + var expectedOutput = """ + System.Action`1[System.Int64[]] + B + """; + + CompileAndVerify(source3, [comp2Ref, comp1bRef], parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source3, [comp2Ref, comp1bRef], expectedOutput: expectedOutput).VerifyDiagnostics(); + + var source4 = """ + var c = ((C)new D()).M; + System.Console.WriteLine(c.GetType()); + c(null); + """; + + expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int64] + A + """; + + CompileAndVerify(source4, [comp2Ref, comp1bRef], parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source4, [comp2Ref, comp1bRef], parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + var verifier = CompileAndVerify(source4, [comp2Ref, comp1bRef], symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + var cm = verifier.Compilation.GetMember("C.M"); + Assert.True(cm.Parameters.Single().IsParams); + var dm = verifier.Compilation.GetMembers("D.M").Single(m => m.OverriddenMethod is not null); + Assert.False(dm.Parameters.Single().IsParams); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + } + + [Fact] + public void SynthesizedDelegateTypes_ParamsArray_MostOverriddenMethod() + { + var source = """ + var c = ((C)new D()).M; + System.Console.WriteLine(c.GetType()); + var d = new D().M; + System.Console.WriteLine(d.GetType()); + + public class D : C + { + public override void M(params int[] xs) { } + } + + public abstract class C + { + public abstract void M(int[] xs); + } + """; + + var expectedOutput = """ + System.Action`1[System.Int32[]] + System.Action`1[System.Int32[]] + """; + + CompileAndVerify(source, parseOptions: TestOptions.Regular12, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics(); + var verifier = CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics(); + + var cm = verifier.Compilation.GetMember("C.M"); + Assert.False(cm.Parameters.Single().IsParams); + var dm = verifier.Compilation.GetMember("D.M"); + Assert.False(dm.Parameters.Single().IsParams); + } + + [Fact] + public void SynthesizedDelegateTypes_ParamsArray_MostOverriddenMethod_Different() + { + var source1a = """ + public abstract class C + { + public abstract void M(params int[] xs); + } + """; + var comp1a = CreateCompilation(source1a, assemblyName: "Lib1").VerifyDiagnostics(); + var comp1aRef = comp1a.EmitToImageReference(); + + var source2 = """ + public class D : C + { + public override void M(int[] xs) { } + } + """; + var comp2 = CreateCompilation(source2, [comp1aRef]).VerifyDiagnostics(); + var comp2Ref = comp2.EmitToImageReference(); + + var source3 = """ + var c = ((C)new D()).M; + System.Console.WriteLine(c.GetType()); + var d = new D().M; + System.Console.WriteLine(d.GetType()); + """; + + var expectedOutput = """ + <>f__AnonymousDelegate0`1[System.Int32] + <>f__AnonymousDelegate0`1[System.Int32] + """; + + CompileAndVerify(source3, [comp2Ref, comp1aRef], parseOptions: TestOptions.Regular12, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source3, [comp2Ref, comp1aRef], parseOptions: TestOptions.Regular13, symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + var verifier = CompileAndVerify(source3, [comp2Ref, comp1aRef], symbolValidator: validateSymbols, expectedOutput: expectedOutput).VerifyDiagnostics(); + + var cm = verifier.Compilation.GetMember("C.M"); + Assert.True(cm.Parameters.Single().IsParams); + var dm = verifier.Compilation.GetMember("D.M"); + Assert.True(dm.Parameters.Single().IsParams); + + static void validateSymbols(ModuleSymbol module) + { + var m = module.GlobalNamespace.GetMember("<>f__AnonymousDelegate0.Invoke"); + Assert.Equal("void <>f__AnonymousDelegate0.Invoke(params T1[] arg)", m.ToTestDisplayString()); + } + + var source1b = """ + public abstract class C + { + public abstract void M(int[] xs); + } + """; + var comp1b = CreateCompilation(source1b, assemblyName: "Lib1").VerifyDiagnostics(); + var comp1bRef = comp1b.EmitToImageReference(); + + expectedOutput = """ + System.Action`1[System.Int32[]] + System.Action`1[System.Int32[]] + """; + + CompileAndVerify(source3, [comp2Ref, comp1bRef], parseOptions: TestOptions.Regular12, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source3, [comp2Ref, comp1bRef], parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics(); + verifier = CompileAndVerify(source3, [comp2Ref, comp1bRef], expectedOutput: expectedOutput).VerifyDiagnostics(); + + cm = verifier.Compilation.GetMember("C.M"); + Assert.False(cm.Parameters.Single().IsParams); + dm = verifier.Compilation.GetMember("D.M"); + Assert.True(dm.Parameters.Single().IsParams); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs index c3dafd51085ba..017ab0d3388b0 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs @@ -3252,7 +3252,7 @@ public async void GetResponseTest() var result = await GetResponse(); } }"; - CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }, options: TestOptions.DebugDll).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }, options: TestOptions.DebugDll).VerifyEmitDiagnostics( // (10,28): error CS0656: Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create' // var result = await GetResponse(); Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "GetResponse()").WithArguments("Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo", "Create").WithLocation(10, 28) @@ -4434,7 +4434,7 @@ static void M1() } "; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, parseOptions: TestOptions.Regular7_2); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.Regular7_2); comp.VerifyEmitDiagnostics( // (8,17): error CS8364: Arguments with 'in' modifier cannot be used in dynamically dispatched expressions. @@ -4459,7 +4459,7 @@ static void M1() } "; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, parseOptions: TestOptions.Regular7_2); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.Regular7_2); comp.VerifyEmitDiagnostics( // (8,20): error CS8364: Arguments with 'in' modifier cannot be used in dynamically dispatched expressions. @@ -4489,7 +4489,7 @@ static void Main() } "; - var comp1 = CreateCompilationWithMscorlib45AndCSharp(source1, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); + var comp1 = CreateCompilationWithMscorlib461AndCSharp(source1, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); comp1.VerifyEmitDiagnostics( // (10,15): error CS8364: Arguments with 'in' modifier cannot be used in dynamically dispatched expressions. @@ -4500,7 +4500,7 @@ static void Main() Diagnostic(ErrorCode.ERR_InDynamicMethodArg, "d").WithLocation(10, 28) ); - comp1 = CreateCompilationWithMscorlib45AndCSharp(source1, parseOptions: TestOptions.Regular7_2, options: TestOptions.DebugExe); + comp1 = CreateCompilationWithMscorlib461AndCSharp(source1, parseOptions: TestOptions.Regular7_2, options: TestOptions.DebugExe); comp1.VerifyEmitDiagnostics( // (10,15): error CS8364: Arguments with 'in' modifier cannot be used in dynamically dispatched expressions. @@ -4525,14 +4525,14 @@ static void Main() } "; - var comp2 = CreateCompilationWithMscorlib45AndCSharp(source2, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); + var comp2 = CreateCompilationWithMscorlib461AndCSharp(source2, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); CompileAndVerify(comp2, expectedOutput: @" True ").VerifyDiagnostics(); - comp2 = CreateCompilationWithMscorlib45AndCSharp(source2, parseOptions: TestOptions.Regular7_2, options: TestOptions.DebugExe); + comp2 = CreateCompilationWithMscorlib461AndCSharp(source2, parseOptions: TestOptions.Regular7_2, options: TestOptions.DebugExe); CompileAndVerify(comp2, expectedOutput: @" @@ -4561,7 +4561,7 @@ class M2 } }"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, parseOptions: TestOptions.Regular7_2); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.Regular7_2); comp.VerifyEmitDiagnostics( // (8,30): error CS8364: Arguments with 'in' modifier cannot be used in dynamically dispatched expressions. @@ -4590,7 +4590,7 @@ class C1 } }"; - var comp = CreateCompilationWithMscorlib45AndCSharp(source, parseOptions: TestOptions.Regular7_2); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.Regular7_2); comp.VerifyEmitDiagnostics( // (8,39): error CS8364: Arguments with 'in' modifier cannot be used in dynamically dispatched expressions. @@ -4635,7 +4635,7 @@ public static bool operator false(C c) } "; - var compilation = CreateCompilationWithMscorlib45AndCSharp(source); + var compilation = CreateCompilationWithMscorlib461AndCSharp(source); CompileAndVerify(compilation, expectedOutput: @"op_Implicit diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ExpressionBodiedMemberTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ExpressionBodiedMemberTests.cs index 771fcb51af1bb..7a14d47173721 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ExpressionBodiedMemberTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ExpressionBodiedMemberTests.cs @@ -24,7 +24,7 @@ public class ExpressionBodiedMemberTests : SemanticModelTestBase [Fact] public void PartialMethods() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" public partial class C { static partial void goo() => System.Console.WriteLine(""test""); @@ -62,7 +62,7 @@ public partial class C [Fact] public void ExprBodiedProp01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class Program { public int F = 1; @@ -117,7 +117,7 @@ class C { int P => /**/P/**/; }"); - var comp = CreateCompilationWithMscorlib45(new[] { tree }); + var comp = CreateCompilationWithMscorlib461(new[] { tree }); var info = GetSemanticInfoForTest(comp); Assert.NotNull(info); @@ -214,7 +214,7 @@ class C [Fact] public void ExprBodiedFunc01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class Program { public int M(int i) => /**/i/**/; @@ -247,7 +247,7 @@ class Program [WorkItem(1009638, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1009638")] public void ExprBodiedFunc02() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public T M(T t) where T : class => /**/t/**/; @@ -270,7 +270,7 @@ class C [Fact] public void ExprBodiedOperator01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class Program { public static Program operator ++(Program p) => /**/p/**/; @@ -302,7 +302,7 @@ class Program [Fact] public void ExprBodiedConversion01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public static C M(int i) => new C(); @@ -413,7 +413,7 @@ static void Main() [Fact, WorkItem(1069421, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1069421")] public void Bug1069421() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class Program { private int x => () => { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs index fd120694a384c..6ac8cbcb83698 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ForEachTests.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Linq; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -2119,7 +2120,7 @@ void Test(string s) } "; - var comp = CreateEmptyCompilation(source, new[] { MscorlibRefPortable }); + var comp = CreateEmptyCompilation(source, [SystemRuntimePP7Ref]); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/FuzzTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/FuzzTests.cs index 8578baf232325..5031508b2e4f9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/FuzzTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/FuzzTests.cs @@ -47,7 +47,7 @@ public static void Main() } } "; - var compilation = CreateCompilationWithMscorlib45(text); + var compilation = CreateCompilationWithMscorlib461(text); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); foreach (var node in tree.GetRoot().DescendantNodes()) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ImplicitlyTypedLocalsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ImplicitlyTypedLocalsTests.cs index 782f14bb1b3da..5a06bbec9efdf 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ImplicitlyTypedLocalsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ImplicitlyTypedLocalsTests.cs @@ -52,7 +52,7 @@ public void ImplicitlyTypedVariableAssignedArrayInitializer() string text = @" var array = { 1, 2 }; "; - CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Script).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Script).VerifyDiagnostics( // (2,5): error CS0820: Cannot initialize an implicitly-typed variable with an array initializer // var array = { 1, 2 }; Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableAssignedArrayInitializer, "array = { 1, 2 }")); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs index f00e3f59dddbe..2d7ff0cb065f0 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InheritanceBindingTests.cs @@ -1775,7 +1775,7 @@ class Derived : Base } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (13,29): error CS8148: 'Derived.Method1()' must match by reference return of overridden member 'Base.Method1()' // public override ref int Method1() { return ref field; } Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Method1").WithArguments("Derived.Method1()", "Base.Method1()").WithLocation(13, 29), @@ -1920,9 +1920,9 @@ class Derived : Base public override ref int Property3 { get { return ref @field; } } } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (15,29): error CS8148: 'Derived.Proprty1' must match by reference return of overridden member 'Base.Proprty1' - // public override ref int Proprty1 { get { return ref field; } } + // public override ref int Proprty1 { get { return ref @field; } } Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "Proprty1").WithArguments("Derived.Proprty1", "Base.Proprty1").WithLocation(15, 29), // (16,25): error CS8148: 'Derived.Property2' must match by reference return of overridden member 'Base.Property2' // public override int Property2 { get { return 0; } } @@ -1979,7 +1979,7 @@ class Derived : Base public override ref int this[string x, int y] { get { return ref field; } } } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (15,29): error CS8148: 'Derived.this[int, int]' must match by reference return of overridden member 'Base.this[int, int]' // public override ref int this[int x, int y] { get { return ref field; } } Diagnostic(ErrorCode.ERR_CantChangeRefReturnOnOverride, "this").WithArguments("Derived.this[int, int]", "Base.this[int, int]").WithLocation(15, 29), @@ -2551,7 +2551,7 @@ class Derived : Base public override ref object Method6(ref object o) { return ref o; } //wrong by-ref return } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (16,16): warning CS0114: 'Derived.Method3()' hides inherited member 'Base.Method3()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. // public int Method3() { return 0; } //wrong return type Diagnostic(ErrorCode.WRN_NewOrOverrideExpected, "Method3").WithArguments("Derived.Method3()", "Base.Method3()").WithLocation(16, 16), @@ -2619,7 +2619,7 @@ public override object Property7 { set { } } public override object Property11 { get { return null; } } } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (23,25): error CS1715: 'Derived.Property3': type must be 'object' to match overridden member 'Base.Property3' // public override int Property3 { get; set; } //wrong type Diagnostic(ErrorCode.ERR_CantChangeTypeOnOverride, "Property3").WithArguments("Derived.Property3", "Base.Property3", "object").WithLocation(23, 25), @@ -2714,7 +2714,7 @@ class Derived : Base public override object this[string w, int x, string y, int z] { get; } } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (36,69): error CS0501: 'Derived.this[string, int, string, int].get' must declare a body because it is not marked abstract, extern, or partial // public override object this[string w, int x, string y, int z] { get; } Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("Derived.this[string, int, string, int].get").WithLocation(36, 69), @@ -2969,7 +2969,7 @@ class Class : Interface public ref object Method4(ref object o) { return ref o; } //wrong by-ref return } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (10,15): error CS8152: 'Class' does not implement interface member 'Interface.Method4(ref object)'. 'Class.Method4(ref object)' cannot implement 'Interface.Method4(ref object)' because it does not have matching return by reference. // class Class : Interface Diagnostic(ErrorCode.ERR_CloseUnimplementedInterfaceMemberWrongRefReturn, "Interface").WithArguments("Class", "Interface.Method4(ref object)", "Class.Method4(ref object)").WithLocation(10, 15), @@ -3072,7 +3072,7 @@ public object Property5 { set { } } public ref object Property9 { get { return ref o; } } } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.Property2.set' // class Class : Interface Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.Property2.set").WithLocation(17, 15), @@ -3133,7 +3133,7 @@ class Class : Interface public ref object this[string w, int x, int y, string z] { get { return ref o; } } } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (17,15): error CS0535: 'Class' does not implement interface member 'Interface.this[int, string, string, string].set' // class Class : Interface Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("Class", "Interface.this[int, string, string, string].set").WithLocation(17, 15), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs index 2b262e99295e7..042a87f2469b6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; @@ -1407,19 +1408,22 @@ public class C "; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular9); comp.VerifyEmitDiagnostics( - // (4,13): error CS8145: Auto-implemented properties cannot return by reference + // 0.cs(4,13): error CS8145: Auto-implemented properties cannot return by reference // ref int Property1 { get; init; } Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "Property1").WithLocation(4, 13), - // (4,30): error CS8147: Properties which return by reference cannot have set accessors + // 0.cs(4,30): error CS8147: Properties which return by reference cannot have set accessors // ref int Property1 { get; init; } Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(4, 30), - // (5,13): error CS8146: Properties which return by reference must have a get accessor + // 0.cs(5,13): error CS8145: Auto-implemented properties cannot return by reference + // ref int Property2 { init; } + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "Property2").WithLocation(5, 13), + // 0.cs(5,13): error CS8146: Properties which return by reference must have a get accessor // ref int Property2 { init; } Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "Property2").WithLocation(5, 13), - // (6,44): error CS8147: Properties which return by reference cannot have set accessors + // 0.cs(6,44): error CS8147: Properties which return by reference cannot have set accessors // ref int Property3 { get => throw null; init => throw null; } Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(6, 44), - // (7,13): error CS8146: Properties which return by reference must have a get accessor + // 0.cs(7,13): error CS8146: Properties which return by reference must have a get accessor // ref int Property4 { init => throw null; } Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "Property4").WithLocation(7, 13) ); @@ -3459,7 +3463,10 @@ void M(C c) "; var reference = CreateMetadataReferenceFromIlSource(il); - var comp = CreateCompilation(source, references: new[] { reference }, parseOptions: TestOptions.Regular9); + var comp = CreateCompilation(source, references: new[] { reference }, parseOptions: TestOptions.Regular9, + options: TestOptions.ReleaseDll.WithSpecificDiagnosticOptions( + // warning CS1685: The predefined type 'DefaultMemberAttribute' is defined in multiple assemblies + ImmutableDictionary.Empty.Add("CS1685", ReportDiagnostic.Suppress))); comp.VerifyEmitDiagnostics( // (4,25): error CS0569: 'Derived.this[int]': cannot override 'C.this[int]' because it is not supported by the language // public override int this[int i] { set { throw null; } } @@ -3555,7 +3562,10 @@ public class Derived2 : C "; var reference = CreateMetadataReferenceFromIlSource(il); - var comp = CreateCompilation(source, references: new[] { reference }, parseOptions: TestOptions.Regular9); + var comp = CreateCompilation(source, references: new[] { reference }, parseOptions: TestOptions.Regular9, + options: TestOptions.ReleaseDll.WithSpecificDiagnosticOptions( + // warning CS1685: The predefined type 'DefaultMemberAttribute' is defined in multiple assemblies + ImmutableDictionary.Empty.Add("CS1685", ReportDiagnostic.Suppress))); comp.VerifyEmitDiagnostics( // (4,39): error CS0570: 'C.this[int].set' is not supported by the language // public override int this[int i] { set { throw null; } } @@ -4581,7 +4591,7 @@ public ClassITest28(int x) { } } "; - var piaCompilation = CreateCompilationWithMscorlib45(new[] { IsExternalInitTypeDefinition, pia }, options: TestOptions.DebugDll); + var piaCompilation = CreateCompilationWithMscorlib461(new[] { IsExternalInitTypeDefinition, pia }, options: TestOptions.DebugDll); CompileAndVerify(piaCompilation); @@ -4597,7 +4607,7 @@ public static void Main() } }"; - var compilation = CreateCompilationWithMscorlib45(new[] { source }, + var compilation = CreateCompilationWithMscorlib461(new[] { source }, new MetadataReference[] { new CSharpCompilationReference(piaCompilation, embedInteropTypes: true) }, options: TestOptions.DebugExe); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs index 91fa4ec491db2..65e93bb7c829f 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs @@ -33,7 +33,7 @@ public InterceptsLocationAttribute(int version, string data) { } } """, "attributes.cs"); - private static readonly CSharpParseOptions RegularWithInterceptors = TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "global"); + private static readonly CSharpParseOptions RegularWithInterceptors = TestOptions.Regular.WithFeature("InterceptorsNamespaces", "global"); private static readonly SyntaxTree s_attributesTree = CSharpTestSource.Parse(s_attributesSource.text, s_attributesSource.path, RegularWithInterceptors); @@ -110,41 +110,41 @@ class D } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "NS")); + var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS")); comp.VerifyEmitDiagnostics( - // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled. Add '$(InterceptorsPreviewNamespaces);NS1' to your project. + // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled. Add '$(InterceptorsNamespaces);NS1' to your project. // [InterceptsLocation("Program.cs", 4, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsPreviewNamespaces);NS1").WithLocation(15, 10)); + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsNamespaces);NS1").WithLocation(15, 10)); - comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "NS1.NS2")); + comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1.NS2")); comp.VerifyEmitDiagnostics( - // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled. Add '$(InterceptorsPreviewNamespaces);NS1' to your project. + // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled. Add '$(InterceptorsNamespaces);NS1' to your project. // [InterceptsLocation("Program.cs", 4, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsPreviewNamespaces);NS1").WithLocation(15, 10)); + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsNamespaces);NS1").WithLocation(15, 10)); - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "NS1"), expectedOutput: "1"); + var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1"), expectedOutput: "1"); verifier.VerifyDiagnostics(); - verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "NS1;NS2"), expectedOutput: "1"); + verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1;NS2"), expectedOutput: "1"); verifier.VerifyDiagnostics(); } [Fact] public void FeatureFlag_Granular_Checksum_01() { - test(TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "NS"), expectedOutput: null, - // Interceptors.cs(7,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsPreviewNamespaces);NS1' to your project. + test(TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS"), expectedOutput: null, + // Interceptors.cs(7,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);NS1' to your project. // [global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "eY+urAo7Kg2rsKgGSGjShwIAAABQcm9ncmFtLmNz")] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "global::System.Runtime.CompilerServices.InterceptsLocationAttribute").WithArguments("$(InterceptorsPreviewNamespaces);NS1").WithLocation(7, 10)); + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "global::System.Runtime.CompilerServices.InterceptsLocationAttribute").WithArguments("$(InterceptorsNamespaces);NS1").WithLocation(7, 10)); - test(TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "NS1.NS2"), expectedOutput: null, - // Interceptors.cs(7,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsPreviewNamespaces);NS1' to your project. + test(TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1.NS2"), expectedOutput: null, + // Interceptors.cs(7,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);NS1' to your project. // [global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "eY+urAo7Kg2rsKgGSGjShwIAAABQcm9ncmFtLmNz")] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "global::System.Runtime.CompilerServices.InterceptsLocationAttribute").WithArguments("$(InterceptorsPreviewNamespaces);NS1").WithLocation(7, 10)); + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, "global::System.Runtime.CompilerServices.InterceptsLocationAttribute").WithArguments("$(InterceptorsNamespaces);NS1").WithLocation(7, 10)); - test(TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "NS1"), expectedOutput: "1"); + test(TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1"), expectedOutput: "1"); - test(TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "NS1;NS2"), expectedOutput: "1"); + test(TestOptions.Regular.WithFeature("InterceptorsNamespaces", "NS1;NS2"), expectedOutput: "1"); void test(CSharpParseOptions options, string? expectedOutput, params DiagnosticDescription[] expected) { @@ -237,16 +237,16 @@ class D void sadCase(string featureValue) { - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", featureValue)); + var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", featureValue)); comp.VerifyEmitDiagnostics( - // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled. Add '$(InterceptorsPreviewNamespaces);NS1.NS2' to your project. + // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled. Add '$(InterceptorsNamespaces);NS1.NS2' to your project. // [InterceptsLocation("Program.cs", 4, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsPreviewNamespaces);NS1.NS2").WithLocation(15, 10)); + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsNamespaces);NS1.NS2").WithLocation(15, 10)); } void happyCase(string featureValue) { - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", featureValue), expectedOutput: "1"); + var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", featureValue), expectedOutput: "1"); verifier.VerifyDiagnostics(); } } @@ -272,7 +272,7 @@ class D } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "")); + var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "")); comp.VerifyEmitDiagnostics( // Program.cs(13,6): error CS9206: An interceptor cannot be declared in the global namespace. // [InterceptsLocation("Program.cs", 4, 3)] @@ -303,10 +303,10 @@ class D } """; - var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "global"), expectedOutput: "1"); + var verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "global"), expectedOutput: "1"); verifier.VerifyDiagnostics(); - verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("interceptorspreviewnamespaces", "global"), expectedOutput: "1"); + verifier = CompileAndVerify(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "global"), expectedOutput: "1"); verifier.VerifyDiagnostics(); } @@ -334,11 +334,11 @@ class D } """; - var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "global.A")); + var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "global.A")); comp.VerifyEmitDiagnostics( - // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsPreviewNamespaces);global.B' to your project. + // Program.cs(15,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);global.B' to your project. // [InterceptsLocation("Program.cs", 4, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsPreviewNamespaces);global.B").WithLocation(15, 10)); + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 4, 3)").WithArguments("$(InterceptorsNamespaces);global.B").WithLocation(15, 10)); } [Fact] @@ -6302,7 +6302,7 @@ public void M() } """, "Interceptor.cs"); - var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "Interceptors")); + var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6347,7 +6347,7 @@ static class D } """, "Interceptor.cs"); - var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "Interceptors")); + var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6358,9 +6358,9 @@ static class D Assert.Null(interceptor); comp.VerifyEmitDiagnostics( - // Interceptor.cs(8,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsPreviewNamespaces);NotInterceptors' to your project. + // Interceptor.cs(8,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);NotInterceptors' to your project. // [InterceptsLocation("Program.cs", 1, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsPreviewNamespaces);NotInterceptors").WithLocation(8, 10)); + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsNamespaces);NotInterceptors").WithLocation(8, 10)); interceptor = model.GetInterceptorMethod(call); Assert.Null(interceptor); @@ -6400,7 +6400,7 @@ public void M() } """, "Interceptor.cs"); - var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "Interceptors")); + var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6449,7 +6449,7 @@ static class D } """, "Interceptor.cs"); - var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "Interceptors")); + var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6505,7 +6505,7 @@ static class D } """, "Interceptor.cs"); - var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "Interceptors")); + var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6515,9 +6515,9 @@ static class D Assert.Equal("void Interceptors.D.Interceptor1()", interceptor.ToTestDisplayString()); comp.VerifyEmitDiagnostics( - // Interceptor.cs(17,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsPreviewNamespaces);NotInterceptors' to your project. + // Interceptor.cs(17,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);NotInterceptors' to your project. // [InterceptsLocation("Program.cs", 1, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsPreviewNamespaces);NotInterceptors").WithLocation(17, 10)); + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsNamespaces);NotInterceptors").WithLocation(17, 10)); interceptor = model.GetInterceptorMethod(call); Assert.Equal("void Interceptors.D.Interceptor1()", interceptor.ToTestDisplayString()); @@ -6553,7 +6553,7 @@ public static class D } """, "Interceptor.cs"); - var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "Interceptors")); + var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6572,7 +6572,7 @@ public static class D [CombinatorialData] public void GetInterceptorMethod_09(bool featureExists) { - // InterceptorsPreviewNamespaces is empty or does not exist + // InterceptorsNamespaces is empty or does not exist var source = (""" C.M(); @@ -6599,7 +6599,7 @@ public static class D } """, "Interceptor.cs"); - var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: featureExists ? TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "") : TestOptions.Regular); + var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: featureExists ? TestOptions.Regular.WithFeature("InterceptorsNamespaces", "") : TestOptions.Regular); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6607,16 +6607,16 @@ public static class D Assert.Null(model.GetInterceptorMethod(call)); comp.VerifyEmitDiagnostics( - // Interceptor.cs(10,14): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsPreviewNamespaces);Interceptors' to your project. + // Interceptor.cs(10,14): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);Interceptors' to your project. // [InterceptsLocation("Program.cs", 1, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsPreviewNamespaces);Interceptors").WithLocation(10, 14)); + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsNamespaces);Interceptors").WithLocation(10, 14)); Assert.Null(model.GetInterceptorMethod(call)); } [Fact] public void GetInterceptorMethod_10() { - // InterceptorsPreviewNamespaces has duplicates + // InterceptorsNamespaces has duplicates var source = (""" C.M(); @@ -6643,7 +6643,7 @@ public static class D } """, "Interceptor.cs"); - var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "Interceptors;Interceptors")); + var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors;Interceptors")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6671,7 +6671,7 @@ class C } """, "Program.cs"); - var comp = CreateCompilation(new[] { source, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "Interceptors")); + var comp = CreateCompilation(new[] { source, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6690,7 +6690,7 @@ class C public void GetInterceptorMethod_12() { // Compilation contains no files - var comp = CreateCompilation([], parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "Interceptors")); + var comp = CreateCompilation([], parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors")); // We can't use GetInterceptorMethod without a SemanticModel and we can't get a SemanticModel when the compilation contains no trees. // But, we can exercise some internal API for theoretical edge cases to see if it is robust (does not throw, updates expected flags). @@ -6730,7 +6730,7 @@ public static class D } """, "Interceptor.cs"); - var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", @namespace)); + var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", @namespace)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6772,7 +6772,7 @@ public static class D } """, "Interceptor.cs"); - var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsPreviewNamespaces", "Interceptors.Nested")); + var comp = CreateCompilation(new[] { source, interceptorSource, s_attributesSource }, parseOptions: TestOptions.Regular.WithFeature("InterceptorsNamespaces", "Interceptors.Nested")); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); @@ -6781,9 +6781,9 @@ public static class D Assert.Null(model.GetInterceptorMethod(call)); comp.VerifyEmitDiagnostics( - // Interceptor.cs(8,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsPreviewNamespaces);Interceptors' to your project. + // Interceptor.cs(8,10): error CS9137: The 'interceptors' experimental feature is not enabled in this namespace. Add '$(InterceptorsNamespaces);Interceptors' to your project. // [InterceptsLocation("Program.cs", 1, 3)] - Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsPreviewNamespaces);Interceptors").WithLocation(8, 10)); + Diagnostic(ErrorCode.ERR_InterceptorsFeatureNotEnabled, @"InterceptsLocation(""Program.cs"", 1, 3)").WithArguments("$(InterceptorsNamespaces);Interceptors").WithLocation(8, 10)); Assert.Null(model.GetInterceptorMethod(call)); } @@ -7513,4 +7513,448 @@ static class Interceptors var method = model.GetInterceptorMethod(node); Assert.Equal($"void Interceptors.M1(this {refKind}S s)", method.ToTestDisplayString()); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71657")] + public void ReceiverCapturedToTemp_StructRvalueReceiver() + { + var source = CSharpTestSource.Parse(""" + using System; + + public struct S + { + void M() => Console.WriteLine(0); + + public static void Main() + { + new S().M(); + } + } + """, "Program.cs", RegularWithInterceptors); + + var comp = CreateCompilation(source); + var model = comp.GetSemanticModel(source); + var node = source.GetRoot().DescendantNodes().OfType().Last(); + var locationSpecifier = model.GetInterceptableLocation(node)!; + + var interceptors = CSharpTestSource.Parse($$""" + using System; + + public static class C + { + {{locationSpecifier.GetInterceptsLocationAttributeSyntax()}} + public static void M1(this ref S s) => Console.WriteLine(1); + } + """, "Interceptors.cs", RegularWithInterceptors); + + var verifier = CompileAndVerify([source, interceptors, s_attributesTree], expectedOutput: "1"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("S.Main", """ + { + // Code size 16 (0x10) + .maxstack 1 + .locals init (S V_0) + IL_0000: ldloca.s V_0 + IL_0002: initobj "S" + IL_0008: ldloca.s V_0 + IL_000a: call "void C.M1(ref S)" + IL_000f: ret + } + """); + + comp = (CSharpCompilation)verifier.Compilation; + model = comp.GetSemanticModel(source); + var method = model.GetInterceptorMethod(node); + Assert.Equal("void C.M1(this ref S s)", method.ToTestDisplayString()); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71657")] + public void ReceiverCapturedToTemp_StructInReceiver() + { + // Implicitly capture receiver to temp in 's.M()' because target method needs a writable reference. + var source = CSharpTestSource.Parse(""" + using System; + + public struct S + { + void M() => Console.WriteLine(0); + + public static void Main() + { + M0(new S()); + } + + static void M0(in S s) + { + s.M(); + } + } + """, "Program.cs", RegularWithInterceptors); + + var comp = CreateCompilation(source); + var model = comp.GetSemanticModel(source); + var node = source.GetRoot().DescendantNodes().OfType().Last(); + var locationSpecifier = model.GetInterceptableLocation(node)!; + + var interceptors = CSharpTestSource.Parse($$""" + using System; + + public static class C + { + {{locationSpecifier.GetInterceptsLocationAttributeSyntax()}} + public static void M1(this ref S s) => Console.WriteLine(1); + } + """, "Interceptors.cs", RegularWithInterceptors); + + var verifier = CompileAndVerify([source, interceptors, s_attributesTree], expectedOutput: "1"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("S.M0", """ + { + // Code size 15 (0xf) + .maxstack 1 + .locals init (S V_0) + IL_0000: ldarg.0 + IL_0001: ldobj "S" + IL_0006: stloc.0 + IL_0007: ldloca.s V_0 + IL_0009: call "void C.M1(ref S)" + IL_000e: ret + } + """); + + comp = (CSharpCompilation)verifier.Compilation; + model = comp.GetSemanticModel(source); + var method = model.GetInterceptorMethod(node); + Assert.Equal("void C.M1(this ref S s)", method.ToTestDisplayString()); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71657")] + public void ReceiverNotCapturedToTemp_StructRefReceiver() + { + var source = CSharpTestSource.Parse(""" + using System; + + public struct S + { + void M() => Console.WriteLine(0); + + public static void Main() + { + S s = default; + M0(ref s); + } + + static void M0(ref S s) + { + s.M(); + } + } + """, "Program.cs", RegularWithInterceptors); + + var comp = CreateCompilation(source); + var model = comp.GetSemanticModel(source); + var node = source.GetRoot().DescendantNodes().OfType().Last(); + var locationSpecifier = model.GetInterceptableLocation(node)!; + + var interceptors = CSharpTestSource.Parse($$""" + using System; + + public static class C + { + {{locationSpecifier.GetInterceptsLocationAttributeSyntax()}} + public static void M1(this ref S s) => Console.WriteLine(1); + } + """, "Interceptors.cs", RegularWithInterceptors); + + var verifier = CompileAndVerify([source, interceptors, s_attributesTree], expectedOutput: "1"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("S.M0", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "void C.M1(ref S)" + IL_0006: ret + } + """); + + comp = (CSharpCompilation)verifier.Compilation; + model = comp.GetSemanticModel(source); + var method = model.GetInterceptorMethod(node); + Assert.Equal("void C.M1(this ref S s)", method.ToTestDisplayString()); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71657")] + public void ReceiverNotCapturedToTemp_StructReadonlyMethod() + { + var source = CSharpTestSource.Parse(""" + using System; + + public struct S + { + readonly void M() => Console.WriteLine(0); + + public static void Main() + { + M0(new S()); + } + + static void M0(in S s) + { + s.M(); + } + } + """, "Program.cs", RegularWithInterceptors); + + var comp = CreateCompilation(source); + var model = comp.GetSemanticModel(source); + var node = source.GetRoot().DescendantNodes().OfType().Last(); + var locationSpecifier = model.GetInterceptableLocation(node)!; + + var interceptors = CSharpTestSource.Parse($$""" + using System; + + public static class C + { + {{locationSpecifier.GetInterceptsLocationAttributeSyntax()}} + public static void M1(this in S s) => Console.WriteLine(1); + } + """, "Interceptors.cs", RegularWithInterceptors); + + var verifier = CompileAndVerify([source, interceptors, s_attributesTree], expectedOutput: "1"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("S.M0", """ + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call "void C.M1(in S)" + IL_0006: ret + } + """); + + comp = (CSharpCompilation)verifier.Compilation; + model = comp.GetSemanticModel(source); + var method = model.GetInterceptorMethod(node); + Assert.Equal("void C.M1(this in S s)", method.ToTestDisplayString()); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71657")] + public void ReceiverNotCapturedToTemp_StructLvalueReceiver() + { + var source = CSharpTestSource.Parse(""" + using System; + + public struct S + { + void M() => Console.WriteLine(0); + + public static void Main() + { + M0(new S()); + } + + static void M0(S s) + { + s.M(); + } + } + """, "Program.cs", RegularWithInterceptors); + + var comp = CreateCompilation(source); + var model = comp.GetSemanticModel(source); + var node = source.GetRoot().DescendantNodes().OfType().Last(); + var locationSpecifier = model.GetInterceptableLocation(node)!; + + var interceptors = CSharpTestSource.Parse($$""" + using System; + + public static class C + { + {{locationSpecifier.GetInterceptsLocationAttributeSyntax()}} + public static void M1(this ref S s) => Console.WriteLine(1); + } + """, "Interceptors.cs", RegularWithInterceptors); + + var verifier = CompileAndVerify([source, interceptors, s_attributesTree], expectedOutput: "1"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("S.M0", """ + { + // Code size 8 (0x8) + .maxstack 1 + IL_0000: ldarga.s V_0 + IL_0002: call "void C.M1(ref S)" + IL_0007: ret + } + """); + + comp = (CSharpCompilation)verifier.Compilation; + model = comp.GetSemanticModel(source); + var method = model.GetInterceptorMethod(node); + Assert.Equal("void C.M1(this ref S s)", method.ToTestDisplayString()); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71657")] + public void ReceiverNotCapturedToTemp_ByValueParameter() + { + var source = CSharpTestSource.Parse(""" + using System; + + public class C + { + void M() => Console.WriteLine(0); + + public static void Main() + { + new C().M(); + } + } + """, "Program.cs", RegularWithInterceptors); + + var comp = CreateCompilation(source); + var model = comp.GetSemanticModel(source); + var node = source.GetRoot().DescendantNodes().OfType().Last(); + var locationSpecifier = model.GetInterceptableLocation(node)!; + + var interceptors = CSharpTestSource.Parse($$""" + using System; + + public static class SC + { + {{locationSpecifier.GetInterceptsLocationAttributeSyntax()}} + public static void M1(this C c) => Console.WriteLine(1); + } + """, "Interceptors.cs", RegularWithInterceptors); + + var verifier = CompileAndVerify([source, interceptors, s_attributesTree], expectedOutput: "1"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("C.Main", """ + { + // Code size 11 (0xb) + .maxstack 1 + IL_0000: newobj "C..ctor()" + IL_0005: call "void SC.M1(C)" + IL_000a: ret + } + """); + + comp = (CSharpCompilation)verifier.Compilation; + model = comp.GetSemanticModel(source); + var method = model.GetInterceptorMethod(node); + Assert.Equal("void SC.M1(this C c)", method.ToTestDisplayString()); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71657")] + public void Receiver_RefReturn_NotCapturedToTemp() + { + var source = CSharpTestSource.Parse(""" + using System; + + public struct S + { + public int F; + + static S s; + static ref S RS() => ref s; + + void M() => throw null!; + + public static void Main() + { + RS().F = 1; + Console.Write(RS().F); + RS().M(); + Console.Write(RS().F); + } + } + """, "Program.cs", RegularWithInterceptors); + + var comp = CreateCompilation(source); + var model = comp.GetSemanticModel(source); + var node = source.GetRoot().DescendantNodes().OfType().Single(i => i.ToString() == "RS().M()"); + var locationSpecifier = model.GetInterceptableLocation(node)!; + + var interceptors = CSharpTestSource.Parse($$""" + public static class SC + { + {{locationSpecifier.GetInterceptsLocationAttributeSyntax()}} + public static void M1(this ref S s) => s.F = 2; + } + """, "Interceptors.cs", RegularWithInterceptors); + + var verifier = CompileAndVerify([source, interceptors, s_attributesTree], expectedOutput: "12"); + verifier.VerifyDiagnostics(); + verifier.VerifyIL("S.Main", """ + { + // Code size 52 (0x34) + .maxstack 2 + IL_0000: call "ref S S.RS()" + IL_0005: ldc.i4.1 + IL_0006: stfld "int S.F" + IL_000b: call "ref S S.RS()" + IL_0010: ldfld "int S.F" + IL_0015: call "void System.Console.Write(int)" + IL_001a: call "ref S S.RS()" + IL_001f: call "void SC.M1(ref S)" + IL_0024: call "ref S S.RS()" + IL_0029: ldfld "int S.F" + IL_002e: call "void System.Console.Write(int)" + IL_0033: ret + } + """); + + comp = (CSharpCompilation)verifier.Compilation; + model = comp.GetSemanticModel(source); + var method = model.GetInterceptorMethod(node); + Assert.Equal("void SC.M1(this ref S s)", method.ToTestDisplayString()); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71657")] + public void CannotReturnRefToImplicitTemp() + { + var source = CSharpTestSource.Parse(""" + using System; + using System.Diagnostics.CodeAnalysis; + + public ref struct S + { + static Span Test() + { + return new S().M(); + } + + [UnscopedRef] + public Span M() => default; + } + """, "Program.cs", RegularWithInterceptors); + + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // Program.cs(8,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // return new S().M(); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "new S()").WithLocation(8, 16)); + + var model = comp.GetSemanticModel(source); + var node = source.GetRoot().DescendantNodes().OfType().Single(i => i.ToString() == "new S().M()"); + var locationSpecifier = model.GetInterceptableLocation(node)!; + + var interceptors = CSharpTestSource.Parse($$""" + using System; + + static class D + { + {{locationSpecifier.GetInterceptsLocationAttributeSyntax()}} + public static Span M(this ref S s) => default; + } + """, "Interceptors.cs", RegularWithInterceptors); + + comp = CreateCompilation([source, interceptors, s_attributesTree], targetFramework: TargetFramework.Net90); + comp.VerifyEmitDiagnostics( + // Program.cs(8,16): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // return new S().M(); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "new S()").WithLocation(8, 16)); + + model = comp.GetSemanticModel(source); + var method = model.GetInterceptorMethod(node); + AssertEx.Equal("System.Span D.M(this ref S s)", method.ToTestDisplayString()); + } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs index 62a6be4a861fc..581c898a232ac 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs @@ -109,7 +109,7 @@ public static void Main(string[] args) Console.WriteLine($""Jenny don\'t change your number { /*trash*/ }.""); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,73): error CS1733: Expected expression // Console.WriteLine("Jenny don\'t change your number \{ /*trash*/ }."); Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(5, 73) @@ -128,7 +128,7 @@ public static void Main(string[] args) } }"; // too many diagnostics perhaps, but it starts the right way. - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,63): error CS1010: Newline in constant // Console.WriteLine($"Jenny don\'t change your number { "); Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(5, 63), @@ -158,7 +158,7 @@ public static void Main(string[] args) } }"; // too many diagnostics perhaps, but it starts the right way. - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,5): error CS1039: Unterminated string literal // } Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "}").WithLocation(6, 5), @@ -185,7 +185,7 @@ public static void Main(string[] args) } }"; // too many diagnostics perhaps, but it starts the right way. - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,60): error CS8076: Missing close delimiter '}' for interpolated expression started with '{'. // Console.WriteLine($"Jenny don\'t change your number { 8675309 /* "); Diagnostic(ErrorCode.ERR_UnclosedExpressionHole, " {").WithLocation(5, 60), @@ -358,7 +358,7 @@ static void Main(string[] args) Console.WriteLine( $""{"" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,31): error CS1010: Newline in constant // Console.WriteLine( $"{" ); Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(6, 31), @@ -386,7 +386,7 @@ static void Main(string[] args) { var x = $"";"; // The precise error messages are not important, but this must be an error. - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,19): error CS1039: Unterminated string literal // var x = $"; Diagnostic(ErrorCode.ERR_UnterminatedStringLit, ";").WithLocation(5, 19), @@ -413,7 +413,7 @@ static void Main(string[] args) Console.WriteLine( $""{3:}"" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,32): error CS8089: Empty format specifier. // Console.WriteLine( $"{3:}" ); Diagnostic(ErrorCode.ERR_EmptyFormatSpecifier, ":").WithLocation(6, 32) @@ -432,7 +432,7 @@ static void Main(string[] args) Console.WriteLine( $""{3:{}"" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,33): error CS1056: Unerwartetes Zeichen "{". // Console.WriteLine( $"{3:{}" ); Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "{").WithArguments("{").WithLocation(6, 33) @@ -451,7 +451,7 @@ static void Main(string[] args) Console.WriteLine( $""{3:d }"" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,32): error CS8088: A format specifier may not contain trailing whitespace. // Console.WriteLine( $"{3:d }" ); Diagnostic(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, ":d ").WithLocation(6, 32) @@ -471,7 +471,7 @@ static void Main(string[] args) }"" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,33): error CS8088: A format specifier may not contain trailing whitespace. // Console.WriteLine( $@"{3:d Diagnostic(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, @":d @@ -491,7 +491,7 @@ static void Main(string[] args) Console.WriteLine( $""{ }"" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,32): error CS1733: Expected expression // Console.WriteLine( $"{ }" ); Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(6, 32) @@ -510,7 +510,7 @@ static void Main(string[] args) Console.WriteLine( $@""{ }"" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,33): error CS1733: Expected expression // Console.WriteLine( $@"{ }" ); Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(6, 33) @@ -607,7 +607,7 @@ static void Main() var s2 = $"" \u007D""; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,21): error CS8087: A '{' character may only be escaped by doubling '{{' in an interpolated string. // var s1 = $" \u007B "; Diagnostic(ErrorCode.ERR_EscapedCurly, @"\u007B").WithArguments("{").WithLocation(5, 21), @@ -645,7 +645,7 @@ static void Main() var t = $""{1,(int)1E10}""; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,22): error CS0266: Cannot implicitly convert type 'double' to 'int'. An explicit conversion exists (are you missing a cast?) // var s = $"{1,1E10}"; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "1E10").WithArguments("double", "int").WithLocation(5, 22), @@ -1131,7 +1131,7 @@ .maxstack 2 } [WorkItem(57750, "https://github.com/dotnet/roslyn/issues/57750")] -#if NETCOREAPP +#if NET [InlineData(TargetFramework.Net60)] [InlineData(TargetFramework.Net50)] #endif @@ -1238,7 +1238,7 @@ .locals init (string V_0, //str } [WorkItem(57750, "https://github.com/dotnet/roslyn/issues/57750")] -#if NETCOREAPP +#if NET [InlineData(TargetFramework.Net60)] [InlineData(TargetFramework.Net50)] #endif @@ -1341,7 +1341,7 @@ .locals init (string V_0, //str } [WorkItem(57750, "https://github.com/dotnet/roslyn/issues/57750")] -#if NETCOREAPP +#if NET [InlineData(TargetFramework.Net60)] [InlineData(TargetFramework.Net50)] #endif @@ -1397,7 +1397,7 @@ .locals init (string V_0, //a } [WorkItem(57750, "https://github.com/dotnet/roslyn/issues/57750")] -#if NETCOREAPP +#if NET [InlineData(TargetFramework.Net60)] [InlineData(TargetFramework.Net50)] #endif @@ -13891,7 +13891,7 @@ public CustomHandler(int literalLength, int formattedCount, dynamic d) : this(li var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false, includeOneTimeHelpers: false); - var comp = CreateCompilation(new[] { code, handler, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, handler, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: "d:1"); verifier.VerifyDiagnostics(); @@ -13936,7 +13936,7 @@ public CustomHandler(dynamic literalLength, int formattedCount) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: "ctor"); verifier.VerifyDiagnostics(); @@ -13981,7 +13981,7 @@ public CustomHandler(dynamic literalLength, int formattedCount) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: "ctor"); verifier.VerifyDiagnostics(); @@ -14024,7 +14024,7 @@ public void AppendLiteral(dynamic d) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: "AppendLiteral"); verifier.VerifyDiagnostics(); @@ -14073,7 +14073,7 @@ public void AppendFormatted(dynamic d) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: "AppendFormatted"); verifier.VerifyDiagnostics(); @@ -14129,7 +14129,7 @@ public void AppendFormatted(dynamic d) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: @" AppendLiteral AppendFormatted"); @@ -14225,7 +14225,7 @@ public void AppendFormatted(int d) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: @" AppendLiteral AppendFormatted"); @@ -14324,7 +14324,7 @@ public bool AppendFormatted(long d) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: @" AppendLiteral AppendFormatted"); @@ -18913,5 +18913,94 @@ .locals init (T V_0, } """); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74427")] + public void InterpolatedStringAsInputToUserDefinedConversion_01() + { + var source = """ + class C + { + static void Main() + { + var y = (C1)$"dog"; // works + System.Console.WriteLine(y); + } + } + + class C1 + { + System.FormattableString x; + public C1(System.FormattableString x) + { + this.x = x; + } + + public static implicit operator C1(System.FormattableString x) => new C1(x); + + public override string ToString() + { + return ("C1:") + x.ToString(); + } + } + """; + + CompileAndVerify(source, expectedOutput: "C1:dog"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74427")] + public void InterpolatedStringAsInputToUserDefinedConversion_02() + { + var source = """ + class C + { + static void Main() + { + var y = (C1)$"dog"; + System.Console.WriteLine(y); + } + } + + class C1 + { + System.IFormattable x; + public C1(System.IFormattable x) + { + this.x = x; + } + + public static implicit operator C1(System.IFormattable x) => new C1(x); + + public override string ToString() + { + return ("C1:") + x.ToString(); + } + } + """; + + CreateCompilation(source).VerifyDiagnostics( + // (18,37): error CS0552: 'C1.implicit operator C1(IFormattable)': user-defined conversions to or from an interface are not allowed + // public static implicit operator C1(System.IFormattable x) => new C1(x); + Diagnostic(ErrorCode.ERR_ConversionWithInterface, "C1").WithArguments("C1.implicit operator C1(System.IFormattable)").WithLocation(18, 37) + ); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74677")] + public void StackOverflow() + { + var source = """ + using System; + + [Obsolete($"{Test2}")] + class Test2 + { + } + """; + + CreateCompilation(source).VerifyEmitDiagnostics( + // (3,14): error CS0119: 'Test2' is a type, which is not valid in the given context + // [Obsolete($"{Test2}")] + Diagnostic(ErrorCode.ERR_BadSKunknown, "Test2").WithArguments("Test2", "type").WithLocation(3, 14) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs index 2a447bcca3b67..170096bd82075 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/IteratorTests.cs @@ -439,7 +439,7 @@ public void TopLevelYieldReturn() { // The incomplete statement is intended var text = "yield return int."; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Script); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Script); comp.VerifyDiagnostics( // (1,18): error CS1001: Identifier expected // yield return int. @@ -471,7 +471,7 @@ public void TopLevelYieldReturn() public void TopLevelYieldBreak() { var text = "yield break;"; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Script); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Script); comp.VerifyDiagnostics( // (1,1): error CS7020: You cannot use 'yield' in top-level script code // yield break; @@ -602,7 +602,7 @@ public IEnumerator> GetEnumerator(KeyValuePair(kvp.Key, kvp.Value); } }"; - var comp = CreateCompilationWithMscorlib45(text); + var comp = CreateCompilationWithMscorlib461(text); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees[0]; @@ -636,7 +636,7 @@ public IEnumerator> GetEnumerator(KeyValuePair(kvp, kvp.Value); } }"; - var comp = CreateCompilationWithMscorlib45(text); + var comp = CreateCompilationWithMscorlib461(text); comp.VerifyDiagnostics( // (8,53): error CS1503: Argument 1: cannot convert from 'System.Collections.Generic.KeyValuePair' to 'TKey' // yield return new KeyValuePair(kvp, kvp.Value); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index c4603025d3465..1e55230cdfaa5 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -368,7 +368,7 @@ public string GetUrl() var comp1 = CreateCompilationWithMscorlib40( new[] { Parse(text1) }, - new[] { TestMetadata.Net451.System }); + new[] { NetFramework.System }); var text2 = @" class Program @@ -414,7 +414,8 @@ public static void Goo(Func func) var comp1 = CreateCompilation( Parse(text1), - new[] { TestReferences.SymbolsTests.NoPia.StdOle.WithEmbedInteropTypes(true) }, + targetFramework: TargetFramework.NetFramework, + references: [TestReferences.SymbolsTests.NoPia.StdOleNetFramework.WithEmbedInteropTypes(true)], options: TestOptions.ReleaseDll); var text2 = @" @@ -429,22 +430,24 @@ public static void Main() var comp2 = CreateCompilation( Parse(text2), - new MetadataReference[] - { + targetFramework: TargetFramework.NetFramework, + references: + [ new CSharpCompilationReference(comp1), - TestReferences.SymbolsTests.NoPia.StdOle.WithEmbedInteropTypes(true) - }, + TestReferences.SymbolsTests.NoPia.StdOleNetFramework.WithEmbedInteropTypes(true) + ], options: TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: "Y").Diagnostics.Verify(); var comp3 = CreateCompilation( Parse(text2), - new MetadataReference[] - { + targetFramework: TargetFramework.NetFramework, + references: + [ comp1.EmitToImageReference(), - TestReferences.SymbolsTests.NoPia.StdOle.WithEmbedInteropTypes(true) - }, + TestReferences.SymbolsTests.NoPia.StdOleNetFramework.WithEmbedInteropTypes(true) + ], options: TestOptions.ReleaseExe); CompileAndVerify(comp3, expectedOutput: "Y").Diagnostics.Verify(); @@ -1261,7 +1264,7 @@ static void M() } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(text).VerifyDiagnostics(); } [Fact] @@ -1282,7 +1285,7 @@ static void M() } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(text).VerifyDiagnostics(); } [Fact] @@ -1310,7 +1313,7 @@ static void M() } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(text).VerifyDiagnostics(); } [Fact] @@ -1333,7 +1336,7 @@ static void M() } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (11,22): error CS8149: By-reference returns may only be used in by-reference returning methods. // ME(() => ref i); Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "i").WithLocation(11, 22), @@ -1363,7 +1366,7 @@ static void M() } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (9,33): error CS8149: By-reference returns may only be used in by-reference returning methods. // var e = new E(() => ref i); Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "i").WithLocation(9, 33), @@ -1408,7 +1411,7 @@ static void M() } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (18,13): error CS8150: By-value returns may only be used in by-value returning methods. // return i; Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "return").WithLocation(18, 13), @@ -1968,7 +1971,7 @@ static void Main(string[] args) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index f7c8978416eb4..44125b156e1d4 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -24,7 +24,7 @@ public class LocalFunctionsTestBase : CSharpTestBase internal static void VerifyDiagnostics(string source, params DiagnosticDescription[] expected) { - var comp = CreateCompilationWithMscorlib45AndCSharp(source, options: TestOptions.ReleaseDll, parseOptions: DefaultParseOptions); + var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseDll, parseOptions: DefaultParseOptions); comp.VerifyDiagnostics(expected); } } @@ -2485,43 +2485,29 @@ void local() { } [Fact] public void ForgotSemicolonLocalFunctionsMistake() { - var src = @" -class C -{ - public void M1() - { - // forget closing brace + var src = """ + class C + { + public void M1() + { + // forget closing brace - public void BadLocal1() - { - this.BadLocal2(); - } + public void BadLocal1() + { + this.BadLocal2(); + } - public void BadLocal2() - { - } + public void BadLocal2() + { + } - public int P => 0; -}"; + public int P => 0; + } + """; VerifyDiagnostics(src, - // (8,5): error CS0106: The modifier 'public' is not valid for this item - // public void BadLocal1() - Diagnostic(ErrorCode.ERR_BadMemberFlag, "public").WithArguments("public").WithLocation(8, 5), - // (13,5): error CS0106: The modifier 'public' is not valid for this item - // public void BadLocal2() - Diagnostic(ErrorCode.ERR_BadMemberFlag, "public").WithArguments("public").WithLocation(13, 5), - // (15,6): error CS1513: } expected - // } - Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(15, 6), - // (10,14): error CS1061: 'C' does not contain a definition for 'BadLocal2' and no extension method 'BadLocal2' accepting a first argument of type 'C' could be found (are you missing a using directive or an assembly reference?) - // this.BadLocal2(); - Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "BadLocal2").WithArguments("C", "BadLocal2").WithLocation(10, 14), - // (8,17): warning CS8321: The local function 'BadLocal1' is declared but never used - // public void BadLocal1() - Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "BadLocal1").WithArguments("BadLocal1").WithLocation(8, 17), - // (13,17): warning CS8321: The local function 'BadLocal2' is declared but never used - // public void BadLocal2() - Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "BadLocal2").WithArguments("BadLocal2").WithLocation(13, 17)); + // (5,6): error CS1513: } expected + // { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 6)); } [Fact] @@ -2707,7 +2693,7 @@ void CallerMemberName([CallerMemberName] int s = 2) // 1 } } "; - CreateCompilationWithMscorlib45AndCSharp(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( // (9,32): error CS4019: CallerMemberNameAttribute cannot be applied because there are no standard conversions from type 'string' to type 'int' // void CallerMemberName([CallerMemberName] int s = 2) // 1 Diagnostic(ErrorCode.ERR_NoConversionForCallerMemberNameParam, "CallerMemberName").WithArguments("string", "int").WithLocation(9, 32), @@ -4101,7 +4087,7 @@ static void Main() Console.WriteLine(f()); } }"; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: DefaultParseOptions); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: DefaultParseOptions); comp.VerifyDiagnostics( // (7,9): error CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code // var f() => 42; @@ -4614,7 +4600,7 @@ public ValueTuple(T1 item1, T2 item2) "; // the scope of an expression variable introduced in the default expression // of a local function parameter is that default expression. - var compilation = CreateCompilationWithMscorlib45(text); + var compilation = CreateCompilationWithMscorlib461(text); compilation.VerifyDiagnostics( // (6,30): error CS1736: Default parameter value for 'b' must be a compile-time constant // void Local1(bool b = M(arg is int z1, z1), int s1 = z1) {} @@ -4963,7 +4949,7 @@ class Test : System.Attribute public bool p {get; set;} } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (10,23): error CS0103: The name 'b2' does not exist in the current context // [Test(p = b2)] @@ -4997,7 +4983,7 @@ static void M() L(m => L(d => d, m), null); } }"; - var comp = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef, CSharpRef }); + var comp = CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef, CSharpRef }); comp.VerifyEmitDiagnostics( // (8,18): error CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type. // L(m => L(d => d, m), null); @@ -5022,7 +5008,7 @@ async Task L(Func t, object p) => await L(async m => L(async d => await d, m), p); } }"; - var comp = CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef, CSharpRef }); + var comp = CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef, CSharpRef }); comp.VerifyEmitDiagnostics( // (8,37): error CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type. // => await L(async m => L(async d => await d, m), p); @@ -10188,7 +10174,13 @@ int P .Where(i => i.Ancestors().Any(a => a.IsKind(SyntaxKind.Attribute))) .Single(); - Assert.Null(model.GetSymbolInfo(node).Symbol); + // int P ... should be pulled into MyAttribute as it's more likely that there's an errant close curly in the + // type, versus a property in a compilation unit. + var symbol = model.GetSymbolInfo(node).Symbol; + Assert.NotNull(symbol); + var property = (IPropertySymbol)symbol; + Assert.Equal("P", property.Name); + Assert.Equal("MyAttribute", property.ContainingType.Name); } [Fact, WorkItem(43697, "https://github.com/dotnet/roslyn/issues/43697")] @@ -10395,5 +10387,206 @@ int LocalFunc(string s) {} Assert.Equal("System.Int32 LocalFunc(System.String s)", methodSymbol.ToTestDisplayString()); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] + public void IdentifierInNameofInAttributeOnLocalFunctionInAccessor() + { + var src = """ +using System; + +[AttributeUsage(AttributeTargets.All)] +class A : Attribute +{ + public A(string s) { } +} + +class C +{ + event EventHandler E + { + add + { + [param: A(nameof(p))] void F(int p) { } + } + remove + { + } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (15,14): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, return'. All attributes in this block will be ignored. + // [param: A(nameof(p))] void F(int p) { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, return").WithLocation(15, 14), + // (15,40): warning CS8321: The local function 'F' is declared but never used + // [param: A(nameof(p))] void F(int p) { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(15, 40)); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var nameof = GetSyntax(tree, "nameof(p)"); + var p = nameof.ArgumentList.Arguments[0].Expression; + Assert.Equal("System.Int32", model.GetTypeInfo(p).Type.ToTestDisplayString()); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] + public void IdentifierInNameofInAttributeOnLocalFunctionInMethod() + { + var src = """ +using System; + +[AttributeUsage(AttributeTargets.All)] +class A : Attribute +{ + public A(string s) { } +} + +class C +{ + void M() + { + [param: A(nameof(p))] void F(int p) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (13,10): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, return'. All attributes in this block will be ignored. + // [param: A(nameof(p))] void F(int p) { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, return").WithLocation(13, 10), + // (13,36): warning CS8321: The local function 'F' is declared but never used + // [param: A(nameof(p))] void F(int p) { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(13, 36)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] + public void IdentifierInNameofInAttributeOnLocalFunctionInMethodWithParameter() + { + var src = """ +using System; + +[AttributeUsage(AttributeTargets.All)] +class A : Attribute +{ + public A(string s) { } +} + +class C +{ + void M(int p) + { + [param: A(nameof(p))] void F(int p2) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (13,10): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, return'. All attributes in this block will be ignored. + // [param: A(nameof(p))] void F(int p2) { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, return").WithLocation(13, 10), + // (13,36): warning CS8321: The local function 'F' is declared but never used + // [param: A(nameof(p))] void F(int p2) { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(13, 36)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] + public void IdentifierInNameofInParamAttributeOnLocalFunctionInPrimaryConstructorType() + { + var src = """ +using System; + +[AttributeUsage(AttributeTargets.All)] +class A : Attribute +{ + public A(string s) { } +} + +class C(int p) +{ + void M() + { + [param: A(nameof(p))] void F(int p2) { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (9,13): warning CS9113: Parameter 'p' is unread. + // class C(int p) + Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "p").WithArguments("p").WithLocation(9, 13), + // (13,10): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, return'. All attributes in this block will be ignored. + // [param: A(nameof(p))] void F(int p2) { } + Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, return").WithLocation(13, 10), + // (13,36): warning CS8321: The local function 'F' is declared but never used + // [param: A(nameof(p))] void F(int p2) { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(13, 36)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] + public void IdentifierInNameofInAttributeOnLocalFunctionInPrimaryConstructorType() + { + var src = """ +using System; + +[AttributeUsage(AttributeTargets.All)] +class A : Attribute +{ + public A(string s) { } +} + +class C(int p) +{ + void M() + { + [A(nameof(p))] void F() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (9,13): warning CS9113: Parameter 'p' is unread. + // class C(int p) + Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "p").WithArguments("p").WithLocation(9, 13), + // (13,29): warning CS8321: The local function 'F' is declared but never used + // [A(nameof(p))] void F() { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(13, 29)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] + public void IdentifierInAttributeOnLocalFunctionInPrimaryConstructorType() + { + var src = """ +using System; + +[AttributeUsage(AttributeTargets.All)] +class A : Attribute +{ + public A(string s) { } +} + +class C(string p) +{ + void M() + { + [A(p)] void F() { } + } +} +"""; + var comp = CreateCompilation(src); + comp.VerifyEmitDiagnostics( + // (9,16): warning CS9113: Parameter 'p' is unread. + // class C(string p) + Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "p").WithArguments("p").WithLocation(9, 16), + // (13,12): error CS9105: Cannot use primary constructor parameter 'string p' in this context. + // [A(p)] void F() { } + Diagnostic(ErrorCode.ERR_InvalidPrimaryConstructorParameterReference, "p").WithArguments("string p").WithLocation(13, 12), + // (13,12): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + // [A(p)] void F() { } + Diagnostic(ErrorCode.ERR_BadAttributeArgument, "p").WithLocation(13, 12), + // (13,21): warning CS8321: The local function 'F' is declared but never used + // [A(p)] void F() { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(13, 21)); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LookupTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LookupTests.cs index 6ed3ec82141cf..6485efc7cbff4 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LookupTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LookupTests.cs @@ -24,7 +24,7 @@ public class GetSemanticInfoTests : SemanticModelTestBase internal List GetLookupNames(string testSrc) { var parseOptions = TestOptions.Regular; - var compilation = CreateCompilationWithMscorlib45(testSrc, parseOptions: parseOptions); + var compilation = CreateCompilationWithMscorlib461(testSrc, parseOptions: parseOptions); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); var position = testSrc.Contains("/**/") ? GetPositionForBinding(tree) : GetPositionForBinding(testSrc); @@ -34,7 +34,7 @@ internal List GetLookupNames(string testSrc) internal List GetLookupSymbols(string testSrc, NamespaceOrTypeSymbol container = null, string name = null, int? arity = null, bool isScript = false, IEnumerable globalUsings = null) { var tree = Parse(testSrc, options: isScript ? TestOptions.Script : TestOptions.Regular); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }, options: TestOptions.ReleaseDll.WithUsings(globalUsings)); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }, options: TestOptions.ReleaseDll.WithUsings(globalUsings)); var model = compilation.GetSemanticModel(tree); var position = testSrc.Contains("/**/") ? GetPositionForBinding(tree) : GetPositionForBinding(testSrc); return model.LookupSymbols(position, container.GetPublicSymbol(), name).Where(s => !arity.HasValue || arity == s.GetSymbol().GetMemberArity()).ToList(); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/MethodTypeInferenceTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/MethodTypeInferenceTests.cs index b6dc2c4d157eb..1a7be280c7429 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/MethodTypeInferenceTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/MethodTypeInferenceTests.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -968,7 +969,7 @@ select packet.ToList() } "; - CreateCompilationWithMscorlib40(source, references: new[] { TestMetadata.Net40.SystemCore }).VerifyDiagnostics(); + CreateCompilationWithMscorlib40(source, references: new[] { Net40.References.SystemCore }).VerifyDiagnostics(); } [WorkItem(543691, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543691")] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameLengthTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameLengthTests.cs index f6892c39b5001..ad5a3bb927077 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameLengthTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameLengthTests.cs @@ -528,7 +528,7 @@ class Async int padding = GeneratedNames.MakeStateMachineTypeName("A", 0, 0).Length - 1; string longName = s_longSymbolName.Substring(padding); var source = string.Format(sourceTemplate, longName); - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics(); // CONSIDER: Location would light up if synthesized methods had them. comp.VerifyEmitDiagnostics( diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index 06edc20696a5f..572f5f8ddd22d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -425,7 +425,7 @@ public class Super2 "; MetadataReference[] references = new[] { SystemCoreRef, CSharpRef }; var option = TestOptions.ReleaseExe.WithWarningLevel(0); - CreateCompilationWithMscorlib45(source, references, options: option).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, references, options: option).VerifyDiagnostics( // (104,31): error CS1501: No overload for method 'nameof' takes 1 arguments // Console.WriteLine(nameof(Class.var)); Diagnostic(ErrorCode.ERR_BadArgCount, "nameof").WithArguments("nameof", "1").WithLocation(104, 31), @@ -1446,7 +1446,7 @@ public static void Main() System.Console.WriteLine(N1 + N2); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); var comp = CompileAndVerify(compilation, expectedOutput: @"N1N2"); } @@ -1460,7 +1460,7 @@ void M( string s = nameof(T) // ok ) { } }"; - var compilation = CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact, WorkItem(10467, "https://github.com/dotnet/roslyn/issues/10467")] @@ -1502,7 +1502,7 @@ public static string GetFromExternal() { } } "; - var compilation = CreateCompilationWithMscorlib45(source, null, TestOptions.UnsafeDebugExe); + var compilation = CreateCompilationWithMscorlib461(source, null, TestOptions.UnsafeDebugExe); CompileAndVerify(compilation, expectedOutput: "MessageType x MessageType").VerifyDiagnostics(); } @@ -1540,7 +1540,7 @@ public static string GetFromExternal() { } } }"; - var compilation = CreateCompilationWithMscorlib45(source, null, + var compilation = CreateCompilationWithMscorlib461(source, null, TestOptions.UnsafeDebugDll).VerifyDiagnostics( // (14,19): error CS1666: You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement. // return nameof(MessageType); @@ -1584,7 +1584,7 @@ public static void Main(string[] args) } } "; - var compilation = CreateCompilationWithMscorlib45(source, null, TestOptions.UnsafeDebugExe); + var compilation = CreateCompilationWithMscorlib461(source, null, TestOptions.UnsafeDebugExe); CompileAndVerify(compilation, expectedOutput: "normalField fixedField fixedField").VerifyDiagnostics(); } @@ -1616,7 +1616,7 @@ public static void Main(string[] args) } } "; - var compilation = CreateCompilationWithMscorlib45(source, null, TestOptions.UnsafeDebugExe); + var compilation = CreateCompilationWithMscorlib461(source, null, TestOptions.UnsafeDebugExe); CompileAndVerify(compilation, expectedOutput: "normalField fixedField").VerifyDiagnostics(); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs index 3d5277f894399..2f54e0e1b624a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs @@ -788,7 +788,7 @@ static void Main() System.Console.WriteLine(""{0}, {1}, {2}, {3}"", F1, F2, F3, F4); } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.Mscorlib45); + comp = CreateCompilation(sourceB, references: new[] { refA }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.Mscorlib461); CompileAndVerify(comp, expectedOutput: $"{int.MinValue}, {int.MaxValue}, -1, 1"); var corLibB = comp.Assembly.CorLibrary; @@ -12384,7 +12384,7 @@ void binaryOperator(string op, string leftType, string rightType, string expecte if (expectedDiagnostics.Length == 0) { - CompileAndVerify(comp); + CompileAndVerify(comp, emitOptions: EmitOptions.Default); } static bool useUnsafe(string type) => type == "void*"; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NonTrailingNamedArgumentsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NonTrailingNamedArgumentsTests.cs index 038f5839f3eee..3f22700628890 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NonTrailingNamedArgumentsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NonTrailingNamedArgumentsTests.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics { @@ -157,10 +158,10 @@ static void Main() c.M(a: 1, 2); } }"; - var verifier = CompileAndVerifyWithMscorlib40(source, expectedOutput: "1 2.", parseOptions: TestOptions.Regular7_2, references: new[] { TestMetadata.Net40.SystemCore }); + var verifier = CompileAndVerifyWithMscorlib40(source, expectedOutput: "1 2.", parseOptions: TestOptions.Regular7_2, references: new[] { Net40.References.SystemCore }); verifier.VerifyDiagnostics(); - var comp = CreateCompilationWithMscorlib40(source, parseOptions: TestOptions.Regular7_1, references: new[] { TestMetadata.Net40.SystemCore }); + var comp = CreateCompilationWithMscorlib40(source, parseOptions: TestOptions.Regular7_1, references: new[] { Net40.References.SystemCore }); comp.VerifyDiagnostics( // (14,19): error CS1738: Named argument specifications must appear after all fixed arguments have been specified. Please use language version 7.2 or greater to allow non-trailing named arguments. // c.M(a: 1, 2); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index 1de85b8adc7bc..acffbb4ef862a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -18,6 +18,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; +using Basic.Reference.Assemblies; using static Microsoft.CodeAnalysis.CSharp.Symbols.FlowAnalysisAnnotations; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics @@ -2613,7 +2614,7 @@ static void M3(this E e) { } static void M4(this S s) { } static void M5(this double d) { } }"; - CreateCompilationWithMscorlib40(source, references: new[] { TestMetadata.Net40.SystemCore }).VerifyDiagnostics( + CreateCompilationWithMscorlib40(source, references: new[] { Net40.References.SystemCore }).VerifyDiagnostics( // (24,29): error CS1113: Extension methods 'SC.M3(E)' defined on value type 'E' cannot be used to create delegates Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "e.M3").WithArguments("SC.M3(E)", "E").WithLocation(24, 29), // (26,29): error CS1113: Extension methods 'SC.M4(S)' defined on value type 'S' cannot be used to create delegates @@ -3244,6 +3245,7 @@ public struct StructEnum comp.VerifyDiagnostics(expected); } } + [Fact] public void RefAssignment_Inferred() { @@ -3504,7 +3506,7 @@ static void Main(string[] args) } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (6,18): error CS0023: Operator '?' cannot be applied to operand of type 'lambda expression' // var x4 = (()=> { return 1; } !) ?.ToString(); Diagnostic(ErrorCode.ERR_BadUnaryOp, "(()=> { return 1; } !) ?.ToString()").WithArguments("?", "lambda expression").WithLocation(6, 18), @@ -7902,12 +7904,12 @@ void M(string? x) // (8,10): error CS8598: The suppression operator is not allowed in this context // (y2! = ref y) = ref y; Diagnostic(ErrorCode.ERR_IllegalSuppression, "y2").WithLocation(8, 10), - // (8,20): warning CS8601: Possible null reference assignment. + // (8,10): error CS8373: The left-hand side of a ref assignment must be a ref variable. // (y2! = ref y) = ref y; - Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "y").WithLocation(8, 20), - // (8,29): warning CS8601: Possible null reference assignment. + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "y2! = ref y").WithLocation(8, 10), + // (8,20): warning CS8601: Possible null reference assignment. // (y2! = ref y) = ref y; - Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "y").WithLocation(8, 29) + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "y").WithLocation(8, 20) ); } @@ -8629,7 +8631,7 @@ static async Task F() return await Task.FromResult(default(string)); } }"; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular7); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular7); comp.VerifyEmitDiagnostics(); } @@ -8654,7 +8656,7 @@ static async Task G(Func> f) throw new NotImplementedException(); } }"; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular7); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular7); comp.VerifyEmitDiagnostics( // (13,32): warning 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 G(Func> f) @@ -15264,6 +15266,12 @@ public override Func P1 { set {} } // warn // (15,39): warning CS8767: Nullability of reference types in type of parameter 'value' of 'void C.P1.set' doesn't match implicitly implemented member 'void A.P1.set' (possibly because of nullability attributes). // public override Func P1 { set {} } // warn Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnImplicitImplementation, "set").WithArguments("value", "void C.P1.set", "void A.P1.set").WithLocation(15, 39), + // (16,34): error CS8080: Auto-implemented properties must override all accessors of the overridden property. + // public override Func P2 { set; } // warn + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P2").WithLocation(16, 34), + // (16,34): warning CS8618: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. + // public override Func P2 { set; } // warn + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "P2").WithArguments("property", "P2").WithLocation(16, 34), // (16,39): error CS8051: Auto-implemented properties must have get accessors. // public override Func P2 { set; } // warn Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithLocation(16, 39), @@ -53204,67 +53212,127 @@ static void F1(bool b, ref string? x1, ref string y1) static void F2(bool b, ref I x2, ref I y2) { (b ? ref x2 : ref x2)/*T:I!*/.P.ToString(); // 6 - (b ? ref y2 : ref x2)/*T:I!*/.P.ToString(); // 7 - (b ? ref x2 : ref y2)/*T:I!*/.P.ToString(); // 8, 9 + (b ? ref y2 : ref x2)/*T:I!*/.P.ToString(); // 7 + (b ? ref x2 : ref y2)/*T:I!*/.P.ToString(); // 8 (b ? ref y2 : ref y2)/*T:I!*/.P.ToString(); } static void F3(bool b, ref IIn x3, ref IIn y3) { (b ? ref x3 : ref x3)/*T:IIn!*/.ToString(); - (b ? ref y3 : ref x3)/*T:IIn!*/.ToString(); // 10 - (b ? ref x3 : ref y3)/*T:IIn!*/.ToString(); // 11 + (b ? ref y3 : ref x3)/*T:IIn!*/.ToString(); // 9 + (b ? ref x3 : ref y3)/*T:IIn!*/.ToString(); // 10 (b ? ref y3 : ref y3)/*T:IIn!*/.ToString(); } static void F4(bool b, ref IOut x4, ref IOut y4) { - (b ? ref x4 : ref x4)/*T:IOut!*/.P.ToString(); // 12 - (b ? ref y4 : ref x4)/*T:IOut!*/.P.ToString(); // 13 - (b ? ref x4 : ref y4)/*T:IOut!*/.P.ToString(); // 14 + (b ? ref x4 : ref x4)/*T:IOut!*/.P.ToString(); // 11 + (b ? ref y4 : ref x4)/*T:IOut!*/.P.ToString(); // 12, 13 + (b ? ref x4 : ref y4)/*T:IOut!*/.P.ToString(); // 14, 15 (b ? ref y4 : ref y4)/*T:IOut!*/.P.ToString(); } }"; var comp = CreateCompilation(source, options: WithNullableEnable()); comp.VerifyTypes(); comp.VerifyDiagnostics( - // (8,10): warning CS8602: Possible dereference of a null reference. + // (8,10): warning CS8602: Dereference of a possibly null reference. // (b ? ref x1 : ref x1)/*T:string?*/.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b ? ref x1 : ref x1").WithLocation(8, 10), - // (9,10): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. - // (b ? ref x1 : ref y1)/*T:string?*/.ToString(); // 2, 3 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x1 : ref y1").WithArguments("string?", "string").WithLocation(9, 10), - // (9,10): warning CS8602: Possible dereference of a null reference. + // (9,10): warning CS8602: Dereference of a possibly null reference. // (b ? ref x1 : ref y1)/*T:string?*/.ToString(); // 2, 3 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b ? ref x1 : ref y1").WithLocation(9, 10), - // (10,10): warning CS8619: Nullability of reference types in value of type 'string' doesn't match target type 'string?'. - // (b ? ref y1 : ref x1)/*T:string?*/.ToString(); // 4, 5 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y1 : ref x1").WithArguments("string", "string?").WithLocation(10, 10), - // (10,10): warning CS8602: Possible dereference of a null reference. + // (9,18): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (b ? ref x1 : ref y1)/*T:string?*/.ToString(); // 2, 3 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(9, 18), + // (10,10): warning CS8602: Dereference of a possibly null reference. // (b ? ref y1 : ref x1)/*T:string?*/.ToString(); // 4, 5 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b ? ref y1 : ref x1").WithLocation(10, 10), - // (15,9): warning CS8602: Possible dereference of a null reference. + // (10,27): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (b ? ref y1 : ref x1)/*T:string?*/.ToString(); // 4, 5 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(10, 27), + // (15,9): warning CS8602: Dereference of a possibly null reference. // (b ? ref x2 : ref x2)/*T:I!*/.P.ToString(); // 6 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(b ? ref x2 : ref x2)/*T:I!*/.P").WithLocation(15, 9), - // (16,10): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. - // (b ? ref y2 : ref x2)/*T:I!*/.P.ToString(); // 7 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y2 : ref x2").WithArguments("I", "I").WithLocation(16, 10), - // (17,10): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. - // (b ? ref x2 : ref y2)/*T:I!*/.P.ToString(); // 8, 9 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x2 : ref y2").WithArguments("I", "I").WithLocation(17, 10), - // (23,10): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn'. - // (b ? ref y3 : ref x3)/*T:IIn!*/.ToString(); // 10 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y3 : ref x3").WithArguments("IIn", "IIn").WithLocation(23, 10), - // (24,10): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn'. - // (b ? ref x3 : ref y3)/*T:IIn!*/.ToString(); // 11 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x3 : ref y3").WithArguments("IIn", "IIn").WithLocation(24, 10), - // (29,9): warning CS8602: Possible dereference of a null reference. - // (b ? ref x4 : ref x4)/*T:IOut!*/.P.ToString(); // 12 + // (16,27): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. + // (b ? ref y2 : ref x2)/*T:I!*/.P.ToString(); // 7 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("I", "I").WithLocation(16, 27), + // (17,18): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. + // (b ? ref x2 : ref y2)/*T:I!*/.P.ToString(); // 8 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x2").WithArguments("I", "I").WithLocation(17, 18), + // (23,27): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn'. + // (b ? ref y3 : ref x3)/*T:IIn!*/.ToString(); // 9 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x3").WithArguments("IIn", "IIn").WithLocation(23, 27), + // (24,18): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn'. + // (b ? ref x3 : ref y3)/*T:IIn!*/.ToString(); // 10 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x3").WithArguments("IIn", "IIn").WithLocation(24, 18), + // (29,9): warning CS8602: Dereference of a possibly null reference. + // (b ? ref x4 : ref x4)/*T:IOut!*/.P.ToString(); // 11 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(b ? ref x4 : ref x4)/*T:IOut!*/.P").WithLocation(29, 9), - // (30,10): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut'. - // (b ? ref y4 : ref x4)/*T:IOut!*/.P.ToString(); // 13 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y4 : ref x4").WithArguments("IOut", "IOut").WithLocation(30, 10), - // (31,10): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut'. - // (b ? ref x4 : ref y4)/*T:IOut!*/.P.ToString(); // 14, 15 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x4 : ref y4").WithArguments("IOut", "IOut").WithLocation(31, 10)); + // (30,9): warning CS8602: Dereference of a possibly null reference. + // (b ? ref y4 : ref x4)/*T:IOut!*/.P.ToString(); // 12, 13 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(b ? ref y4 : ref x4)/*T:IOut!*/.P").WithLocation(30, 9), + // (30,18): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut'. + // (b ? ref y4 : ref x4)/*T:IOut!*/.P.ToString(); // 12, 13 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y4").WithArguments("IOut", "IOut").WithLocation(30, 18), + // (31,9): warning CS8602: Dereference of a possibly null reference. + // (b ? ref x4 : ref y4)/*T:IOut!*/.P.ToString(); // 14, 15 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(b ? ref x4 : ref y4)/*T:IOut!*/.P").WithLocation(31, 9), + // (31,27): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut'. + // (b ? ref x4 : ref y4)/*T:IOut!*/.P.ToString(); // 14, 15 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y4").WithArguments("IOut", "IOut").WithLocation(31, 27)); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/73928")] + public void ConditionalOperator_Ref_Assignment() + { + var source = """ + #nullable enable + class C + { + static void M1(bool b, ref string? x1, ref string y1, ref string? x2, ref string y2) + { + (b ? ref x1 : ref y1) = x2; + (b ? ref x1 : ref y1) = y2; + + (b ? ref x1! : ref y1) = x2; + (b ? ref x1! : ref y1) = y2; + + (b ? ref y1 : ref x1) = x2; + (b ? ref y1 : ref x1) = y2; + + (b ? ref y1 : ref x1!) = x2; + (b ? ref y1 : ref x1!) = y2; + + (b ? ref x1! : ref y1) = x2!; + (b ? ref y1 : ref x1!) = x2!; + } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (6,18): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (b ? ref x1 : ref y1) = x2; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(6, 18), + // (6,33): warning CS8601: Possible null reference assignment. + // (b ? ref x1 : ref y1) = x2; + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "x2").WithLocation(6, 33), + // (7,18): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (b ? ref x1 : ref y1) = y2; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(7, 18), + // (9,34): warning CS8601: Possible null reference assignment. + // (b ? ref x1! : ref y1) = x2; + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "x2").WithLocation(9, 34), + // (12,27): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (b ? ref y1 : ref x1) = x2; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(12, 27), + // (12,33): warning CS8601: Possible null reference assignment. + // (b ? ref y1 : ref x1) = x2; + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "x2").WithLocation(12, 33), + // (13,27): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (b ? ref y1 : ref x1) = y2; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(13, 27), + // (15,34): warning CS8601: Possible null reference assignment. + // (b ? ref y1 : ref x1!) = x2; + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "x2").WithLocation(15, 34)); } [Fact] @@ -53306,12 +53374,12 @@ void M1(bool b, string? s) void M(bool b, string? s) { - _ = (b ? ref D2(s) : ref D2(s!)) /*T:C.MyDelegate!*/; // 9 - _ = (b ? ref D2(s!) : ref D2(s)) /*T:C.MyDelegate!*/; // 10 - _ = (true ? ref D2(s) : ref D2(s!)) /*T:C.MyDelegate!*/; // 11 + _ = (b ? ref D2(s) : ref D2(s!)) /*T:C.MyDelegate!*/; // 9 + _ = (b ? ref D2(s!) : ref D2(s)) /*T:C.MyDelegate!*/; // 10 + _ = (true ? ref D2(s) : ref D2(s!)) /*T:C.MyDelegate!*/; // 11 _ = (true ? ref D2(s!) : ref D2(s)) /*T:C.MyDelegate!*/; _ = (false ? ref D2(s) : ref D2(s!)) /*T:C.MyDelegate!*/; - _ = (false ? ref D2(s!) : ref D2(s)) /*T:C.MyDelegate!*/; // 12 + _ = (false ? ref D2(s!) : ref D2(s)) /*T:C.MyDelegate!*/; // 12 } }"; @@ -53322,18 +53390,18 @@ void M(bool b, string? s) var comp = CreateCompilation(source, options: WithNullableEnable()); comp.VerifyTypes(); comp.VerifyDiagnostics( - // (36,14): warning CS8619: Nullability of reference types in value of type 'C.MyDelegate' doesn't match target type 'C.MyDelegate'. - // _ = (b ? ref D2(s) : ref D2(s!)) /*T:C.MyDelegate!*/; // 9 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref D2(s) : ref D2(s!)").WithArguments("C.MyDelegate", "C.MyDelegate").WithLocation(36, 14), - // (37,14): warning CS8619: Nullability of reference types in value of type 'C.MyDelegate' doesn't match target type 'C.MyDelegate'. - // _ = (b ? ref D2(s!) : ref D2(s)) /*T:C.MyDelegate!*/; // 10 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref D2(s!) : ref D2(s)").WithArguments("C.MyDelegate", "C.MyDelegate").WithLocation(37, 14), - // (38,14): warning CS8619: Nullability of reference types in value of type 'C.MyDelegate' doesn't match target type 'C.MyDelegate'. - // _ = (true ? ref D2(s) : ref D2(s!)) /*T:C.MyDelegate!*/; // 11 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "true ? ref D2(s) : ref D2(s!)").WithArguments("C.MyDelegate", "C.MyDelegate").WithLocation(38, 14), - // (41,14): warning CS8619: Nullability of reference types in value of type 'C.MyDelegate' doesn't match target type 'C.MyDelegate'. - // _ = (false ? ref D2(s!) : ref D2(s)) /*T:C.MyDelegate!*/; // unexpected type - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "false ? ref D2(s!) : ref D2(s)").WithArguments("C.MyDelegate", "C.MyDelegate").WithLocation(41, 14) + // (36,22): warning CS8619: Nullability of reference types in value of type 'C.MyDelegate' doesn't match target type 'C.MyDelegate'. + // _ = (b ? ref D2(s) : ref D2(s!)) /*T:C.MyDelegate!*/; // 9 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "D2(s)").WithArguments("C.MyDelegate", "C.MyDelegate").WithLocation(36, 22), + // (37,35): warning CS8619: Nullability of reference types in value of type 'C.MyDelegate' doesn't match target type 'C.MyDelegate'. + // _ = (b ? ref D2(s!) : ref D2(s)) /*T:C.MyDelegate!*/; // 10 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "D2(s)").WithArguments("C.MyDelegate", "C.MyDelegate").WithLocation(37, 35), + // (38,25): warning CS8619: Nullability of reference types in value of type 'C.MyDelegate' doesn't match target type 'C.MyDelegate'. + // _ = (true ? ref D2(s) : ref D2(s!)) /*T:C.MyDelegate!*/; // 11 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "D2(s)").WithArguments("C.MyDelegate", "C.MyDelegate").WithLocation(38, 25), + // (41,39): warning CS8619: Nullability of reference types in value of type 'C.MyDelegate' doesn't match target type 'C.MyDelegate'. + // _ = (false ? ref D2(s!) : ref D2(s)) /*T:C.MyDelegate!*/; // 12 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "D2(s)").WithArguments("C.MyDelegate", "C.MyDelegate").WithLocation(41, 39) ); } @@ -53393,26 +53461,32 @@ class C { static void M1(bool b, string s, string? s2) { - (b ? ref Create(s, s2) : ref Create(s2, s)) /*T:C!*/ = null; - (b ? ref Create(s2, s) : ref Create(s, s2)) /*T:C!*/ = null; + (b ? ref Create(s, s2) : ref Create(s2, s)) /*T:C!*/ = null; + (b ? ref Create(s2, s) : ref Create(s, s2)) /*T:C!*/ = null; } static ref C Create(U1 x, U2 y) => throw null!; }"; var comp = CreateCompilation(source, options: WithNullableEnable()); comp.VerifyTypes(); comp.VerifyDiagnostics( - // (6,10): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C'. - // (b ? ref Create(s, s2) : ref Create(s2, s)) /*T:C!*/ = null; - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref Create(s, s2) : ref Create(s2, s)").WithArguments("C", "C").WithLocation(6, 10), - // (6,80): warning CS8625: Cannot convert null literal to non-nullable reference type. - // (b ? ref Create(s, s2) : ref Create(s2, s)) /*T:C!*/ = null; - Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(6, 80), - // (7,10): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C'. - // (b ? ref Create(s2, s) : ref Create(s, s2)) /*T:C!*/ = null; - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref Create(s2, s) : ref Create(s, s2)").WithArguments("C", "C").WithLocation(7, 10), - // (7,80): warning CS8625: Cannot convert null literal to non-nullable reference type. - // (b ? ref Create(s2, s) : ref Create(s, s2)) /*T:C!*/ = null; - Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 80) + // (6,18): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C'. + // (b ? ref Create(s, s2) : ref Create(s2, s)) /*T:C!*/ = null; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "Create(s, s2)").WithArguments("C", "C").WithLocation(6, 18), + // (6,38): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C'. + // (b ? ref Create(s, s2) : ref Create(s2, s)) /*T:C!*/ = null; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "Create(s2, s)").WithArguments("C", "C").WithLocation(6, 38), + // (6,82): warning CS8625: Cannot convert null literal to non-nullable reference type. + // (b ? ref Create(s, s2) : ref Create(s2, s)) /*T:C!*/ = null; + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(6, 82), + // (7,18): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C'. + // (b ? ref Create(s2, s) : ref Create(s, s2)) /*T:C!*/ = null; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "Create(s2, s)").WithArguments("C", "C").WithLocation(7, 18), + // (7,38): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C'. + // (b ? ref Create(s2, s) : ref Create(s, s2)) /*T:C!*/ = null; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "Create(s, s2)").WithArguments("C", "C").WithLocation(7, 38), + // (7,82): warning CS8625: Cannot convert null literal to non-nullable reference type. + // (b ? ref Create(s2, s) : ref Create(s, s2)) /*T:C!*/ = null; + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 82) ); } @@ -53445,30 +53519,30 @@ static void F1(bool b, ref string? x1, ref string y1) // (6,14): warning CS8625: Cannot convert null literal to non-nullable reference type. // y1 = null; // 1 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(6, 14), - // (7,10): warning CS8602: Possible dereference of a null reference. + // (7,10): warning CS8602: Dereference of a possibly null reference. // (b ? ref x1 : ref x1)/*T:string?*/.ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b ? ref x1 : ref x1").WithLocation(7, 10), - // (8,10): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. - // (b ? ref x1 : ref y1)/*T:string?*/.ToString(); // 3, 4 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x1 : ref y1").WithArguments("string?", "string").WithLocation(8, 10), - // (8,10): warning CS8602: Possible dereference of a null reference. + // (8,10): warning CS8602: Dereference of a possibly null reference. // (b ? ref x1 : ref y1)/*T:string?*/.ToString(); // 3, 4 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b ? ref x1 : ref y1").WithLocation(8, 10), - // (9,10): warning CS8619: Nullability of reference types in value of type 'string' doesn't match target type 'string?'. - // (b ? ref y1 : ref x1)/*T:string?*/.ToString(); // 5, 6 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y1 : ref x1").WithArguments("string", "string?").WithLocation(9, 10), - // (9,10): warning CS8602: Possible dereference of a null reference. + // (8,18): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (b ? ref x1 : ref y1)/*T:string?*/.ToString(); // 3, 4 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(8, 18), + // (9,10): warning CS8602: Dereference of a possibly null reference. // (b ? ref y1 : ref x1)/*T:string?*/.ToString(); // 5, 6 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b ? ref y1 : ref x1").WithLocation(9, 10), - // (10,10): warning CS8602: Possible dereference of a null reference. + // (9,27): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (b ? ref y1 : ref x1)/*T:string?*/.ToString(); // 5, 6 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(9, 27), + // (10,10): warning CS8602: Dereference of a possibly null reference. // (b ? ref y1 : ref y1)/*T:string?*/.ToString(); // 7 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b ? ref y1 : ref y1").WithLocation(10, 10), - // (15,10): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (15,18): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. // (b ? ref x1 : ref y1)/*T:string!*/.ToString(); // 8 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x1 : ref y1").WithArguments("string?", "string").WithLocation(15, 10), - // (16,10): warning CS8619: Nullability of reference types in value of type 'string' doesn't match target type 'string?'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(15, 18), + // (16,27): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. // (b ? ref y1 : ref x1)/*T:string!*/.ToString(); // 9 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y1 : ref x1").WithArguments("string", "string?").WithLocation(16, 10) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(16, 27) ); } @@ -53608,17 +53682,17 @@ static void F1(bool b) var comp = CreateCompilation(source, options: WithNullableEnable()); comp.VerifyTypes(); comp.VerifyDiagnostics( - // (6,10): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (6,18): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. // (b ? ref M1(false ? 1 : throw new System.Exception()) : ref M2(2)) /*T:string!*/ = null; // 1, 2 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref M1(false ? 1 : throw new System.Exception()) : ref M2(2)").WithArguments("string?", "string").WithLocation(6, 10), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "M1(false ? 1 : throw new System.Exception())").WithArguments("string?", "string").WithLocation(6, 18), // (6,92): warning CS8625: Cannot convert null literal to non-nullable reference type. // (b ? ref M1(false ? 1 : throw new System.Exception()) : ref M2(2)) /*T:string!*/ = null; // 1, 2 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(6, 92), - // (7,10): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. - // (b ? ref M1(1) : ref M2(false ? 2 : throw new System.Exception())) /*T:string?*/ = null; // 3, 4 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref M1(1) : ref M2(false ? 2 : throw new System.Exception())").WithArguments("string?", "string").WithLocation(7, 10), + // (7,18): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (b ? ref M1(1) : ref M2(false ? 2 : throw new System.Exception())) /*T:string!*/ = null; // 3, 4 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "M1(1)").WithArguments("string?", "string").WithLocation(7, 18), // (7,92): warning CS8625: Cannot convert null literal to non-nullable reference type. - // (b ? ref M1(1) : ref M2(false ? 2 : throw new System.Exception())) /*T:string?*/ = null; // 3, 4 + // (b ? ref M1(1) : ref M2(false ? 2 : throw new System.Exception())) /*T:string!*/ = null; // 3, 4 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 92) ); } @@ -53666,30 +53740,30 @@ static void F1(bool b, ref string? x1, ref string y1) var comp = CreateCompilation(source, options: WithNullableEnable()); comp.VerifyTypes(); comp.VerifyDiagnostics( - // (7,10): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (7,29): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. // ((b && false) ? ref x1 : ref y1)/*T:string!*/ = null; // 1, 2 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "(b && false) ? ref x1 : ref y1").WithArguments("string?", "string").WithLocation(7, 10), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(7, 29), // (7,57): warning CS8625: Cannot convert null literal to non-nullable reference type. // ((b && false) ? ref x1 : ref y1)/*T:string!*/ = null; // 1, 2 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 57), - // (8,10): warning CS8619: Nullability of reference types in value of type 'string' doesn't match target type 'string?'. - // ((b && false) ? ref y1 : ref x1)/*T:string?*/ = null; // 3, 4 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "(b && false) ? ref y1 : ref x1").WithArguments("string", "string?").WithLocation(8, 10), + // (8,38): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // ((b && false) ? ref y1 : ref x1)/*T:string!*/ = null; // 3, 4 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(8, 38), // (8,57): warning CS8625: Cannot convert null literal to non-nullable reference type. - // ((b && false) ? ref y1 : ref x1)/*T:string?*/ = null; // 3, 4 + // ((b && false) ? ref y1 : ref x1)/*T:string!*/ = null; // 3, 4 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 57), // (9,57): warning CS8625: Cannot convert null literal to non-nullable reference type. // ((b && false) ? ref y1 : ref y1)/*T:string!*/ = null; // 5 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(9, 57), - // (12,10): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. - // ((b || true) ? ref x1 : ref y1)/*T:string?*/ = null; // 6, 7 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "(b || true) ? ref x1 : ref y1").WithArguments("string?", "string").WithLocation(12, 10), + // (12,28): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // ((b || true) ? ref x1 : ref y1)/*T:string!*/ = null; // 6, 7 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(12, 28), // (12,56): warning CS8625: Cannot convert null literal to non-nullable reference type. - // ((b || true) ? ref x1 : ref y1)/*T:string?*/ = null; // 6, 7 + // ((b || true) ? ref x1 : ref y1)/*T:string!*/ = null; // 6, 7 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(12, 56), - // (13,10): warning CS8619: Nullability of reference types in value of type 'string' doesn't match target type 'string?'. + // (13,37): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. // ((b || true) ? ref y1 : ref x1)/*T:string!*/ = null; // 8, 9 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "(b || true) ? ref y1 : ref x1").WithArguments("string", "string?").WithLocation(13, 10), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x1").WithArguments("string?", "string").WithLocation(13, 37), // (13,56): warning CS8625: Cannot convert null literal to non-nullable reference type. // ((b || true) ? ref y1 : ref x1)/*T:string!*/ = null; // 8, 9 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(13, 56), @@ -55045,12 +55119,12 @@ static void F(bool b, object? x, object y) }"; var comp = CreateCompilation(source, options: WithNullableEnable(), references: new[] { ref0 }); comp.VerifyDiagnostics( - // (6,26): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. + // (6,34): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. // ref var xy = ref b ? ref x : ref y; // 1 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x : ref y").WithArguments("object?", "object").WithLocation(6, 26), - // (8,26): warning CS8619: Nullability of reference types in value of type 'object' doesn't match target type 'object?'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("object?", "object").WithLocation(6, 34), + // (8,42): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. // ref var yx = ref b ? ref y : ref x; // 2 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y : ref x").WithArguments("object", "object?").WithLocation(8, 26) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("object?", "object").WithLocation(8, 42) ); } @@ -55118,64 +55192,310 @@ static void F3(bool b, IOut x3, IOut y3) }"; var comp = CreateCompilation(source, options: WithNullableEnable(), references: new[] { ref0 }); comp.VerifyDiagnostics( - // (7,26): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. + // (7,43): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. // ref var xy = ref b ? ref x1 : ref y1; // 1 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x1 : ref y1").WithArguments("I", "I").WithLocation(7, 26), - // (8,26): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I?'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y1").WithArguments("I", "I").WithLocation(7, 43), + // (8,43): warning CS8619: Nullability of reference types in value of type 'I?' doesn't match target type 'I'. // ref var xz = ref b ? ref x1 : ref z1; // 2 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x1 : ref z1").WithArguments("I", "I?").WithLocation(8, 26), - // (9,26): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z1").WithArguments("I?", "I").WithLocation(8, 43), + // (9,34): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. // ref var yx = ref b ? ref y1 : ref x1; // 3 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y1 : ref x1").WithArguments("I", "I").WithLocation(9, 26), - // (11,26): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I?'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y1").WithArguments("I", "I").WithLocation(9, 34), + // (11,43): warning CS8619: Nullability of reference types in value of type 'I?' doesn't match target type 'I'. // ref var yz = ref b ? ref y1 : ref z1; // 4 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y1 : ref z1").WithArguments("I", "I?").WithLocation(11, 26), - // (12,26): warning CS8619: Nullability of reference types in value of type 'I?' doesn't match target type 'I'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z1").WithArguments("I?", "I").WithLocation(11, 43), + // (12,34): warning CS8619: Nullability of reference types in value of type 'I?' doesn't match target type 'I'. // ref var zx = ref b ? ref z1 : ref x1; // 5 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref z1 : ref x1").WithArguments("I?", "I").WithLocation(12, 26), - // (13,26): warning CS8619: Nullability of reference types in value of type 'I?' doesn't match target type 'I'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z1").WithArguments("I?", "I").WithLocation(12, 34), + // (13,34): warning CS8619: Nullability of reference types in value of type 'I?' doesn't match target type 'I'. // ref var zy = ref b ? ref z1 : ref y1; // 6 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref z1 : ref y1").WithArguments("I?", "I").WithLocation(13, 26), - // (20,26): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z1").WithArguments("I?", "I").WithLocation(13, 34), + // (20,43): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn'. // ref var xy = ref b ? ref x2 : ref y2; // 7 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x2 : ref y2").WithArguments("IIn", "IIn").WithLocation(20, 26), - // (21,26): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn?'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y2").WithArguments("IIn", "IIn").WithLocation(20, 43), + // (21,43): warning CS8619: Nullability of reference types in value of type 'IIn?' doesn't match target type 'IIn'. // ref var xz = ref b ? ref x2 : ref z2; // 8 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x2 : ref z2").WithArguments("IIn", "IIn?").WithLocation(21, 26), - // (22,26): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z2").WithArguments("IIn?", "IIn").WithLocation(21, 43), + // (22,34): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn'. // ref var yx = ref b ? ref y2 : ref x2; // 9 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y2 : ref x2").WithArguments("IIn", "IIn").WithLocation(22, 26), - // (24,26): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn?'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y2").WithArguments("IIn", "IIn").WithLocation(22, 34), + // (24,43): warning CS8619: Nullability of reference types in value of type 'IIn?' doesn't match target type 'IIn'. // ref var yz = ref b ? ref y2 : ref z2; // 10 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y2 : ref z2").WithArguments("IIn", "IIn?").WithLocation(24, 26), - // (25,26): warning CS8619: Nullability of reference types in value of type 'IIn?' doesn't match target type 'IIn'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z2").WithArguments("IIn?", "IIn").WithLocation(24, 43), + // (25,34): warning CS8619: Nullability of reference types in value of type 'IIn?' doesn't match target type 'IIn'. // ref var zx = ref b ? ref z2 : ref x2; // 11 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref z2 : ref x2").WithArguments("IIn?", "IIn").WithLocation(25, 26), - // (26,26): warning CS8619: Nullability of reference types in value of type 'IIn?' doesn't match target type 'IIn'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z2").WithArguments("IIn?", "IIn").WithLocation(25, 34), + // (26,34): warning CS8619: Nullability of reference types in value of type 'IIn?' doesn't match target type 'IIn'. // ref var zy = ref b ? ref z2 : ref y2; // 12 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref z2 : ref y2").WithArguments("IIn?", "IIn").WithLocation(26, 26), - // (33,26): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z2").WithArguments("IIn?", "IIn").WithLocation(26, 34), + // (33,34): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut'. // ref var xy = ref b ? ref x3 : ref y3; // 13 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x3 : ref y3").WithArguments("IOut", "IOut").WithLocation(33, 26), - // (34,26): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut?'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x3").WithArguments("IOut", "IOut").WithLocation(33, 34), + // (34,43): warning CS8619: Nullability of reference types in value of type 'IOut?' doesn't match target type 'IOut'. // ref var xz = ref b ? ref x3 : ref z3; // 14 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x3 : ref z3").WithArguments("IOut", "IOut?").WithLocation(34, 26), - // (35,26): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z3").WithArguments("IOut?", "IOut").WithLocation(34, 43), + // (35,43): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut'. // ref var yx = ref b ? ref y3 : ref x3; // 15 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y3 : ref x3").WithArguments("IOut", "IOut").WithLocation(35, 26), - // (37,26): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut?'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x3").WithArguments("IOut", "IOut").WithLocation(35, 43), + // (37,43): warning CS8619: Nullability of reference types in value of type 'IOut?' doesn't match target type 'IOut'. // ref var yz = ref b ? ref y3 : ref z3; // 17 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y3 : ref z3").WithArguments("IOut", "IOut?").WithLocation(37, 26), - // (38,26): warning CS8619: Nullability of reference types in value of type 'IOut?' doesn't match target type 'IOut'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z3").WithArguments("IOut?", "IOut").WithLocation(37, 43), + // (38,34): warning CS8619: Nullability of reference types in value of type 'IOut?' doesn't match target type 'IOut'. // ref var zx = ref b ? ref z3 : ref x3; // 18 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref z3 : ref x3").WithArguments("IOut?", "IOut").WithLocation(38, 26), - // (39,26): warning CS8619: Nullability of reference types in value of type 'IOut?' doesn't match target type 'IOut'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z3").WithArguments("IOut?", "IOut").WithLocation(38, 34), + // (39,34): warning CS8619: Nullability of reference types in value of type 'IOut?' doesn't match target type 'IOut'. // ref var zy = ref b ? ref z3 : ref y3; // 19 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref z3 : ref y3").WithArguments("IOut?", "IOut").WithLocation(39, 26) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "z3").WithArguments("IOut?", "IOut").WithLocation(39, 34) ); comp.VerifyTypes(); } + [Fact] + public void ConditionalOperator_Suppression() + { + var source = """ + #nullable enable + class C + { + object M1(bool b, object? x, object y) => b ? x : y; + object M2(bool b, object? x, object y) => b ? x! : y; + object M3(bool b, object? x, object y) => b ? x : y!; + object M4(bool b, object? x, object y) => b ? x! : y!; + object M5(bool b, object? x, object y) => (b ? x : y)!; + object M6(bool b, object? x, object y) => (b ? x! : y)!; + object M7(bool b, object? x, object y) => (b ? x : y!)!; + object M8(bool b, object? x, object y) => (b ? x! : y!)!; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,47): warning CS8603: Possible null reference return. + // object M1(bool b, object? x, object y) => b ? x : y; + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "b ? x : y").WithLocation(4, 47), + // (6,47): warning CS8603: Possible null reference return. + // object M3(bool b, object? x, object y) => b ? x : y!; + Diagnostic(ErrorCode.WRN_NullReferenceReturn, "b ? x : y!").WithLocation(6, 47)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73928")] + public void ConditionalOperator_Suppression_Ref_01() + { + var source = """ + #nullable enable + class C + { + ref object M1(bool b, ref object? x, ref object y) => ref b ? ref x : ref y; + ref object M2(bool b, ref object? x, ref object y) => ref b ? ref x! : ref y; + ref object M3(bool b, ref object? x, ref object y) => ref b ? ref x : ref y!; + ref object M4(bool b, ref object? x, ref object y) => ref b ? ref x! : ref y!; + ref object M5(bool b, ref object? x, ref object y) => ref (b ? ref x : ref y)!; + ref object M6(bool b, ref object? x, ref object y) => ref (b ? ref x! : ref y)!; + ref object M7(bool b, ref object? x, ref object y) => ref (b ? ref x : ref y!)!; + ref object M8(bool b, ref object? x, ref object y) => ref (b ? ref x! : ref y!)!; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,63): warning CS8601: Possible null reference assignment. + // ref object M1(bool b, ref object? x, ref object y) => ref b ? ref x : ref y; + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "b ? ref x : ref y").WithLocation(4, 63), + // (4,71): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. + // ref object M1(bool b, ref object? x, ref object y) => ref b ? ref x : ref y; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("object?", "object").WithLocation(4, 71), + // (6,63): warning CS8601: Possible null reference assignment. + // ref object M3(bool b, ref object? x, ref object y) => ref b ? ref x : ref y!; + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "b ? ref x : ref y!").WithLocation(6, 63), + // (6,71): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. + // ref object M3(bool b, ref object? x, ref object y) => ref b ? ref x : ref y!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("object?", "object").WithLocation(6, 71), + // (8,72): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. + // ref object M5(bool b, ref object? x, ref object y) => ref (b ? ref x : ref y)!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("object?", "object").WithLocation(8, 72), + // (10,72): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. + // ref object M7(bool b, ref object? x, ref object y) => ref (b ? ref x : ref y!)!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("object?", "object").WithLocation(10, 72)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73928")] + public void ConditionalOperator_Suppression_Ref_02() + { + var source = """ + #nullable enable + class C + { + ref object? M1(bool b, ref object? x, ref object y) => ref b ? ref x : ref y; + ref object? M2(bool b, ref object? x, ref object y) => ref b ? ref x! : ref y; + ref object? M3(bool b, ref object? x, ref object y) => ref b ? ref x : ref y!; + ref object? M4(bool b, ref object? x, ref object y) => ref b ? ref x! : ref y!; + ref object? M5(bool b, ref object? x, ref object y) => ref (b ? ref x : ref y)!; + ref object? M6(bool b, ref object? x, ref object y) => ref (b ? ref x! : ref y)!; + ref object? M7(bool b, ref object? x, ref object y) => ref (b ? ref x : ref y!)!; + ref object? M8(bool b, ref object? x, ref object y) => ref (b ? ref x! : ref y!)!; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,64): warning CS8619: Nullability of reference types in value of type 'object' doesn't match target type 'object?'. + // ref object? M1(bool b, ref object? x, ref object y) => ref b ? ref x : ref y; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x : ref y").WithArguments("object", "object?").WithLocation(4, 64), + // (4,72): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. + // ref object? M1(bool b, ref object? x, ref object y) => ref b ? ref x : ref y; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("object?", "object").WithLocation(4, 72), + // (5,64): warning CS8619: Nullability of reference types in value of type 'object' doesn't match target type 'object?'. + // ref object? M2(bool b, ref object? x, ref object y) => ref b ? ref x! : ref y; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x! : ref y").WithArguments("object", "object?").WithLocation(5, 64), + // (6,64): warning CS8619: Nullability of reference types in value of type 'object' doesn't match target type 'object?'. + // ref object? M3(bool b, ref object? x, ref object y) => ref b ? ref x : ref y!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x : ref y!").WithArguments("object", "object?").WithLocation(6, 64), + // (6,72): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. + // ref object? M3(bool b, ref object? x, ref object y) => ref b ? ref x : ref y!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("object?", "object").WithLocation(6, 72), + // (7,64): warning CS8619: Nullability of reference types in value of type 'object' doesn't match target type 'object?'. + // ref object? M4(bool b, ref object? x, ref object y) => ref b ? ref x! : ref y!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x! : ref y!").WithArguments("object", "object?").WithLocation(7, 64), + // (8,73): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. + // ref object? M5(bool b, ref object? x, ref object y) => ref (b ? ref x : ref y)!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("object?", "object").WithLocation(8, 73), + // (10,73): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. + // ref object? M7(bool b, ref object? x, ref object y) => ref (b ? ref x : ref y!)!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("object?", "object").WithLocation(10, 73)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73928")] + public void ConditionalOperator_Suppression_Ref_03() + { + var source = """ + #nullable enable + class C + { + ref object? M1(bool b, ref object? x, ref object y) + { + ref object? y1 = ref y!; + return ref b ? ref x : ref y1; + } + ref object M2(bool b, ref object? x, ref object y) + { + ref object x1 = ref x!; + return ref b ? ref x1 : ref y; + } + } + """; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73928")] + public void ConditionalOperator_Suppression_Ref_04() + { + var source = """ + #nullable enable + class C + { + ref object M1(bool b, ref object? x, ref object? y) => ref b ? ref x : ref y; + ref object M2(bool b, ref object? x, ref object? y) => ref (b ? ref x : ref y)!; + ref object? M3(bool b, ref object x, ref object y) => ref b ? ref x : ref y; + ref object? M4(bool b, ref object x, ref object y) => ref (b ? ref x : ref y)!; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,64): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. + // ref object M1(bool b, ref object? x, ref object? y) => ref b ? ref x : ref y; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x : ref y").WithArguments("object?", "object").WithLocation(4, 64), + // (6,63): warning CS8619: Nullability of reference types in value of type 'object' doesn't match target type 'object?'. + // ref object? M3(bool b, ref object x, ref object y) => ref b ? ref x : ref y; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x : ref y").WithArguments("object", "object?").WithLocation(6, 63)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73928")] + public void ConditionalOperator_Suppression_Ref_05() + { + var source = """ + #nullable enable + class C + { + ref object? M1(bool b, ref object? x, ref object? y) => ref b ? ref x : ref y; + ref object? M2(bool b, ref object? x, ref object? y) => ref (b ? ref x : ref y)!; + ref object M3(bool b, ref object x, ref object y) => ref b ? ref x : ref y; + ref object M4(bool b, ref object x, ref object y) => ref (b ? ref x : ref y)!; + } + """; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73928")] + public void ConditionalOperator_Suppression_Ref_Nested_01() + { + var source = """ + #nullable enable + using System.Collections.Generic; + class C + { + ref List? M1(bool b, ref List? x, ref List? y) => ref b ? ref x : ref y; + ref List? M2(bool b, ref List? x, ref List? y) => ref b ? ref x! : ref y; + ref List? M3(bool b, ref List? x, ref List? y) => ref b ? ref x : ref y!; + ref List? M4(bool b, ref List? x, ref List? y) => ref b ? ref x! : ref y!; + ref List? M5(bool b, ref List? x, ref List? y) => ref (b ? ref x : ref y)!; + ref List? M6(bool b, ref List? x, ref List? y) => ref (b ? ref x! : ref y)!; + ref List? M7(bool b, ref List? x, ref List? y) => ref (b ? ref x : ref y!)!; + ref List? M8(bool b, ref List? x, ref List? y) => ref (b ? ref x! : ref y!)!; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (5,92): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M1(bool b, ref List? x, ref List? y) => ref b ? ref x : ref y; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(5, 92), + // (7,92): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M3(bool b, ref List? x, ref List? y) => ref b ? ref x : ref y!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(7, 92), + // (9,93): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M5(bool b, ref List? x, ref List? y) => ref (b ? ref x : ref y)!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(9, 93), + // (11,93): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M7(bool b, ref List? x, ref List? y) => ref (b ? ref x : ref y!)!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(11, 93)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73928")] + public void ConditionalOperator_Suppression_Ref_Nested_02() + { + var source = """ + #nullable enable + using System.Collections.Generic; + class C + { + ref List? M1(bool b, ref List? x, ref List? y) => ref b ? ref x : ref y; + ref List? M2(bool b, ref List? x, ref List? y) => ref b ? ref x! : ref y; + ref List? M3(bool b, ref List? x, ref List? y) => ref b ? ref x : ref y!; + ref List? M4(bool b, ref List? x, ref List? y) => ref b ? ref x! : ref y!; + ref List? M5(bool b, ref List? x, ref List? y) => ref (b ? ref x : ref y)!; + ref List? M6(bool b, ref List? x, ref List? y) => ref (b ? ref x! : ref y)!; + ref List? M7(bool b, ref List? x, ref List? y) => ref (b ? ref x : ref y!)!; + ref List? M8(bool b, ref List? x, ref List? y) => ref (b ? ref x! : ref y!)!; + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (5,85): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M1(bool b, ref List? x, ref List? y) => ref b ? ref x : ref y; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x : ref y").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(5, 85), + // (5,93): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M1(bool b, ref List? x, ref List? y) => ref b ? ref x : ref y; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(5, 93), + // (6,85): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M2(bool b, ref List? x, ref List? y) => ref b ? ref x! : ref y; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x! : ref y").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(6, 85), + // (7,85): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M3(bool b, ref List? x, ref List? y) => ref b ? ref x : ref y!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x : ref y!").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(7, 85), + // (7,93): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M3(bool b, ref List? x, ref List? y) => ref b ? ref x : ref y!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(7, 93), + // (8,85): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M4(bool b, ref List? x, ref List? y) => ref b ? ref x! : ref y!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x! : ref y!").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(8, 85), + // (9,94): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M5(bool b, ref List? x, ref List? y) => ref (b ? ref x : ref y)!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(9, 94), + // (11,94): warning CS8619: Nullability of reference types in value of type 'System.Collections.Generic.List?' doesn't match target type 'System.Collections.Generic.List?'. + // ref List? M7(bool b, ref List? x, ref List? y) => ref (b ? ref x : ref y!)!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Collections.Generic.List?", "System.Collections.Generic.List?").WithLocation(11, 94)); + } + [Fact, WorkItem(33664, "https://github.com/dotnet/roslyn/issues/33664")] public void ConditionalOperator_AssigningToRefConditional() { @@ -55212,15 +55532,15 @@ void M4(bool c, ref string x, ref string? y) }", options: WithNullableEnable(), references: new[] { ref0 }); comp.VerifyDiagnostics( - // (6,10): warning CS8619: Nullability of reference types in value of type 'string' doesn't match target type 'string?'. + // (6,26): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. // (c ? ref x : ref y) = null; // 1, 2 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "c ? ref x : ref y").WithArguments("string", "string?").WithLocation(6, 10), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y").WithArguments("string?", "string").WithLocation(6, 26), // (6,31): warning CS8625: Cannot convert null literal to non-nullable reference type. // (c ? ref x : ref y) = null; // 1, 2 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(6, 31), - // (10,10): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // (10,18): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. // (c ? ref y : ref x) = null; // 3, 4 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "c ? ref y : ref x").WithArguments("string?", "string").WithLocation(10, 10), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y").WithArguments("string?", "string").WithLocation(10, 18), // (10,31): warning CS8625: Cannot convert null literal to non-nullable reference type. // (c ? ref y : ref x) = null; // 3, 4 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(10, 31), @@ -59410,9 +59730,9 @@ public ClassITest28(int x){} } "; - var piaCompilation = CreateCompilationWithMscorlib45(pia, options: WithNullableEnable(TestOptions.DebugDll)); + var piaCompilation = CreateCompilationWithMscorlib461(pia, options: WithNullableEnable(TestOptions.DebugDll)); - CSharpCompilation c = CreateCompilationWithMscorlib45( + CSharpCompilation c = CreateCompilationWithMscorlib461( new[] { @" class C { @@ -59468,9 +59788,9 @@ public ClassITest28(int x){} } "; - var piaCompilation = CreateCompilationWithMscorlib45(pia, options: WithNullableEnable(TestOptions.DebugDll)); + var piaCompilation = CreateCompilationWithMscorlib461(pia, options: WithNullableEnable(TestOptions.DebugDll)); - CSharpCompilation c = CreateCompilationWithMscorlib45( + CSharpCompilation c = CreateCompilationWithMscorlib461( new[] { @" class C { @@ -63424,7 +63744,7 @@ static class E { internal static U[] F(this T[] a, Func f) => throw new Exception(); }"; - var comp = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( new[] { source }, parseOptions: TestOptions.Regular7); comp.VerifyDiagnostics(); @@ -74268,7 +74588,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return true; } } }"; - CreateCompilationWithMscorlib45(new[] { source }, options: WithNullableEnable()).VerifyDiagnostics( + CreateCompilationWithMscorlib461(new[] { source }, options: WithNullableEnable()).VerifyDiagnostics( ); } @@ -74301,7 +74621,7 @@ public void OnCompleted(Action x) { } public bool IsCompleted { get { return true; } } }"; - CreateCompilationWithMscorlib45(new[] { source }, options: WithNullableEnable()).VerifyDiagnostics( + CreateCompilationWithMscorlib461(new[] { source }, options: WithNullableEnable()).VerifyDiagnostics( // (10,20): warning CS8600: Converting null literal or possible null value to non-nullable type. // object x = await new D(); Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "await new D()").WithLocation(10, 20) @@ -74785,7 +75105,7 @@ public ClassITest28(int x){} } "; - var piaCompilation = CreateCompilationWithMscorlib45(pia, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular7); + var piaCompilation = CreateCompilationWithMscorlib461(pia, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular7); CompileAndVerify(piaCompilation); @@ -74807,7 +75127,7 @@ void Test2(ITest28 x2) } }"; - var compilation = CreateCompilationWithMscorlib45(new[] { source }, + var compilation = CreateCompilationWithMscorlib461(new[] { source }, new MetadataReference[] { new CSharpCompilationReference(piaCompilation, embedInteropTypes: true) }, options: WithNullableEnable(TestOptions.DebugExe)); @@ -76892,7 +77212,7 @@ internal static void F(this string s) } }"; - var comp = CreateCompilationWithMscorlib45(source, options: WithNullableEnable()); + var comp = CreateCompilationWithMscorlib461(source, options: WithNullableEnable()); comp.VerifyDiagnostics( // (15,18): error CS8651: It is not legal to use nullable reference type 'string?' in an as expression; use the underlying type 'string' instead. // (null as string?).F(); @@ -77151,7 +77471,7 @@ static class E { internal static void F(this object[] o) { } }"; - var comp = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( new[] { source }, options: WithNullableEnable(), parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics(); @@ -77776,7 +78096,7 @@ static class E internal static void F1(this I o) { } internal static void F2(this I o) { } }"; - var comp = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( new[] { source }, options: WithNullableEnable(), parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( @@ -90558,6 +90878,49 @@ static class Extensions comp.VerifyDiagnostics(); } + [Fact] + public void Foreach_NullableElementType_Suppression() + { + var source = """ + #nullable enable + class C + { + void M1(object?[] a) { foreach (object item in a) { } } + void M2(object[] a) { foreach (object item in a!) { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (4,44): warning CS8600: Converting null literal or possible null value to non-nullable type. + // void M1(object?[] a) { foreach (object item in a) { } } + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "item").WithLocation(4, 44)); + } + + [Fact] + public void Foreach_NullableElementType_Suppression_Ref() + { + var source = """ + #nullable enable + class RefList + { + public RefEnumerator GetEnumerator() => new RefEnumerator(); + public struct RefEnumerator + { + public ref object? Current => throw null!; + public bool MoveNext() => false; + } + } + class C + { + void M1(RefList refList) { foreach (ref object item in refList) { } } + void M2(RefList refList) { foreach (ref object item in refList!) { } } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (13,41): warning CS8619: Nullability of reference types in value of type 'object?' doesn't match target type 'object'. + // void M1(RefList refList) { foreach (ref object item in refList) { } } + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "ref object").WithArguments("object?", "object").WithLocation(13, 41)); + } + [Fact] public void TypeInference_01() { @@ -136355,6 +136718,235 @@ static void validate(ModuleSymbol module) Assert.False(c.HasUnsupportedMetadata); } + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/73338")] + [InlineData("static abstract void M();")] + [InlineData("static virtual void M() { }")] + public void AnnotationMismatch_Interface_StaticVirtualMethod_01(string def) + { + var source = $$""" + #nullable enable + partial class C : + #nullable disable + I + #nullable enable + { + } + + partial class C : I + { + public static void M() { } + } + + interface I + { + {{def}} + } + """; + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net60, + verify: ExecutionConditionUtil.IsDesktop ? Verification.Skipped : Verification.Passes, + symbolValidator: validate); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var cm = module.GlobalNamespace.GetMember("C.M"); + var cme = Assert.Single(cm.GetExplicitInterfaceImplementations()); + var im = module.GlobalNamespace.GetMember("I.M"); + Assert.Same(im, cme.OriginalDefinition); + } + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/73338")] + [InlineData("static abstract void M();")] + [InlineData("static virtual void M() { }")] + public void AnnotationMismatch_Interface_StaticVirtualMethod_02(string def) + { + var source = $$""" + #nullable enable + partial class C : + #nullable disable + I + #nullable enable + { + } + + partial class C : I + { + public static void M() { } + } + + interface I + { + {{def}} + } + """; + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net60, + verify: ExecutionConditionUtil.IsDesktop ? Verification.Skipped : Verification.Passes, + symbolValidator: validate); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var cm = module.GlobalNamespace.GetMember("C.M"); + var cme = Assert.Single(cm.GetExplicitInterfaceImplementations()); + var im = module.GlobalNamespace.GetMember("I.M"); + Assert.Same(im, cme.OriginalDefinition); + } + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/73338")] + [InlineData("static abstract void M();")] + [InlineData("static virtual void M() { }")] + public void AnnotationMismatch_Interface_StaticVirtualMethod_03(string def) + { + var source = $$""" + #nullable enable + class C : I, I + { + public static void M() { } + } + + interface I + { + {{def}} + } + """; + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net60, + verify: ExecutionConditionUtil.IsDesktop ? Verification.Skipped : Verification.Passes, + symbolValidator: validate); + verifier.VerifyDiagnostics( + // (2,7): warning CS8645: 'I' is already listed in the interface list on type 'C' with different nullability of reference types. + // class C : I, I + Diagnostic(ErrorCode.WRN_DuplicateInterfaceWithNullabilityMismatchInBaseList, "C").WithArguments("I", "C").WithLocation(2, 7)); + + static void validate(ModuleSymbol module) + { + var cm = module.GlobalNamespace.GetMember("C.M"); + var cme = Assert.Single(cm.GetExplicitInterfaceImplementations()); + var im = module.GlobalNamespace.GetMember("I.M"); + Assert.Same(im, cme.OriginalDefinition); + } + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/73338")] + [InlineData("static abstract void M();")] + [InlineData("static virtual void M() { }")] + public void AnnotationMismatch_Interface_StaticVirtualMethod_04(string def) + { + var source = $$""" + #nullable enable + class C : I, I + { + static void I.M() { } + } + + interface I + { + {{def}} + } + """; + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net60, + verify: ExecutionConditionUtil.IsDesktop ? Verification.Skipped : Verification.Passes, + symbolValidator: validate); + verifier.VerifyDiagnostics( + // (2,7): warning CS8645: 'I' is already listed in the interface list on type 'C' with different nullability of reference types. + // class C : I, I + Diagnostic(ErrorCode.WRN_DuplicateInterfaceWithNullabilityMismatchInBaseList, "C").WithArguments("I", "C").WithLocation(2, 7)); + + static void validate(ModuleSymbol module) + { + var cm = module.GlobalNamespace.GetMember("C.I.M"); + var cme = Assert.Single(cm.GetExplicitInterfaceImplementations()); + var im = module.GlobalNamespace.GetMember("I.M"); + Assert.Same(im, cme.OriginalDefinition); + } + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/73338")] + public void AnnotationMismatch_Interface_StaticVirtualMethod_05( + [CombinatorialValues("static abstract void M();", "static virtual void M() { }")] string def, + bool metadataOnly) + { + var source = $$""" + #nullable enable + partial class C : + #nullable disable + I + #nullable enable + { + } + + partial class C : B, I + { + } + + class B + { + public static void M() { } + } + + public interface I + { + {{def}} + } + """; + var verifier = CompileAndVerify(source, targetFramework: TargetFramework.Net60, + verify: ExecutionConditionUtil.IsDesktop ? Verification.Skipped : Verification.Passes, + emitOptions: CodeAnalysis.Emit.EmitOptions.Default.WithEmitMetadataOnly(metadataOnly), + symbolValidator: validate); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var im = module.GlobalNamespace.GetMember("I.M"); + var cm = (MethodSymbol)Assert.Single(module.GlobalNamespace.GetTypeMember("C").GetMembers("I.M")); + var cme = Assert.Single(cm.GetExplicitInterfaceImplementations()); + Assert.Same(im, cme.OriginalDefinition); + } + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/73338")] + public void AnnotationMismatch_Interface_InstanceForwardingMethod(bool metadataOnly) + { + var source1 = """ + public class B + { + public void M() { } + } + public interface I + { + void M(); + } + """; + var comp1 = CreateCompilation(source1, assemblyName: nameof(source1)).VerifyDiagnostics().EmitToImageReference(); + + var source2 = """ + #nullable enable + partial class C : + #nullable disable + I + #nullable enable + { + } + partial class C : B, I + { + } + """; + var verifier = CompileAndVerify(source2, [comp1], + emitOptions: CodeAnalysis.Emit.EmitOptions.Default.WithEmitMetadataOnly(metadataOnly), + symbolValidator: validate); + verifier.VerifyDiagnostics(); + + static void validate(ModuleSymbol module) + { + var im = module.ReferencedAssemblySymbols.Single(a => a.Name == nameof(source1)) + .GlobalNamespace.GetMember("I.M"); + var cm = (MethodSymbol)Assert.Single(module.GlobalNamespace.GetTypeMember("C").GetMembers("I.M")); + var cme = Assert.Single(cm.GetExplicitInterfaceImplementations()); + Assert.Same(im, cme.OriginalDefinition); + } + } + [Fact] public void PartialMethodsWithConstraints_01() { @@ -151490,21 +152082,21 @@ static void F4(bool b, I x4, I y4) // (15,25): warning CS8619: Nullability of reference types in value of type 'T' doesn't match target type 'T?'. // ref T? t2 = ref b ? ref x2 : ref y2; // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x2 : ref y2").WithArguments("T", "T?").WithLocation(15, 25), - // (15,25): warning CS8619: Nullability of reference types in value of type 'T' doesn't match target type 'T?'. + // (15,42): warning CS8619: Nullability of reference types in value of type 'T?' doesn't match target type 'T'. // ref T? t2 = ref b ? ref x2 : ref y2; // 1 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x2 : ref y2").WithArguments("T", "T?").WithLocation(15, 25), - // (16,25): warning CS8619: Nullability of reference types in value of type 'T?' doesn't match target type 'T'. - // ref T? t3 = ref b ? ref y2 : ref x2; // 2 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y2 : ref x2").WithArguments("T?", "T").WithLocation(16, 25), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y2").WithArguments("T?", "T").WithLocation(15, 42), // (16,25): warning CS8619: Nullability of reference types in value of type 'T' doesn't match target type 'T?'. // ref T? t3 = ref b ? ref y2 : ref x2; // 2 Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y2 : ref x2").WithArguments("T", "T?").WithLocation(16, 25), - // (29,28): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. + // (16,33): warning CS8619: Nullability of reference types in value of type 'T?' doesn't match target type 'T'. + // ref T? t3 = ref b ? ref y2 : ref x2; // 2 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y2").WithArguments("T?", "T").WithLocation(16, 33), + // (29,36): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. // ref I t2 = ref b ? ref x4 : ref y4; // 3 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref x4 : ref y4").WithArguments("I", "I").WithLocation(29, 28), - // (30,28): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x4").WithArguments("I", "I").WithLocation(29, 36), + // (30,45): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. // ref I t3 = ref b ? ref y4 : ref x4; // 4 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b ? ref y4 : ref x4").WithArguments("I", "I").WithLocation(30, 28)); + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x4").WithArguments("I", "I").WithLocation(30, 45)); } [Fact] @@ -157890,9 +158482,9 @@ public ClassITest28(int x){} } "; - var piaCompilation = CreateCompilationWithMscorlib45(pia, options: WithNullableEnable(TestOptions.DebugDll)); + var piaCompilation = CreateCompilationWithMscorlib461(pia, options: WithNullableEnable(TestOptions.DebugDll)); - CSharpCompilation c = CreateCompilationWithMscorlib45( + CSharpCompilation c = CreateCompilationWithMscorlib461( new[] { @" class C { @@ -157948,9 +158540,9 @@ public ClassITest28(int x){} } "; - var piaCompilation = CreateCompilationWithMscorlib45(pia, options: WithNullableEnable(TestOptions.DebugDll)); + var piaCompilation = CreateCompilationWithMscorlib461(pia, options: WithNullableEnable(TestOptions.DebugDll)); - CSharpCompilation c = CreateCompilationWithMscorlib45( + CSharpCompilation c = CreateCompilationWithMscorlib461( new[] { @" class C { @@ -157997,9 +158589,9 @@ public ClassITest28(int x){} } "; - var piaCompilation = CreateCompilationWithMscorlib45(pia, options: WithNullableEnable(TestOptions.DebugDll)); + var piaCompilation = CreateCompilationWithMscorlib461(pia, options: WithNullableEnable(TestOptions.DebugDll)); - CSharpCompilation c = CreateCompilationWithMscorlib45( + CSharpCompilation c = CreateCompilationWithMscorlib461( new[] { @" class C { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs index b4990d8031bfd..74966d84778a6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OperatorTests.cs @@ -7849,7 +7849,7 @@ public void BinaryIntrinsicSymbols1() var source = builder.ToString(); - var compilation = CreateCompilation(source, targetFramework: TargetFramework.Mscorlib45Extended, options: TestOptions.ReleaseDll.WithOverflowChecks(true)); + var compilation = CreateCompilation(source, targetFramework: TargetFramework.Mscorlib461Extended, options: TestOptions.ReleaseDll.WithOverflowChecks(true)); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); @@ -8971,7 +8971,7 @@ static void M(C x, C y) private sealed class EmptyRewriter : BoundTreeRewriter { - protected override BoundExpression VisitExpressionWithoutStackGuard(BoundExpression node) + protected override BoundNode VisitExpressionOrPatternWithoutStackGuard(BoundNode node) { throw new NotImplementedException(); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTestBase.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTestBase.cs index bb1ee1028fdd4..faedb492cc0a3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTestBase.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTestBase.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using Xunit; using Roslyn.Test.Utilities; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -26,7 +27,7 @@ internal void TestOverloadResolutionWithDiff(string source, MetadataReference[] // from it the nodes that describe the method symbols. We then compare the description of // the symbols given to the comment that follows the call. - var mscorlibRef = AssemblyMetadata.CreateFromImage(TestMetadata.ResourcesNet451.mscorlib).GetReference(display: "mscorlib"); + var mscorlibRef = AssemblyMetadata.CreateFromImage(Net461.Resources.mscorlib).GetReference(display: "mscorlib"); var references = new[] { mscorlibRef }.Concat(additionalRefs ?? Array.Empty()); var compilation = CreateEmptyCompilation(source, references, TestOptions.ReleaseDll); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs index 29eae2695f2e0..2bb1c84896e73 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -513,7 +514,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - CreateCompilationWithMscorlib45(source1).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source1).VerifyDiagnostics( // (9,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.h(Func>)' and 'C.h(Func>)' // h(async () => { await (Task)null; return 1; }); Diagnostic(ErrorCode.ERR_AmbigCall, "h").WithArguments("C.h(System.Func>)", "C.h(System.Func>)").WithLocation(9, 9) @@ -562,7 +563,7 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - CreateCompilationWithMscorlib45(source2).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source2).VerifyDiagnostics( // (9,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.k(Func>)' and 'C.k(Func>)' // k(async () => { await (Task)null; return 1; }); Diagnostic(ErrorCode.ERR_AmbigCall, "k").WithArguments("C.k(System.Func>)", "C.k(System.Func>)").WithLocation(9, 9) @@ -604,7 +605,7 @@ struct MyTaskMethodBuilder namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeDebugDll); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.UnsafeDebugDll); compilation.VerifyDiagnostics(); var type = compilation.GetMember("C.F0").Type; @@ -684,7 +685,7 @@ public TupleElementNamesAttribute(string[] names) { } namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source, assemblyName: "comp"); + var compilation = CreateCompilationWithMscorlib461(source, assemblyName: "comp"); compilation.VerifyEmitDiagnostics(); var type = compilation.GetMember("C.F0").Type; @@ -767,7 +768,7 @@ .method public hidebysig specialname rtspecialname instance void .ctor(class [ms var source = @""; var reference = CompileIL(ilSource); - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { reference }); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { reference }); compilation.VerifyDiagnostics(); var type = compilation.GetMember("C.F0").Type; @@ -797,7 +798,7 @@ struct MyTaskMethodBuilder namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeDebugDll); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.UnsafeDebugDll); compilation.VerifyDiagnostics( // (6,28): warning CS8500: This takes the address of, gets the size of, or declares a pointer to a managed type ('C>') // static C>* F0; @@ -838,7 +839,7 @@ .method public hidebysig specialname rtspecialname instance void .ctor(class [ms var source = @""; var reference = CompileIL(ilSource); - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { reference }); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { reference }); compilation.VerifyDiagnostics(); var type = compilation.GetMember("C.F0").Type; @@ -871,7 +872,7 @@ struct MyTaskMethodBuilder namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.Regular9); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics(); assert("F0", "delegate*>>", "delegate*>>"); @@ -925,7 +926,7 @@ .method public hidebysig specialname rtspecialname instance void .ctor(class [ms var source = @""; var reference = CompileIL(ilSource); - var compilation = CreateCompilationWithMscorlib45(source, references: new[] { reference }); + var compilation = CreateCompilationWithMscorlib461(source, references: new[] { reference }); compilation.VerifyDiagnostics(); var type = compilation.GetMember("C.F0").Type; @@ -962,7 +963,7 @@ struct MyTaskMethodBuilder namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyDiagnostics( // (5,19): error CS0246: The type or namespace name 'B' could not be found (are you missing a using directive or an assembly reference?) // static MyTask F1; @@ -1016,7 +1017,7 @@ class MyTaskMethodBuilder namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyDiagnostics(); var type = compilation.GetMember("C.F0").Type; @@ -1069,7 +1070,7 @@ class MyTaskMethodBuilder namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.VerifyDiagnostics(); var type = compilation.GetMember("C.F0").Type; @@ -7296,7 +7297,7 @@ public async void Run() Console.WriteLine(xxx); // 3; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -7325,7 +7326,7 @@ public void Run() Console.WriteLine(xxx); // 3; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact, WorkItem(718294, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/718294")] @@ -7362,7 +7363,7 @@ public static void Add(this IViewable2 @this, T item, object obj = null) { } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact, WorkItem(667132, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/667132")] @@ -7392,7 +7393,7 @@ static void Goo(IGoo o) Console.WriteLine(g); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact] @@ -7718,7 +7719,7 @@ static void Main() } "; - var compilation = CreateCompilationWithMscorlib45(source1, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source1, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: @"2 2 2 @@ -7751,7 +7752,7 @@ static void Main() } "; - var compilation = CreateCompilationWithMscorlib45(source1, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source1, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: @"2 2 2 @@ -7779,7 +7780,7 @@ static void Main() } "; - var compilation = CreateCompilationWithMscorlib45(source1, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source1, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: @"2 1"); @@ -8192,7 +8193,7 @@ static void Main(string[] args) } "; - var compilation = CreateCompilationWithMscorlib40(source1, new[] { TestMetadata.Net40.SystemCore }, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib40(source1, new[] { Net40.References.SystemCore }, options: TestOptions.DebugExe); compilation.VerifyDiagnostics(); } @@ -8228,7 +8229,7 @@ static void Main(string[] args) } "; - var compilation = CreateCompilationWithMscorlib40(source1, new[] { TestMetadata.Net40.SystemCore }, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib40(source1, new[] { Net40.References.SystemCore }, options: TestOptions.DebugExe); compilation.VerifyDiagnostics(); } @@ -8964,7 +8965,7 @@ void goo() } }"; - var compilation = CreateCompilationWithMscorlib45(source1); + var compilation = CreateCompilationWithMscorlib461(source1); compilation.VerifyDiagnostics( // (34,18): error CS0121: The call is ambiguous between the following methods or properties: 'FluentAssertions.AssertionExtensions.Should(System.Collections.Generic.IDictionary)' and 'Extensions.TestExtensions.Should(System.Collections.Generic.IReadOnlyDictionary)' @@ -9029,7 +9030,7 @@ public static void RemoveDetail(this TMain main, TChild child) System.Console.WriteLine(""RemoveDetail""); } }"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); CompileAndVerify(compilation, expectedOutput: @"RemoveDetail RemoveDetail @@ -11497,7 +11498,7 @@ public static class Extensions } "; - var libComp = CreateCompilationWithMscorlib40(librarySrc, references: new[] { TestMetadata.Net40.SystemCore }).VerifyDiagnostics(); + var libComp = CreateCompilationWithMscorlib40(librarySrc, references: new[] { Net40.References.SystemCore }).VerifyDiagnostics(); var code = @" class D diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests.cs index 3af66f2b18f0f..c4bea55c06bbd 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests.cs @@ -105,7 +105,7 @@ public static void Main(string[] args) Console.WriteLine($""""""Jenny don\'t change your number { /*trash*/ }.""""""); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,75): error CS1733: Expected expression // Console.WriteLine($"""Jenny don\'t change your number { /*trash*/ }."""); Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(5, 75)); @@ -123,7 +123,7 @@ public static void Main(string[] args) } }"; // too many diagnostics perhaps, but it starts the right way. - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,70): error CS8997: Unterminated raw string literal // Console.WriteLine($"""Jenny don\'t change your number { """); Diagnostic(ErrorCode.ERR_UnterminatedRawString, @" @@ -154,7 +154,7 @@ public static void Main(string[] args) } }"; // too many diagnostics perhaps, but it starts the right way. - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,5): error CS8997: Unterminated raw string literal // } Diagnostic(ErrorCode.ERR_UnterminatedRawString, "}").WithLocation(6, 5), @@ -181,7 +181,7 @@ public static void Main(string[] args) } }"; // too many diagnostics perhaps, but it starts the right way. - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,63): error CS8076: Missing close delimiter '}' for interpolated expression started with '{'. // Console.WriteLine($"""Jenny don\'t change your number { 8675309 /* """); Diagnostic(ErrorCode.ERR_UnclosedExpressionHole, "{").WithLocation(5, 63), @@ -408,7 +408,7 @@ static void Main(string[] args) Console.WriteLine( $""""""{"""""" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,39): error CS8997: Unterminated raw string literal // Console.WriteLine( $"""{""" ); Diagnostic(ErrorCode.ERR_UnterminatedRawString, @" @@ -437,7 +437,7 @@ static void Main(string[] args) { var x = $"""""";"; // The precise error messages are not important, but this must be an error. - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,21): error CS8997: Unterminated raw string literal // var x = $"""; Diagnostic(ErrorCode.ERR_UnterminatedRawString, ";").WithLocation(5, 21), @@ -464,7 +464,7 @@ static void Main(string[] args) Console.WriteLine( $""""""{3:}"""""" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,34): error CS8089: Empty format specifier. // Console.WriteLine( $"""{3:}""" ); Diagnostic(ErrorCode.ERR_EmptyFormatSpecifier, ":").WithLocation(6, 34)); @@ -482,7 +482,7 @@ static void Main(string[] args) Console.WriteLine( $""""""{3:d }"""""" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,34): error CS8088: A format specifier may not contain trailing whitespace. // Console.WriteLine( $"""{3:d }""" ); Diagnostic(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, ":d ").WithLocation(6, 34)); @@ -501,7 +501,7 @@ static void Main(string[] args) }"""""" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,34): error CS8088: A format specifier may not contain trailing whitespace. // Console.WriteLine( $"""{3:d Diagnostic(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, @":d @@ -520,7 +520,7 @@ static void Main(string[] args) Console.WriteLine( $""""""{ }"""""" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,34): error CS1733: Expected expression // Console.WriteLine( $"""{ }""" ); Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(6, 34)); @@ -538,7 +538,7 @@ static void Main(string[] args) Console.WriteLine( $""""""{ }"""""" ); } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,34): error CS1733: Expected expression // Console.WriteLine( $"""{ }""" ); Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(6, 34)); @@ -629,7 +629,7 @@ static void Main() var s2 = $"""""" \u007D""""""; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(source).VerifyDiagnostics(); } [Fact, WorkItem(1119878, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1119878")] @@ -660,7 +660,7 @@ static void Main() var t = $""""""{1,(int)1E10}""""""; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,24): error CS0266: Cannot implicitly convert type 'double' to 'int'. An explicit conversion exists (are you missing a cast?) // var s = $"""{1,1E10}"""; Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "1E10").WithArguments("double", "int").WithLocation(5, 24), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs index 66c7ffdcd12cd..bde5a43a8840b 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs @@ -10541,7 +10541,7 @@ public CustomHandler(int literalLength, int formattedCount, dynamic d) : this(li var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial struct", useBoolReturns: false, includeOneTimeHelpers: false); - var comp = CreateCompilation(new[] { code, handler, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, handler, InterpolatedStringHandlerArgumentAttribute, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: "d:1"); verifier.VerifyDiagnostics(); @@ -10592,7 +10592,7 @@ public CustomHandler(dynamic literalLength, int formattedCount) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: "ctor"); verifier.VerifyDiagnostics(); @@ -10643,7 +10643,7 @@ public CustomHandler(dynamic literalLength, int formattedCount) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: "ctor"); verifier.VerifyDiagnostics(); @@ -10688,7 +10688,7 @@ public void AppendLiteral(dynamic d) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: "AppendLiteral"); verifier.VerifyDiagnostics(); @@ -10739,7 +10739,7 @@ public void AppendFormatted(dynamic d) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: "AppendFormatted"); verifier.VerifyDiagnostics(); @@ -10800,7 +10800,7 @@ public void AppendFormatted(int d) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: @" AppendLiteral AppendFormatted"); @@ -10899,7 +10899,7 @@ public bool AppendFormatted(int d) } "; - var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib45AndCSharp); + var comp = CreateCompilation(new[] { code, InterpolatedStringHandlerAttribute }, targetFramework: TargetFramework.Mscorlib461AndCSharp); var verifier = CompileAndVerify(comp, expectedOutput: @" AppendLiteral AppendFormatted"); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs index bf3e005bd40d0..2ba2019210be3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs @@ -1608,12 +1608,12 @@ public struct S public int P1 { get; private set; } } "; - var moduleMetadata = CreateCompilation(csharp, options: TestOptions.DebugModule, targetFramework: TargetFramework.Mscorlib45).EmitToImageReference(); + var moduleMetadata = CreateCompilation(csharp, options: TestOptions.DebugModule, targetFramework: TargetFramework.Mscorlib461).EmitToImageReference(); var moduleComp = CreateCompilation("", new[] { moduleMetadata }); var moduleGetter = moduleComp.GetMember("S.P1").GetMethod; Assert.False(moduleGetter.IsDeclaredReadOnly); - var dllMetadata = CreateCompilation(csharp, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib45).EmitToImageReference(); + var dllMetadata = CreateCompilation(csharp, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461).EmitToImageReference(); var dllComp = CreateCompilation("", new[] { dllMetadata }); var dllGetter = dllComp.GetMember("S.P1").GetMethod; Assert.True(dllGetter.IsDeclaredReadOnly); @@ -1636,12 +1636,12 @@ public struct S public int P1 { get; private set; } } "; - var moduleMetadata = CreateCompilation(csharp, options: TestOptions.DebugModule, targetFramework: TargetFramework.Mscorlib45).EmitToImageReference(); + var moduleMetadata = CreateCompilation(csharp, options: TestOptions.DebugModule, targetFramework: TargetFramework.Mscorlib461).EmitToImageReference(); var moduleComp = CreateCompilation("", new[] { moduleMetadata }); var moduleGetter = moduleComp.GetMember("S.P1").GetMethod; Assert.False(moduleGetter.IsDeclaredReadOnly); - var dllMetadata = CreateCompilation(csharp, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib45).EmitToImageReference(); + var dllMetadata = CreateCompilation(csharp, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461).EmitToImageReference(); var dllComp = CreateCompilation("", new[] { dllMetadata }); var dllGetter = dllComp.GetMember("S.P1").GetMethod; Assert.False(dllGetter.IsDeclaredReadOnly); @@ -1664,13 +1664,13 @@ public struct S public int P1 { readonly get; private set; } } "; - var moduleComp = CreateCompilation(csharp, options: TestOptions.DebugModule, targetFramework: TargetFramework.Mscorlib45); + var moduleComp = CreateCompilation(csharp, options: TestOptions.DebugModule, targetFramework: TargetFramework.Mscorlib461); moduleComp.VerifyDiagnostics( // (12,30): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.IsReadOnlyAttribute..ctor' // public int P1 { readonly get; private set; } Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "get").WithArguments("System.Runtime.CompilerServices.IsReadOnlyAttribute", ".ctor").WithLocation(12, 30)); - var dllComp = CreateCompilation(csharp, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib45); + var dllComp = CreateCompilation(csharp, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461); dllComp.VerifyDiagnostics( // (12,30): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.IsReadOnlyAttribute..ctor' // public int P1 { readonly get; private set; } @@ -1686,13 +1686,13 @@ public struct S public int P1 { readonly get; private set; } } "; - var moduleComp = CreateCompilation(csharp, options: TestOptions.DebugModule, targetFramework: TargetFramework.Mscorlib45); + var moduleComp = CreateCompilation(csharp, options: TestOptions.DebugModule, targetFramework: TargetFramework.Mscorlib461); moduleComp.VerifyDiagnostics( // (4,30): error CS0518: Predefined type 'System.Runtime.CompilerServices.IsReadOnlyAttribute' is not defined or imported // public int P1 { readonly get; private set; } Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "get").WithArguments("System.Runtime.CompilerServices.IsReadOnlyAttribute").WithLocation(4, 30)); - var dllComp = CreateCompilation(csharp, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib45); + var dllComp = CreateCompilation(csharp, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461); dllComp.VerifyDiagnostics(); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs index ddb864685943f..3b21e8954a2a3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs @@ -3997,14 +3997,14 @@ record struct Pos2(int X) // (2,15): error CS0171: Field 'Pos.x' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field. // record struct Pos(int X) Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "Pos").WithArguments("Pos.x", "11.0").WithLocation(2, 15), - // (5,16): error CS8050: Only auto-implemented properties can have initializers. + // (5,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public int X { get { return x; } set { x = value; } } = X; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16) ); comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyEmitDiagnostics( - // (5,16): error CS8050: Only auto-implemented properties can have initializers. + // (5,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public int X { get { return x; } set { x = value; } } = X; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16) ); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs index d81418ff4961c..937a9988ccf5d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs @@ -3369,6 +3369,89 @@ static void Test() ); } + [Fact] + public void RefLikeEscapeMixingObjectInitializer4() + { + var tree = SyntaxFactory.ParseSyntaxTree(""" + using System; + + public ref struct S1 + { + public S1(ref Span span) { } + int this[in Span span] { get => 0; set {} } + + static void Test() + { + Span stackSpan = stackalloc int[10]; + Span heapSpan = default; + + var local1 = new S1(ref heapSpan) { [heapSpan] = 0 }; + var local2 = new S1(ref heapSpan) { [stackSpan] = 0 }; // 1 + var local3 = new S1(ref stackSpan) { [heapSpan] = 0 }; + var local4 = new S1(ref stackSpan) { [stackSpan] = 0 }; + } + } + + public ref struct S2 + { + public S2(scoped ref Span span) { } + int this[Span span] { get => 0; set {} } + + static void Test() + { + Span stackSpan = stackalloc int[10]; + Span heapSpan = default; + + var local1 = new S2(ref heapSpan) { [heapSpan] = 0 }; + var local2 = new S2(ref heapSpan) { [stackSpan] = 0 }; + var local3 = new S2(ref stackSpan) { [heapSpan] = 0 }; + var local4 = new S2(ref stackSpan) { [stackSpan] = 0 }; + } + } + + public ref struct S3 + { + public S3(ref Span span) { } + int this[scoped Span span] { get => 0; set {} } + + static void Test() + { + Span stackSpan = stackalloc int[10]; + Span heapSpan = default; + + var local1 = new S3(ref heapSpan) { [heapSpan] = 0 }; + var local2 = new S3(ref heapSpan) { [stackSpan] = 0 }; + var local3 = new S3(ref stackSpan) { [heapSpan] = 0 }; + var local4 = new S3(ref stackSpan) { [stackSpan] = 0 }; + } + } + + public struct S5 + { + public S5(Span span) { } + Span this[int index] { get => default; set { } } + + static void Test() + { + Span stackSpan = stackalloc int[] { 13 }; + Span heapSpan = default; + + S5 local; + local = new S5(stackSpan) { [0] = stackSpan }; + local = new S5(stackSpan) { [0] = heapSpan }; + local = new S5(heapSpan) { [0] = stackSpan }; + local = new S5(heapSpan) { [0] = heapSpan }; + } + } + """, TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp11)); + var comp = CreateCompilationWithSpan(tree, TestOptions.UnsafeDebugDll); + comp.VerifyEmitDiagnostics( + // (14,33): error CS8350: This combination of arguments to 'S1.S1(ref Span)' is disallowed because it may expose variables referenced by parameter 'span' outside of their declaration scope + // var local2 = new S1(ref heapSpan) { [stackSpan] = 0 }; // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "heapSpan").WithArguments("S1.S1(ref System.Span)", "span").WithLocation(14, 33) + ); + } + [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] @@ -3946,6 +4029,103 @@ static void Test() ); } + [Fact] + public void ObjectInitializer_Indexer_In_Escape() + { + var code = """ + using System; + using System.Diagnostics.CodeAnalysis; + + public ref struct S1 + { + public S1() { } + string this[in int x] { get => default; set { } } + + static void Test(int[] array, int x) + { + int y = 0; + S1 local; + + local = new() { [in array[0]] = "" }; + local = new() { [in x] = "" }; + local = new() { [in y] = "" }; + local = new() { [0] = "" }; + } + } + + public ref struct S2 + { + public S2() { } + string this[[UnscopedRef] in int x] { get => default; set { } } + + static void Test(int x, in int y, [UnscopedRef] in int z) + { + S2 local = default; + local = new() { [x] = "" }; // 1 + local = new() { [y] = "" }; // 2 + local = new() { [z] = "" }; + local[x] = ""; // 3 + local[y] = ""; // 4 + local[z] = ""; + } + } + """; + + var comp = CreateCompilationWithSpan([code, UnscopedRefAttributeDefinition], TestOptions.UnsafeDebugDll, TestOptions.Regular11); + comp.VerifyEmitDiagnostics( + // (29,23): error CS8352: Cannot use variable '[x] = ""' in this context because it may expose referenced variables outside of their declaration scope + // local = new() { [x] = "" }; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, @"{ [x] = """" }").WithArguments(@"[x] = """"").WithLocation(29, 23), + // (30,23): error CS8352: Cannot use variable '[y] = ""' in this context because it may expose referenced variables outside of their declaration scope + // local = new() { [y] = "" }; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, @"{ [y] = """" }").WithArguments(@"[y] = """"").WithLocation(30, 23), + // (32,9): error CS8350: This combination of arguments to 'S2.this[in int]' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope + // local[x] = ""; // 3 + Diagnostic(ErrorCode.ERR_CallArgMixing, "local[x]").WithArguments("S2.this[in int]", "x").WithLocation(32, 9), + // (32,15): error CS8166: Cannot return a parameter by reference 'x' because it is not a ref parameter + // local[x] = ""; // 3 + Diagnostic(ErrorCode.ERR_RefReturnParameter, "x").WithArguments("x").WithLocation(32, 15), + // (33,9): error CS8350: This combination of arguments to 'S2.this[in int]' is disallowed because it may expose variables referenced by parameter 'x' outside of their declaration scope + // local[y] = ""; // 4 + Diagnostic(ErrorCode.ERR_CallArgMixing, "local[y]").WithArguments("S2.this[in int]", "x").WithLocation(33, 9), + // (33,15): error CS9077: Cannot return a parameter by reference 'y' through a ref parameter; it can only be returned in a return statement + // local[y] = ""; // 4 + Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "y").WithArguments("y").WithLocation(33, 15) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/66056")] + public void ObjectInitializer_Indexer_Unscoped() + { + var code = """ + using System; + using System.Diagnostics.CodeAnalysis; + + public ref struct S1 + { + public S1() { } + string this[[UnscopedRef] in int x] { get => default; set { } } + + static S1 Test1(int x) => new S1() { [in x] = "" }; // 1 + static S1 Test2(in int x) => new S1() { [in x] = "" }; + static S1 Test3(scoped in int x) => new S1() { [in x] = "" }; // 2 + static S1 Test3(int[] x) => new S1() { [in x[0]] = "" }; + } + + """; + + var comp = CreateCompilationWithSpan([code, UnscopedRefAttributeDefinition], TestOptions.UnsafeDebugDll, TestOptions.Regular11); + comp.VerifyEmitDiagnostics( + // (9,40): error CS8352: Cannot use variable '[in x] = ""' in this context because it may expose referenced variables outside of their declaration scope + // static S1 Test1(int x) => new S1() { [in x] = "" }; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, @"{ [in x] = """" }").WithArguments(@"[in x] = """"").WithLocation(9, 40), + // (11,50): error CS8352: Cannot use variable '[in x] = ""' in this context because it may expose referenced variables outside of their declaration scope + // static S1 Test3(scoped in int x) => new S1() { [in x] = "" }; // 2 + Diagnostic(ErrorCode.ERR_EscapeVariable, @"{ [in x] = """" }").WithArguments(@"[in x] = """"").WithLocation(11, 50) + ); + } + [Theory] [InlineData(LanguageVersion.CSharp10)] [InlineData(LanguageVersion.CSharp11)] @@ -9489,6 +9669,149 @@ public C M(scoped C c, C c1) CreateCompilation(source, targetFramework: TargetFramework.Net70).VerifyDiagnostics(); } + [Theory] + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] + [WorkItem("https://github.com/dotnet/roslyn/issues/63852")] + public void UserDefinedBinaryOperator_RefStruct_Compound_RegressionTest1(LanguageVersion languageVersion) + { + var tree = SyntaxFactory.ParseSyntaxTree(""" + using System; + + public ref struct S1 + { + public S1(Span span) { } + public static S1 operator +(S1 a, S1 b) => default; + + static void Test() + { + S1 stackLocal = new S1(stackalloc int[1]); + S1 heapLocal = new S1(default); + + stackLocal += stackLocal; + stackLocal += heapLocal; + heapLocal += heapLocal; + heapLocal += stackLocal; // 1 + + } + } + """, TestOptions.Regular.WithLanguageVersion(languageVersion)); + var comp = CreateCompilationWithSpan(tree, TestOptions.UnsafeDebugDll); + comp.VerifyEmitDiagnostics( + // (16,9): error CS8347: Cannot use a result of 'S1.operator +(S1, S1)' in this context because it may expose variables referenced by parameter 'b' outside of their declaration scope + // heapLocal += stackLocal; // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "heapLocal += stackLocal").WithArguments("S1.operator +(S1, S1)", "b").WithLocation(16, 9), + // (16,22): error CS8352: Cannot use variable 'stackLocal' in this context because it may expose referenced variables outside of their declaration scope + // heapLocal += stackLocal; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "stackLocal").WithArguments("stackLocal").WithLocation(16, 22) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/63852")] + public void UserDefinedBinaryOperator_RefStruct_Compound_RegressionTest2() + { + var tree = SyntaxFactory.ParseSyntaxTree(""" + using System; + + public ref struct S1 + { + public S1(Span span) { } + public static S1 operator +(S1 a, S1 b) => default; + + static void Test() + { + S1 stackLocal = new(stackalloc int[1]); + S1 heapLocal = new(default); + + stackLocal += stackLocal; + stackLocal += heapLocal; + heapLocal += heapLocal; + heapLocal += stackLocal; // 1 + + } + } + + public ref struct S2 + { + public S2(Span span) { } + public static S2 operator +(S2 a, scoped S2 b) => default; + + static void Test() + { + S2 stackLocal = new(stackalloc int[1]); + S2 heapLocal = new(default); + + stackLocal += stackLocal; + stackLocal += heapLocal; + heapLocal += heapLocal; + heapLocal += stackLocal; + } + } + + public ref struct S3 + { + public S3(Span span) { } + public static S3 operator +(in S3 a, in S3 b) => default; + + static void Test() + { + S3 stackLocal = new(stackalloc int[1]); + S3 heapLocal = new(default); + + stackLocal += stackLocal; + stackLocal += heapLocal; + heapLocal += heapLocal; // 2 + heapLocal += stackLocal; // 3 + } + } + + public ref struct S4 + { + public S4(Span span) { } + public static S4 operator +(scoped in S4 a, scoped in S4 b) => default; + + static void Test() + { + S4 stackLocal = new(stackalloc int[1]); + S4 heapLocal = new(default); + + stackLocal += stackLocal; + stackLocal += heapLocal; + heapLocal += heapLocal; + heapLocal += stackLocal; // 4 + } + } + """, TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp11)); + var comp = CreateCompilationWithSpan(tree, TestOptions.UnsafeDebugDll); + comp.VerifyEmitDiagnostics( + // (16,9): error CS8347: Cannot use a result of 'S1.operator +(S1, S1)' in this context because it may expose variables referenced by parameter 'b' outside of their declaration scope + // heapLocal += stackLocal; // 1 + Diagnostic(ErrorCode.ERR_EscapeCall, "heapLocal += stackLocal").WithArguments("S1.operator +(S1, S1)", "b").WithLocation(16, 9), + // (16,22): error CS8352: Cannot use variable 'stackLocal' in this context because it may expose referenced variables outside of their declaration scope + // heapLocal += stackLocal; // 1 + Diagnostic(ErrorCode.ERR_EscapeVariable, "stackLocal").WithArguments("stackLocal").WithLocation(16, 22), + // (50,9): error CS8168: Cannot return local 'heapLocal' by reference because it is not a ref local + // heapLocal += heapLocal; // 2 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "heapLocal").WithArguments("heapLocal").WithLocation(50, 9), + // (50,9): error CS8347: Cannot use a result of 'S3.operator +(in S3, in S3)' in this context because it may expose variables referenced by parameter 'a' outside of their declaration scope + // heapLocal += heapLocal; // 2 + Diagnostic(ErrorCode.ERR_EscapeCall, "heapLocal += heapLocal").WithArguments("S3.operator +(in S3, in S3)", "a").WithLocation(50, 9), + // (51,9): error CS8168: Cannot return local 'heapLocal' by reference because it is not a ref local + // heapLocal += stackLocal; // 3 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "heapLocal").WithArguments("heapLocal").WithLocation(51, 9), + // (51,9): error CS8347: Cannot use a result of 'S3.operator +(in S3, in S3)' in this context because it may expose variables referenced by parameter 'a' outside of their declaration scope + // heapLocal += stackLocal; // 3 + Diagnostic(ErrorCode.ERR_EscapeCall, "heapLocal += stackLocal").WithArguments("S3.operator +(in S3, in S3)", "a").WithLocation(51, 9), + // (68,9): error CS8347: Cannot use a result of 'S4.operator +(scoped in S4, scoped in S4)' in this context because it may expose variables referenced by parameter 'b' outside of their declaration scope + // heapLocal += stackLocal; // 4 + Diagnostic(ErrorCode.ERR_EscapeCall, "heapLocal += stackLocal").WithArguments("S4.operator +(scoped in S4, scoped in S4)", "b").WithLocation(68, 9), + // (68,22): error CS8352: Cannot use variable 'stackLocal' in this context because it may expose referenced variables outside of their declaration scope + // heapLocal += stackLocal; // 4 + Diagnostic(ErrorCode.ERR_EscapeVariable, "stackLocal").WithArguments("stackLocal").WithLocation(68, 22) + ); + } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71773")] public void UserDefinedUnaryOperator_RefStruct() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index af3302d0bb501..524e3e7ab5cb4 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -335,7 +335,7 @@ ref struct B { A A; }"; - comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib45); + comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib461); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, verify: Verification.Skipped); @@ -4931,7 +4931,7 @@ static ref R F(__arglist) return ref r; } }"; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyEmitDiagnostics( // (11,20): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference // return ref r; @@ -4958,7 +4958,7 @@ static ref int F2() return ref F1(__arglist(ref i)); } }"; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); comp.VerifyEmitDiagnostics( // (7,20): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // return ref __refvalue(args.GetNextArg(), int); @@ -4989,10 +4989,10 @@ static R F2() } }"; - var comp = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular10); + var comp = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Regular10); comp.VerifyEmitDiagnostics(); - comp = CreateCompilationWithMscorlib45(source); + comp = CreateCompilationWithMscorlib461(source); comp.VerifyEmitDiagnostics( // (12,16): error CS8347: Cannot use a result of 'R.R(ref int)' in this context because it may expose variables referenced by parameter 't' outside of their declaration scope // return new R(ref i); @@ -11540,7 +11540,7 @@ static void Main() A.F(default, 0); } }"; - comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib45); + comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib461); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp); @@ -22447,7 +22447,7 @@ static ref readonly int F2(bool b) return ref r2[0]; // 2 } }"; - comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib45); + comp = CreateCompilation(sourceB, new[] { refA }, targetFramework: TargetFramework.Mscorlib461); comp.VerifyEmitDiagnostics( // (12,27): error CS8168: Cannot return local 'r2' by reference because it is not a ref local // if (b) return ref r2.Get(); // 1 @@ -30084,5 +30084,779 @@ ref struct RS // public RS() => ri = 0; Diagnostic(ErrorCode.WRN_UseDefViolationRefField, "ri").WithArguments("ri").WithLocation(4, 20)); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + public void RefField_AsRefArgument_01() + { + var verifier = CompileAndVerify(""" + ref struct S + { + public ref int F1; + + public static S GetS() => default; + + static void M(ref int x){} + + static void Test1() + { + M(ref GetS().F1); + } + } + """, + verify: Verification.Skipped, + targetFramework: TargetFramework.NetCoreApp); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("S.Test1", +@" +{ + // Code size 19 (0x13) + .maxstack 1 + .locals init (S V_0) + IL_0000: call ""S S.GetS()"" + IL_0005: stloc.0 + IL_0006: ldloca.s V_0 + IL_0008: ldfld ""ref int S.F1"" + IL_000d: call ""void S.M(ref int)"" + IL_0012: ret +} +"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + public void RefField_AsRefArgument_02() + { + var comp = CreateCompilation(""" + ref struct S + { + public ref readonly int F1; + + public static S GetS() => default; + + static void M(ref readonly int x){} + + static void Test1() + { + M(ref GetS().F1); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + + comp.VerifyDiagnostics( + // (11,15): error CS8329: Cannot use field 'F1' as a ref or out value because it is a readonly variable + // M(ref GetS().F1); + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "GetS().F1").WithArguments("field", "F1").WithLocation(11, 15) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + [WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void RefField_AsRefArgument_03() + { + var verifier = CompileAndVerify(""" + ref struct S + { + public ref readonly int F1; + + public static S GetS() => default; + + static void M(ref readonly int x){} + + static void Test1() + { + M(in GetS().F1); + } + } + """, + verify: Verification.Skipped, + targetFramework: TargetFramework.NetCoreApp); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("S.Test1", """ + { + // Code size 19 (0x13) + .maxstack 1 + .locals init (S V_0) + IL_0000: call "S S.GetS()" + IL_0005: stloc.0 + IL_0006: ldloca.s V_0 + IL_0008: ldfld "ref readonly int S.F1" + IL_000d: call "void S.M(ref readonly int)" + IL_0012: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + public void RefField_AsRefArgument_04() + { + var comp = CreateCompilation(""" + ref struct S + { + public ref readonly int F1; + + public static S GetS() => default; + + static void M(in int x){} + + static void Test1() + { + M(ref GetS().F1); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + + comp.VerifyDiagnostics( + // (11,15): error CS8329: Cannot use field 'F1' as a ref or out value because it is a readonly variable + // M(ref GetS().F1); + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "GetS().F1").WithArguments("field", "F1").WithLocation(11, 15) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + [WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void RefField_AsRefArgument_05() + { + var verifier = CompileAndVerify(""" + ref struct S + { + public ref readonly int F1; + + public static S GetS() => default; + + static void M(in int x){} + + static void Test1() + { + M(in GetS().F1); + } + } + """, + verify: Verification.Skipped, + targetFramework: TargetFramework.NetCoreApp); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("S.Test1", """ + { + // Code size 19 (0x13) + .maxstack 1 + .locals init (S V_0) + IL_0000: call "S S.GetS()" + IL_0005: stloc.0 + IL_0006: ldloca.s V_0 + IL_0008: ldfld "ref readonly int S.F1" + IL_000d: call "void S.M(in int)" + IL_0012: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + public void RefField_AsRefArgument_06() + { + var verifier = CompileAndVerify(""" + #pragma warning disable CS0649 // Field 'S.F1' is never assigned to, and will always have its default value 0 + + ref struct S + { + public ref readonly int F1; + + public static S GetS() => default; + + static void M(in int x){} + + static void Test1() + { + M(GetS().F1); + } + } + """, + verify: Verification.Skipped, + targetFramework: TargetFramework.NetCoreApp); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("S.Test1", +@" +{ + // Code size 19 (0x13) + .maxstack 1 + .locals init (S V_0) + IL_0000: call ""S S.GetS()"" + IL_0005: stloc.0 + IL_0006: ldloca.s V_0 + IL_0008: ldfld ""ref readonly int S.F1"" + IL_000d: call ""void S.M(in int)"" + IL_0012: ret +} +"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + public void RefField_AsRefArgument_07() + { + var verifier = CompileAndVerify(""" + ref struct S + { + public readonly ref int F1; + + public static S GetS() => default; + + static void M(ref int x){} + + static void Test1() + { + M(ref GetS().F1); + } + } + """, + verify: Verification.Skipped, + targetFramework: TargetFramework.NetCoreApp); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("S.Test1", +@" +{ + // Code size 19 (0x13) + .maxstack 1 + .locals init (S V_0) + IL_0000: call ""S S.GetS()"" + IL_0005: stloc.0 + IL_0006: ldloca.s V_0 + IL_0008: ldfld ""ref int S.F1"" + IL_000d: call ""void S.M(ref int)"" + IL_0012: ret +} +"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + public void RefField_AsRefArgument_08() + { + var verifier = CompileAndVerify(""" + ref struct S + { + public readonly ref int F1; + + public static S GetS() => default; + + static void M(ref readonly int x){} + + static void Test1() + { + M(ref GetS().F1); + } + } + """, + verify: Verification.Skipped, + targetFramework: TargetFramework.NetCoreApp); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("S.Test1", +@" +{ + // Code size 19 (0x13) + .maxstack 1 + .locals init (S V_0) + IL_0000: call ""S S.GetS()"" + IL_0005: stloc.0 + IL_0006: ldloca.s V_0 + IL_0008: ldfld ""ref int S.F1"" + IL_000d: call ""void S.M(ref readonly int)"" + IL_0012: ret +} +"); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + [WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void RefField_AsRefArgument_09() + { + var verifier = CompileAndVerify(""" + ref struct S + { + public readonly ref int F1; + + public static S GetS() => default; + + static void M(ref readonly int x){} + + static void Test1() + { + M(in GetS().F1); + } + } + """, + verify: Verification.Skipped, + targetFramework: TargetFramework.NetCoreApp); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("S.Test1", """ + { + // Code size 19 (0x13) + .maxstack 1 + .locals init (S V_0) + IL_0000: call "S S.GetS()" + IL_0005: stloc.0 + IL_0006: ldloca.s V_0 + IL_0008: ldfld "ref int S.F1" + IL_000d: call "void S.M(ref readonly int)" + IL_0012: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + public void RefField_AsRefArgument_10() + { + var verifier = CompileAndVerify(""" + ref struct S + { + public readonly ref int F1; + + public static S GetS() => default; + + static void M(in int x){} + + static void Test1() + { + M(ref GetS().F1); + } + } + """, + verify: Verification.Skipped, + targetFramework: TargetFramework.NetCoreApp); + + verifier.VerifyDiagnostics( + // (11,15): warning CS9191: The 'ref' modifier for argument 1 corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead. + // M(ref GetS().F1); + Diagnostic(ErrorCode.WRN_BadArgRef, "GetS().F1").WithArguments("1").WithLocation(11, 15) + ); + + verifier.VerifyIL("S.Test1", +@" +{ + // Code size 19 (0x13) + .maxstack 1 + .locals init (S V_0) + IL_0000: call ""S S.GetS()"" + IL_0005: stloc.0 + IL_0006: ldloca.s V_0 + IL_0008: ldfld ""ref int S.F1"" + IL_000d: call ""void S.M(in int)"" + IL_0012: ret +} +"); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + [WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void RefField_AsRefArgument_11() + { + var verifier = CompileAndVerify(""" + ref struct S + { + public readonly ref int F1; + + public static S GetS() => default; + + static void M(in int x){} + + static void Test1() + { + M(in GetS().F1); + } + } + """, + verify: Verification.Skipped, + targetFramework: TargetFramework.NetCoreApp); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("S.Test1", """ + { + // Code size 19 (0x13) + .maxstack 1 + .locals init (S V_0) + IL_0000: call "S S.GetS()" + IL_0005: stloc.0 + IL_0006: ldloca.s V_0 + IL_0008: ldfld "ref int S.F1" + IL_000d: call "void S.M(in int)" + IL_0012: ret + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75035")] + public void RefField_AsRefArgument_12() + { + var verifier = CompileAndVerify(""" + #pragma warning disable CS0649 // Field 'S.F1' is never assigned to, and will always have its default value 0 + + ref struct S + { + public readonly ref int F1; + + public static S GetS() => default; + + static void M(in int x){} + + static void Test1() + { + M(GetS().F1); + } + } + """, + verify: Verification.Skipped, + targetFramework: TargetFramework.NetCoreApp); + + verifier.VerifyDiagnostics(); + + verifier.VerifyIL("S.Test1", +@" +{ + // Code size 19 (0x13) + .maxstack 1 + .locals init (S V_0) + IL_0000: call ""S S.GetS()"" + IL_0005: stloc.0 + IL_0006: ldloca.s V_0 + IL_0008: ldfld ""ref int S.F1"" + IL_000d: call ""void S.M(in int)"" + IL_0012: ret +} +"); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_RefOfRef() + { + var comp = CreateCompilation(""" + ref struct R + { + public ref int F; + + public static R GetValue() => default; + + static void M(ref readonly int x) { } + + static void Test() + { + M(ref GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_InOfRef() + { + var comp = CreateCompilation(""" + ref struct R + { + public ref int F; + + public static R GetValue() => default; + + static void M(ref readonly int x) { } + + static void Test() + { + M(in GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_InOfRef_Nested() + { + var comp = CreateCompilation(""" + ref struct R + { + public ref int F; + + public R GetR() => default; + + public static R GetValue() => default; + + static void M(ref readonly int x) { } + + static void Test() + { + M(in GetValue().GetR().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_OutOfRef() + { + var comp = CreateCompilation(""" + ref struct R + { + public ref int F; + + public static R GetValue() => default; + + static void M(out int x) => throw null; + + static void Test() + { + M(out GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_ValueOfRef_ToRefReadonly() + { + var comp = CreateCompilation(""" + #pragma warning disable CS0649 // Field 'R.F' is never assigned to, and will always have its default value 0 + + ref struct R + { + public ref int F; + + public static R GetValue() => default; + + static void M(ref readonly int x) { } + + static void Test() + { + M(GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (13,11): warning CS9192: Argument 1 should be passed with 'ref' or 'in' keyword + // M(GetValue().F); + Diagnostic(ErrorCode.WRN_ArgExpectedRefOrIn, "GetValue().F").WithArguments("1").WithLocation(13, 11)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_ValueOfRef_ToIn() + { + var comp = CreateCompilation(""" + #pragma warning disable CS0649 // Field 'R.F' is never assigned to, and will always have its default value 0 + + ref struct R + { + public ref int F; + + public static R GetValue() => default; + + static void M(in int x) { } + + static void Test() + { + M(GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_ValueOfRef_ToRef() + { + var comp = CreateCompilation(""" + #pragma warning disable CS0649 // Field 'R.F' is never assigned to, and will always have its default value 0 + + ref struct R + { + public ref int F; + + public static R GetValue() => default; + + static void M(ref int x) { } + + static void Test() + { + M(GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (13,11): error CS1620: Argument 1 must be passed with the 'ref' keyword + // M(GetValue().F); + Diagnostic(ErrorCode.ERR_BadArgRef, "GetValue().F").WithArguments("1", "ref").WithLocation(13, 11)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_RefOfRefReadonly() + { + var comp = CreateCompilation(""" + ref struct R + { + public ref readonly int F; + + public static R GetValue() => default; + + static void M(ref readonly int x) { } + + static void Test() + { + M(ref GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (11,15): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable + // M(ref GetValue().F); + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "GetValue().F").WithArguments("field", "F").WithLocation(11, 15)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_InOfRefReadonly() + { + var comp = CreateCompilation(""" + ref struct R + { + public ref readonly int F; + + public static R GetValue() => default; + + static void M(ref readonly int x) { } + + static void Test() + { + M(in GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_OutOfRefReadonly() + { + var comp = CreateCompilation(""" + ref struct R + { + public ref readonly int F; + + public static R GetValue() => default; + + static void M(out int x) => throw null; + + static void Test() + { + M(out GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (11,15): error CS8329: Cannot use field 'F' as a ref or out value because it is a readonly variable + // M(out GetValue().F); + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "GetValue().F").WithArguments("field", "F").WithLocation(11, 15)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_ValueOfRefReadonly_ToRefReadonly() + { + var comp = CreateCompilation(""" + #pragma warning disable CS0649 // Field 'R.F' is never assigned to, and will always have its default value 0 + + ref struct R + { + public ref readonly int F; + + public static R GetValue() => default; + + static void M(ref readonly int x) { } + + static void Test() + { + M(GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (13,11): warning CS9195: Argument 1 should be passed with the 'in' keyword + // M(GetValue().F); + Diagnostic(ErrorCode.WRN_ArgExpectedIn, "GetValue().F").WithArguments("1").WithLocation(13, 11)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_ValueOfRefReadonly_ToIn() + { + var comp = CreateCompilation(""" + #pragma warning disable CS0649 // Field 'R.F' is never assigned to, and will always have its default value 0 + + ref struct R + { + public ref readonly int F; + + public static R GetValue() => default; + + static void M(in int x) { } + + static void Test() + { + M(GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75082")] + public void ThroughValue_ValueOfRefReadonly_ToRef() + { + var comp = CreateCompilation(""" + #pragma warning disable CS0649 // Field 'R.F' is never assigned to, and will always have its default value 0 + + ref struct R + { + public ref readonly int F; + + public static R GetValue() => default; + + static void M(ref int x) { } + + static void Test() + { + M(GetValue().F); + } + } + """, + targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (13,11): error CS1620: Argument 1 must be passed with the 'ref' keyword + // M(GetValue().F); + Diagnostic(ErrorCode.ERR_BadArgRef, "GetValue().F").WithArguments("1", "ref").WithLocation(13, 11)); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs index c338cdeac1d2d..a8697628f5712 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs @@ -1028,6 +1028,42 @@ ref int P Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P").WithLocation(8, 9)); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75023")] + public void RefReassignToRefTernary() + { + var source = """ + class C + { + void M(bool b, ref int x, ref int y, ref int z) + { + (b ? ref x : ref y) = ref z; + } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (5,10): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // (b ? ref x : ref y) = ref z; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "b ? ref x : ref y").WithLocation(5, 10)); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75023")] + public void RefReassignToRefAssignment() + { + var source = """ + class C + { + void M(ref int x, ref int y, ref int z) + { + (x = ref y) = ref z; + } + } + """; + CreateCompilation(source).VerifyDiagnostics( + // (5,10): error CS8373: The left-hand side of a ref assignment must be a ref variable. + // (x = ref y) = ref z; + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "x = ref y").WithLocation(5, 10)); + } + [Fact, WorkItem(44153, "https://github.com/dotnet/roslyn/issues/44153")] public void RefErrorProperty() { @@ -2639,7 +2675,7 @@ ref char Goo2(ref char c, ref char b) } }"; var options = TestOptions.Regular; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: options); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: options); comp.VerifyDiagnostics( // (14,13): error CS8149: By-reference returns may only be used in methods that return by reference // return ref b; @@ -2681,7 +2717,7 @@ public static void Main() } }"; var options = TestOptions.Regular; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: options); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: options); comp.VerifyDiagnostics( // (9,50): error CS8149: By-reference returns may only be used in methods that return by reference // char Goo1(ref char a, ref char b) => ref b; @@ -2732,7 +2768,7 @@ void F(object[] a, object[,] a2, int i) public int this[int i] => 1; } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (7,13): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?) // j = a[ref i]; // error 1 Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "a[ref i]").WithArguments("object", "int").WithLocation(7, 13), @@ -3492,7 +3528,7 @@ async Task TestMethod() Write(ref Save(await Task.FromResult(0)), await Task.FromResult(1)); } }"; - CreateCompilationWithMscorlib45(code).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461(code).VerifyEmitDiagnostics( // (26,19): error CS8178: A reference returned by a call to 'TestClass.Save(int)' cannot be preserved across 'await' or 'yield' boundary. // Write(ref Save(await Task.FromResult(0)), await Task.FromResult(1)); Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "Save(await Task.FromResult(0))").WithArguments("TestClass.Save(int)").WithLocation(26, 19) @@ -4407,7 +4443,7 @@ public async Task Do(int i) } "; - CreateCompilationWithMscorlib45(text).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyEmitDiagnostics( // (32,17): error CS8178: A reference returned by a call to 'S.Instance.get' cannot be preserved across 'await' or 'yield' boundary. // var a = S.Instance.Echo(await Do(i - 1)); Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "S.Instance").WithArguments("S.Instance.get").WithLocation(32, 17), @@ -4458,7 +4494,7 @@ async Task TestMethod() inst[1, 2] = await Task.FromResult(1); } }"; - CreateCompilationWithMscorlib45(code).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461(code).VerifyEmitDiagnostics( // (28,9): error CS8178: A reference returned by a call to 'TestClass.Save(int)' cannot be preserved across 'await' or 'yield' boundary. // Save(1) = await Task.FromResult(0); Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "Save(1)").WithArguments("TestClass.Save(int)").WithLocation(28, 9), @@ -4471,7 +4507,7 @@ async Task TestMethod() [Fact] public void RefReadOnlyInAsyncMethodDisallowed() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" using System.Threading.Tasks; class Test { @@ -4489,7 +4525,7 @@ async Task Method(in int p) [Fact] public void RefReadOnlyInIteratorMethodsDisallowed() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" using System.Collections.Generic; class Test { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs index be699d39c1ad2..d28b066fbe8fd 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs @@ -232,7 +232,7 @@ public void ThisIndexerAccessInScript() string test = @" this[1] "; - var compilation = CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.Script); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); @@ -262,7 +262,7 @@ public void MainInScript2() var tree = SyntaxFactory.ParseSyntaxTree(text, options: TestOptions.Script); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); compilation.VerifyDiagnostics( // (1,13): warning CS7022: The entry point of the program is global script code; ignoring 'Main()' entry point. @@ -285,7 +285,7 @@ public void MainInScript1() var tree = SyntaxFactory.ParseSyntaxTree(text, options: TestOptions.Script); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); compilation.VerifyDiagnostics( // (1,13): warning CS7022: The entry point of the program is global script code; ignoring 'Main()' entry point. @@ -442,7 +442,7 @@ enum F { } "; var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script); - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); @@ -484,7 +484,7 @@ public void UsingStaticClass() "; var tree = SyntaxFactory.ParseSyntaxTree(test, options: TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp6)); - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { tree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); @@ -517,7 +517,7 @@ public void Labels() @"L0: ; goto L0;"; var tree = Parse(source, options: TestOptions.Script); - var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false); + var model = CreateCompilationWithMscorlib461(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false); var root = tree.GetCompilationUnitRoot(); var statements = root.ChildNodes().Select(n => ((GlobalStatementSyntax)n).Statement).ToArray(); var symbol0 = model.GetDeclaredSymbol((LabeledStatementSyntax)statements[0]); @@ -533,7 +533,7 @@ public void Variables() @"int x = 1; object y = x;"; var tree = Parse(source, options: TestOptions.Script); - var model = CreateCompilationWithMscorlib45(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false); + var model = CreateCompilationWithMscorlib461(new[] { tree }).GetSemanticModel(tree, ignoreAccessibility: false); var root = tree.GetCompilationUnitRoot(); var declarations = root.ChildNodes().Select(n => ((FieldDeclarationSyntax)n).Declaration.Variables[0]).ToArray(); var symbol0 = model.GetDeclaredSymbol(declarations[0]); @@ -624,7 +624,7 @@ public void CheckedDecimalAddition() decimal d = checked(2M + 1M); "; - var compilation = CreateCompilationWithMscorlib45(new[] { Parse(source, options: TestOptions.Script) }); + var compilation = CreateCompilationWithMscorlib461(new[] { Parse(source, options: TestOptions.Script) }); compilation.VerifyDiagnostics(); } @@ -637,7 +637,7 @@ public void CheckedEnumAddition() FileAccess fa = checked(FileAccess.Read + 1); "; - var compilation = CreateCompilationWithMscorlib45(new[] { Parse(source, options: TestOptions.Script) }); + var compilation = CreateCompilationWithMscorlib461(new[] { Parse(source, options: TestOptions.Script) }); compilation.VerifyDiagnostics(); } @@ -649,7 +649,7 @@ public void DelegateAddition() System.Action a = null; a += null; "; - var compilation = CreateCompilationWithMscorlib45(new[] { Parse(source, options: TestOptions.Script) }); + var compilation = CreateCompilationWithMscorlib461(new[] { Parse(source, options: TestOptions.Script) }); compilation.VerifyDiagnostics(); } @@ -1105,7 +1105,7 @@ public void TopLevelGoto() [Fact] public void DefineExtensionMethods() { - var references = new[] { TestMetadata.Net451.SystemCore }; + var references = new[] { NetFramework.SystemCore }; // No error for extension method defined in interactive session. var s0 = CreateSubmission("static void E(this object o) { }", references); @@ -1132,7 +1132,7 @@ public void FixedBuffer_01() @"fixed int x[3]; "; var tree = Parse(source, options: TestOptions.Script); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics( // (1,11): error CS1642: Fixed size buffer fields may only be members of structs @@ -1152,7 +1152,7 @@ public void FixedBuffer_02() @"fixed var x[3] = 1; "; var tree = Parse(source, options: TestOptions.Script); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }); compilation.VerifyDiagnostics( // (1,16): error CS1003: Syntax error, ',' expected @@ -1178,7 +1178,7 @@ public void Errors_01() var code = "System.Console.WriteLine(1);"; var compilationUnit = CSharp.SyntaxFactory.ParseCompilationUnit(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script)); var syntaxTree = compilationUnit.SyntaxTree; - var compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }); + var compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }); var semanticModel = compilation.GetSemanticModel(syntaxTree, true); MemberAccessExpressionSyntax node5 = ErrorTestsGetNode(syntaxTree); Assert.Equal("WriteLine", node5.Name.ToString()); @@ -1190,7 +1190,7 @@ public void Errors_01() Diagnostic(ErrorCode.ERR_GlobalStatement, "System.Console.WriteLine(1);").WithLocation(1, 1) ); - compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); + compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); semanticModel = compilation.GetSemanticModel(syntaxTree, true); node5 = ErrorTestsGetNode(syntaxTree); Assert.Equal("WriteLine", node5.Name.ToString()); @@ -1205,7 +1205,7 @@ public void Errors_01() ); syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script)); - compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe); + compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }, options: TestOptions.ReleaseExe); semanticModel = compilation.GetSemanticModel(syntaxTree, true); node5 = ErrorTestsGetNode(syntaxTree); Assert.Equal("WriteLine", node5.Name.ToString()); @@ -1214,7 +1214,7 @@ public void Errors_01() CompileAndVerify(compilation, expectedOutput: "1").VerifyDiagnostics(); syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script)); - compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); + compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script")); semanticModel = compilation.GetSemanticModel(syntaxTree, true); node5 = ErrorTestsGetNode(syntaxTree); Assert.Equal("WriteLine", node5.Name.ToString()); @@ -1223,7 +1223,7 @@ public void Errors_01() CompileAndVerify(compilation, expectedOutput: "1").VerifyDiagnostics(); syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script)); - compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("")); + compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("")); semanticModel = compilation.GetSemanticModel(syntaxTree, true); node5 = ErrorTestsGetNode(syntaxTree); Assert.Equal("WriteLine", node5.Name.ToString()); @@ -1235,7 +1235,7 @@ public void Errors_01() ); syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script)); - compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName(null)); + compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName(null)); semanticModel = compilation.GetSemanticModel(syntaxTree, true); node5 = ErrorTestsGetNode(syntaxTree); Assert.Equal("WriteLine", node5.Name.ToString()); @@ -1247,7 +1247,7 @@ public void Errors_01() ); syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script)); - compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("a\0b")); + compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("a\0b")); semanticModel = compilation.GetSemanticModel(syntaxTree, true); node5 = ErrorTestsGetNode(syntaxTree); Assert.Equal("WriteLine", node5.Name.ToString()); @@ -1272,7 +1272,7 @@ public void Errors_02() Assert.Equal("WriteLine", node1.Name.ToString()); Assert.Equal("WriteLine", node2.Name.ToString()); - var compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree1, syntaxTree2 }); + var compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree1, syntaxTree2 }); var semanticModel1 = compilation.GetSemanticModel(syntaxTree1, true); var semanticModel2 = compilation.GetSemanticModel(syntaxTree2, true); Assert.Null(semanticModel1.GetSymbolInfo(node1.Name).Symbol); @@ -1284,7 +1284,7 @@ public void Errors_02() Diagnostic(ErrorCode.ERR_GlobalStatement, "System.Console.WriteLine(1);").WithLocation(2, 1) ); - compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree2, syntaxTree1 }); + compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree2, syntaxTree1 }); semanticModel1 = compilation.GetSemanticModel(syntaxTree1, true); semanticModel2 = compilation.GetSemanticModel(syntaxTree2, true); Assert.Null(semanticModel1.GetSymbolInfo(node1.Name).Symbol); @@ -1305,7 +1305,7 @@ public void Errors_03() var code = "System.Console.WriteLine(out var x, x);"; var compilationUnit = CSharp.SyntaxFactory.ParseCompilationUnit(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script)); var syntaxTree = compilationUnit.SyntaxTree; - var compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }); + var compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }); var semanticModel = compilation.GetSemanticModel(syntaxTree, true); MemberAccessExpressionSyntax node5 = ErrorTestsGetNode(syntaxTree); Assert.Equal("WriteLine", node5.Name.ToString()); @@ -1319,7 +1319,7 @@ public void Errors_03() Diagnostic(ErrorCode.ERR_GlobalStatement, "System.Console.WriteLine(out var x, x);").WithLocation(1, 1) ); - compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script1")); + compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script1")); semanticModel = compilation.GetSemanticModel(syntaxTree, true); node5 = ErrorTestsGetNode(syntaxTree); Assert.Equal("WriteLine", node5.Name.ToString()); @@ -1334,7 +1334,7 @@ public void Errors_03() ); syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script)); - compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }); + compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }); semanticModel = compilation.GetSemanticModel(syntaxTree, true); node5 = ErrorTestsGetNode(syntaxTree); Assert.Equal("WriteLine", node5.Name.ToString()); @@ -1349,7 +1349,7 @@ public void Errors_03() ); syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options: new CSharp.CSharpParseOptions(kind: SourceCodeKind.Script)); - compilation = CreateCompilationWithMscorlib45(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script1")); + compilation = CreateCompilationWithMscorlib461(new[] { syntaxTree }, options: TestOptions.ReleaseExe.WithScriptClassName("Script1")); semanticModel = compilation.GetSemanticModel(syntaxTree, true); node5 = ErrorTestsGetNode(syntaxTree); Assert.Equal("WriteLine", node5.Name.ToString()); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs index da3628474c6a9..1c536714a4cf7 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs @@ -16,7 +16,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -1381,7 +1381,7 @@ void goo() this.goo(); // OK } }"; - var comp = CreateCompilationWithMscorlib45( + var comp = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(text, options: TestOptions.Script) }); comp.VerifyDiagnostics( // (4,9): error CS0027: Keyword 'this' is not available in the current context @@ -3908,7 +3908,7 @@ static void M() const int x = x + x; } }"; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,27): error CS0110: The evaluation of the constant value for 'x' involves a circular definition // const int x = x + x; Diagnostic(ErrorCode.ERR_CircConstValue, "x").WithArguments("x").WithLocation(5, 27), @@ -4010,9 +4010,6 @@ static void N(int q) // (24,17): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // int value = 0; // CS0136 Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "value").WithArguments("value").WithLocation(24, 17), - // (25,15): info CS9258: 'value' is a contextual keyword in property accessors starting in language version preview. Use '@value' instead. - // M(value); - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "value").WithArguments("value", "preview").WithLocation(25, 15), // (30,35): error CS0136: A local or parameter named 'q' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // System.Func f = q=>q; // 0136 Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "q").WithArguments("q").WithLocation(30, 35)); @@ -4027,10 +4024,7 @@ static void N(int q) Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "y").WithArguments("y").WithLocation(9, 17), // (24,17): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // int value = 0; // CS0136 - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "value").WithArguments("value").WithLocation(24, 17), - // (25,15): info CS9258: 'value' is a contextual keyword in property accessors starting in language version preview. Use '@value' instead. - // M(value); - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "value").WithArguments("value", "preview").WithLocation(25, 15)); + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "value").WithArguments("value").WithLocation(24, 17)); } [Fact] @@ -6813,7 +6807,7 @@ public void TestIdenticalEventName() } } "; - CreateCompilation(source, targetFramework: TargetFramework.Mscorlib45).VerifyDiagnostics( + CreateCompilation(source, targetFramework: TargetFramework.Mscorlib461).VerifyDiagnostics( // (9,9): error CS0176: Member 'Delegate.CreateDelegate(Type, object, string)' cannot be accessed with an instance reference; qualify it with a type name instead // D.CreateDelegate(null, null, null); // CS0176 Diagnostic(ErrorCode.ERR_ObjectProhibited, "D.CreateDelegate").WithArguments("System.Delegate.CreateDelegate(System.Type, object, string)").WithLocation(9, 9) @@ -7242,7 +7236,7 @@ static void Main() M(__arglist); } }"; - var comp = CreateCompilation(source, targetFramework: TargetFramework.Mscorlib45); + var comp = CreateCompilation(source, targetFramework: TargetFramework.Mscorlib461); comp.VerifyDiagnostics( // (11,7): error CS0190: The __arglist construct is valid only within a variable argument method // M(__arglist); @@ -7309,7 +7303,7 @@ static void Main() { } }"; - CreateCompilationWithMscorlib45(source).VerifyEmitDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyEmitDiagnostics( // (10,34): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside a nested function, query expression, iterator block or async method // RuntimeArgumentHandle h2 = h; // Bad use of h Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "h").WithArguments("System.RuntimeArgumentHandle").WithLocation(10, 34), @@ -9942,7 +9936,7 @@ static void M() // Note that none of these errors except the first one are reported by the native compiler, because // it does not report additional errors after an error is found in a parameter of a method. - CreateCompilationWithMscorlib40(text, references: new[] { Net40.SystemCore }).VerifyDiagnostics( + CreateCompilationWithMscorlib40(text, references: new[] { Net40.References.SystemCore }).VerifyDiagnostics( // (9,36): error CS0310: 'U' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'D' // internal static void E(D d) { } // Error: missing constraint on E to satisfy constraint on D Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "d").WithArguments("D", "T", "U").WithLocation(9, 36), @@ -10052,7 +10046,7 @@ static class S { internal static void E(this T t) where T : new() { } }"; - CreateCompilationWithMscorlib40(text, references: new[] { Net40.SystemCore }).VerifyDiagnostics( + CreateCompilationWithMscorlib40(text, references: new[] { Net40.References.SystemCore }).VerifyDiagnostics( // (15,9): error CS0310: 'B' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'V' in the generic type or method 'C.M(V)' // M(b); Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "M").WithArguments("C.M(V)", "V", "B").WithLocation(15, 9), @@ -11531,7 +11525,7 @@ public class Test public System.RuntimeArgumentHandle[][] y; } "; - var comp = CreateCompilation(text, targetFramework: TargetFramework.Mscorlib45); + var comp = CreateCompilation(text, targetFramework: TargetFramework.Mscorlib461); comp.VerifyDiagnostics( // (4,12): error CS0611: Array elements cannot be of type 'System.TypedReference' // public System.TypedReference[] x; @@ -11556,7 +11550,7 @@ static void M() var z = new[] { new RuntimeArgumentHandle() }; } }"; - var comp = CreateCompilation(text, targetFramework: TargetFramework.Mscorlib45); + var comp = CreateCompilation(text, targetFramework: TargetFramework.Mscorlib461); comp.VerifyDiagnostics( // (6,17): error CS0611: Array elements cannot be of type 'System.ArgIterator' // var x = new[] { new ArgIterator() }; @@ -11703,7 +11697,7 @@ class C [Fact] public void CS0670ERR_FieldCantHaveVoidType_Var() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" var x = default(void); ", parseOptions: TestOptions.Script).VerifyDiagnostics( // (2,17): error CS1547: Keyword 'void' cannot be used in this context @@ -11879,7 +11873,7 @@ static void N(object o) [Fact] public void CS0723ERR_VarDeclIsStaticClass_Fields() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" static class SC {} var sc2 = new SC(); @@ -12143,7 +12137,7 @@ static void M() {} [Fact] public void CS0815ERR_ImplicitlyTypedVariableAssignedBadValue_Field() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" static void M() {} var m = M; @@ -12190,7 +12184,7 @@ public static int Main() [Fact] public void CS0818ERR_ImplicitlyTypedVariableWithNoInitializer_Fields() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" var a; // CS0818 ", parseOptions: TestOptions.Script).VerifyDiagnostics( // (1,5): error CS0818: Implicitly-typed variables must be initialized @@ -12225,7 +12219,7 @@ public static int Main() [Fact] public void CS0819ERR_ImplicitlyTypedVariableMultipleDeclarator_Fields() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" var goo = 4, bar = 4.5; ", parseOptions: TestOptions.Script).VerifyDiagnostics( // (2,1): error CS0819: Implicitly-typed fields cannot have multiple declarators @@ -12257,7 +12251,7 @@ public static int Main() [Fact] public void CS0820ERR_ImplicitlyTypedVariableAssignedArrayInitializer_Fields() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" var y = { 1, 2, 3 }; ", parseOptions: TestOptions.Script).VerifyDiagnostics( // (1,5): error CS0820: Cannot initialize an implicitly-typed variable with an array initializer @@ -12322,7 +12316,7 @@ public static void Main() [Fact] public void CS0822ERR_ImplicitlyTypedVariableCannotBeConst_Fields() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" const var x = 0; // CS0822.cs ", parseOptions: TestOptions.Script).VerifyDiagnostics( // (2,7): error CS0822: Implicitly-typed variables cannot be constant @@ -12332,7 +12326,7 @@ public void CS0822ERR_ImplicitlyTypedVariableCannotBeConst_Fields() [Fact] public void CS0825ERR_ImplicitlyTypedVariableCannotBeUsedAsTheTypeOfAParameter_Fields() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" void goo(var arg) { } var goo(int arg) { return 2; } ", parseOptions: TestOptions.Script).VerifyDiagnostics( @@ -12345,7 +12339,7 @@ void goo(var arg) { } [Fact] public void CS0825ERR_ImplicitlyTypedVariableCannotBeUsedAsTheTypeOfAParameter_Fields2() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" T goo() { return default(T); } goo(); ", parseOptions: TestOptions.Script).VerifyDiagnostics( @@ -12905,7 +12899,7 @@ static void M() [Fact] public void CS0841ERR_VariableUsedBeforeDeclaration04() { - var systemRef = Net451.System; + var systemRef = NetFramework.System; CreateCompilationWithMscorlib40AndSystemCore( @"using System.Collections.Generic; class Base @@ -13746,7 +13740,7 @@ static void M3(this E e) { } static void M4(this S s) { } static void M5(this double d) { } }"; - CreateCompilationWithMscorlib40(source, references: new[] { Net40.SystemCore }).VerifyDiagnostics( + CreateCompilationWithMscorlib40(source, references: new[] { Net40.References.SystemCore }).VerifyDiagnostics( // (24,29): error CS1113: Extension methods 'SC.M3(E)' defined on value type 'E' cannot be used to create delegates Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "e.M3").WithArguments("SC.M3(E)", "E").WithLocation(24, 29), // (26,29): error CS1113: Extension methods 'SC.M4(S)' defined on value type 'S' cannot be used to create delegates @@ -13792,7 +13786,7 @@ static class E internal static void M1(this T t) { } internal static void M2(this T t) { } }"; - CreateCompilationWithMscorlib40(source, references: new[] { Net40.SystemCore }).VerifyDiagnostics( + CreateCompilationWithMscorlib40(source, references: new[] { Net40.References.SystemCore }).VerifyDiagnostics( // (13,13): error CS1113: Extension methods 'E.M1(int)' defined on value type 'int' cannot be used to create delegates Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "i.M1").WithArguments("E.M1(int)", "int").WithLocation(13, 13), // (14,13): error CS1113: Extension methods 'E.M2(int)' defined on value type 'int' cannot be used to create delegates @@ -13853,7 +13847,7 @@ static class E internal static void M1(this T t) { } internal static void M2(this T t) { } }"; - CreateCompilation(source, references: new[] { Net40.SystemCore }).VerifyDiagnostics( + CreateCompilation(source, references: new[] { Net40.References.SystemCore }).VerifyDiagnostics( // (12,11): error CS1113: Extension methods 'E.M1(int)' defined on value type 'int' cannot be used to create delegates Diagnostic(ErrorCode.ERR_ValueTypeExtDelegate, "i.M1").WithArguments("E.M1(int)", "int").WithLocation(12, 11), // (13,11): error CS1113: Extension methods 'E.M2(int)' defined on value type 'int' cannot be used to create delegates @@ -16980,7 +16974,7 @@ static class S { internal static void F(this double d) { } }"; - var compilation = CreateCompilationWithMscorlib40(text, references: new[] { Net40.SystemCore }); + var compilation = CreateCompilationWithMscorlib40(text, references: new[] { Net40.References.SystemCore }); // Previously ERR_BadExtensionArgTypes. compilation.VerifyDiagnostics( // (5,9): error CS1929: 'float' does not contain a definition for 'F' and the best extension method overload 'S.F(double)' requires a receiver of type 'double' @@ -17003,7 +16997,7 @@ static class S { internal static void E(this B b) { } }"; - var compilation = CreateCompilationWithMscorlib40(source, references: new[] { Net40.SystemCore }); + var compilation = CreateCompilationWithMscorlib40(source, references: new[] { Net40.References.SystemCore }); compilation.VerifyDiagnostics( // (6,9): error CS1929: 'A' does not contain a definition for 'E' and the best extension method overload 'S.E(B)' requires a receiver of type 'B' // a.E(); @@ -21585,7 +21579,7 @@ static int Main() } "; - var compilation = CreateCompilation(text, targetFramework: TargetFramework.Mscorlib45, options: TestOptions.DebugExe); + var compilation = CreateCompilation(text, targetFramework: TargetFramework.Mscorlib461, options: TestOptions.DebugExe); var exebits = new System.IO.MemoryStream(); var pdbbits = new System.IO.MemoryStream(); @@ -22585,7 +22579,7 @@ static void M() } static void E(this object o) { } }"; - CreateCompilationWithMscorlib40(source, references: new[] { Net40.SystemCore }, parseOptions: TestOptions.Regular7_3).VerifyDiagnostics( + CreateCompilationWithMscorlib40(source, references: new[] { Net40.References.SystemCore }, parseOptions: TestOptions.Regular7_3).VerifyDiagnostics( // (20,9): warning CS1720: Expression will always cause a System.NullReferenceException because the default value of 'object' is null // default(object).GetHashCode(); Diagnostic(ErrorCode.WRN_DotOnDefault, "default(object).GetHashCode").WithArguments("object").WithLocation(20, 9), @@ -22598,7 +22592,7 @@ static void E(this object o) { } // (28,9): warning CS1720: Expression will always cause a System.NullReferenceException because the default value of 'T6' is null // default(T6).P = null; Diagnostic(ErrorCode.WRN_DotOnDefault, "default(T6).P").WithArguments("T6").WithLocation(28, 9)); - CreateCompilationWithMscorlib40(source, references: new[] { Net40.SystemCore }, options: TestOptions.ReleaseDll.WithNullableContextOptions(NullableContextOptions.Disable)).VerifyDiagnostics( + CreateCompilationWithMscorlib40(source, references: new[] { Net40.References.SystemCore }, options: TestOptions.ReleaseDll.WithNullableContextOptions(NullableContextOptions.Disable)).VerifyDiagnostics( ); } @@ -22692,13 +22686,13 @@ internal static bool IsNull(this string val) } } "; - CompileAndVerifyWithMscorlib40(source, expectedOutput: "True", references: new[] { Net40.SystemCore }, parseOptions: TestOptions.Regular7_3).VerifyDiagnostics( + CompileAndVerifyWithMscorlib40(source, expectedOutput: "True", references: new[] { Net40.References.SystemCore }, parseOptions: TestOptions.Regular7_3).VerifyDiagnostics( // Do not report the following warning: // (5,34): warning CS1720: Expression will always cause a System.NullReferenceException because the default value of 'string' is null // System.Console.WriteLine(default(string).IsNull()); // Diagnostic(ErrorCode.WRN_DotOnDefault, "default(string).IsNull").WithArguments("string").WithLocation(5, 34) ); - CompileAndVerifyWithMscorlib40(source, expectedOutput: "True", references: new[] { Net40.SystemCore }).VerifyDiagnostics(); + CompileAndVerifyWithMscorlib40(source, expectedOutput: "True", references: new[] { Net40.References.SystemCore }).VerifyDiagnostics(); } [Fact] @@ -24099,7 +24093,7 @@ static void Main(string[] args) } } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (13,21): error CS0023: Operator '?' cannot be applied to operand of type 'int' // var x = 123 ?.ToString(); Diagnostic(ErrorCode.ERR_BadUnaryOp, "?").WithArguments("?", "int").WithLocation(13, 21), @@ -24167,7 +24161,7 @@ static void Main(string[] args) } } "; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (14,24): error CS8977: 'method group' cannot be made nullable. // var x1 = p.P1 ?.ToString; Diagnostic(ErrorCode.ERR_CannotBeMadeNullable, ".ToString").WithArguments("method group").WithLocation(14, 24) @@ -24206,7 +24200,7 @@ static void Main(string[] args) } } "; - var compilation = CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + var compilation = CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (11,18): error CS0175: Use of keyword 'base' is not valid in this context // var x6 = base?.ToString(); Diagnostic(ErrorCode.ERR_BaseIllegal, "base").WithLocation(11, 18), @@ -24264,7 +24258,7 @@ unsafe static void Main() } "; - CreateCompilationWithMscorlib45(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (9,24): error CS8977: 'void*' cannot be made nullable. // var p = intPtr?.ToPointer(); Diagnostic(ErrorCode.ERR_CannotBeMadeNullable, ".ToPointer()").WithArguments("void*").WithLocation(9, 24) @@ -24296,7 +24290,7 @@ static void Main() } } "; - CreateCompilationWithMscorlib45(text, new[] { Net451.System, Net451.SystemCore, Net451.MicrosoftCSharp }, options: TestOptions.ReleaseDll).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text, new[] { NetFramework.System, NetFramework.SystemCore, NetFramework.MicrosoftCSharp }, options: TestOptions.ReleaseDll).VerifyDiagnostics( // (9,44): error CS8072: An expression tree lambda may not contain a null propagating operator. // Expression> s = () => x?.ToString(); Diagnostic(ErrorCode.ERR_NullPropagatingOpInExpressionTree, "x?.ToString()").WithLocation(9, 44), @@ -24337,7 +24331,7 @@ static void Main() } } "; - CreateCompilationWithMscorlib45(text, new[] { Net451.System, Net451.SystemCore, Net451.MicrosoftCSharp }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text, new[] { NetFramework.System, NetFramework.SystemCore, NetFramework.MicrosoftCSharp }).VerifyDiagnostics( // (10,87): error CS8073: An expression tree lambda may not contain a dictionary initializer. // Expression>> s = () => new Dictionary () {[1] = 2}; Diagnostic(ErrorCode.ERR_DictionaryInitializerInExpressionTree, "[1]").WithLocation(10, 87) @@ -24377,7 +24371,7 @@ class Goo } "; - CreateCompilationWithMscorlib45(text, new[] { Net451.System, Net451.SystemCore, Net451.MicrosoftCSharp }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text, new[] { NetFramework.System, NetFramework.SystemCore, NetFramework.MicrosoftCSharp }).VerifyDiagnostics( // (25,72): error CS8075: An expression tree lambda may not contain an extension collection element initializer. // public Expression>> E = () => new Stack { 42 }; Diagnostic(ErrorCode.ERR_ExtensionCollectionElementInitializerInExpressionTree, "42").WithLocation(25, 72) @@ -24405,7 +24399,7 @@ static void Main() } "; - CreateCompilationWithMscorlib45(text, new[] { Net451.System, Net451.SystemCore, Net451.MicrosoftCSharp }).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text, new[] { NetFramework.System, NetFramework.SystemCore, NetFramework.MicrosoftCSharp }).VerifyDiagnostics( // (9,53): error CS8073: An expression tree lambda may not contain a dictionary initializer. // Expression> e = () => new C { H = { ["Key"] = "Value" } }; Diagnostic(ErrorCode.ERR_DictionaryInitializerInExpressionTree, @"[""Key""]").WithLocation(9, 53) @@ -24559,7 +24553,7 @@ static void Main() } } "; - CreateCompilationWithMscorlib45(text, + CreateCompilationWithMscorlib461(text, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp5)).VerifyDiagnostics( // (8,46): error CS8026: Feature 'dictionary initializer' is not available in C# 5. Please use language version 6 or greater. @@ -24593,7 +24587,7 @@ static void Goo() } } "; - CreateCompilationWithMscorlib45(text, + CreateCompilationWithMscorlib461(text, new[] { SystemRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929, CSharpRef }, parseOptions: TestOptions.Regular).VerifyDiagnostics( // (9,47): error CS0165: Use of unassigned local variable 'i' @@ -24618,7 +24612,7 @@ static void Main() } } "; - CreateCompilationWithMscorlib45(text, options: TestOptions.ReleaseDll).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text, options: TestOptions.ReleaseDll).VerifyDiagnostics( // (8,9): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // x?.Length; Diagnostic(ErrorCode.ERR_IllegalStatement, "x?.Length").WithLocation(8, 9), @@ -24664,7 +24658,7 @@ public ref struct S2 public S1 field; } "; - CreateCompilationWithMscorlib45(text, options: TestOptions.ReleaseDll).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text, options: TestOptions.ReleaseDll).VerifyDiagnostics( // (10,19): error CS8977: 'S2' cannot be made nullable. // var x = o?.F(); Diagnostic(ErrorCode.ERR_CannotBeMadeNullable, ".F()").WithArguments("S2").WithLocation(10, 19), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs index 09bf15745a0ba..b8b1b411deac3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs @@ -941,7 +941,7 @@ .locals init (Program.S1 V_0) [WorkItem(20226, "https://github.com/dotnet/roslyn/issues/20226")] [Fact] - public void RefIteratorInAsync() + public void RefIteratorInAsync_01() { var text = @" using System; @@ -987,18 +987,87 @@ public bool MoveNext() "; - CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (15,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // foreach (var i in obj) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(15, 9)); - comp.VerifyDiagnostics( - // (15,9): error CS8344: foreach statement cannot operate on enumerators of type 'C1.S1' in async or iterator methods because 'C1.S1' is a ref struct or a type parameter that allows ref struct. + var expectedDiagnostics = new[] + { + // (15,9): error CS4007: Instance of type 'C1.S1' cannot be preserved across 'await' or 'yield' boundary. // foreach (var i in obj) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C1.S1").WithLocation(15, 9) - ); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"foreach (var i in obj) + { + await Task.Yield(); + System.Console.WriteLine(i); + }").WithArguments("C1.S1").WithLocation(15, 9) + }; + + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithMscorlibAndSpan(text).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74793")] + public void RefIteratorInAsync_02() + { + var text = @" +using System.Threading.Tasks; + +class Program +{ + static async Task Main() + { + var obj = new C1(); + + foreach (var i in obj) + { + System.Console.Write(i); + } + + await Task.Yield(); + + System.Console.Write(-1); + } +} + +class C1 +{ + public S1 GetEnumerator() + { + return new S1(); + } + + public ref struct S1 + { + public int Current { get; private set; } + + public bool MoveNext() + { + Current++; + return Current < 3; + } + } +} + +"; + + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (10,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // foreach (var i in obj) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(10, 9)); + + var expectedOutput = "12-1"; + + var comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe, TestOptions.Regular13); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + + comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); } [WorkItem(20226, "https://github.com/dotnet/roslyn/issues/20226")] [Fact] - public void RefIteratorInIterator() + public void RefIteratorInIterator_01() { var text = @" using System; @@ -1034,6 +1103,7 @@ static IEnumerable Test() // this is an error foreach (var i in new C1()) { + yield return 0; } yield return 1; @@ -1059,13 +1129,87 @@ public bool MoveNext() } "; - CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (33,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // foreach (var i in new C1()) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(33, 9)); - comp.VerifyDiagnostics( - // (33,9): error CS8344: foreach statement cannot operate on enumerators of type 'C1.S1' in async or iterator methods because 'C1.S1' is a ref struct or a type parameter that allows ref struct. + var expectedDiagnostics = new[] + { + // (33,9): error CS4007: Instance of type 'C1.S1' cannot be preserved across 'await' or 'yield' boundary. // foreach (var i in new C1()) - Diagnostic(ErrorCode.ERR_BadSpecialByRefIterator, "foreach").WithArguments("C1.S1").WithLocation(33, 9) - ); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, @"foreach (var i in new C1()) + { + yield return 0; + }").WithArguments("C1.S1").WithLocation(33, 9) + }; + + CreateCompilationWithMscorlibAndSpan(text, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics); + CreateCompilationWithMscorlibAndSpan(text).VerifyEmitDiagnostics(expectedDiagnostics); + } + + [Fact] + public void RefIteratorInIterator_02() + { + var text = @" +using System; +using System.Collections.Generic; + +class Program +{ + static void Main(string[] args) + { + foreach (var i in Test()) + { + Console.Write(i); + } + } + + static IEnumerable Test() + { + foreach (var i in new C1()) + { + Console.Write(i); + } + + yield return -1; + + Console.Write(-2); + } +} + +class C1 +{ + public S1 GetEnumerator() + { + return new S1(); + } + + public ref struct S1 + { + public int Current { get; private set; } + + public bool MoveNext() + { + Current++; + return Current < 3; + } + } +} +"; + + CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe, TestOptions.Regular12).VerifyDiagnostics( + // (17,9): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. + // foreach (var i in new C1()) + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "foreach").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(17, 9)); + + var expectedOutput = "12-1-2"; + + var comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe, TestOptions.Regular13); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); + + comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: expectedOutput, verify: Verification.FailsILVerify).VerifyDiagnostics(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs index 5b0e41ef03aa2..f4473b324d7aa 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/StructConstructorTests.cs @@ -3232,7 +3232,7 @@ static void Main() Console.WriteLine(new S3().X); } }"; - comp = CreateCompilation(sourceB, references: new[] { refA }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.Mscorlib45); + comp = CreateCompilation(sourceB, references: new[] { refA }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9, targetFramework: TargetFramework.Mscorlib461); CompileAndVerify(comp, expectedOutput: @"2 0"); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs index 853cac424e3ae..3a48f854b3685 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics { @@ -370,7 +371,7 @@ .maxstack 2 [Fact] public void RetargetedSynthesizedStructConstructor() { - var oldMsCorLib = TestMetadata.Net40.mscorlib; + var oldMsCorLib = Net40.References.mscorlib; var c1 = CSharpCompilation.Create("C1", new[] { Parse(@"public struct S { }") }, @@ -609,7 +610,7 @@ public struct X public X? recursiveFld; } "; - CreateCompilation(source, targetFramework: TargetFramework.Mscorlib45).VerifyDiagnostics( + CreateCompilation(source, targetFramework: TargetFramework.Mscorlib461).VerifyDiagnostics( // (4,15): error CS0523: Struct member 'X.recursiveFld' of type 'X?' causes a cycle in the struct layout // public X? recursiveFld; Diagnostic(ErrorCode.ERR_StructLayoutCycle, "recursiveFld").WithArguments("X.recursiveFld", "X?") @@ -673,7 +674,7 @@ public void StructNonAutoPropertyInitializer() // (3,16): error CS8773: Feature 'struct field initializers' is not available in C# 9.0. Please use language version 10.0 or greater. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "I").WithArguments("struct field initializers", "10.0").WithLocation(3, 16), - // (3,16): error CS8050: Only auto-implemented properties can have initializers. + // (3,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(3, 16)); @@ -682,7 +683,7 @@ public void StructNonAutoPropertyInitializer() // (1,8): error CS8983: A 'struct' with field initializers must include an explicitly declared constructor. // struct S Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S").WithLocation(1, 8), - // (3,16): error CS8050: Only auto-implemented properties can have initializers. + // (3,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public int I { get { throw null; } set {} } = 9; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(3, 16)); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs index 108df11815a37..cdf89bc5dfc13 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs @@ -2392,7 +2392,7 @@ public void SwitchFallOut_Script() case 2: Console.WriteLine(2); }"; - CreateCompilationWithMscorlib45(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef }, parseOptions: TestOptions.Script).VerifyDiagnostics( // (4,5): error CS0163: Control cannot fall through from one case label ('default:') to another // default: Diagnostic(ErrorCode.ERR_SwitchFallThrough, "default:").WithArguments("default:").WithLocation(4, 5), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TypeOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TypeOfTests.cs index fb6da4b4f8889..61ee254c26203 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TypeOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TypeOfTests.cs @@ -27,7 +27,7 @@ public C(int i) } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var node = (ObjectCreationExpressionSyntax)tree.GetRoot().DescendantNodes().Where(n => n.ToString() == "new C(0)").Last(); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs index cdc7c38eca163..22c58d94fdcf9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs @@ -2631,6 +2631,9 @@ public C() // (5,19): error CS0548: 'C.P': property or indexer must have at least one accessor // public string P { } Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "P").WithArguments("C.P").WithLocation(5, 19), + // (7,19): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // public string P3 { } = string.Empty; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(7, 19), // (7,19): error CS0548: 'C.P3': property or indexer must have at least one accessor // public string P3 { } = string.Empty; Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "P3").WithArguments("C.P3").WithLocation(7, 19), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 746ea4fedd118..975aaf9cc10b7 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -73,7 +73,7 @@ unsafe void M(byte* p) unsafe IntPtr M2(IntPtr p) => p; }"; - var comp2 = CreateCompilationWithMscorlib45(text2, + var comp2 = CreateCompilationWithMscorlib461(text2, references: new[] { ref1 }, options: TestOptions.UnsafeDebugDll); comp2.VerifyDiagnostics( diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UseSiteErrorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UseSiteErrorTests.cs index 1db2d5c04601c..172b3255fee4b 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UseSiteErrorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UseSiteErrorTests.cs @@ -1021,39 +1021,49 @@ public static void bar2(int p) [Fact, WorkItem(531090, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/531090")] public void Constructor() { - string srcLib1 = @" -using System; + string delSource = """ + using System; -public sealed class A -{ - public A(int a, Func example) {} - public A(Func example) {} -} -"; + public delegate string MyFunc(string arg); + """; + var delComp = CreateEmptyCompilation( + delSource, + assemblyName: "Delegate.Util", + references: [NetFramework.mscorlib], + options: TestOptions.ReleaseDll.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default)); - var lib1 = CreateEmptyCompilation( - new[] { Parse(srcLib1) }, - new[] { TestMetadata.Net20.mscorlib, TestMetadata.Net35.SystemCore }, + string lib1Source = """ + using System; + + public sealed class A + { + public A(int a, MyFunc example) {} + public A(MyFunc example) {} + } + """; + var lib1Comp = CreateEmptyCompilation( + lib1Source, + references: [NetFramework.mscorlib, delComp.ToMetadataReference()], TestOptions.ReleaseDll.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default)); - string srcLib2 = @" -class Program -{ - static void Main() - { - new A(x => x); - } -} -"; - var lib2 = CreateEmptyCompilation( - new[] { Parse(srcLib2) }, - new[] { MscorlibRef, new CSharpCompilationReference(lib1) }, + string lib2Source = """ + class Program + { + static void Main() + { + new A(x => x); + } + } + """; + var lib2Comp = CreateEmptyCompilation( + lib2Source, + references: [NetFramework.mscorlib, lib1Comp.ToMetadataReference()], TestOptions.ReleaseDll.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default)); - lib2.VerifyDiagnostics( - // (6,13): error CS0012: The type 'System.Func<,>' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. + lib2Comp.VerifyDiagnostics( + // (5,13): error CS0012: The type 'MyFunc' is defined in an assembly that is not referenced. You must add a reference to assembly 'Delegate.Util, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. // new A(x => x); - Diagnostic(ErrorCode.ERR_NoTypeDef, "A").WithArguments("System.Func<,>", "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")); + Diagnostic(ErrorCode.ERR_NoTypeDef, "A").WithArguments("MyFunc", "Delegate.Util, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null").WithLocation(5, 13)); } [Fact, WorkItem(530974, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530974")] diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs index c512d89774c85..8370bf4a28641 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs @@ -3051,12 +3051,17 @@ class C { } }); } +#pragma warning disable RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + [Theory] [CombinatorialData] [InlineData(IncrementalGeneratorOutputKind.Source | IncrementalGeneratorOutputKind.Implementation)] [InlineData(IncrementalGeneratorOutputKind.Source | IncrementalGeneratorOutputKind.PostInit)] [InlineData(IncrementalGeneratorOutputKind.Implementation | IncrementalGeneratorOutputKind.PostInit)] + [InlineData(IncrementalGeneratorOutputKind.Source | IncrementalGeneratorOutputKind.Host)] + [InlineData(IncrementalGeneratorOutputKind.Implementation | IncrementalGeneratorOutputKind.Host)] [InlineData(IncrementalGeneratorOutputKind.Source | IncrementalGeneratorOutputKind.Implementation | IncrementalGeneratorOutputKind.PostInit)] + [InlineData(IncrementalGeneratorOutputKind.Source | IncrementalGeneratorOutputKind.Implementation | IncrementalGeneratorOutputKind.PostInit | IncrementalGeneratorOutputKind.Host)] public void Generator_Output_Kinds_Can_Be_Disabled(IncrementalGeneratorOutputKind disabledOutput) { var source = @" @@ -3072,6 +3077,7 @@ class C { } ctx.RegisterPostInitializationOutput((context) => context.AddSource("PostInit", "")); ctx.RegisterSourceOutput(ctx.CompilationProvider, (context, ct) => context.AddSource("Source", "")); ctx.RegisterImplementationSourceOutput(ctx.CompilationProvider, (context, ct) => context.AddSource("Implementation", "")); + ctx.RegisterHostOutput(ctx.CompilationOptionsProvider, (context, ct) => context.AddOutput("Host", "")); }); GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, driverOptions: new GeneratorDriverOptions(disabledOutput), parseOptions: parseOptions); @@ -3090,17 +3096,33 @@ class C { } if (disabledOutput.HasFlag((IncrementalGeneratorOutputKind)kind)) { - Assert.DoesNotContain(result.Results[0].GeneratedSources, isTextForKind); + if (kind == IncrementalGeneratorOutputKind.Host) + { + Assert.DoesNotContain(result.Results[0].HostOutputs, o => o.Key == "Host"); + } + else + { + Assert.DoesNotContain(result.Results[0].GeneratedSources, isTextForKind); + } } else { - Assert.Contains(result.Results[0].GeneratedSources, isTextForKind); + if (kind == IncrementalGeneratorOutputKind.Host) + { + Assert.Contains(result.Results[0].HostOutputs, o => o.Key == "Host"); + } + else + { + Assert.Contains(result.Results[0].GeneratedSources, isTextForKind); + } } bool isTextForKind(GeneratedSourceResult s) => s.HintName == Enum.GetName(typeof(IncrementalGeneratorOutputKind), kind) + ".cs"; } } +#pragma warning restore RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + [Fact] public void IncrementalGeneratorInputSourcesHaveNames() { @@ -3223,22 +3245,24 @@ class C { } [WorkItem(59190, "https://github.com/dotnet/roslyn/issues/59190")] public void LongBinaryExpression() { - var source = @" -class C { -public static readonly string F = ""a"" -"; - - for (int i = 0; i < 7000; i++) + const int count = 7000; + const string header = """ + class C { + public static readonly string F = "a" + """; + const string expr = @" + ""a"""; + var capacity = header.Length + (expr.Length * count) + 5; + var builder = new StringBuilder(capacity); + builder.Append(header); + for (int i = 0; i < count; i++) { - source += @" + ""a"" -"; + builder.Append(expr); } - - source += @"; -} -"; + builder.AppendLine(";"); + builder.Append("}"); + Assert.True(capacity >= builder.Capacity); var parseOptions = TestOptions.RegularPreview; - Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); + Compilation compilation = CreateCompilation(builder.ToString(), options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); compilation.VerifyDiagnostics(); Assert.Single(compilation.SyntaxTrees); @@ -4075,7 +4099,7 @@ private static void VerifyArgumentExceptionDiagnostic( bool initialization = false) { var expectedMessage = -#if NETCOREAPP +#if NET $"{message} (Parameter '{parameterName}')"; #else $"{message}{Environment.NewLine}Parameter name: {parameterName}"; @@ -4108,7 +4132,7 @@ public void GetInterceptsLocationSpecifier_01() { var generator = new IncrementalGeneratorWrapper(new InterceptorGenerator1()); - var parseOptions = TestOptions.RegularPreview.WithFeature("InterceptorsPreviewNamespaces", "global"); + var parseOptions = TestOptions.RegularPreview.WithFeature("InterceptorsNamespaces", "global"); var source1 = (""" public class Program @@ -4465,5 +4489,132 @@ public void GeneratorDriver_ReparsesPostInitTrees_IfParseOptionsChange_WhileSupp Assert.Same(newParseOptions, result.GeneratedTrees[0].Options); Assert.Same(newParseOptions, result.GeneratedTrees[1].Options); } + +#pragma warning disable RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + [Fact] + public void GeneratorDriver_Makes_HostOutputs_Available() + { + var generator = new PipelineCallbackGenerator((ctx) => { ctx.RegisterHostOutput(ctx.CompilationProvider, (hostCtx, c) => { hostCtx.AddOutput("a", "value"); }); }); + + var parseOptions = CSharpParseOptions.Default; + var compilation = CreateCompilation("class Compilation1{}", parseOptions: parseOptions); + GeneratorDriver driver = CSharpGeneratorDriver.Create([generator.AsSourceGenerator()], parseOptions: parseOptions); + + driver = driver.RunGenerators(compilation); + var runResult = driver.GetRunResult(); + var result = Assert.Single(runResult.Results); + var (key, value) = Assert.Single(result.HostOutputs); + Assert.Equal("a", key); + Assert.Equal("value", value); + } + + [Fact] + public void GeneratorDriver_No_HostOutputs_WhenDisabled() + { + var generator = new PipelineCallbackGenerator((ctx) => { ctx.RegisterHostOutput(ctx.CompilationProvider, (hostCtx, c) => { hostCtx.AddOutput("a", "value"); }); }); + + var parseOptions = CSharpParseOptions.Default; + var compilation = CreateCompilation("class Compilation1{}", parseOptions: parseOptions); + GeneratorDriver driver = CSharpGeneratorDriver.Create([generator.AsSourceGenerator()], parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.Host)); + + driver = driver.RunGenerators(compilation); + var runResult = driver.GetRunResult(); + var result = Assert.Single(runResult.Results); + Assert.Empty(result.HostOutputs); + } + + [Fact] + public void GeneratorDriver_Multiple_HostOutputs() + { + var generator = new PipelineCallbackGenerator((ctx) => { ctx.RegisterHostOutput(ctx.CompilationProvider, (hostCtx, c) => { hostCtx.AddOutput("a", "value"); hostCtx.AddOutput("b", "value2"); }); }); + + var parseOptions = CSharpParseOptions.Default; + var compilation = CreateCompilation("class Compilation1{}", parseOptions: parseOptions); + GeneratorDriver driver = CSharpGeneratorDriver.Create([generator.AsSourceGenerator()], parseOptions: parseOptions); + + driver = driver.RunGenerators(compilation); + var runResult = driver.GetRunResult(); + var result = Assert.Single(runResult.Results); + + Assert.Equal(2, result.HostOutputs.Keys.Count()); + Assert.Contains("a", (IDictionary)result.HostOutputs); + Assert.Equal("value", result.HostOutputs["a"]); + Assert.Contains("b", (IDictionary)result.HostOutputs); + Assert.Equal("value2", result.HostOutputs["b"]); + } + + [Fact] + public void GeneratorDriver_Multiple_HostOutputs_SameName() + { + var generator = new PipelineCallbackGenerator((ctx) => { ctx.RegisterHostOutput(ctx.CompilationProvider, (hostCtx, c) => { hostCtx.AddOutput("a", "value"); hostCtx.AddOutput("a", "value2"); }); }); + + var parseOptions = CSharpParseOptions.Default; + var compilation = CreateCompilation("class Compilation1{}", parseOptions: parseOptions); + GeneratorDriver driver = CSharpGeneratorDriver.Create([generator.AsSourceGenerator()], parseOptions: parseOptions); + + driver = driver.RunGenerators(compilation); + var runResult = driver.GetRunResult(); + var result = Assert.Single(runResult.Results); + + Assert.Empty(result.HostOutputs); + Assert.IsType(result.Exception); + } + + [Fact] + public void GeneratorDriver_Makes_HostOutputs_MultipleGenerators() + { + var generator1 = new PipelineCallbackGenerator((ctx) => { ctx.RegisterHostOutput(ctx.CompilationProvider, (hostCtx, c) => { hostCtx.AddOutput("gen1", "value1"); }); }); + var generator2 = new PipelineCallbackGenerator2((ctx) => { ctx.RegisterHostOutput(ctx.CompilationProvider, (hostCtx, c) => { hostCtx.AddOutput("gen2", "value2"); }); }); + + var parseOptions = CSharpParseOptions.Default; + var compilation = CreateCompilation("class Compilation1{}", parseOptions: parseOptions); + GeneratorDriver driver = CSharpGeneratorDriver.Create([generator1.AsSourceGenerator(), generator2.AsSourceGenerator()], parseOptions: parseOptions); + driver = driver.RunGenerators(compilation); + var runResult = driver.GetRunResult(); + + Assert.Collection(runResult.Results, + (r) => { var result = Assert.Single(r.HostOutputs); Assert.Equal("gen1", result.Key); Assert.Equal("value1", result.Value); }, + (r) => { var result = Assert.Single(r.HostOutputs); Assert.Equal("gen2", result.Key); Assert.Equal("value2", result.Value); } + ); + } + + [Fact] + public void GeneratorDriver_Makes_HostOutputs_MultipleGenerators_SameName() + { + var generator1 = new PipelineCallbackGenerator((ctx) => { ctx.RegisterHostOutput(ctx.CompilationProvider, (hostCtx, c) => { hostCtx.AddOutput("gen", "value1"); }); }); + var generator2 = new PipelineCallbackGenerator2((ctx) => { ctx.RegisterHostOutput(ctx.CompilationProvider, (hostCtx, c) => { hostCtx.AddOutput("gen", "value2"); }); }); + + var parseOptions = CSharpParseOptions.Default; + var compilation = CreateCompilation("class Compilation1{}", parseOptions: parseOptions); + GeneratorDriver driver = CSharpGeneratorDriver.Create([generator1.AsSourceGenerator(), generator2.AsSourceGenerator()], parseOptions: parseOptions); + driver = driver.RunGenerators(compilation); + var runResult = driver.GetRunResult(); + + Assert.Collection(runResult.Results, + (r) => { var result = Assert.Single(r.HostOutputs); Assert.Equal("gen", result.Key); Assert.Equal("value1", result.Value); }, + (r) => { var result = Assert.Single(r.HostOutputs); Assert.Equal("gen", result.Key); Assert.Equal("value2", result.Value); } + ); + } + + [Fact] + public void GeneratorDriver_HostOutputs_Throws() + { + var generator = new PipelineCallbackGenerator((ctx) => { ctx.RegisterHostOutput(ctx.CompilationProvider, (hostCtx, c) => { throw new InvalidOperationException("failed"); }); }); + + var parseOptions = CSharpParseOptions.Default; + var compilation = CreateCompilation("class Compilation1{}", parseOptions: parseOptions); + GeneratorDriver driver = CSharpGeneratorDriver.Create([generator.AsSourceGenerator()], parseOptions: parseOptions); + + driver = driver.RunGenerators(compilation); + var runResult = driver.GetRunResult(); + var result = Assert.Single(runResult.Results); + + Assert.Empty(result.HostOutputs); + var exception = Assert.IsType(result.Exception); + Assert.Equal("failed", exception.Message); + } + +#pragma warning restore RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. } } diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.cs index c04f59b7d7121..e671ee50f8dd6 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_FullyQualifiedName.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.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -41,7 +38,7 @@ public static IncrementalValuesProvider ForAttributeWithMetadataName( } } -public class GeneratorDriverTests_Attributes_FullyQualifiedName : CSharpTestBase +public sealed class GeneratorDriverTests_Attributes_FullyQualifiedName : CSharpTestBase { #region Non-Incremental tests @@ -51,22 +48,22 @@ public class GeneratorDriverTests_Attributes_FullyQualifiedName : CSharpTestBase [Fact] public void FindCorrectAttributeOnTopLevelClass_WhenSearchingForClassDeclaration1() { - var source = @" -[N1.X] -class C1 { } -[N2.X] -class C2 { } + var source = """ + [N1.X] + class C1 { } + [N2.X] + class C2 { } -namespace N1 -{ - class XAttribute : System.Attribute { } -} + namespace N1 + { + class XAttribute : System.Attribute { } + } -namespace N2 -{ - class XAttribute : System.Attribute { } -} -"; + namespace N2 + { + class XAttribute : System.Attribute { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -93,22 +90,22 @@ class XAttribute : System.Attribute { } [InlineData("N1.x")] public void DoNotFindAttributeOnTopLevelClass_WhenSearchingSimpleName1(string name) { - var source = @" -[N1.X] -class C1 { } -[N2.X] -class C2 { } + var source = """ + [N1.X] + class C1 { } + [N2.X] + class C2 { } -namespace N1 -{ - class XAttribute : System.Attribute { } -} + namespace N1 + { + class XAttribute : System.Attribute { } + } -namespace N2 -{ - class XAttribute : System.Attribute { } -} -"; + namespace N2 + { + class XAttribute : System.Attribute { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -130,22 +127,22 @@ class XAttribute : System.Attribute { } [Fact] public void FindCorrectAttributeOnTopLevelClass_WhenSearchingForClassDeclaration2() { - var source = @" -[N1.X] -class C1 { } -[N2.X] -class C2 { } + var source = """ + [N1.X] + class C1 { } + [N2.X] + class C2 { } -namespace N1 -{ - class XAttribute : System.Attribute { } -} + namespace N1 + { + class XAttribute : System.Attribute { } + } -namespace N2 -{ - class XAttribute : System.Attribute { } -} -"; + namespace N2 + { + class XAttribute : System.Attribute { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -172,10 +169,10 @@ class XAttribute : System.Attribute { } [InlineData("System.CLSCompliantAttribute(true)")] public void FindAssemblyAttribute1(string attribute) { - var source = @$" -using System; -[assembly: {attribute}] -"; + var source = $""" + using System; + [assembly: {attribute}] + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -202,10 +199,10 @@ public void FindAssemblyAttribute1(string attribute) [InlineData("System.CLSCompliantAttribute(true)")] public void FindModuleAttribute1(string attribute) { - var source = @$" -using System; -[module: {attribute}] -"; + var source = $""" + using System; + [module: {attribute}] + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -230,10 +227,10 @@ public void FindModuleAttribute1(string attribute) [InlineData("class WithoutAttributes { }")] public void FindAssemblyAttribute2(string source2) { - var source1 = @" -using System; -[assembly: CLSCompliant(true)] -"; + var source1 = """ + using System; + [assembly: CLSCompliant(true)] + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -257,10 +254,10 @@ public void FindAssemblyAttribute2(string source2) [InlineData("class WithoutAttributes { }")] public void FindAssemblyAttribute3(string source1) { - var source2 = @" -using System; -[assembly: CLSCompliant(true)] -"; + var source2 = """ + using System; + [assembly: CLSCompliant(true)] + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -282,14 +279,14 @@ public void FindAssemblyAttribute3(string source1) [Fact] public void FindAssemblyAttribute4() { - var source1 = @" -using System; -[assembly: CLSCompliant(true)] -"; - var source2 = @" -using System; -[assembly: CLSCompliant(false)] -"; + var source1 = """ + using System; + [assembly: CLSCompliant(true)] + """; + var source2 = """ + using System; + [assembly: CLSCompliant(false)] + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -311,14 +308,14 @@ public void FindAssemblyAttribute4() [Fact] public void FindTopLocalFunctionAttribute1() { - var source = @" -using System; + var source = """ + using System; -[CLSCompliant(true)] -void LocalFunc() -{ -} -"; + [CLSCompliant(true)] + void LocalFunc() + { + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -341,20 +338,20 @@ void LocalFunc() [Fact] public void FindNestedLocalFunctionAttribute1() { - var source = @" -using System; + var source = """ + using System; -class C -{ - void M() - { - [CLSCompliant(true)] - void LocalFunc() - { - } - } -} -"; + class C + { + void M() + { + [CLSCompliant(true)] + void LocalFunc() + { + } + } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -377,23 +374,23 @@ void LocalFunc() [Fact] public void FindNestedLocalFunctionAttribute2() { - var source = @" -using System; + var source = """ + using System; -class C -{ - void M() - { - var v = () => - { - [CLSCompliant(true)] - void LocalFunc() + class C { + void M() + { + var v = () => + { + [CLSCompliant(true)] + void LocalFunc() + { + } + }; + } } - }; - } -} -"; + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -416,13 +413,13 @@ void LocalFunc() [Fact] public void FindTypeParameterFunctionAttribute1() { - var source = @" -using System; + var source = """ + using System; -class C<[CLSCompliant(true)] T> -{ -} -"; + class C<[CLSCompliant(true)] T> + { + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -445,17 +442,17 @@ class C<[CLSCompliant(true)] T> [Fact] public void FindMethodAttribute1() { - var source = @" -using System; + var source = """ + using System; -class C -{ - [CLSCompliant(true)] - void M() - { - } -} -"; + class C + { + [CLSCompliant(true)] + void M() + { + } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -478,17 +475,17 @@ void M() [Fact] public void FindMethodReturnAttribute1() { - var source = @" -using System; + var source = """ + using System; -class C -{ - [return: CLSCompliant(true)] - void M() - { - } -} -"; + class C + { + [return: CLSCompliant(true)] + void M() + { + } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -511,16 +508,16 @@ void M() [Fact] public void FindPartialMethodAttribute1() { - var source = @" -using System; + var source = """ + using System; -class C -{ - [CLSCompliant(true)] - internal partial void M(); - internal partial void M() { } -} -"; + class C + { + [CLSCompliant(true)] + internal partial void M(); + internal partial void M() { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -543,16 +540,16 @@ internal partial void M() { } [Fact] public void FindPartialMethodAttribute2() { - var source = @" -using System; + var source = """ + using System; -class C -{ - internal partial void M(); - [CLSCompliant(true)] - internal partial void M() { } -} -"; + class C + { + internal partial void M(); + [CLSCompliant(true)] + internal partial void M() { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -575,15 +572,15 @@ internal partial void M() { } [Fact] public void FindFieldAttribute1() { - var source = @" -using System; + var source = """ + using System; -class C -{ - [CLSCompliant(true)] - int m; -} -"; + class C + { + [CLSCompliant(true)] + int m; + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -606,15 +603,15 @@ class C [Fact] public void FindFieldAttribute2() { - var source = @" -using System; + var source = """ + using System; -class C -{ - [CLSCompliant(true)] - int m, n; -} -"; + class C + { + [CLSCompliant(true)] + int m, n; + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -639,15 +636,15 @@ class C [Fact] public void FindEventFieldAttribute1() { - var source = @" -using System; + var source = """ + using System; -class C -{ - [CLSCompliant(true)] - event Action m; -} -"; + class C + { + [CLSCompliant(true)] + event Action m; + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -670,15 +667,15 @@ class C [Fact] public void FindEventFieldAttribute2() { - var source = @" -using System; + var source = """ + using System; -class C -{ - [CLSCompliant(true)] - event Action m, n; -} -"; + class C + { + [CLSCompliant(true)] + event Action m, n; + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -703,11 +700,11 @@ class C [Fact] public void FindParenthesizedLambdaAttribute1() { - var source = @" -using System; + var source = """ + using System; -Func v = [CLSCompliant(true)] (int i) => i; -"; + Func v = [CLSCompliant(true)] (int i) => i; + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -730,18 +727,18 @@ public void FindParenthesizedLambdaAttribute1() [Fact] public void FindAccessorAttribute1() { - var source = @" -using System; + var source = """ + using System; -class C -{ - int Prop - { - [CLSCompliant(true)] - get => 0; - } -} -"; + class C + { + int Prop + { + [CLSCompliant(true)] + get => 0; + } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -764,13 +761,13 @@ int Prop [Fact] public void FindTypeParameterAttribute1() { - var source = @" -using System; + var source = """ + using System; -class C<[CLSCompliant(true)]T> -{ -} -"; + class C<[CLSCompliant(true)]T> + { + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -793,21 +790,21 @@ class C<[CLSCompliant(true)]T> [Fact] public void FindNestedAttribute1() { - var source = @" -[Outer1.Inner] -class C1 { } -[Outer2.Inner] -class C2 { } + var source = """ + [Outer1.Inner] + class C1 { } + [Outer2.Inner] + class C2 { } -class Outer1 -{ - public class InnerAttribute : System.Attribute { } -} -class Outer2 -{ - public class InnerAttribute : System.Attribute { } -} -"; + class Outer1 + { + public class InnerAttribute : System.Attribute { } + } + class Outer2 + { + public class InnerAttribute : System.Attribute { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -830,21 +827,21 @@ public class InnerAttribute : System.Attribute { } [Fact] public void FindNestedAttribute2() { - var source = @" -[Outer1.Inner] -class C1 { } -[Outer2.Inner] -class C2 { } + var source = """ + [Outer1.Inner] + class C1 { } + [Outer2.Inner] + class C2 { } -class Outer1 -{ - public class InnerAttribute : System.Attribute { } -} -class Outer2 -{ - public class InnerAttribute : System.Attribute { } -} -"; + class Outer1 + { + public class InnerAttribute : System.Attribute { } + } + class Outer2 + { + public class InnerAttribute : System.Attribute { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -867,21 +864,21 @@ public class InnerAttribute : System.Attribute { } [Fact] public void FindNestedGenericAttribute1() { - var source = @" -[Outer1.Inner] -class C1 { } -[Outer2.Inner] -class C2 { } + var source = """ + [Outer1.Inner] + class C1 { } + [Outer2.Inner] + class C2 { } -class Outer1 -{ - public class InnerAttribute : System.Attribute{ } -} -class Outer2 -{ - public class InnerAttribute : System.Attribute { } -} -"; + class Outer1 + { + public class InnerAttribute : System.Attribute{ } + } + class Outer2 + { + public class InnerAttribute : System.Attribute { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -904,21 +901,21 @@ public class InnerAttribute : System.Attribute { } [Fact] public void FindNestedGenericAttribute2() { - var source = @" -[Outer1.Inner] -class C1 { } -[Outer2.Inner] -class C2 { } + var source = """ + [Outer1.Inner] + class C1 { } + [Outer2.Inner] + class C2 { } -class Outer1 -{ - public class InnerAttribute : System.Attribute{ } -} -class Outer2 -{ - public class InnerAttribute : System.Attribute { } -} -"; + class Outer1 + { + public class InnerAttribute : System.Attribute{ } + } + class Outer2 + { + public class InnerAttribute : System.Attribute { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -941,21 +938,21 @@ public class InnerAttribute : System.Attribute { } [Fact] public void DoNotFindNestedGenericAttribute1() { - var source = @" -[Outer1.Inner] -class C1 { } -[Outer2.Inner] -class C2 { } + var source = """ + [Outer1.Inner] + class C1 { } + [Outer2.Inner] + class C2 { } -class Outer1 -{ - public class InnerAttribute : System.Attribute{ } -} -class Outer2 -{ - public class InnerAttribute : System.Attribute { } -} -"; + class Outer1 + { + public class InnerAttribute : System.Attribute{ } + } + class Outer2 + { + public class InnerAttribute : System.Attribute { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -977,21 +974,21 @@ public class InnerAttribute : System.Attribute { } [Fact] public void DoNotFindNestedGenericAttribute2() { - var source = @" -[Outer1.Inner] -class C1 { } -[Outer2.Inner] -class C2 { } + var source = """ + [Outer1.Inner] + class C1 { } + [Outer2.Inner] + class C2 { } -class Outer1 -{ - public class InnerAttribute : System.Attribute{ } -} -class Outer2 -{ - public class InnerAttribute : System.Attribute { } -} -"; + class Outer1 + { + public class InnerAttribute : System.Attribute{ } + } + class Outer2 + { + public class InnerAttribute : System.Attribute { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1013,12 +1010,12 @@ public class InnerAttribute : System.Attribute { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_MultipleAttributeLists1() { - var source = @" -[X][X] -class C { } + var source = """ + [X][X] + class C { } -class XAttribute : System.Attribute { } -"; + class XAttribute : System.Attribute { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1050,12 +1047,12 @@ class XAttribute : System.Attribute { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_MultipleAttributeLists1B() { - var source = @" -[X, X] -class C { } + var source = """ + [X, X] + class C { } -class XAttribute : System.Attribute { } -"; + class XAttribute : System.Attribute { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1087,13 +1084,13 @@ class XAttribute : System.Attribute { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_MultipleAttributeLists2() { - var source = @" -[X][Y] -class C { } + var source = """ + [X][Y] + class C { } -class XAttribute : System.Attribute { } -class YAttribute : System.Attribute { } -"; + class XAttribute : System.Attribute { } + class YAttribute : System.Attribute { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1125,13 +1122,13 @@ class YAttribute : System.Attribute { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_MultipleAttributeLists2B() { - var source = @" -[X, Y] -class C { } + var source = """ + [X, Y] + class C { } -class XAttribute : System.Attribute { } -class YAttribute : System.Attribute { } -"; + class XAttribute : System.Attribute { } + class YAttribute : System.Attribute { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1163,13 +1160,13 @@ class YAttribute : System.Attribute { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_MultipleAttributeLists3() { - var source = @" -[Y][X] -class C { } + var source = """ + [Y][X] + class C { } -class XAttribute : System.Attribute { } -class YAttribute : System.Attribute { } -"; + class XAttribute : System.Attribute { } + class YAttribute : System.Attribute { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1201,13 +1198,13 @@ class YAttribute : System.Attribute { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_MultipleAttributeLists3B() { - var source = @" -[Y, X] -class C { } + var source = """ + [Y, X] + class C { } -class XAttribute : System.Attribute { } -class YAttribute : System.Attribute { } -"; + class XAttribute : System.Attribute { } + class YAttribute : System.Attribute { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1304,6 +1301,98 @@ static void replace(ref Compilation compilation, CSharpParseOptions parseOptions } } + [Fact, WorkItem("https://github.com/dotnet/runtime/issues/105137")] + public void LocalFileAlias_AttributeUsedMultipleTimes1() + { + var source = """ + using System.Runtime.InteropServices; + + namespace NetPlayground + { + using Import = LibraryImportAttribute; + + internal partial class TestImport + { + [Import("somedll.dll")] + partial void SomeFunction(int a); + + [Import("somedll.dll")] + partial void SomeFunction2(int a); + } + } + + namespace System.Runtime.InteropServices + { + class LibraryImportAttribute(string s) : System.Attribute { } + } + """; + var parseOptions = TestOptions.RegularPreview; + var compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); + + Assert.Single(compilation.SyntaxTrees); + + var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => + { + var input = ctx.ForAttributeWithMetadataName("System.Runtime.InteropServices.LibraryImportAttribute"); + ctx.RegisterSourceOutput(input, (spc, node) => { }); + })); + + var driver = CSharpGeneratorDriver.Create([generator], parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + var runResult = driver.RunGenerators(compilation).GetRunResult().Results[0]; + + Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], + step => Assert.True( + step.Outputs is [ + { Value: MethodDeclarationSyntax { Identifier.ValueText: "SomeFunction" } }, + { Value: MethodDeclarationSyntax { Identifier.ValueText: "SomeFunction2" } }])); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/runtime/issues/105137")] + public void LocalFileAlias_AttributeUsedMultipleTimes2(bool withAttribute) + { + var source = $$""" + using System.Runtime.InteropServices; + + namespace NetPlayground + { + using ImportAttribute = LibraryImportAttribute; + + internal partial class TestImport + { + [Import{{(withAttribute ? "Attribute" : "")}}("somedll.dll")] + partial void SomeFunction(int a); + + [Import{{(withAttribute ? "Attribute" : "")}}("somedll.dll")] + partial void SomeFunction2(int a); + } + } + + namespace System.Runtime.InteropServices + { + class LibraryImportAttribute(string s) : System.Attribute { } + } + """; + var parseOptions = TestOptions.RegularPreview; + var compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); + + Assert.Single(compilation.SyntaxTrees); + + var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(ctx => + { + var input = ctx.ForAttributeWithMetadataName("System.Runtime.InteropServices.LibraryImportAttribute"); + ctx.RegisterSourceOutput(input, (spc, node) => { }); + })); + + var driver = CSharpGeneratorDriver.Create([generator], parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + var runResult = driver.RunGenerators(compilation).GetRunResult().Results[0]; + + Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], + step => Assert.True( + step.Outputs is [ + { Value: MethodDeclarationSyntax { Identifier.ValueText: "SomeFunction" } }, + { Value: MethodDeclarationSyntax { Identifier.ValueText: "SomeFunction2" } }])); + } + #endregion #region Incremental tests @@ -1313,14 +1402,14 @@ static void replace(ref Compilation compilation, CSharpParseOptions parseOptions [Fact] public void RerunOnSameCompilationCachesResultFully() { - var source = @" -[X] -class C { } + var source = """ + [X] + class C { } -class XAttribute : System.Attribute -{ -} -"; + class XAttribute : System.Attribute + { + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1360,14 +1449,14 @@ class XAttribute : System.Attribute [Fact] public void RerunWithReferencesChange() { - var source = @" -[X] -class C { } + var source = """ + [X] + class C { } -class XAttribute : System.Attribute -{ -} -"; + class XAttribute : System.Attribute + { + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1407,14 +1496,14 @@ class XAttribute : System.Attribute [Fact] public void RerunWithAddedFile1() { - var source = @" -[X] -class C { } + var source = """ + [X] + class C { } -class XAttribute : System.Attribute -{ -} -"; + class XAttribute : System.Attribute + { + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1454,10 +1543,10 @@ class XAttribute : System.Attribute [Fact] public void RerunWithAddedFile2() { - var source = @" -[X] -class C { } -"; + var source = """ + [X] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1475,10 +1564,11 @@ class C { } Assert.False(runResult.TrackedSteps.ContainsKey("result_ForAttributeWithMetadataName")); - driver = driver.RunGenerators(compilation.AddSyntaxTrees(compilation.SyntaxTrees.First().WithChangedText(SourceText.From(@" -class XAttribute : System.Attribute -{ -}")))); + driver = driver.RunGenerators(compilation.AddSyntaxTrees(compilation.SyntaxTrees.First().WithChangedText(SourceText.From(""" + class XAttribute : System.Attribute + { + } + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], @@ -1499,12 +1589,12 @@ class XAttribute : System.Attribute [Fact] public void RerunWithAddedFile_MultipleResults_SameFile1() { - var source = @" -[X] -class C1 { } -[X] -class C2 { } -"; + var source = """ + [X] + class C1 { } + [X] + class C2 { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1522,10 +1612,11 @@ class C2 { } Assert.False(runResult.TrackedSteps.ContainsKey("result_ForAttributeWithMetadataName")); - driver = driver.RunGenerators(compilation.AddSyntaxTrees(compilation.SyntaxTrees.First().WithChangedText(SourceText.From(@" -class XAttribute : System.Attribute -{ -}")))); + driver = driver.RunGenerators(compilation.AddSyntaxTrees(compilation.SyntaxTrees.First().WithChangedText(SourceText.From(""" + class XAttribute : System.Attribute + { + } + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], @@ -1551,14 +1642,14 @@ class XAttribute : System.Attribute [Fact] public void RerunWithAddedFile_MultipleResults_MultipleFile1() { - var source1 = @" -[X] -class C1 { } -"; - var source2 = @" -[X] -class C2 { } -"; + var source1 = """ + [X] + class C1 { } + """; + var source2 = """ + [X] + class C2 { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1574,10 +1665,11 @@ class C2 { } Assert.False(runResult.TrackedSteps.ContainsKey("result_ForAttributeWithMetadataName")); - driver = driver.RunGenerators(compilation.AddSyntaxTrees(compilation.SyntaxTrees.First().WithChangedText(SourceText.From(@" -class XAttribute : System.Attribute -{ -}")))); + driver = driver.RunGenerators(compilation.AddSyntaxTrees(compilation.SyntaxTrees.First().WithChangedText(SourceText.From(""" + class XAttribute : System.Attribute + { + } + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], @@ -1608,13 +1700,13 @@ class XAttribute : System.Attribute [Fact] public void RerunWithChangedFileThatNowReferencesAttribute1() { - var source = @" -class C { } + var source = """ + class C { } -class XAttribute : System.Attribute -{ -} -"; + class XAttribute : System.Attribute + { + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1634,14 +1726,14 @@ class XAttribute : System.Attribute driver = driver.RunGenerators(compilation.ReplaceSyntaxTree( compilation.SyntaxTrees.First(), - compilation.SyntaxTrees.First().WithChangedText(SourceText.From(@" -[X] -class C { } + compilation.SyntaxTrees.First().WithChangedText(SourceText.From(""" + [X] + class C { } -class XAttribute : System.Attribute -{ -} -")))); + class XAttribute : System.Attribute + { + } + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], @@ -1661,14 +1753,14 @@ class XAttribute : System.Attribute [Fact] public void RerunWithChangedFileThatNowReferencesAttribute2() { - var source1 = @" -class C { } -"; - var source2 = @" -class XAttribute : System.Attribute -{ -} -"; + var source1 = """ + class C { } + """; + var source2 = """ + class XAttribute : System.Attribute + { + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1686,10 +1778,10 @@ class XAttribute : System.Attribute driver = driver.RunGenerators(compilation.ReplaceSyntaxTree( compilation.SyntaxTrees.First(), - compilation.SyntaxTrees.First().WithChangedText(SourceText.From(@" -[X] -class C { } -")))); + compilation.SyntaxTrees.First().WithChangedText(SourceText.From(""" + [X] + class C { } + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["result_ForAttributeWithMetadataName"], diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.cs index d095dc41f9d41..9698bd6ec6414 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests_Attributes_SimpleName.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; using System.Linq; -using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -16,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.SourceGeneration; -public class GeneratorDriverTests_Attributes_SimpleName : CSharpTestBase +public sealed class GeneratorDriverTests_Attributes_SimpleName : CSharpTestBase { #region Non-Incremental tests @@ -33,10 +30,10 @@ public class GeneratorDriverTests_Attributes_SimpleName : CSharpTestBase [InlineData("[X][X]")] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration1(string attribute) { - var source = @$" -{attribute} -class C {{ }} -"; + var source = $$""" + {{attribute}} + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -65,10 +62,10 @@ class C {{ }} [InlineData("global::A.X")] public void FindFullAttributeNameOnTopLevelClass(string attribute) { - var source = @$" -[{attribute}] -class C {{ }} -"; + var source = $$""" + [{{attribute}}] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -91,10 +88,10 @@ class C {{ }} [Fact] public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForDelegateDeclaration1() { - var source = @" -[X] -class C { } -"; + var source = """ + [X] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -116,10 +113,10 @@ class C { } [Fact] public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForDifferentName() { - var source = @" -[X] -class C { } -"; + var source = """ + [X] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -141,10 +138,10 @@ class C { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForSyntaxNode1() { - var source = @" -[X] -class C { } -"; + var source = """ + [X] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -167,12 +164,12 @@ class C { } [Fact] public void FindAttributeOnTopLevelClasses_WhenSearchingForClassDeclaration1() { - var source = @" -[X] -class C { } -[X] -class D { } -"; + var source = """ + [X] + class C { } + [X] + class D { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -199,12 +196,12 @@ class D { } [Fact] public void FindAttributeOnTopLevelClasses_WhenSearchingForClassDeclaration2() { - var source = @" -[X] -class C { } -[Y] -class D { } -"; + var source = """ + [X] + class C { } + [Y] + class D { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -231,12 +228,12 @@ class D { } [Fact] public void FindAttributeOnTopLevelClasses_WhenSearchingForClassDeclaration3() { - var source = @" -[Y] -class C { } -[X] -class D { } -"; + var source = """ + [Y] + class C { } + [X] + class D { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -263,14 +260,14 @@ class D { } [Fact] public void FindAttributeOnNestedClasses_WhenSearchingForClassDeclaration1() { - var source = @" -[X] -class C -{ - [X] - class D { } -} -"; + var source = """ + [X] + class C + { + [X] + class D { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -297,13 +294,13 @@ class D { } [Fact] public void FindAttributeOnClassInNamespace_WhenSearchingForClassDeclaration1() { - var source = @" -namespace N -{ - [X] - class C { } -} -"; + var source = """ + namespace N + { + [X] + class C { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -326,10 +323,10 @@ class C { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_FullAttributeName1() { - var source = @" -[X] -class C { } -"; + var source = """ + [X] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -352,10 +349,10 @@ class C { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_ShortAttributeName1() { - var source = @" -[X] -class C { } -"; + var source = """ + [X] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -378,10 +375,10 @@ class C { } [Fact] public void FindFullAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_FullAttributeName1() { - var source = @" -[XAttribute] -class C { } -"; + var source = """ + [XAttribute] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -409,12 +406,12 @@ class C { } [InlineData("A = global::M.XAttribute")] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_WithLocalAlias1(string alias) { - var source = @$" -using {alias}; + var source = $$""" + using {{alias}}; -[A] -class C {{ }} -"; + [A] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -437,12 +434,12 @@ class C {{ }} [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_WithLocalAlias3() { - var source = @" -using AAttribute = XAttribute; + var source = """ + using AAttribute = XAttribute; -[AAttribute] -class C { } -"; + [AAttribute] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -465,12 +462,12 @@ class C { } [Fact] public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_WithLocalAlias1() { - var source = @" -using AAttribute : X; + var source = """ + using AAttribute : X; -[AAttribute] -class C { } -"; + [AAttribute] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -492,12 +489,12 @@ class C { } [Fact] public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_WithLocalAlias2() { - var source = @" -using AAttribute : XAttribute; + var source = """ + using AAttribute : XAttribute; -[B] -class C { } -"; + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -519,16 +516,16 @@ class C { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_ThroughMultipleAliases1() { - var source = @" -using B = XAttribute; -namespace N -{ - using A = B; + var source = """ + using B = XAttribute; + namespace N + { + using A = B; - [A] - class C { } -} -"; + [A] + class C { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -552,16 +549,16 @@ class C { } public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_OuterAliasReferencesInnerAlias() { // note: this is not legal. it's ok if this ever stops working in the futuer. - var source = @" -using BAttribute = AAttribute; -namespace N -{ - using AAttribute = XAttribute; + var source = """ + using BAttribute = AAttribute; + namespace N + { + using AAttribute = XAttribute; - [B] - class C { } -} -"; + [B] + class C { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -584,16 +581,16 @@ class C { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_ThroughMultipleAliases2() { - var source = @" -using B = XAttribute; -namespace N -{ - using AAttribute = B; + var source = """ + using B = XAttribute; + namespace N + { + using AAttribute = B; - [A] - class C { } -} -"; + [A] + class C { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -616,16 +613,16 @@ class C { } [Fact] public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_ThroughMultipleAliases2() { - var source = @" -using BAttribute = XAttribute; -namespace N -{ - using AAttribute = B; + var source = """ + using BAttribute = XAttribute; + namespace N + { + using AAttribute = B; - [A] - class C { } -} -"; + [A] + class C { } + } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -647,13 +644,13 @@ class C { } [Fact] public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_RecursiveAlias1() { - var source = @" -using AAttribute = BAttribute; -using BAttribute = AAttribute; + var source = """ + using AAttribute = BAttribute; + using BAttribute = AAttribute; -[A] -class C { } -"; + [A] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -675,13 +672,13 @@ class C { } [Fact] public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_RecursiveAlias2() { - var source = @" -using A = BAttribute; -using B = AAttribute; + var source = """ + using A = BAttribute; + using B = AAttribute; -[A] -class C { } -"; + [A] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -703,13 +700,13 @@ class C { } [Fact] public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_RecursiveAlias3() { - var source = @" -using A = B; -using B = A; + var source = """ + using A = B; + using B = A; -[A] -class C { } -"; + [A] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -731,13 +728,13 @@ class C { } [Fact] public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_LocalAliasInDifferentFile1() { - var source1 = @" -[A] -class C { } -"; - var source2 = @" -using A = XAttribute; -"; + var source1 = """ + [A] + class C { } + """; + var source2 = """ + using A = XAttribute; + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -758,13 +755,13 @@ class C { } [Fact] public void DoNotFindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_LocalAliasInDifferentFile2() { - var source1 = @" -[A] -class C { } -"; - var source2 = @" -using AAttribute = XAttribute; -"; + var source1 = """ + [A] + class C { } + """; + var source2 = """ + using AAttribute = XAttribute; + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -787,12 +784,12 @@ class C { } [InlineData("AAttribute = XAttribute")] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_GlobalAliasInSameFile1(string alias) { - var source = @$" -global using {alias}; + var source = $$""" + global using {{alias}}; -[A] -class C {{ }} -"; + [A] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -817,13 +814,13 @@ class C {{ }} [InlineData("BAttribute = AAttribute")] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_GlobalAndLocalAliasInSameFile1(string alias) { - var source = @$" -global using AAttribute = XAttribute; -using {alias}; + var source = $$""" + global using AAttribute = XAttribute; + using {{alias}}; -[B] -class C {{ }} -"; + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -848,13 +845,13 @@ class C {{ }} [InlineData("AAttribute = XAttribute")] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_GlobalAliasDifferentFile1(string alias) { - var source1 = @" -[A] -class C { } -"; - var source2 = @$" -global using {alias}; -"; + var source1 = """ + [A] + class C { } + """; + var source2 = $""" + global using {alias}; + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -876,14 +873,14 @@ class C { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_BothGlobalAndLocalAliasDifferentFile1() { - var source1 = @" -[B] -class C { } -"; - var source2 = @" -global using AAttribute = XAttribute; -using B = AAttribute; -"; + var source1 = """ + [B] + class C { } + """; + var source2 = """ + global using AAttribute = XAttribute; + using B = AAttribute; + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -904,14 +901,14 @@ class C { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_GlobalAliasLoop1() { - var source1 = @" -[A] -class C { } -"; - var source2 = @" -global using AAttribute = BAttribute; -global using BAttribute = AAttribute; -"; + var source1 = """ + [A] + class C { } + """; + var source2 = """ + global using AAttribute = BAttribute; + global using BAttribute = AAttribute; + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -932,14 +929,14 @@ class C { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_GlobalAndLocalAliasDifferentFile1() { - var source1 = @" -using B = AAttribute; -[B] -class C { } -"; - var source2 = @" -global using AAttribute = XAttribute; -"; + var source1 = """ + using B = AAttribute; + [B] + class C { } + """; + var source2 = """ + global using AAttribute = XAttribute; + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -961,14 +958,14 @@ class C { } [Fact] public void FindAttributeOnTopLevelClass_WhenSearchingForClassDeclaration_GlobalAndLocalAliasDifferentFile2() { - var source1 = @" -using BAttribute = AAttribute; -[B] -class C { } -"; - var source2 = @" -global using AAttribute = XAttribute; -"; + var source1 = """ + using BAttribute = AAttribute; + [B] + class C { } + """; + var source2 = """ + global using AAttribute = XAttribute; + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -996,10 +993,10 @@ class C { } [Fact] public void RerunOnSameCompilationCachesResultFully() { - var source = @" -[X] -class C { } -"; + var source = """ + [X] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1036,10 +1033,10 @@ class C { } [Fact] public void RerunOnCompilationWithReferencesChangeCachesResultFully() { - var source = @" -[X] -class C { } -"; + var source = """ + [X] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1076,16 +1073,18 @@ class C { } [Fact] public void TestSourceFileRemoved1() { - var source1 = @" -global using AAttribute = XAttribute;"; - - var source2 = @" -global using BAttribute = AAttribute;"; - - var source3 = @" -[B] -class C { } -"; + var source1 = """ + global using AAttribute = XAttribute; + """; + + var source2 = """ + global using BAttribute = AAttribute; + """; + + var source3 = """ + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1127,16 +1126,18 @@ class C { } [Fact] public void TestSourceFileChanged_AttributeRemoved1() { - var source1 = @" -global using AAttribute = XAttribute;"; - - var source2 = @" -global using BAttribute = AAttribute;"; - - var source3 = @" -[B] -class C { } -"; + var source1 = """ + global using AAttribute = XAttribute; + """; + + var source2 = """ + global using BAttribute = AAttribute; + """; + + var source3 = """ + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1155,9 +1156,9 @@ class C { } driver = driver.RunGenerators(compilation.ReplaceSyntaxTree( compilation.SyntaxTrees.Last(), - compilation.SyntaxTrees.Last().WithChangedText(SourceText.From(@" -class C { } -")))); + compilation.SyntaxTrees.Last().WithChangedText(SourceText.From(""" + class C { } + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], @@ -1177,15 +1178,17 @@ class C { } [Fact] public void TestSourceFileChanged_AttributeAdded1() { - var source1 = @" -global using AAttribute = XAttribute;"; + var source1 = """ + global using AAttribute = XAttribute; + """; - var source2 = @" -global using BAttribute = AAttribute;"; + var source2 = """ + global using BAttribute = AAttribute; + """; - var source3 = @" -class C { } -"; + var source3 = """ + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1203,10 +1206,10 @@ class C { } driver = driver.RunGenerators(compilation.ReplaceSyntaxTree( compilation.SyntaxTrees.Last(), - compilation.SyntaxTrees.Last().WithChangedText(SourceText.From(@" -[B] -class C { } -")))); + compilation.SyntaxTrees.Last().WithChangedText(SourceText.From(""" + [B] + class C { } + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], @@ -1229,16 +1232,18 @@ class C { } [Fact] public void TestSourceFileChanged_NonVisibleChangeToGlobalAttributeFile() { - var source1 = @" -global using AAttribute = XAttribute;"; - - var source2 = @" -global using BAttribute = AAttribute;"; - - var source3 = @" -[B] -class C { } -"; + var source1 = """ + global using AAttribute = XAttribute; + """; + + var source2 = """ + global using BAttribute = AAttribute; + """; + + var source3 = """ + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1257,10 +1262,10 @@ class C { } driver = driver.RunGenerators(compilation.ReplaceSyntaxTree( compilation.SyntaxTrees.First(), - compilation.SyntaxTrees.First().WithChangedText(SourceText.From(@" -global using AAttribute = XAttribute; -class Dummy {} -")))); + compilation.SyntaxTrees.First().WithChangedText(SourceText.From(""" + global using AAttribute = XAttribute; + class Dummy {} + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], @@ -1280,16 +1285,18 @@ class Dummy {} [Fact] public void TestRemoveGlobalAttributeFile1() { - var source1 = @" -global using AAttribute = XAttribute;"; - - var source2 = @" -global using BAttribute = AAttribute;"; - - var source3 = @" -[B] -class C { } -"; + var source1 = """ + global using AAttribute = XAttribute; + """; + + var source2 = """ + global using BAttribute = AAttribute; + """; + + var source3 = """ + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1336,16 +1343,18 @@ public void TestRemoveGlobalAttributeFile2() { var source0 = ""; - var source1 = @" -global using AAttribute = XAttribute;"; + var source1 = """ + global using AAttribute = XAttribute; + """; - var source2 = @" -global using BAttribute = AAttribute;"; + var source2 = """ + global using BAttribute = AAttribute; + """; - var source3 = @" -[B] -class C { } -"; + var source3 = """ + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source0, source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1386,13 +1395,14 @@ class C { } [Fact] public void TestAddGlobalAttributeFile1() { - var source2 = @" -global using BAttribute = AAttribute;"; - - var source3 = @" -[B] -class C { } -"; + var source2 = """ + global using BAttribute = AAttribute; + """; + + var source3 = """ + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1409,8 +1419,9 @@ class C { } Assert.False(runResult.TrackedSteps.ContainsKey("result_ForAttribute")); driver = driver.RunGenerators(compilation.AddSyntaxTrees( - compilation.SyntaxTrees.First().WithChangedText(SourceText.From(@" -global using AAttribute = XAttribute;")))); + compilation.SyntaxTrees.First().WithChangedText(SourceText.From(""" + global using AAttribute = XAttribute; + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], @@ -1433,10 +1444,10 @@ class C { } [Fact] public void TestAddGlobalAttributeFile2() { - var source3 = @" -[B] -class C { } -"; + var source3 = """ + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1453,8 +1464,9 @@ class C { } Assert.False(runResult.TrackedSteps.ContainsKey("result_ForAttribute")); driver = driver.RunGenerators(compilation.AddSyntaxTrees( - compilation.SyntaxTrees.First().WithChangedText(SourceText.From(@" -global using BAttribute = XAttribute;")))); + compilation.SyntaxTrees.First().WithChangedText(SourceText.From(""" + global using BAttribute = XAttribute; + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], @@ -1475,16 +1487,18 @@ class C { } [Fact] public void TestAddSourceFileWithoutAttribute() { - var source1 = @" -global using AAttribute = XAttribute;"; - - var source2 = @" -global using BAttribute = AAttribute;"; - - var source3 = @" -[B] -class C { } -"; + var source1 = """ + global using AAttribute = XAttribute; + """; + + var source2 = """ + global using BAttribute = AAttribute; + """; + + var source3 = """ + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1502,8 +1516,9 @@ class C { } step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); driver = driver.RunGenerators(compilation.AddSyntaxTrees( - compilation.SyntaxTrees.First().WithChangedText(SourceText.From(@" -class D { }")))); + compilation.SyntaxTrees.First().WithChangedText(SourceText.From(""" + class D { } + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], @@ -1523,16 +1538,18 @@ class D { }")))); [Fact] public void TestAddSourceFileWithAttribute() { - var source1 = @" -global using AAttribute = XAttribute;"; - - var source2 = @" -global using BAttribute = AAttribute;"; - - var source3 = @" -[B] -class C { } -"; + var source1 = """ + global using AAttribute = XAttribute; + """; + + var source2 = """ + global using BAttribute = AAttribute; + """; + + var source3 = """ + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1550,9 +1567,10 @@ class C { } step => Assert.True(step.Outputs.Single().Value is ClassDeclarationSyntax { Identifier.ValueText: "C" })); driver = driver.RunGenerators(compilation.AddSyntaxTrees( - compilation.SyntaxTrees.First().WithChangedText(SourceText.From(@" -[A] -class D { }")))); + compilation.SyntaxTrees.First().WithChangedText(SourceText.From(""" + [A] + class D { } + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], @@ -1581,16 +1599,18 @@ class D { }")))); [Fact] public void TestReplaceSourceFileWithDifferentAttribute() { - var source1 = @" -global using AAttribute = XAttribute;"; - - var source2 = @" -global using BAttribute = AAttribute;"; - - var source3 = @" -[B] -class C { } -"; + var source1 = """ + global using AAttribute = XAttribute; + """; + + var source2 = """ + global using BAttribute = AAttribute; + """; + + var source3 = """ + [B] + class C { } + """; var parseOptions = TestOptions.RegularPreview; Compilation compilation = CreateCompilation(new[] { source1, source2, source3 }, options: TestOptions.DebugDllThrowing, parseOptions: parseOptions); @@ -1609,9 +1629,10 @@ class C { } driver = driver.RunGenerators(compilation.ReplaceSyntaxTree( compilation.SyntaxTrees.Last(), - compilation.SyntaxTrees.Last().WithChangedText(SourceText.From(@" -[A] -class D { }")))); + compilation.SyntaxTrees.Last().WithChangedText(SourceText.From(""" + [A] + class D { } + """)))); runResult = driver.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps["individualFileGlobalAliases_ForAttribute"], diff --git a/src/Compilers/CSharp/Test/Symbol/BadSymbolReference.cs b/src/Compilers/CSharp/Test/Symbol/BadSymbolReference.cs index dd87092228414..fd0a942b8de22 100644 --- a/src/Compilers/CSharp/Test/Symbol/BadSymbolReference.cs +++ b/src/Compilers/CSharp/Test/Symbol/BadSymbolReference.cs @@ -740,8 +740,8 @@ public void MissingTypes3() var references = new[] { MscorlibRef, - TestMetadata.Net451.SystemData, - TestMetadata.Net451.System, + NetFramework.SystemData, + NetFramework.System, cl2, cl3 }; diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs index 8ec1f3ac1c9d5..3fd08e070b8d2 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/CompilationAPITests.cs @@ -27,7 +27,6 @@ using Roslyn.Utilities; using Xunit; using static Roslyn.Test.Utilities.TestHelpers; -using static Roslyn.Test.Utilities.TestMetadata; using KeyValuePairUtil = Roslyn.Utilities.KeyValuePairUtil; using VB = Microsoft.CodeAnalysis.VisualBasic; @@ -355,7 +354,7 @@ class G { } listSyntaxTree.Add(t1); // System.dll - listRef.Add(Net451.System.WithEmbedInteropTypes(true)); + listRef.Add(NetFramework.System.WithEmbedInteropTypes(true)); var ops = TestOptions.ReleaseExe; // Create Compilation with Option is not null var comp = CSharpCompilation.Create("Compilation", listSyntaxTree, listRef, ops); @@ -488,8 +487,8 @@ public void ReferenceAPITest() var opt = TestOptions.DebugExe; // Create Compilation takes two args var comp = CSharpCompilation.Create("Compilation", options: TestOptions.DebugExe); - var ref1 = Net451.mscorlib; - var ref2 = Net451.System; + var ref1 = NetFramework.mscorlib; + var ref2 = NetFramework.System; var ref3 = new TestMetadataReference(fullPath: @"c:\xml.bms"); var ref4 = new TestMetadataReference(fullPath: @"c:\aaa.dll"); // Add a new empty item @@ -587,21 +586,21 @@ public void ReferenceDirectiveTests() var rd4 = t4.GetRoot().GetDirectives().Cast().ToArray(); Assert.Equal(1, rd4.Length); - var c = CreateCompilationWithMscorlib45(new[] { t1, t2 }, options: TestOptions.ReleaseDll.WithMetadataReferenceResolver( + var c = CreateCompilationWithMscorlib461(new[] { t1, t2 }, options: TestOptions.ReleaseDll.WithMetadataReferenceResolver( new TestMetadataReferenceResolver(files: new Dictionary() { - { @"a.dll", Net451.MicrosoftCSharp }, - { @"b.dll", Net451.MicrosoftVisualBasic }, + { @"a.dll", NetFramework.MicrosoftCSharp }, + { @"b.dll", NetFramework.MicrosoftVisualBasic }, }))); c.VerifyDiagnostics(); // same containing script file name and directive string - Assert.Same(Net451.MicrosoftCSharp, c.GetDirectiveReference(rd1[0])); - Assert.Same(Net451.MicrosoftCSharp, c.GetDirectiveReference(rd1[1])); - Assert.Same(Net451.MicrosoftCSharp, c.GetDirectiveReference(rd2[0])); - Assert.Same(Net451.MicrosoftVisualBasic, c.GetDirectiveReference(rd2[1])); - Assert.Same(Net451.MicrosoftCSharp, c.GetDirectiveReference(rd3[0])); + Assert.Same(NetFramework.MicrosoftCSharp, c.GetDirectiveReference(rd1[0])); + Assert.Same(NetFramework.MicrosoftCSharp, c.GetDirectiveReference(rd1[1])); + Assert.Same(NetFramework.MicrosoftCSharp, c.GetDirectiveReference(rd2[0])); + Assert.Same(NetFramework.MicrosoftVisualBasic, c.GetDirectiveReference(rd2[1])); + Assert.Same(NetFramework.MicrosoftCSharp, c.GetDirectiveReference(rd3[0])); // different script name or directive string: Assert.Null(c.GetDirectiveReference(rd4[0])); @@ -963,7 +962,7 @@ public void ChainedOperations() // Create compilation with args is disordered CSharpCompilation comp1 = CSharpCompilation.Create(assemblyName: "Compilation", syntaxTrees: null, options: TestOptions.ReleaseDll, references: null); - var ref1 = Net451.mscorlib; + var ref1 = NetFramework.mscorlib; var listRef = new List(); listRef.Add(ref1); listRef.Add(ref1); @@ -1183,8 +1182,8 @@ public void MixedRefType() var compRef = vbComp.ToMetadataReference(embedInteropTypes: true); - var ref1 = Net451.mscorlib; - var ref2 = Net451.System; + var ref1 = NetFramework.mscorlib; + var ref2 = NetFramework.System; // Add CompilationReference comp = CSharpCompilation.Create( @@ -1408,10 +1407,10 @@ public void NegGetSymbol1() [Fact, WorkItem(537574, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537574")] public void NegReference2() { - var ref1 = Net451.mscorlib; - var ref2 = Net451.System; - var ref3 = Net451.SystemData; - var ref4 = Net451.SystemXml; + var ref1 = NetFramework.mscorlib; + var ref2 = NetFramework.System; + var ref3 = NetFramework.SystemData; + var ref4 = NetFramework.SystemXml; var comp = CSharpCompilation.Create("Compilation"); comp = comp.AddReferences(ref1, ref1); @@ -1449,7 +1448,7 @@ public void NegReference3() [Fact, WorkItem(537567, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537567")] public void NegReference4() { - var ref1 = Net451.mscorlib; + var ref1 = NetFramework.mscorlib; var comp = CSharpCompilation.Create("Compilation"); Assert.Throws( @@ -1470,8 +1469,8 @@ public void NegReference4() [Fact, WorkItem(537566, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537566")] public void NegReference5() { - var ref1 = Net451.mscorlib; - var ref2 = Net451.SystemXml; + var ref1 = NetFramework.mscorlib; + var ref2 = NetFramework.SystemXml; var comp = CSharpCompilation.Create("Compilation"); Assert.Throws( delegate @@ -1484,7 +1483,7 @@ public void NegReference5() Assert.Throws( delegate { - comp.ReplaceReference(newReference: Net451.System, oldReference: ref2); + comp.ReplaceReference(newReference: NetFramework.System, oldReference: ref2); }); Assert.Equal(0, comp.SyntaxTrees.Length); Assert.Throws(() => comp.ReplaceSyntaxTree(newTree: SyntaxFactory.ParseSyntaxTree("Using System;"), oldTree: t1)); @@ -1766,7 +1765,7 @@ void AssertCompilationCorlib(CSharpCompilation compilation) public void GetEntryPoint_Script() { var source = @"System.Console.WriteLine(1);"; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Script); compilation.VerifyDiagnostics(); var scriptMethod = compilation.GetMember("Script.
"); @@ -1787,7 +1786,7 @@ class A static void Main() { } } "; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script); compilation.VerifyDiagnostics( // (4,17): warning CS7022: The entry point of the program is global script code; ignoring 'A.Main()' entry point. // static void Main() { } @@ -1892,7 +1891,7 @@ public void CanReadAndWriteDefaultWin32Res() [Fact, WorkItem(750437, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/750437")] public void ConflictingAliases() { - var alias = Net451.System.WithAliases(new[] { "alias" }); + var alias = NetFramework.System.WithAliases(new[] { "alias" }); var text = @"extern alias alias; @@ -2248,8 +2247,8 @@ public void AppConfig1() { var references = new MetadataReference[] { - Net451.mscorlib, - Net451.System, + NetFramework.mscorlib, + NetFramework.System, TestReferences.NetFx.silverlight_v5_0_5_0.System }; @@ -2259,8 +2258,8 @@ public void AppConfig1() options: TestOptions.ReleaseDll.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default)); compilation.VerifyDiagnostics( - // error CS1703: Multiple assemblies with equivalent identity have been imported: 'System.dll' and 'System.v5.0.5.0_silverlight.dll'. Remove one of the duplicate references. - Diagnostic(ErrorCode.ERR_DuplicateImport).WithArguments("System.dll (net451)", "System.v5.0.5.0_silverlight.dll")); + // error CS1703: Multiple assemblies with equivalent identity have been imported: 'System (net461)' and 'System.v5.0.5.0_silverlight.dll'. Remove one of the duplicate references. + Diagnostic(ErrorCode.ERR_DuplicateImport).WithArguments("System (net461)", "System.v5.0.5.0_silverlight.dll").WithLocation(1, 1)); var appConfig = new MemoryStream(Encoding.UTF8.GetBytes( @" @@ -2291,7 +2290,7 @@ public void AppConfig2() public class C { public static FrameworkName Goo() { return null; }}"; var libComp = CreateEmptyCompilation( libSource, - references: new[] { MscorlibRef, Net451.System }, + references: new[] { MscorlibRef, NetFramework.System }, options: TestOptions.ReleaseDll); libComp.VerifyDiagnostics(); @@ -2301,8 +2300,8 @@ public void AppConfig2() var references = new[] { - Net451.mscorlib, - Net451.System, + NetFramework.mscorlib, + NetFramework.System, TestReferences.NetFx.silverlight_v5_0_5_0.System, mdRef }; @@ -2316,11 +2315,11 @@ public void AppConfig2() options: TestOptions.ReleaseDll.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default)); c1.VerifyDiagnostics( - // error CS1703: Multiple assemblies with equivalent identity have been imported: 'System.dll' and 'System.v5.0.5.0_silverlight.dll'. Remove one of the duplicate references. - Diagnostic(ErrorCode.ERR_DuplicateImport).WithArguments("System.dll (net451)", "System.v5.0.5.0_silverlight.dll"), - // error CS7069: Reference to type 'System.Runtime.Versioning.FrameworkName' claims it is defined in 'System', but it could not be found - Diagnostic(ErrorCode.ERR_MissingTypeInAssembly, "C.Goo").WithArguments( - "System.Runtime.Versioning.FrameworkName", "System")); + // error CS1703: Multiple assemblies with equivalent identity have been imported: 'System (net461)' and 'System.v5.0.5.0_silverlight.dll'. Remove one of the duplicate references. + Diagnostic(ErrorCode.ERR_DuplicateImport).WithArguments("System (net461)", "System.v5.0.5.0_silverlight.dll").WithLocation(1, 1), + // (1,52): error CS7069: Reference to type 'FrameworkName' claims it is defined in 'System', but it could not be found + // class A { public static void Main(string[] args) { C.Goo(); } } + Diagnostic(ErrorCode.ERR_MissingTypeInAssembly, "C.Goo").WithArguments("System.Runtime.Versioning.FrameworkName", "System").WithLocation(1, 52)); var appConfig = new MemoryStream(Encoding.UTF8.GetBytes( @" @@ -2348,7 +2347,7 @@ public void AppConfig2() public void GetMetadataReferenceAPITest() { var comp = CSharpCompilation.Create("Compilation"); - var metadata = Net451.mscorlib; + var metadata = NetFramework.mscorlib; comp = comp.AddReferences(metadata); var assemblySmb = comp.GetReferencedAssemblySymbol(metadata); var reference = comp.GetMetadataReference(assemblySmb); @@ -3385,7 +3384,7 @@ void M1() script.VerifyDiagnostics(); Assert.True(script.HasSubmissionResult()); - var compilation = CreateCompilationWithMscorlib45(@" + var compilation = CreateCompilationWithMscorlib461(@" void M1() { return; diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/GetUnusedImportDirectivesTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/GetUnusedImportDirectivesTests.cs index 19d0b01c73ab9..19eade3f36f0a 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/GetUnusedImportDirectivesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/GetUnusedImportDirectivesTests.cs @@ -396,7 +396,7 @@ public void UnusedUsingInteractive() public void UnusedUsingScript() { var tree = Parse("using System;", options: TestOptions.Script); - var comp = CreateCompilationWithMscorlib45(new[] { tree }); + var comp = CreateCompilationWithMscorlib461(new[] { tree }); comp.VerifyDiagnostics( // (2,1): info CS8019: Unnecessary using directive. diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/LoadDirectiveTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/LoadDirectiveTests.cs index 0747d8ae0724b..ad8449221c71f 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/LoadDirectiveTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/LoadDirectiveTests.cs @@ -19,7 +19,7 @@ public void EmptyFile() { var code = "#load \"\""; var options = TestOptions.DebugDll.WithSourceReferenceResolver(TestSourceReferenceResolver.Default); - var compilation = CreateCompilationWithMscorlib45(code, options: options, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(code, options: options, parseOptions: TestOptions.Script); Assert.Single(compilation.SyntaxTrees); compilation.VerifyDiagnostics( @@ -32,7 +32,7 @@ public void MissingFile() { var code = "#load \"missing\""; var options = TestOptions.DebugDll.WithSourceReferenceResolver(TestSourceReferenceResolver.Default); - var compilation = CreateCompilationWithMscorlib45(code, options: options, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(code, options: options, parseOptions: TestOptions.Script); Assert.Single(compilation.SyntaxTrees); compilation.VerifyDiagnostics( @@ -51,7 +51,7 @@ public void FileWithErrors() #load ""b.csx"" asdf();")); var options = TestOptions.DebugDll.WithSourceReferenceResolver(resolver); - var compilation = CreateCompilationWithMscorlib45(code, options: options, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(code, options: options, parseOptions: TestOptions.Script); Assert.Equal(2, compilation.SyntaxTrees.Length); compilation.GetParseDiagnostics().Verify( @@ -76,7 +76,7 @@ public void FileThatCannotBeDecoded() KeyValuePairUtil.Create("a.csx", new byte[] { 0xd8, 0x00, 0x00, 0x00 }), KeyValuePairUtil.Create("b.csx", "#load \"a.csx\"")); var options = TestOptions.DebugDll.WithSourceReferenceResolver(resolver); - var compilation = CreateCompilationWithMscorlib45(code, sourceFileName: "external1.csx", options: options, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(code, sourceFileName: "external1.csx", options: options, parseOptions: TestOptions.Script); var external1 = compilation.SyntaxTrees.Last(); var external2 = Parse(code, "external2.csx", TestOptions.Script); compilation = compilation.AddSyntaxTrees(external2); @@ -126,7 +126,7 @@ public void FileThatCannotBeDecoded() public void NoSourceReferenceResolver() { var code = "#load \"test\""; - var compilation = CreateCompilationWithMscorlib45(code, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(code, parseOptions: TestOptions.Script); Assert.Single(compilation.SyntaxTrees); compilation.VerifyDiagnostics( @@ -142,7 +142,7 @@ public void ErrorInInactiveRegion() #if undefined #load nothing #endif"; - var compilation = CreateCompilationWithMscorlib45(code, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(code, parseOptions: TestOptions.Script); Assert.Single(compilation.SyntaxTrees); compilation.VerifyDiagnostics(); @@ -154,7 +154,7 @@ public void Cycles() var code = "#load \"a.csx\""; var resolver = TestSourceReferenceResolver.Create(KeyValuePairUtil.Create("a.csx", code)); var options = TestOptions.DebugDll.WithSourceReferenceResolver(resolver); - var compilation = CreateCompilationWithMscorlib45(code, options: options, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(code, options: options, parseOptions: TestOptions.Script); Assert.Equal(2, compilation.SyntaxTrees.Length); compilation.VerifyDiagnostics(); @@ -174,7 +174,7 @@ public void Cycles() KeyValuePairUtil.Create("a.csx", "#load \"b.csx\""), KeyValuePairUtil.Create("b.csx", code)); options = TestOptions.DebugDll.WithSourceReferenceResolver(resolver); - compilation = CreateCompilationWithMscorlib45(code, options: options, parseOptions: TestOptions.Script); + compilation = CreateCompilationWithMscorlib461(code, options: options, parseOptions: TestOptions.Script); Assert.Equal(3, compilation.SyntaxTrees.Length); compilation.VerifyDiagnostics(); diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs index e84398b7fd102..c36e797067d56 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/ReferenceManagerTests.cs @@ -17,7 +17,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -738,8 +738,8 @@ public static void Main(string[] args) } }"; var tree = Parse(source); - var r1 = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemCore).GetReference(filePath: @"c:\temp\aa.dll", display: "System.Core.v4_0_30319.dll"); - var r2 = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemCore).GetReference(filePath: @"c:\temp\aa.dll", display: "System.Core.v4_0_30319.dll"); + var r1 = AssemblyMetadata.CreateFromImage(Net461.Resources.SystemCore).GetReference(filePath: @"c:\temp\aa.dll", display: "System.Core.v4_0_30319.dll"); + var r2 = AssemblyMetadata.CreateFromImage(Net461.Resources.SystemCore).GetReference(filePath: @"c:\temp\aa.dll", display: "System.Core.v4_0_30319.dll"); var r2_SysCore = r2.WithAliases(new[] { "SysCore" }); var compilation = CreateEmptyCompilation(tree, new[] { MscorlibRef, r1, r2_SysCore }, TestOptions.DebugExe, assemblyName: "Test"); @@ -990,7 +990,7 @@ public interface I {}"; [Fact] public void DuplicateAssemblyReferences_EquivalentName() { - string p1 = Temp.CreateFile().WriteAllBytes(ResourcesNet451.SystemCore).Path; + string p1 = Temp.CreateFile().WriteAllBytes(Net461.Resources.SystemCore).Path; string p2 = Temp.CreateFile().CopyContentFrom(p1).Path; var r1 = MetadataReference.CreateFromFile(p1); @@ -1010,8 +1010,8 @@ public void DuplicateAssemblyReferences_EquivalentName() [WorkItem(546026, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546026"), WorkItem(546169, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546169")] public void CS1703ERR_DuplicateImport() { - var p1 = Temp.CreateFile().WriteAllBytes(ResourcesNet451.System).Path; - var p2 = Temp.CreateFile().WriteAllBytes(ResourcesNet20.System).Path; + var p1 = Temp.CreateFile().WriteAllBytes(Net461.Resources.System).Path; + var p2 = Temp.CreateFile().WriteAllBytes(Net20.Resources.System).Path; var text = @"namespace N {}"; var comp = CSharpCompilation.Create( @@ -1358,7 +1358,7 @@ public void ReferenceResolution_RelativePaths() var rd2 = (ReferenceDirectiveTriviaSyntax)t2.GetRoot().GetDirectives().Single(); - var c = CreateCompilationWithMscorlib45(new[] { t1, t2 }, options: TestOptions.ReleaseDll.WithMetadataReferenceResolver( + var c = CreateCompilationWithMscorlib461(new[] { t1, t2 }, options: TestOptions.ReleaseDll.WithMetadataReferenceResolver( new TestMetadataReferenceResolver( pathResolver: new VirtualizedRelativePathResolver(new[] { @@ -1367,14 +1367,14 @@ public void ReferenceResolution_RelativePaths() }), files: new Dictionary() { - { @"C:\A\lib.dll", Net451.MicrosoftCSharp }, - { @"C:\B\lib.dll", Net451.MicrosoftVisualBasic }, + { @"C:\A\lib.dll", NetFramework.MicrosoftCSharp }, + { @"C:\B\lib.dll", NetFramework.MicrosoftVisualBasic }, }))); c.VerifyDiagnostics(); - Assert.Same(Net451.MicrosoftCSharp, c.GetDirectiveReference(rd1)); - Assert.Same(Net451.MicrosoftVisualBasic, c.GetDirectiveReference(rd2)); + Assert.Same(NetFramework.MicrosoftCSharp, c.GetDirectiveReference(rd1)); + Assert.Same(NetFramework.MicrosoftVisualBasic, c.GetDirectiveReference(rd2)); } [Fact] @@ -2206,10 +2206,10 @@ public void ReferenceSupersession_FxUnification1() { var c = CreateSubmissionWithExactReferences("System.Diagnostics.Process.GetCurrentProcess()", new[] { - Net20.mscorlib, - Net20.System, - Net451.mscorlib, - Net451.System, + Net20.References.mscorlib, + Net20.References.System, + NetFramework.mscorlib, + NetFramework.System, }); c.VerifyDiagnostics(); @@ -2314,8 +2314,8 @@ public void ReferenceDirective_RecursiveReferenceWithNoAliases() { // c - b (alias X) // - a (via #r) -> b - var bRef = CreateCompilationWithMscorlib45("public class B { }", assemblyName: "B").EmitToImageReference(); - var aRef = CreateCompilationWithMscorlib45("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); + var bRef = CreateCompilationWithMscorlib461("public class B { }", assemblyName: "B").EmitToImageReference(); + var aRef = CreateCompilationWithMscorlib461("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); var source = @" #r ""a"" @@ -2344,8 +2344,8 @@ public void ReferenceDirective_NonRecursiveReferenceWithNoAliases() { // c - b (alias X) // - a (via #r) -> b - var bRef = CreateCompilationWithMscorlib45("public class B { }", assemblyName: "B").EmitToImageReference(); - var aRef = CreateCompilationWithMscorlib45("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); + var bRef = CreateCompilationWithMscorlib461("public class B { }", assemblyName: "B").EmitToImageReference(); + var aRef = CreateCompilationWithMscorlib461("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); var source = @" #r ""a"" @@ -2376,8 +2376,8 @@ public void ReferenceDirective_RecursiveReferenceWithAlias1() // c - b (alias X) // - a // - a (recursive alias Y) -> b - var bRef = CreateCompilationWithMscorlib45("public class B { }", assemblyName: "B").EmitToImageReference(); - var aRef = CreateCompilationWithMscorlib45("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); + var bRef = CreateCompilationWithMscorlib461("public class B { }", assemblyName: "B").EmitToImageReference(); + var aRef = CreateCompilationWithMscorlib461("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); var source = @" extern alias X; @@ -2412,8 +2412,8 @@ public void ReferenceDirective_RecursiveReferenceWithAlias2() // c - b (alias X) // - a (recursive alias Y) -> b // - a - var bRef = CreateCompilationWithMscorlib45("public class B { }", assemblyName: "B").EmitToImageReference(); - var aRef = CreateCompilationWithMscorlib45("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); + var bRef = CreateCompilationWithMscorlib461("public class B { }", assemblyName: "B").EmitToImageReference(); + var aRef = CreateCompilationWithMscorlib461("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); var source = @" extern alias X; @@ -2448,8 +2448,8 @@ public void ReferenceDirective_RecursiveReferenceWithAlias3() // c - b (alias X) // - a (recursive alias Y) -> b // - a - var bRef = CreateCompilationWithMscorlib45("public class B { }", assemblyName: "B").EmitToImageReference(); - var aRef = CreateCompilationWithMscorlib45("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); + var bRef = CreateCompilationWithMscorlib461("public class B { }", assemblyName: "B").EmitToImageReference(); + var aRef = CreateCompilationWithMscorlib461("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); var source = @" extern alias X; @@ -2486,9 +2486,9 @@ public void ReferenceDirective_RecursiveReferenceWithAlias4() // c - b (alias X) // - a (recursive alias Y) -> b // - d (recursive alias Z) -> a - var bRef = CreateCompilationWithMscorlib45("public class B { }", assemblyName: "B").EmitToImageReference(); - var aRef = CreateCompilationWithMscorlib45("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); - var dRef = CreateCompilationWithMscorlib45("public class D : A { }", new[] { aRef, bRef }, assemblyName: "D").EmitToImageReference(); + var bRef = CreateCompilationWithMscorlib461("public class B { }", assemblyName: "B").EmitToImageReference(); + var aRef = CreateCompilationWithMscorlib461("public class A : B { }", new[] { bRef }, assemblyName: "A").EmitToImageReference(); + var dRef = CreateCompilationWithMscorlib461("public class D : A { }", new[] { aRef, bRef }, assemblyName: "D").EmitToImageReference(); var source = @" extern alias X; @@ -3175,16 +3175,16 @@ public void MissingAssemblyResolution_Supersession_FxUnification() // "System, v2" // b -> "mscorlib, v4" // "System, v4" - var aRef = CreateEmptyCompilation(@"public interface A { System.Diagnostics.Process PA { get; } }", new[] { Net20.mscorlib, Net20.System }, + var aRef = CreateEmptyCompilation(@"public interface A { System.Diagnostics.Process PA { get; } }", new[] { Net20.References.mscorlib, Net20.References.System }, options: options, assemblyName: "A").EmitToImageReference(); - var bRef = CreateEmptyCompilation(@"public interface B { System.Diagnostics.Process PB { get; } }", new[] { MscorlibRef_v4_0_30316_17626, Net451.System }, + var bRef = CreateEmptyCompilation(@"public interface B { System.Diagnostics.Process PB { get; } }", new[] { MscorlibRef_v4_0_30316_17626, NetFramework.System }, options: options, assemblyName: "B").EmitToImageReference(); var resolverC = new TestMissingMetadataReferenceResolver(new Dictionary { - { "System, 2.0.0.0", Net20.System }, - { "System, 4.0.0.0", Net451.System }, + { "System, 2.0.0.0", Net20.References.System }, + { "System, 4.0.0.0", NetFramework.System }, }); var c = CreateSubmissionWithExactReferences("public interface C : A, B { System.Diagnostics.Process PC { get; } }", new[] { MscorlibRef_v4_0_30316_17626, aRef, bRef }, @@ -3194,11 +3194,11 @@ public void MissingAssemblyResolution_Supersession_FxUnification() resolverC.VerifyResolutionAttempts( "B -> System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", - "System.dll (net451) -> System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", - "System.dll (net451) -> System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", + "System (net461) -> System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "System (net461) -> System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "A -> System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", - "System.dll (net20) -> System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", - "System.dll (net20) -> System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); + "System (net20) -> System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "System (net20) -> System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); c.VerifyAssemblyVersionsAndAliases( "mscorlib, Version=4.0.0.0", diff --git a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs index a71a6b2989f0c..8b6b16d4ef626 100644 --- a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs @@ -15,7 +15,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -1093,6 +1093,81 @@ class @true { SymbolDisplayPartKind.Punctuation); } + [Fact] + public void TestEscapeRecordKeywordIdentifiers_EscapesTypeNames() + { + var text = @" +class @record { + @record @struct(@record @true, string name, bool @bool = true) { return @record; } } +"; + + Func findSymbol = global => + global.GetTypeMembers("record", 0).Single(). + GetMembers("struct").Single(); + + var format = new SymbolDisplayFormat( + memberOptions: SymbolDisplayMemberOptions.IncludeType | SymbolDisplayMemberOptions.IncludeParameters, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeName | SymbolDisplayParameterOptions.IncludeDefaultValue, + miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers | SymbolDisplayMiscellaneousOptions.UseSpecialTypes); + + TestSymbolDescription( + text, + findSymbol, + format, + "@record @struct(@record @true, string name, bool @bool = true)", + SymbolDisplayPartKind.ClassName, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.MethodName, //@struct + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.ClassName, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.ParameterName, //@record + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Keyword, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.ParameterName, //string + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Keyword, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.ParameterName, //@bool + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Keyword, + SymbolDisplayPartKind.Punctuation); + } + + [Fact] + public void TestEscapeRecordKeywordIdentifiers_DoesNotEscapesMethodNames() + { + var text = @" +class C { + C record() { return default; } } +"; + + Func findSymbol = global => + global.GetTypeMembers("C", 0).Single(). + GetMembers("record").Single(); + + var format = new SymbolDisplayFormat( + memberOptions: SymbolDisplayMemberOptions.IncludeType | SymbolDisplayMemberOptions.IncludeParameters, + parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeName | SymbolDisplayParameterOptions.IncludeDefaultValue, + miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers | SymbolDisplayMiscellaneousOptions.UseSpecialTypes); + + TestSymbolDescription( + text, + findSymbol, + format, + "C record()", + SymbolDisplayPartKind.ClassName, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.MethodName, //record + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Punctuation); + } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74117")] public void TestRecordStructName() { @@ -2589,7 +2664,7 @@ class C2 {} } } } GetTypeMembers("C2").Single(); var format = new SymbolDisplayFormat( - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces); + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers); TestSymbolDescription( text, @@ -2605,6 +2680,35 @@ class C2 {} } } } SymbolDisplayPartKind.ClassName); } + [Fact] + public void TestAliases_AliasesNamedRecordAreEscaped() + { + var text = @" +using @record = N1; + +namespace N1 { + class C1 {} } +"; + + Func findSymbol = global => + global.GetNestedNamespace("N1"). + GetTypeMembers("C1").Single(); + + var format = new SymbolDisplayFormat( + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers); + + TestSymbolDescription( + text, + findSymbol, + format, + "@record.C1", + text.IndexOf("namespace", StringComparison.Ordinal), + true, + SymbolDisplayPartKind.AliasName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.ClassName); + } + [Fact] public void TestAlias2() { @@ -3019,7 +3123,7 @@ public void TestMethodCustomModifierPositions() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, - Net40.mscorlib + Net40.References.mscorlib }); var globalNamespace = assemblies[0].GlobalNamespace; @@ -3148,7 +3252,7 @@ public void TestPropertyCustomModifierPositions() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, - Net40.mscorlib + Net40.References.mscorlib }); var globalNamespace = assemblies[0].GlobalNamespace; @@ -3209,7 +3313,7 @@ public void TestFieldCustomModifierPositions() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, - Net40.mscorlib + Net40.References.mscorlib }); var globalNamespace = assemblies[0].GlobalNamespace; @@ -3270,7 +3374,7 @@ public void TestMultipleCustomModifier() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, - Net40.mscorlib + Net40.References.mscorlib }); var globalNamespace = assemblies[0].GlobalNamespace; @@ -6404,7 +6508,7 @@ async unsafe Task Local(ref int* x, out char? c) } }"); var root = srcTree.GetRoot(); - var comp = CreateCompilationWithMscorlib45(new[] { srcTree }); + var comp = CreateCompilationWithMscorlib461(new[] { srcTree }); var semanticModel = comp.GetSemanticModel(comp.SyntaxTrees.Single()); var local = root.DescendantNodes() @@ -6499,7 +6603,7 @@ async unsafe Task Local(in int* x, out char? c) } }"); var root = srcTree.GetRoot(); - var comp = CreateCompilationWithMscorlib45(new[] { srcTree }); + var comp = CreateCompilationWithMscorlib461(new[] { srcTree }); var semanticModel = comp.GetSemanticModel(comp.SyntaxTrees.Single()); var local = root.DescendantNodes() diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/AssemblyAndNamespaceTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/AssemblyAndNamespaceTests.cs index 50c991a278791..2f1f955c3ecc0 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/AssemblyAndNamespaceTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/AssemblyAndNamespaceTests.cs @@ -370,7 +370,7 @@ public void SpecialTypesAndAliases() { var source = @"public class C { }"; - var aliasedCorlib = TestMetadata.Net451.mscorlib.WithAliases(ImmutableArray.Create("Goo")); + var aliasedCorlib = NetFramework.mscorlib.WithAliases(ImmutableArray.Create("Goo")); var comp = CreateEmptyCompilation(source, new[] { aliasedCorlib }); @@ -409,10 +409,10 @@ async void AM() { } } "; - var libComp = CreateCompilationWithMscorlib45(lib, assemblyName: "lib"); + var libComp = CreateCompilationWithMscorlib461(lib, assemblyName: "lib"); var libRef = libComp.EmitToImageReference(aliases: ImmutableArray.Create("myTask")); - var comp = CreateCompilationWithMscorlib45(source, new[] { libRef }); + var comp = CreateCompilationWithMscorlib461(source, new[] { libRef }); // NOTE: As in dev11, we don't consider myTask::System.Threading.Tasks.Task to be // ambiguous with global::System.Threading.Tasks.Task (prefer global). @@ -455,7 +455,7 @@ public static int Main() } " + cb + @" "; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( // (2,1): error CS1671: A namespace declaration cannot have modifiers or attributes Diagnostic(ErrorCode.ERR_BadModifiersOnNamespace, "public").WithLocation(2, 1)); } @@ -467,7 +467,7 @@ public void CS1671ERR_BadModifiersOnNamespace02() namespace N { } "; - CreateCompilationWithMscorlib45(test).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test).VerifyDiagnostics( // (2,1): error CS1671: A namespace declaration cannot have modifiers or attributes Diagnostic(ErrorCode.ERR_BadModifiersOnNamespace, "[System.Obsolete]").WithLocation(1, 1)); } @@ -478,7 +478,7 @@ public void NamespaceWithSemicolon1() var test = @"namespace A;"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics(); } [Fact] @@ -487,7 +487,7 @@ public void NamespaceWithSemicolon3() var test = @"namespace A.B;"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics(); } [Fact] @@ -497,7 +497,7 @@ public void MultipleFileScopedNamespaces() @"namespace A; namespace B;"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( // (2,11): error CS8907: Source file can only contain one file-scoped namespace declaration. // namespace B; Diagnostic(ErrorCode.ERR_MultipleFileScopedNamespace, "B").WithLocation(2, 11)); @@ -512,7 +512,7 @@ public void FileScopedNamespaceNestedInNormalNamespace() namespace B; }"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( // (3,15): error CS8908: Source file can not contain both file-scoped and normal namespace declarations. // namespace B; Diagnostic(ErrorCode.ERR_FileScopedAndNormalNamespace, "B").WithLocation(3, 15)); @@ -527,7 +527,7 @@ namespace B { }"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( // (2,11): error CS8908: error CS8908: Source file can not contain both file-scoped and normal namespace declarations. // namespace B Diagnostic(ErrorCode.ERR_FileScopedAndNormalNamespace, "B").WithLocation(2, 11)); @@ -542,7 +542,7 @@ public void NormalAndFileScopedNamespace2() } namespace B;"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( // (4,11): error CS8909: File-scoped namespace must precede all other members in a file. // namespace B; Diagnostic(ErrorCode.ERR_FileScopedNamespaceNotBeforeAllMembers, "B").WithLocation(4, 11)); @@ -555,7 +555,7 @@ public void NamespaceWithPrecedingUsing() @"using System; namespace A;"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( // (1,1): hidden CS8019: Unnecessary using directive. // using System; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using System;").WithLocation(1, 1)); @@ -568,7 +568,7 @@ public void NamespaceWithFollowingUsing() @"namespace X; using System;"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( // (2,1): hidden CS8019: Unnecessary using directive. // using System; Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using System;").WithLocation(2, 1)); @@ -581,7 +581,7 @@ public void NamespaceWithPrecedingType() @"class X { } namespace System;"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( // (2,11): error CS8909: File-scoped namespace must precede all other members in a file. // namespace System; Diagnostic(ErrorCode.ERR_FileScopedNamespaceNotBeforeAllMembers, "System").WithLocation(2, 11)); @@ -594,7 +594,7 @@ public void NamespaceWithFollowingType() @"namespace System; class X { }"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics(); } [Fact] @@ -605,7 +605,7 @@ public void FileScopedNamespaceWithPrecedingStatement() System.Console.WriteLine(); namespace B;"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( // (3,11): error CS8914: File-scoped namespace must precede all other members in a file. // namespace B; Diagnostic(ErrorCode.ERR_FileScopedNamespaceNotBeforeAllMembers, "B").WithLocation(3, 11)); @@ -619,7 +619,7 @@ public void FileScopedNamespaceWithFollowingStatement() namespace B; System.Console.WriteLine();"; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( // (3,16): error CS0116: A namespace cannot directly contain members such as fields or methods // System.Console.WriteLine(); Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "WriteLine").WithLocation(3, 16), @@ -660,7 +660,7 @@ void M() } "; - CreateCompilationWithMscorlib45(new[] { source1, source2 }, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics(); + CreateCompilationWithMscorlib461(new[] { source1, source2 }, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics(); } [Fact] @@ -671,7 +671,7 @@ namespace B; int x; // 1 "; - CreateCompilationWithMscorlib45(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test, parseOptions: TestOptions.RegularWithFileScopedNamespaces).VerifyDiagnostics( // (3,5): error CS0116: A namespace cannot directly contain members such as fields, methods or statements // int x; // 1 Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "x").WithLocation(3, 5)); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CompilationCreationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CompilationCreationTests.cs index a16c746ef12fc..57cad756170cb 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CompilationCreationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CompilationCreationTests.cs @@ -17,7 +17,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -106,7 +106,7 @@ public void CorLibTypes() [Fact] public void CyclicReference() { - var mscorlibRef = Net451.mscorlib; + var mscorlibRef = NetFramework.mscorlib; var cyclic2Ref = TestReferences.SymbolsTests.Cyclic.Cyclic2.dll; var tc1 = CSharpCompilation.Create("Cyclic1", references: new[] { mscorlibRef, cyclic2Ref }); @@ -128,7 +128,7 @@ public void MultiTargeting1() var varV1MTTestLib2Ref = TestReferences.SymbolsTests.V1.MTTestLib2.dll; var asm1 = MetadataTestHelpers.GetSymbolsForReferences(mrefs: new[] { - Net451.mscorlib, + NetFramework.mscorlib, varV1MTTestLib2Ref }); @@ -143,7 +143,7 @@ public void MultiTargeting1() var asm2 = MetadataTestHelpers.GetSymbolsForReferences(new[] { - Net451.mscorlib, + NetFramework.mscorlib, varV1MTTestLib2Ref, TestReferences.SymbolsTests.V1.MTTestLib1.dll }); @@ -172,7 +172,7 @@ public void MultiTargeting1() var varV2MTTestLib3Ref = TestReferences.SymbolsTests.V2.MTTestLib3.dll; var asm3 = MetadataTestHelpers.GetSymbolsForReferences(new[] { - Net451.mscorlib, + NetFramework.mscorlib, varV1MTTestLib2Ref, TestReferences.SymbolsTests.V2.MTTestLib1.dll, varV2MTTestLib3Ref @@ -229,7 +229,7 @@ public void MultiTargeting1() var varV3MTTestLib4Ref = TestReferences.SymbolsTests.V3.MTTestLib4.dll; var asm4 = MetadataTestHelpers.GetSymbolsForReferences(new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, varV1MTTestLib2Ref, TestReferences.SymbolsTests.V3.MTTestLib1.dll, varV2MTTestLib3Ref, @@ -326,7 +326,7 @@ public void MultiTargeting1() var asm5 = MetadataTestHelpers.GetSymbolsForReferences(new[] { - Net451.mscorlib, + NetFramework.mscorlib, varV2MTTestLib3Ref }); @@ -335,7 +335,7 @@ public void MultiTargeting1() var asm6 = MetadataTestHelpers.GetSymbolsForReferences(new[] { - Net451.mscorlib, + NetFramework.mscorlib, varV1MTTestLib2Ref }); @@ -344,7 +344,7 @@ public void MultiTargeting1() var asm7 = MetadataTestHelpers.GetSymbolsForReferences(new[] { - Net451.mscorlib, + NetFramework.mscorlib, varV1MTTestLib2Ref, varV2MTTestLib3Ref, varV3MTTestLib4Ref @@ -413,7 +413,7 @@ public void MultiTargeting1() // This test shows that simple reordering of references doesn't pick different set of assemblies var asm8 = MetadataTestHelpers.GetSymbolsForReferences(new[] { - Net451.mscorlib, + NetFramework.mscorlib, varV3MTTestLib4Ref, varV1MTTestLib2Ref, varV2MTTestLib3Ref @@ -429,7 +429,7 @@ public void MultiTargeting1() var asm9 = MetadataTestHelpers.GetSymbolsForReferences(new[] { - Net451.mscorlib, + NetFramework.mscorlib, varV3MTTestLib4Ref }); @@ -438,7 +438,7 @@ public void MultiTargeting1() var asm10 = MetadataTestHelpers.GetSymbolsForReferences(new[] { - Net451.mscorlib, + NetFramework.mscorlib, varV1MTTestLib2Ref, TestReferences.SymbolsTests.V3.MTTestLib1.dll, varV2MTTestLib3Ref, @@ -691,7 +691,7 @@ public class Class1 } " }, - new[] { Net451.mscorlib }); + new[] { NetFramework.mscorlib }); var asm_MTTestLib1_V1 = varC_MTTestLib1_V1.SourceAssembly().BoundReferences(); @@ -713,7 +713,7 @@ Class1 Foo() } " }, - new MetadataReference[] { Net451.mscorlib, varC_MTTestLib1_V1.ToMetadataReference() }); + new MetadataReference[] { NetFramework.mscorlib, varC_MTTestLib1_V1.ToMetadataReference() }); var asm_MTTestLib2 = varC_MTTestLib2.SourceAssembly().BoundReferences(); @@ -724,7 +724,7 @@ Class1 Foo() null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V1.ToMetadataReference() }); @@ -767,7 +767,7 @@ public class Class2 } " }, - new MetadataReference[] { Net451.mscorlib }); + new MetadataReference[] { NetFramework.mscorlib }); var asm_MTTestLib1_V2 = varC_MTTestLib1_V2.SourceAssembly().BoundReferences(); @@ -802,7 +802,7 @@ Class4 Foo3() }, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V2.ToMetadataReference() }); @@ -817,7 +817,7 @@ Class4 Foo3() null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V2.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference() @@ -893,7 +893,7 @@ public class Class3 } " }, - new MetadataReference[] { Net451.mscorlib }); + new MetadataReference[] { NetFramework.mscorlib }); var asm_MTTestLib1_V3 = varC_MTTestLib1_V3.SourceAssembly().BoundReferences(); @@ -939,7 +939,7 @@ Class5 Foo5() } " }, - new MetadataReference[] { Net451.mscorlib, + new MetadataReference[] { NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V3.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference() }); var asm_MTTestLib4 = varC_MTTestLib4.SourceAssembly().BoundReferences(); @@ -953,7 +953,7 @@ Class5 Foo5() null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V3.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference(), @@ -1056,7 +1056,7 @@ Class5 Foo5() var c5 = CreateCompilation(new AssemblyIdentity("c5"), null, - new MetadataReference[] { Net451.mscorlib, varC_MTTestLib3.ToMetadataReference() }); + new MetadataReference[] { NetFramework.mscorlib, varC_MTTestLib3.ToMetadataReference() }); var asm5 = c5.SourceAssembly().BoundReferences(); @@ -1065,7 +1065,7 @@ Class5 Foo5() var c6 = CreateCompilation(new AssemblyIdentity("c6"), null, - new MetadataReference[] { Net451.mscorlib, varC_MTTestLib2.ToMetadataReference() }); + new MetadataReference[] { NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference() }); var asm6 = c6.SourceAssembly().BoundReferences(); @@ -1074,7 +1074,7 @@ Class5 Foo5() var c7 = CreateCompilation(new AssemblyIdentity("c7"), null, - new MetadataReference[] { Net451.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference(), varC_MTTestLib4.ToMetadataReference() }); + new MetadataReference[] { NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference(), varC_MTTestLib4.ToMetadataReference() }); var asm7 = c7.SourceAssembly().BoundReferences(); @@ -1142,7 +1142,7 @@ Class5 Foo5() // This test shows that simple reordering of references doesn't pick different set of assemblies var c8 = CreateCompilation(new AssemblyIdentity("c8"), null, - new MetadataReference[] { Net451.mscorlib, varC_MTTestLib4.ToMetadataReference(), varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference() }); + new MetadataReference[] { NetFramework.mscorlib, varC_MTTestLib4.ToMetadataReference(), varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference() }); var asm8 = c8.SourceAssembly().BoundReferences(); @@ -1156,7 +1156,7 @@ Class5 Foo5() var c9 = CreateCompilation(new AssemblyIdentity("c9"), null, - new MetadataReference[] { Net451.mscorlib, varC_MTTestLib4.ToMetadataReference() }); + new MetadataReference[] { NetFramework.mscorlib, varC_MTTestLib4.ToMetadataReference() }); var asm9 = c9.SourceAssembly().BoundReferences(); @@ -1166,7 +1166,7 @@ Class5 Foo5() var c10 = CreateCompilation(new AssemblyIdentity("c10"), null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V3.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference(), @@ -1420,7 +1420,7 @@ public void MultiTargeting3() var varC_MTTestLib2 = CreateCompilation(varMTTestLib2_Name, (string[])null, new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V1.MTTestLib1.dll, TestReferences.SymbolsTests.V1.MTTestModule2.netmodule }); @@ -1430,7 +1430,7 @@ public void MultiTargeting3() var c2 = CreateCompilation(new AssemblyIdentity("c2"), null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V1.MTTestLib1.dll, new CSharpCompilationReference(varC_MTTestLib2) }); @@ -1469,7 +1469,7 @@ public void MultiTargeting3() null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V2.MTTestLib1.dll, new CSharpCompilationReference(varC_MTTestLib2), TestReferences.SymbolsTests.V2.MTTestModule3.netmodule @@ -1486,7 +1486,7 @@ public void MultiTargeting3() null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V2.MTTestLib1.dll, new CSharpCompilationReference(varC_MTTestLib2), new CSharpCompilationReference(varC_MTTestLib3) @@ -1554,7 +1554,7 @@ public void MultiTargeting3() null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V3.MTTestLib1.dll, new CSharpCompilationReference(varC_MTTestLib2), new CSharpCompilationReference(varC_MTTestLib3), @@ -1573,7 +1573,7 @@ public void MultiTargeting3() var c4 = CreateCompilation(new AssemblyIdentity("c4"), null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V3.MTTestLib1.dll, new CSharpCompilationReference(varC_MTTestLib2), new CSharpCompilationReference(varC_MTTestLib3), @@ -1678,7 +1678,7 @@ public void MultiTargeting3() var c5 = CreateCompilation(new AssemblyIdentity("c5"), null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, new CSharpCompilationReference(varC_MTTestLib3) }); @@ -1690,7 +1690,7 @@ public void MultiTargeting3() var c6 = CreateCompilation(new AssemblyIdentity("c6"), null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, new CSharpCompilationReference(varC_MTTestLib2) }); @@ -1702,7 +1702,7 @@ public void MultiTargeting3() var c7 = CreateCompilation(new AssemblyIdentity("c7"), null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, new CSharpCompilationReference(varC_MTTestLib2), new CSharpCompilationReference(varC_MTTestLib3), new CSharpCompilationReference(varC_MTTestLib4) @@ -1779,7 +1779,7 @@ public void MultiTargeting3() var c8 = CreateCompilation(new AssemblyIdentity("c8"), null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, new CSharpCompilationReference(varC_MTTestLib4), new CSharpCompilationReference(varC_MTTestLib2), new CSharpCompilationReference(varC_MTTestLib3) @@ -1798,7 +1798,7 @@ public void MultiTargeting3() var c9 = CreateCompilation(new AssemblyIdentity("c9"), null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, new CSharpCompilationReference(varC_MTTestLib4) }); @@ -1810,7 +1810,7 @@ public void MultiTargeting3() var c10 = CreateCompilation(new AssemblyIdentity("c10"), null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V3.MTTestLib1.dll, new CSharpCompilationReference(varC_MTTestLib2), new CSharpCompilationReference(varC_MTTestLib3), @@ -2082,7 +2082,7 @@ public C1.C2 Foo() } " }, - new[] { Net451.mscorlib }); + new[] { NetFramework.mscorlib }); var asm1_V1 = localC1_V1.SourceAssembly(); @@ -2104,7 +2104,7 @@ public C1.C2 Foo() } " }, - new MetadataReference[] { Net451.mscorlib }); + new MetadataReference[] { NetFramework.mscorlib }); var asm1_V2 = localC1_V2.SourceAssembly(); @@ -2119,7 +2119,7 @@ public class C4 } " }, - new MetadataReference[] { Net451.mscorlib }); + new MetadataReference[] { NetFramework.mscorlib }); var asm4_V1 = localC4_V1.SourceAssembly(); @@ -2134,7 +2134,7 @@ public class C4 } " }, - new MetadataReference[] { Net451.mscorlib }); + new MetadataReference[] { NetFramework.mscorlib }); var asm4_V2 = localC4_V2.SourceAssembly(); @@ -2149,7 +2149,7 @@ public class C8 { } " }, - new MetadataReference[] { Net451.mscorlib }); + new MetadataReference[] { NetFramework.mscorlib }); var asm7 = c7.SourceAssembly(); @@ -2231,7 +2231,7 @@ public class C305 } " }, - new MetadataReference[] { Net451.mscorlib, + new MetadataReference[] { NetFramework.mscorlib, new CSharpCompilationReference(localC1_V1), new CSharpCompilationReference(localC4_V1), new CSharpCompilationReference(c7) @@ -2252,7 +2252,7 @@ public class C5 : " }, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, new CSharpCompilationReference(c3), new CSharpCompilationReference(localC1_V2), new CSharpCompilationReference(localC4_V2), @@ -2557,7 +2557,7 @@ Class4 M3() var c2 = CreateCompilation(c2_Name, null, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V2.MTTestLib1.dll, new CSharpCompilationReference(c1) }); @@ -2611,9 +2611,9 @@ private bool HasSingleTypeOfKind(CSharpCompilation c, TypeKind kind, string full [Fact] public void AddRemoveReferences() { - var mscorlibRef = Net451.mscorlib; - var systemCoreRef = Net451.SystemCore; - var systemRef = Net451.System; + var mscorlibRef = NetFramework.mscorlib; + var systemCoreRef = NetFramework.SystemCore; + var systemRef = NetFramework.System; CSharpCompilation c = CSharpCompilation.Create("Test"); Assert.False(HasSingleTypeOfKind(c, TypeKind.Struct, "System.Int32")); @@ -2674,10 +2674,10 @@ public override ImmutableArray ResolveReference(str [Fact] public void CompilationWithReferenceDirectives() { - var data = Temp.CreateFile().WriteAllBytes(ResourcesNet451.SystemData).Path; - var core = Temp.CreateFile().WriteAllBytes(ResourcesNet451.SystemCore).Path; - var xml = Temp.CreateFile().WriteAllBytes(ResourcesNet451.SystemXml).Path; - var system = Temp.CreateFile().WriteAllBytes(ResourcesNet451.System).Path; + var data = Temp.CreateFile().WriteAllBytes(Net461.Resources.SystemData).Path; + var core = Temp.CreateFile().WriteAllBytes(Net461.Resources.SystemCore).Path; + var xml = Temp.CreateFile().WriteAllBytes(Net461.Resources.SystemXml).Path; + var system = Temp.CreateFile().WriteAllBytes(Net461.Resources.System).Path; var trees = new[] { @@ -2698,7 +2698,7 @@ public void CompilationWithReferenceDirectives() ", options: TestOptions.Script) }; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( trees, options: TestOptions.ReleaseDll.WithMetadataReferenceResolver(new Resolver(data, core, system))); @@ -2719,9 +2719,9 @@ public void CompilationWithReferenceDirectives() [Fact] public void CompilationWithReferenceDirectives_Errors() { - var data = Temp.CreateFile().WriteAllBytes(ResourcesNet451.SystemData).Path; - var core = Temp.CreateFile().WriteAllBytes(ResourcesNet451.SystemCore).Path; - var system = Temp.CreateFile().WriteAllBytes(ResourcesNet451.System).Path; + var data = Temp.CreateFile().WriteAllBytes(Net461.Resources.SystemData).Path; + var core = Temp.CreateFile().WriteAllBytes(Net461.Resources.SystemCore).Path; + var system = Temp.CreateFile().WriteAllBytes(Net461.Resources.System).Path; var trees = new[] { SyntaxFactory.ParseSyntaxTree(@" @@ -2734,7 +2734,7 @@ public void CompilationWithReferenceDirectives_Errors() ", TestOptions.Regular) }; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( trees, options: TestOptions.ReleaseDll.WithMetadataReferenceResolver(new Resolver(data, core, system))); @@ -2779,7 +2779,7 @@ public void MetadataReferenceProvider() #r """ + csInterfaces01 + @""" class C : Metadata.ICSPropImpl { }"; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { Parse(source, options: TestOptions.Script) }, options: TestOptions.ReleaseDll.WithMetadataReferenceResolver(new DummyReferenceResolver(csClasses01))); @@ -2789,7 +2789,7 @@ class C : Metadata.ICSPropImpl { }"; [Fact] public void CompilationWithReferenceDirective_NoResolver() { - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( new[] { SyntaxFactory.ParseSyntaxTree(@"#r ""bar""", TestOptions.Script, "a.csx", Encoding.UTF8) }, options: TestOptions.ReleaseDll.WithMetadataReferenceResolver(null)); @@ -2816,7 +2816,7 @@ class C ", TestOptions.Regular) }; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( trees, options: TestOptions.ReleaseDll.WithUsings(ImmutableArray.Create("System.Console", "System"))); @@ -2838,7 +2838,7 @@ public void GlobalUsings_Errors() ", options: TestOptions.Script) }; - var compilation = CreateCompilationWithMscorlib45( + var compilation = CreateCompilationWithMscorlib461( trees, options: TestOptions.ReleaseDll.WithUsings("System.Console!", "Blah")); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs index 2172bf636d89c..c461c0a0129c9 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ConversionTests.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols { @@ -20,7 +21,7 @@ public class ConversionTests : CSharpTestBase [Fact] public void Test1() { - var mscorlibRef = TestMetadata.Net40.mscorlib; + var mscorlibRef = Net40.References.mscorlib; var compilation = CSharpCompilation.Create("Test", references: new MetadataReference[] { mscorlibRef }); var sys = compilation.GlobalNamespace.ChildNamespace("System"); Conversions c = new BuckStopsHereBinder(compilation, associatedFileIdentifier: null).Conversions; @@ -221,7 +222,7 @@ class X { O f10; } "; - var mscorlibRef = TestMetadata.Net40.mscorlib; + var mscorlibRef = Net40.References.mscorlib; var compilation = CSharpCompilation.Create("Test", new[] { Parse(code) }, new[] { mscorlibRef }); var global = compilation.GlobalNamespace; diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/Choosing.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/Choosing.cs index 5c29a560d0689..a7847f138347a 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/Choosing.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CorLibrary/Choosing.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.CorLibrary { @@ -19,7 +20,7 @@ public void MultipleMscorlibReferencesInMetadata() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CorLibrary.GuidTest2.exe, - TestMetadata.Net40.mscorlib + Net40.References.mscorlib }); Assert.Same(assemblies[1], assemblies[0].Modules[0].CorLibrary()); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CovariantReturnTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CovariantReturnTests.cs index c4c0b0ca9ca17..942fb93ac05c7 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CovariantReturnTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CovariantReturnTests.cs @@ -262,7 +262,7 @@ private static void VerifyOverride( { Assert.True(method.IsOverride); Assert.False(method.IsVirtual); - Assert.True(method.IsMetadataVirtual(ignoreInterfaceImplementationChanges: true)); + Assert.True(method.IsMetadataVirtual(MethodSymbol.IsMetadataVirtualOption.IgnoreInterfaceImplementationChanges)); var isCovariant = !method.ReturnType.Equals(overriddenMethod.ReturnType, TypeCompareKind.AllIgnoreOptions); var checkMetadata = hasReturnConversion(method.ReturnType, overriddenMethod.ReturnType); if (checkMetadata) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CustomModifiersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CustomModifiersTests.cs index 73a57fcf805fc..f10d3b39d86ca 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CustomModifiersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CustomModifiersTests.cs @@ -1522,7 +1522,7 @@ public override void Test(System.Nullable x) Assert.Same(compilation1.SourceModule.CorLibrary(), test.Parameters.First().Type.OriginalDefinition.ContainingAssembly); Assert.Same(compilation1.SourceModule.CorLibrary(), ((CSharpCustomModifier)((NamedTypeSymbol)test.Parameters.First().Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0].CustomModifiers.First()).ModifierSymbol.ContainingAssembly); - var compilation2 = CreateCompilationWithMscorlib45(new SyntaxTree[] { }, references: new[] { new CSharpCompilationReference(compilation1) }); + var compilation2 = CreateCompilationWithMscorlib461(new SyntaxTree[] { }, references: new[] { new CSharpCompilationReference(compilation1) }); test = compilation2.GetTypeByMetadataName("Module1").GetMember("Test"); Assert.Equal("void Module1.Test(System.Int32 modopt(System.Runtime.CompilerServices.IsLong)? x)", test.ToTestDisplayString()); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index 6466391693427..252bf355fe09b 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -1594,7 +1594,7 @@ class Test1 : I1 {} "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview); var m1 = compilation1.GetMember("I1.M1"); @@ -1632,7 +1632,7 @@ class Test2 : I1 "; var compilation3 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, - options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: isStatic ? TestOptions.Regular11 : TestOptions.Regular8); m1 = compilation3.GetMember("I1.M1"); @@ -1688,7 +1688,7 @@ class Test2 : I1 foreach (var reference in new[] { compilation1.EmitToImageReference(), compilation1.ToMetadataReference() }) { var compilation3 = CreateCompilation(source2, new[] { reference }, - options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: isStatic ? TestOptions.Regular11 : TestOptions.Regular8); var m1 = compilation3.GetMember("I1.M1"); @@ -1754,7 +1754,7 @@ public void M2() {} foreach (var reference in new[] { compilation1.EmitToImageReference(), compilation1.ToMetadataReference() }) { var compilation3 = CreateCompilation(source2, new[] { reference }, options: TestOptions.DebugDll, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular7_3); Assert.False(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); var m1 = compilation3.GetMember("I1.M1"); @@ -1785,7 +1785,7 @@ public interface I1 class Test1 : I1 {} "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: isStatic ? TestOptions.Regular10 : TestOptions.Regular7_3, skipUsesIsNullable: true); var m1 = compilation1.GetMember("I1.M1"); @@ -1829,7 +1829,7 @@ class Test2 : I1 "; var compilation3 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, - options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: isStatic ? TestOptions.Regular10 : TestOptions.Regular7_3); m1 = compilation3.GetMember("I1.M1"); @@ -1980,7 +1980,7 @@ public interface I1 } } "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular11); var m1 = compilation1.GetMember("I1.M1"); @@ -2049,7 +2049,7 @@ class Test1 : I1 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (4,17): error CS8701: Target runtime doesn't support default interface implementation. @@ -3217,7 +3217,7 @@ public interface I1 // (4,34): error CS1014: A get or set accessor expected // static abstract int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_GetOrSetExpected, "remove").WithLocation(4, 34), - // (4,25): error CS8050: Only auto-implemented properties can have initializers. + // (4,25): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static abstract int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 25), // (4,25): error CS0548: 'I1.P1': property or indexer must have at least one accessor @@ -3245,14 +3245,17 @@ public interface I1 targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation1.VerifyEmitDiagnostics( - // (4,13): error CS1014: A get, set or init accessor expected - // int P1 {add; remove;} = 0; + // (4,28): error CS1014: A get or set accessor expected + // static virtual int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_GetOrSetExpected, "add").WithLocation(4, 28), - // (4,18): error CS1014: A get, set or init accessor expected - // int P1 {add; remove;} = 0; + // (4,33): error CS1014: A get or set accessor expected + // static virtual int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_GetOrSetExpected, "remove").WithLocation(4, 33), - // (4,9): error CS0548: 'I1.P1': property or indexer must have at least one accessor - // int P1 {add; remove;} = 0; + // (4,24): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. + // static virtual int P1 {add; remove;} = 0; + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 24), + // (4,24): error CS0548: 'I1.P1': property or indexer must have at least one accessor + // static virtual int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "P1").WithArguments("I1.P1").WithLocation(4, 24) ); @@ -3306,7 +3309,7 @@ public interface I1 targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation1.VerifyEmitDiagnostics( - // (4,25): error CS8050: Only auto-implemented properties can have initializers. + // (4,25): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static abstract int P1 {get; set;} = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(4, 25) ); @@ -3343,7 +3346,7 @@ public interface I1 [Theory] [CombinatorialData] - public void PropertyImplementation_109(bool isStatic) + public void PropertyImplementation_109A(bool isStatic, bool useCSharp13) { string declModifiers = isStatic ? "static virtual " : ""; @@ -3366,17 +3369,39 @@ class Test1 : I1 {} "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview, + parseOptions: useCSharp13 ? TestOptions.Regular13 : TestOptions.RegularPreview, targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); - // According to LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, - // we don't want to allow only one accessor to have an implementation. - compilation1.VerifyDiagnostics( - // (11,9): error CS0501: 'I1.P1.set' must declare a body because it is not marked abstract, extern, or partial - // set; - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "set").WithArguments("I1.P1.set").WithLocation(11, 9) - ); + switch (isStatic, useCSharp13) + { + case (true, true): + compilation1.VerifyDiagnostics( + // (4,24): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static virtual int P1 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(4, 24)); + break; + case (true, false): + compilation1.VerifyDiagnostics(); + break; + case (false, true): + compilation1.VerifyDiagnostics( + // (4,9): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int P1 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(4, 9), + // (4,9): error CS0525: Interfaces cannot contain instance fields + // int P1 + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P1").WithLocation(4, 9)); + break; + case (false, false): + // See also earlier LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, + // we don't want to allow only one accessor to have an implementation. + compilation1.VerifyDiagnostics( + // (4,9): error CS0525: Interfaces cannot contain instance fields + // int P1 + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P1").WithLocation(4, 9)); + break; + } var p1 = compilation1.GetMember("I1.P1"); var getP1 = p1.GetMethod; @@ -3384,6 +3409,9 @@ class Test1 : I1 Assert.False(p1.IsReadOnly); Assert.False(p1.IsWriteOnly); + var field1 = ((SourcePropertySymbolBase)p1).BackingField; + Assert.Equal("System.Int32 I1.k__BackingField", field1?.ToTestDisplayString()); + Assert.False(p1.IsAbstract); Assert.True(p1.IsVirtual); Assert.False(getP1.IsAbstract); @@ -3403,7 +3431,72 @@ class Test1 : I1 [Theory] [CombinatorialData] - public void PropertyImplementation_110(bool isStatic) + public void PropertyImplementation_109B(bool useCSharp13) + { + var source1 = +@" +public interface I1 +{ + static int P1 + { + get + { + System.Console.WriteLine(""get P1""); + return 0; + } + set; + } +} + +class Test1 : I1 +{} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: useCSharp13 ? TestOptions.Regular13 : TestOptions.RegularPreview, + targetFramework: TargetFramework.Net60); + Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); + + if (useCSharp13) + { + compilation1.VerifyDiagnostics( + // (4,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static int P1 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(4, 16)); + } + else + { + compilation1.VerifyDiagnostics(); + } + + var p1 = compilation1.GetMember("I1.P1"); + var getP1 = p1.GetMethod; + var setP1 = p1.SetMethod; + Assert.False(p1.IsReadOnly); + Assert.False(p1.IsWriteOnly); + + var field1 = ((SourcePropertySymbolBase)p1).BackingField; + Assert.Equal("System.Int32 I1.k__BackingField", field1?.ToTestDisplayString()); + + Assert.False(p1.IsAbstract); + Assert.False(p1.IsVirtual); + Assert.False(getP1.IsAbstract); + Assert.False(getP1.IsVirtual); + Assert.False(setP1.IsAbstract); + Assert.False(setP1.IsVirtual); + + var test1 = compilation1.GetTypeByMetadataName("Test1"); + + Assert.Null(test1.FindImplementationForInterfaceMember(p1)); + Assert.Null(test1.FindImplementationForInterfaceMember(getP1)); + Assert.Null(test1.FindImplementationForInterfaceMember(setP1)); + + Assert.False(getP1.IsMetadataVirtual()); + Assert.False(setP1.IsMetadataVirtual()); + } + + [Theory] + [CombinatorialData] + public void PropertyImplementation_110A(bool isStatic, bool useCSharp13) { string declModifiers = isStatic ? "static virtual " : ""; @@ -3422,17 +3515,39 @@ class Test1 : I1 {} "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview, + parseOptions: useCSharp13 ? TestOptions.Regular13 : TestOptions.RegularPreview, targetFramework: TargetFramework.Net60); Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); - // According to LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, - // we don't want to allow only one accessor to have an implementation. - compilation1.VerifyDiagnostics( - // (6,9): error CS0501: 'I1.P1.get' must declare a body because it is not marked abstract, extern, or partial - // get; - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("I1.P1.get").WithLocation(6, 9) - ); + switch (isStatic, useCSharp13) + { + case (true, true): + compilation1.VerifyDiagnostics( + // (4,24): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static virtual int P1 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(4, 24)); + break; + case (true, false): + compilation1.VerifyDiagnostics(); + break; + case (false, true): + compilation1.VerifyDiagnostics( + // (4,9): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int P1 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(4, 9), + // (4,9): error CS0525: Interfaces cannot contain instance fields + // int P1 + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P1").WithLocation(4, 9)); + break; + case (false, false): + // See also earlier LDM decision captured at https://github.com/dotnet/csharplang/blob/main/meetings/2017/LDM-2017-04-18.md, + // we don't want to allow only one accessor to have an implementation. + compilation1.VerifyDiagnostics( + // (4,9): error CS0525: Interfaces cannot contain instance fields + // int P1 + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "P1").WithLocation(4, 9)); + break; + } var p1 = compilation1.GetMember("I1.P1"); var getP1 = p1.GetMethod; @@ -3440,6 +3555,9 @@ class Test1 : I1 Assert.False(p1.IsReadOnly); Assert.False(p1.IsWriteOnly); + var field1 = ((SourcePropertySymbolBase)p1).BackingField; + Assert.Equal("System.Int32 I1.k__BackingField", field1?.ToTestDisplayString()); + Assert.False(p1.IsAbstract); Assert.True(p1.IsVirtual); Assert.False(getP1.IsAbstract); @@ -3457,6 +3575,67 @@ class Test1 : I1 Assert.True(setP1.IsMetadataVirtual()); } + [Theory] + [CombinatorialData] + public void PropertyImplementation_110B(bool useCSharp13) + { + var source1 = +@" +public interface I1 +{ + static int P1 + { + get; + set => System.Console.WriteLine(""set P1""); + } +} + +class Test1 : I1 +{} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: useCSharp13 ? TestOptions.Regular13 : TestOptions.RegularPreview, + targetFramework: TargetFramework.Net60); + Assert.True(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); + + if (useCSharp13) + { + compilation1.VerifyDiagnostics( + // (4,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static int P1 + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P1").WithArguments("field keyword").WithLocation(4, 16)); + } + else + { + compilation1.VerifyDiagnostics(); + } + + var p1 = compilation1.GetMember("I1.P1"); + var getP1 = p1.GetMethod; + var setP1 = p1.SetMethod; + Assert.False(p1.IsReadOnly); + Assert.False(p1.IsWriteOnly); + + var field1 = ((SourcePropertySymbolBase)p1).BackingField; + Assert.Equal("System.Int32 I1.k__BackingField", field1?.ToTestDisplayString()); + + Assert.False(p1.IsAbstract); + Assert.False(p1.IsVirtual); + Assert.False(getP1.IsAbstract); + Assert.False(getP1.IsVirtual); + Assert.False(setP1.IsAbstract); + Assert.False(setP1.IsVirtual); + + var test1 = compilation1.GetTypeByMetadataName("Test1"); + + Assert.Null(test1.FindImplementationForInterfaceMember(p1)); + Assert.Null(test1.FindImplementationForInterfaceMember(getP1)); + Assert.Null(test1.FindImplementationForInterfaceMember(setP1)); + + Assert.False(getP1.IsMetadataVirtual()); + Assert.False(setP1.IsMetadataVirtual()); + } + [Theory] [CombinatorialData] public void PropertyImplementation_201(bool isStatic) @@ -4037,7 +4216,7 @@ class Test1 : I1 {} "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview, skipUsesIsNullable: true); if (!isStatic) @@ -4090,7 +4269,7 @@ class Test2 : I1 "; var compilation3 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, - options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview); if (!isStatic) @@ -4218,7 +4397,7 @@ class Test2 : I1 "; var compilation3 = CreateCompilation(source2, new[] { compilation1.EmitToImageReference() }, - options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview); if (!isStatic) @@ -4302,7 +4481,7 @@ public void M2() {} "; var compilation3 = CreateCompilation(source2, new[] { compilation1.EmitToImageReference() }, - targetFramework: TargetFramework.DesktopLatestExtended, options: TestOptions.DebugDll, + targetFramework: TargetFramework.Mscorlib461Extended, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular); Assert.False(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -4346,7 +4525,7 @@ public interface I1 class Test1 : I1 {} "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular7_3, skipUsesIsNullable: true); Assert.False(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -4392,7 +4571,7 @@ class Test2 : I1 "; var compilation3 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, - options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular7_3); Assert.False(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -5638,7 +5817,7 @@ class Test1 : I1 {} "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular, skipUsesIsNullable: true); Assert.False(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation1.VerifyDiagnostics( @@ -5668,7 +5847,7 @@ class Test2 : I1 "; var compilation3 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, - options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular); Assert.False(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -5778,7 +5957,7 @@ class Test2 : I1 "; var compilation3 = CreateCompilation(source2, new[] { compilation1.EmitToImageReference() }, - options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular); Assert.False(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -5843,7 +6022,7 @@ public void M2() {} "; var compilation3 = CreateCompilation(source2, new[] { compilation1.EmitToImageReference() }, options: TestOptions.DebugDll, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular); Assert.False(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -5893,7 +6072,7 @@ int this[long i] class Test1 : I1 {} "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular7_3, skipUsesIsNullable: true); Assert.False(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -5939,7 +6118,7 @@ class Test2 : I1 "; var compilation3 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, - options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular7_3); Assert.False(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -7121,7 +7300,7 @@ class Test1 : I1 {} "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview, skipUsesIsNullable: true); if (!isStatic) @@ -7156,7 +7335,7 @@ class Test2 : I1 "; var compilation3 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, - options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview); if (!isStatic) @@ -7242,7 +7421,7 @@ class Test2 : I1 "; var compilation3 = CreateCompilation(source2, new[] { compilation1.EmitToImageReference() }, - targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, options: TestOptions.DebugDll, + targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview); if (!isStatic) @@ -7309,7 +7488,7 @@ public void M2() {} "; var compilation3 = CreateCompilation(source2, new[] { compilation1.EmitToImageReference() }, options: TestOptions.DebugDll, - targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview); var test2 = compilation3.GetTypeByMetadataName("Test2"); @@ -7344,7 +7523,7 @@ event System.Action E7 class Test1 : I1 {} "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular7_3, skipUsesIsNullable: true); Assert.False(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -7372,7 +7551,7 @@ class Test2 : I1 "; var compilation3 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, - options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular7_3); Assert.False(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -8492,7 +8671,7 @@ public interface I1 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); Assert.False(compilation2.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation2.VerifyDiagnostics( @@ -10319,7 +10498,7 @@ void Validate(ModuleSymbol m) Validate(compilation2.SourceModule); - var compilation3 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + var compilation3 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular, skipUsesIsNullable: true); Assert.False(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -11167,7 +11346,7 @@ static partial void M8() {} var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularWithExtendedPartialMethods, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (4,24): error CS8794: Partial method 'I1.M1()' must have accessibility modifiers because it has a non-void return type. @@ -11447,7 +11626,7 @@ partial interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation1.VerifyDiagnostics(); @@ -11460,7 +11639,7 @@ partial void M1() {} "; var compilation2 = CreateCompilation(source1 + source2, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (9,18): error CS8701: Target runtime doesn't support default interface implementation. @@ -13471,7 +13650,7 @@ public interface I1 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); Assert.False(compilation2.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation2.VerifyDiagnostics( @@ -14043,7 +14222,7 @@ public static int GetP6() Validate(compilation1.SourceModule); var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), - parseOptions: TestOptions.Regular, targetFramework: TargetFramework.DesktopLatestExtended); + parseOptions: TestOptions.Regular, targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (6,9): error CS8701: Target runtime doesn't support default interface implementation. @@ -16737,7 +16916,7 @@ void ValidateP3Accessor(MethodSymbol accessor) Validate(compilation2.SourceModule); - var compilation3 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + var compilation3 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular, skipUsesIsNullable: true); Assert.False(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -21945,7 +22124,7 @@ public interface I19{ int this[int x] { get; private protected set;} } var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); Assert.False(compilation2.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation2.VerifyDiagnostics( // (3,37): error CS8707: Target runtime doesn't support 'protected', 'protected internal', or 'private protected' accessibility for a member of an interface. @@ -27037,7 +27216,7 @@ extern event System.Action P11 {add{} remove{}} var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); Assert.False(compilation2.Assembly.RuntimeSupportsDefaultInterfaceImplementation); compilation2.GetDiagnostics().Where(d => d.Code != (int)ErrorCode.ERR_EventNeedsBothAccessors).Verify( // (5,35): error CS8707: Target runtime doesn't support 'protected', 'protected internal', or 'private protected' accessibility for a member of an interface. @@ -27696,7 +27875,7 @@ static void Main() Validate(compilation2.SourceModule); var compilation3 = CreateCompilation(source2, options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), - parseOptions: TestOptions.Regular, targetFramework: TargetFramework.DesktopLatestExtended); + parseOptions: TestOptions.Regular, targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyEmitDiagnostics( // (4,39): error CS8701: Target runtime doesn't support default interface implementation. @@ -30131,7 +30310,7 @@ void ValidateP5Accessor(MethodSymbol accessor) Validate(compilation2.SourceModule); - var compilation3 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + var compilation3 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular, skipUsesIsNullable: true); Assert.False(compilation3.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -31746,7 +31925,7 @@ public void M1() var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); for (int i = 1; i <= 5; i++) { @@ -31937,7 +32116,7 @@ public void M1() var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); for (int i = 1; i <= 5; i++) { @@ -32295,7 +32474,7 @@ public void M1() var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); for (int i = 1; i <= 5; i++) { @@ -33095,7 +33274,7 @@ class Test1 : I1 {} "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular, skipUsesIsNullable: true); Assert.False(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -33120,7 +33299,7 @@ class Test1 : I1 "; var compilation2 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, - options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular); Assert.False(compilation2.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -33644,7 +33823,7 @@ void Validate1(ModuleSymbol m) Validate1(compilation2.SourceModule); - var compilation3 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + var compilation3 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview, skipUsesIsNullable: true); if (!isStatic) @@ -37187,7 +37366,7 @@ class Test1 : I1 private void ValidatePropertyImplementationInDerived_03(string source1, bool isStatic, DiagnosticDescription[] expected1, params DiagnosticDescription[] expected2) { - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview, skipUsesIsNullable: true); compilation1.VerifyDiagnostics(expected1); @@ -37204,7 +37383,7 @@ class Test1 : I1 "; var compilation2 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, - options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview); compilation2.VerifyDiagnostics(expected2); @@ -37807,7 +37986,7 @@ void Validate1(ModuleSymbol m) Validate1(compilation2.SourceModule); - var compilation3 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended, + var compilation3 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview, skipUsesIsNullable: true); compilation3.VerifyDiagnostics(expected3); @@ -40205,7 +40384,7 @@ class Test1 : I1 {} "; - var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular, skipUsesIsNullable: true); Assert.False(compilation1.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -40236,7 +40415,7 @@ class Test1 : I1 "; var compilation2 = CreateCompilation(source2, new[] { compilation1.ToMetadataReference() }, - options: TestOptions.DebugDll, targetFramework: TargetFramework.DesktopLatestExtended, + options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular); Assert.False(compilation2.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -43510,7 +43689,7 @@ public interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation1.VerifyEmitDiagnostics( // (4,9): error CS0525: Interfaces cannot contain instance fields @@ -43682,7 +43861,7 @@ static void Main() var compilation5 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation5.VerifyDiagnostics( // (4,16): error CS8701: Target runtime doesn't support default interface implementation. @@ -43817,7 +43996,7 @@ static void Main() Validate1(compilation4.SourceModule); var compilation5 = CreateCompilation(source1, options: TestOptions.DebugExe, - parseOptions: TestOptions.Regular, targetFramework: TargetFramework.DesktopLatestExtended); + parseOptions: TestOptions.Regular, targetFramework: TargetFramework.Mscorlib461Extended); compilation5.VerifyDiagnostics( // (4,25): error CS8701: Target runtime doesn't support default interface implementation. @@ -43947,7 +44126,7 @@ static void Main() Validate1(compilation4.SourceModule); var compilation5 = CreateCompilation(source1, options: TestOptions.DebugExe, - parseOptions: TestOptions.Regular, targetFramework: TargetFramework.DesktopLatestExtended); + parseOptions: TestOptions.Regular, targetFramework: TargetFramework.Mscorlib461Extended); compilation5.VerifyDiagnostics( // (4,15): error CS8701: Target runtime doesn't support default interface implementation. @@ -44234,7 +44413,7 @@ interface I6 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (4,12): error CS8701: Target runtime doesn't support default interface implementation. @@ -44958,7 +45137,7 @@ static void Main() var compilation5 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation5.VerifyDiagnostics( // (4,20): error CS8701: Target runtime doesn't support default interface implementation. @@ -45111,7 +45290,7 @@ static void Main() var compilation5 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation5.VerifyDiagnostics( // (4,20): error CS8701: Target runtime doesn't support default interface implementation. @@ -45253,7 +45432,7 @@ static void Main() var compilation5 = CreateCompilation(source1, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation5.VerifyDiagnostics( // (4,20): error CS8701: Target runtime doesn't support default interface implementation. @@ -45440,7 +45619,7 @@ static void Main() Validate1(compilation4.SourceModule); var compilation5 = CreateCompilation(source1, options: TestOptions.DebugExe, - parseOptions: TestOptions.Regular, targetFramework: TargetFramework.DesktopLatestExtended); + parseOptions: TestOptions.Regular, targetFramework: TargetFramework.Mscorlib461Extended); compilation5.VerifyDiagnostics( // (4,32): error CS8701: Target runtime doesn't support default interface implementation. @@ -45577,7 +45756,7 @@ static void Main() Validate1(compilation4.SourceModule); var compilation5 = CreateCompilation(source1, options: TestOptions.DebugExe, - parseOptions: TestOptions.Regular, targetFramework: TargetFramework.DesktopLatestExtended); + parseOptions: TestOptions.Regular, targetFramework: TargetFramework.Mscorlib461Extended); compilation5.VerifyDiagnostics( // (4,32): error CS8701: Target runtime doesn't support default interface implementation. @@ -45748,7 +45927,7 @@ remove E40 P50 "); - var compilation4 = CreateCompilation(source4, options: TestOptions.DebugExe, targetFramework: TargetFramework.DesktopLatestExtended, + var compilation4 = CreateCompilation(source4, options: TestOptions.DebugExe, targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.Regular); compilation4 = compilation4.AddReferences(refs.comp1); Assert.False(compilation4.Assembly.RuntimeSupportsDefaultInterfaceImplementation); @@ -45847,7 +46026,7 @@ static void Main() foreach (var reference in new[] { compilation0.ToMetadataReference(), compilation0.EmitToImageReference() }) { var compilation2 = CreateCompilation(source2, options: TestOptions.DebugExe, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { reference }, parseOptions: TestOptions.Regular); @@ -45973,7 +46152,7 @@ static void Main() foreach (var reference in new[] { compilation1.ToMetadataReference(), compilation1.EmitToImageReference() }) { var compilation3 = CreateCompilation(source3, options: TestOptions.DebugExe, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { reference }, parseOptions: TestOptions.Regular); @@ -46011,7 +46190,7 @@ static void Main() ); var compilation4 = CreateCompilation(source4, options: TestOptions.DebugExe, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { reference }, parseOptions: TestOptions.Regular); @@ -46116,7 +46295,7 @@ interface Test6 : I1.I3 foreach (var reference in new[] { compilation1.ToMetadataReference(), compilation1.EmitToImageReference() }) { var compilation3 = CreateCompilation(source3, options: TestOptions.DebugExe, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { reference }, parseOptions: TestOptions.Regular); @@ -46130,7 +46309,7 @@ interface Test6 : I1.I3 ); var compilation4 = CreateCompilation(source4, options: TestOptions.DebugDll, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { reference }, parseOptions: TestOptions.Regular); @@ -46503,7 +46682,7 @@ static void Main() ); var compilation61 = CreateCompilation(source1 + source2, options: TestOptions.DebugDll, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, parseOptions: TestOptions.RegularPreview); compilation61.VerifyDiagnostics( @@ -52246,7 +52425,7 @@ public interface I2 : I1 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.DesktopLatestExtended); + targetFramework: isStatic ? TargetFramework.Net50 : TargetFramework.Mscorlib461Extended); if (!isStatic) { @@ -56681,7 +56860,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only auto-implemented properties can have initializers. + // (9,28): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static abstract int I1.P1 { get; set; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' @@ -56739,7 +56918,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only auto-implemented properties can have initializers. + // (9,28): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static abstract int I1.P1 { get; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' @@ -56797,7 +56976,7 @@ class Test1 : I2 } "; ValidatePropertyReAbstraction_014(source1, isStatic: true, - // (9,28): error CS8050: Only auto-implemented properties can have initializers. + // (9,28): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static abstract int I1.P1 { set; } = 0; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(9, 28), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' @@ -57045,7 +57224,7 @@ public interface I2 : I1 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (9,25): error CS8701: Target runtime doesn't support default interface implementation. // abstract int I1.P1 {get; set;} @@ -57127,7 +57306,7 @@ public interface I2 : I1 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (9,25): error CS8701: Target runtime doesn't support default interface implementation. // abstract int I1.P1 {get;} @@ -57203,7 +57382,7 @@ public interface I2 : I1 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (9,25): error CS8701: Target runtime doesn't support default interface implementation. // abstract int I1.P1 {set;} @@ -59236,7 +59415,7 @@ public interface I2 : I1 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (9,37): error CS8701: Target runtime doesn't support default interface implementation. // abstract event System.Action I1.P1; @@ -62023,7 +62202,7 @@ public interface I2 : I1 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (9,34): error CS8701: Target runtime doesn't support default interface implementation. // abstract int I1.this[int i] {get; set;} @@ -62061,7 +62240,7 @@ public interface I2 : I1 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (9,34): error CS8701: Target runtime doesn't support default interface implementation. // abstract int I1.this[int i] {get;} @@ -62096,7 +62275,7 @@ public interface I2 : I1 var compilation2 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation2.VerifyDiagnostics( // (9,34): error CS8701: Target runtime doesn't support default interface implementation. // abstract int I1.this[int i] {set;} @@ -67575,6 +67754,9 @@ interface IC // (9,30): error CS8147: Properties which return by reference cannot have set accessors // static ref int PB { get; set;} Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(9, 30), + // (14,20): error CS8145: Auto-implemented properties cannot return by reference + // static ref int PC { set;} + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PC").WithLocation(14, 20), // (14,20): error CS8146: Properties which return by reference must have a get accessor // static ref int PC { set;} Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PC").WithLocation(14, 20) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs index 7a1c02d8e1e74..2efaa17455327 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ExtensionMethodTests.cs @@ -15,8 +15,8 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; +using Basic.Reference.Assemblies; using Utils = Microsoft.CodeAnalysis.CSharp.UnitTests.CompilationUtils; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols { @@ -1005,7 +1005,7 @@ static class S3 { internal static object F3(this N.C x, object y) { return null; } }"; - CreateCompilationWithMscorlib40(source, references: new[] { Net40.SystemCore }, + CreateCompilationWithMscorlib40(source, references: new[] { Net40.References.SystemCore }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (10,16): error CS0407: 'void S2.F1(object, object)' has the wrong return type // M1(c.F1); // wrong return type @@ -1028,7 +1028,7 @@ static class S3 // diagnostic (the caller has to grub through the diagnostic bag to see that there is no error there) and then the caller // has to produce a generic error message, which we see below. It does not appear that all callers have that test, though, // suggesting there may be a latent bug of missing diagnostics. - CreateCompilationWithMscorlib40(source, references: new[] { Net40.SystemCore }).VerifyDiagnostics( + CreateCompilationWithMscorlib40(source, references: new[] { Net40.References.SystemCore }).VerifyDiagnostics( // (10,16): error CS1503: Argument 1: cannot convert from 'method group' to 'Func' // M1(c.F1); // wrong return type Diagnostic(ErrorCode.ERR_BadArgType, "c.F1").WithArguments("1", "method group", "System.Func").WithLocation(10, 16), @@ -2202,7 +2202,7 @@ internal static void M1(this object o) { } private static void Main(string[] args) { } } "; - var compilation = CreateEmptyCompilation(source, new[] { Net40.mscorlib }); + var compilation = CreateEmptyCompilation(source, new[] { Net40.References.mscorlib }); compilation.VerifyDiagnostics( // (4,29): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(4, 29)); @@ -3797,7 +3797,7 @@ class C } var o = new object(); o.F();"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script); compilation.VerifyDiagnostics(); } @@ -4139,5 +4139,26 @@ public static void M(this A s, ref int i) {} // public A(int x, A a = new A().M(1)) { } Diagnostic(ErrorCode.ERR_BadArgRef, "1").WithArguments("2", "ref").WithLocation(8, 37)); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74404")] + public void Repro_74404() + { + var source = """ + #nullable enable + class C; + static class CExt + { + public static void M(this C c) + { + c.M = 42; + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (7,9): error CS1656: Cannot assign to 'M' because it is a 'method group' + // c.M = 42; + Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "c.M").WithArguments("M", "method group").WithLocation(7, 9)); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs index 2920beb40267d..6aa2da403f3bc 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; using Utils = Microsoft.CodeAnalysis.CSharp.UnitTests.CompilationUtils; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols @@ -1095,12 +1096,12 @@ static void E(this object o) { } static void F(this object o) { } static void F(this T t) where T : struct { } }"; - CreateCompilationWithMscorlib40(text, references: new[] { TestMetadata.Net40.SystemCore }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( + CreateCompilationWithMscorlib40(text, references: new[] { Net40.References.SystemCore }, parseOptions: TestOptions.WithoutImprovedOverloadCandidates).VerifyDiagnostics( // (7,9): error CS0310: 'I' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'C.E(T)' Diagnostic(ErrorCode.ERR_NewConstraintNotSatisfied, "i.E").WithArguments("C.E(T)", "T", "I").WithLocation(7, 9), // (9,9): error CS0453: The type 'I' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'C.F(T)' Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "i.F").WithArguments("C.F(T)", "T", "I").WithLocation(9, 9)); - CreateCompilationWithMscorlib40(text, references: new[] { TestMetadata.Net40.SystemCore }).VerifyDiagnostics(); + CreateCompilationWithMscorlib40(text, references: new[] { Net40.References.SystemCore }).VerifyDiagnostics(); } [ClrOnlyFact] @@ -7294,7 +7295,7 @@ public class D : A.B metadataComp.VerifyDiagnostics(); var comp = CreateCompilation(@"System.Console.WriteLine(typeof(C.D).FullName);", new[] { metadataComp.EmitToImageReference() }, - targetFramework: TargetFramework.Mscorlib45); + targetFramework: TargetFramework.Mscorlib461); // warning CS1701: Assuming assembly reference 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' used by 'assembly1' matches identity 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' of 'mscorlib', you may need to supply runtime policy DiagnosticDescription expectedDiagnostic = Diagnostic(ErrorCode.WRN_UnifyReferenceMajMin).WithArguments("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "assembly1", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "mscorlib").WithLocation(1, 1); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ImplicitClassTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ImplicitClassTests.cs index 588af3b14e08b..b0c1e1777ebdf 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ImplicitClassTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ImplicitClassTests.cs @@ -38,7 +38,7 @@ void Goo() Assert.False(implicitClass.IsSubmissionClass); Assert.False(implicitClass.IsScriptClass); - var c2 = CreateCompilationWithMscorlib45("", new[] { c.ToMetadataReference() }); + var c2 = CreateCompilationWithMscorlib461("", new[] { c.ToMetadataReference() }); n = ((NamespaceSymbol)c2.GlobalNamespace.GetMembers("N").Single()); implicitClass = ((NamedTypeSymbol)n.GetMembers().Single()); @@ -79,7 +79,7 @@ void Goo() [Fact, WorkItem(531535, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/531535")] public void Events() { - var c = CreateCompilationWithMscorlib45(@" + var c = CreateCompilationWithMscorlib461(@" event System.Action e; ", parseOptions: TestOptions.Script); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/IndexerTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/IndexerTests.cs index 7b2e39ec0ca3c..1b89d582db2c3 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/IndexerTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/IndexerTests.cs @@ -19,6 +19,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols { @@ -2829,7 +2830,7 @@ public void M() "; #endregion - var comp1 = CreateEmptyCompilation(src1, new[] { TestMetadata.Net40.mscorlib }); + var comp1 = CreateEmptyCompilation(src1, new[] { Net40.References.mscorlib }); var comp2 = CreateCompilation(src2, new[] { new CSharpCompilationReference(comp1) }); var typeSymbol = comp1.SourceModule.GlobalNamespace.GetMember("IGoo"); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/InterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/InterfaceImplementationTests.cs index c2c4c274dc589..0897a9360a77e 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/InterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/InterfaceImplementationTests.cs @@ -862,7 +862,7 @@ public void TestExplicitMethodImplementationOnNonDeclaringType() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - TestMetadata.Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Methods.IL, }); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/MetadataTypeTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/MetadataTypeTests.cs index bea5d1fb9611c..30d7d89a248f1 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/MetadataTypeTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/MetadataTypeTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -275,11 +276,11 @@ protected void WriteTransferEventHelper(int eventId, Guid relatedActivityId, par } "; - var compilation1 = CreateEmptyCompilation(source1, new[] { TestMetadata.Net40.mscorlib, TestMetadata.Net40.SystemCore }); + var compilation1 = CreateEmptyCompilation(source1, new[] { Net40.References.mscorlib, Net40.References.SystemCore }); compilation1.VerifyDiagnostics(); var source2 = "public class A {}"; - var compilation2 = CreateEmptyCompilation(source2, new MetadataReference[] { TestMetadata.Net40.mscorlib, TestMetadata.Net40.SystemCore, compilation1.EmitToImageReference() }, + var compilation2 = CreateEmptyCompilation(source2, new MetadataReference[] { Net40.References.mscorlib, Net40.References.SystemCore, compilation1.EmitToImageReference() }, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal)); var compilation1Lib = compilation2.ExternalReferences[2]; diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/BaseTypeResolution.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/BaseTypeResolution.cs index 71f4e5b649744..bb7335bfb4a7d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/BaseTypeResolution.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/BaseTypeResolution.cs @@ -15,7 +15,7 @@ using Xunit; using CSReferenceManager = Microsoft.CodeAnalysis.CSharp.CSharpCompilation.ReferenceManager; using System.Reflection.Metadata; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -24,7 +24,7 @@ public class BaseTypeResolution : CSharpTestBase [Fact] public void Test1() { - var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.mscorlib); + var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.References.mscorlib); TestBaseTypeResolutionHelper1(assembly); @@ -32,7 +32,7 @@ public void Test1() { TestReferences.SymbolsTests.MDTestLib1, TestReferences.SymbolsTests.MDTestLib2, - Net40.mscorlib + Net40.References.mscorlib }); TestBaseTypeResolutionHelper2(assemblies); @@ -306,7 +306,7 @@ public void Test2() [Fact] public void Test3() { - var mscorlibRef = Net40.mscorlib; + var mscorlibRef = Net40.References.mscorlib; var c1 = CSharpCompilation.Create("Test", references: new MetadataReference[] { mscorlibRef }); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/DynamicTransformsTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/DynamicTransformsTests.cs index ed3dd1fa2c437..cb338eb655837 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/DynamicTransformsTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/DynamicTransformsTests.cs @@ -29,7 +29,7 @@ private void CommonTestInitialization() { _assembly = MetadataTestHelpers.GetSymbolsForReferences( TestReferences.SymbolsTests.Metadata.DynamicAttributeLib, - TestMetadata.Net451.mscorlib)[0]; + NetFramework.mscorlib)[0]; _base0Class = _assembly.Modules[0].GlobalNamespace.GetMember("Base0"); _base1Class = _assembly.Modules[0].GlobalNamespace.GetMember("Base1"); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadCustomModifiers.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadCustomModifiers.cs index 209b543333869..503ed63f23c16 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadCustomModifiers.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadCustomModifiers.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -24,7 +24,7 @@ public void Test1() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, - Net40.mscorlib + Net40.References.mscorlib }); var modifiersModule = assemblies[0].Modules[0]; @@ -121,7 +121,7 @@ public void TestCustomModifierComparisons() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, - Net40.mscorlib + Net40.References.mscorlib }); var globalNamespace = assemblies[0].GlobalNamespace; @@ -151,7 +151,7 @@ public void TestPropertyTypeCustomModifiers() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, - Net40.mscorlib + Net40.References.mscorlib }); var globalNamespace = assemblies[0].GlobalNamespace; @@ -178,7 +178,7 @@ public void TestMethodCustomModifierCount() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, - Net40.mscorlib + Net40.References.mscorlib }); var globalNamespace = assemblies[0].GlobalNamespace; @@ -209,7 +209,7 @@ public void TestPropertyCustomModifierCount() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, - Net40.mscorlib + Net40.References.mscorlib }); var globalNamespace = assemblies[0].GlobalNamespace; @@ -228,7 +228,7 @@ public void TestEventCustomModifierCount() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, - Net40.mscorlib + Net40.References.mscorlib }); var globalNamespace = assemblies[0].GlobalNamespace; @@ -247,7 +247,7 @@ public void TestFieldCustomModifierCount() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll, - Net40.mscorlib + Net40.References.mscorlib }); var globalNamespace = assemblies[0].GlobalNamespace; diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingAttributes.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingAttributes.cs index e3bf94ed97712..c6a2daaa785f0 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingAttributes.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingAttributes.cs @@ -13,7 +13,7 @@ using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -26,7 +26,7 @@ public void TestAssemblyAttributes() { TestReferences.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestReferences.SymbolsTests.Metadata.MDTestAttributeDefLib, - Net40.mscorlib + Net40.References.mscorlib }); var assembly0 = assemblies[0]; @@ -98,7 +98,7 @@ public void TestModuleAttributes() { TestReferences.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestReferences.SymbolsTests.Metadata.MDTestAttributeDefLib, - Net40.mscorlib + Net40.References.mscorlib }); var assembly1 = assemblies[1]; @@ -170,7 +170,7 @@ public void TestAttributesOnClassAndMembers() { TestReferences.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestReferences.SymbolsTests.Metadata.MDTestAttributeDefLib, - Net40.mscorlib + Net40.References.mscorlib }); // @@ -237,7 +237,7 @@ public void TestNamedAttributes() { TestReferences.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestReferences.SymbolsTests.Metadata.MDTestAttributeDefLib, - Net40.mscorlib + Net40.References.mscorlib }); var aBoolClass = assemblies[1].Modules[0].GlobalNamespace.GetMember("ABooleanAttribute") as NamedTypeSymbol; @@ -303,7 +303,7 @@ public void TestNamedAttributesWithArrays() { TestReferences.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestReferences.SymbolsTests.Metadata.MDTestAttributeDefLib, - Net40.mscorlib + Net40.References.mscorlib }); var aBoolClass = assemblies[1].Modules[0].GlobalNamespace.GetMember("ABooleanAttribute") as NamedTypeSymbol; @@ -353,7 +353,7 @@ public void TestAttributesOnReturnTypes() { TestReferences.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestReferences.SymbolsTests.Metadata.MDTestAttributeDefLib, - Net40.mscorlib + Net40.References.mscorlib }); // @@ -405,7 +405,7 @@ public void TestAttributesWithTypesAndArrays() { TestReferences.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestReferences.SymbolsTests.Metadata.MDTestAttributeDefLib, - Net40.mscorlib + Net40.References.mscorlib }); //Public Class C2(Of T1) @@ -529,7 +529,7 @@ public void TestDumpAllAttributesTesLib() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.Metadata.MDTestAttributeDefLib , - Net40.mscorlib + Net40.References.mscorlib }); var assemblyArgs = new AttributeArgs[] { @@ -579,7 +579,7 @@ public void TestInteropAttributesAssembly() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.Metadata.AttributeInterop01, - Net40.mscorlib + Net40.References.mscorlib }); //[assembly: ImportedFromTypeLib("InteropAttributes")] @@ -660,7 +660,7 @@ public void TestInteropAttributesInterface() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.Metadata.AttributeInterop01, - Net40.mscorlib + Net40.References.mscorlib }); //[ComImport, Guid("ABCDEF5D-2448-447A-B786-64682CBEF123")] @@ -725,7 +725,7 @@ public void TestInteropAttributesDelegate() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.Metadata.AttributeInterop01, - Net40.mscorlib + Net40.References.mscorlib }); // [Serializable, ComVisible(false)] @@ -766,7 +766,7 @@ public void TestInteropAttributesEnum() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.Metadata.AttributeInterop02, - Net40.mscorlib + Net40.References.mscorlib }); // [Guid("31230DD5-2448-447A-B786-64682CBEFEEE"), Flags] @@ -804,7 +804,7 @@ public void TestInteropAttributesMembers() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.Metadata.AttributeInterop01, - Net40.mscorlib + Net40.References.mscorlib }); //[ComImport, TypeLibType(TypeLibTypeFlags.FAggregatable)] @@ -904,7 +904,7 @@ public void TestAttributesNames() { TestReferences.SymbolsTests.Metadata.AttributeTestLib01, TestReferences.SymbolsTests.Metadata.AttributeTestDef01, - Net40.mscorlib + Net40.References.mscorlib }); var caNS = (NamespaceSymbol)assemblies[1].GlobalNamespace.GetMember("CustomAttribute"); @@ -939,7 +939,7 @@ public void TestAttributesOnTypeParameters() { TestReferences.SymbolsTests.Metadata.AttributeTestLib01 , TestReferences.SymbolsTests.Metadata.AttributeTestDef01 , - Net40.mscorlib + Net40.References.mscorlib }); var caNS = (NamespaceSymbol)assemblies[1].GlobalNamespace.GetMember("CustomAttribute"); @@ -1041,7 +1041,7 @@ public void TestAttributesMultiples() var assemblies = MetadataTestHelpers.GetSymbolsForReferences(mrefs: new[]{ TestReferences.SymbolsTests.Metadata.AttributeTestLib01, TestReferences.SymbolsTests.Metadata.AttributeTestDef01, - Net40.mscorlib + Net40.References.mscorlib }); var caNS = (NamespaceSymbol)assemblies[1].GlobalNamespace.GetMember("CustomAttribute"); @@ -1169,9 +1169,9 @@ where a.AttributeConstructor.Equals((MethodSymbol)mctors[3]) public void TestAttributesAssemblyVersionValue() { var assemblies = MetadataTestHelpers.GetSymbolsForReferences(mrefs: new[] { - Net451.SystemCore, - Net451.System, - Net40.mscorlib + NetFramework.SystemCore, + NetFramework.System, + Net40.References.mscorlib }); var sysNS = (NamespaceSymbol)assemblies[2].GlobalNamespace.GetMember("System"); @@ -1180,20 +1180,20 @@ public void TestAttributesAssemblyVersionValue() var asmFileAttr = (NamedTypeSymbol)refNS.GetTypeMembers("AssemblyFileVersionAttribute").Single(); var attr1 = assemblies[0].GetAttribute(asmFileAttr); - attr1.VerifyValue(0, TypedConstantKind.Primitive, "4.0.30319.18408"); + attr1.VerifyValue(0, TypedConstantKind.Primitive, "4.6.1055.0"); var asmInfoAttr = (NamedTypeSymbol)refNS.GetTypeMembers("AssemblyInformationalVersionAttribute").Single(); attr1 = assemblies[0].GetAttribute(asmInfoAttr); - attr1.VerifyValue(0, TypedConstantKind.Primitive, "4.0.30319.18408"); + attr1.VerifyValue(0, TypedConstantKind.Primitive, "4.6.1055.0"); } [Fact] public void TestAttributesWithTypeOfInternalClass() { var assemblies = MetadataTestHelpers.GetSymbolsForReferences(mrefs: new[]{ - Net451.SystemCore, - Net451.System, - Net40.mscorlib + NetFramework.SystemCore, + NetFramework.System, + Net40.References.mscorlib }); var corsysNS = assemblies[2].GlobalNamespace.GetMembers("System").Single() as NamespaceSymbol; @@ -1221,9 +1221,9 @@ public void TestAttributesStaticInstanceCtors() { var assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { - Net451.SystemConfiguration, - Net451.System, - Net40.mscorlib + Net461.References.SystemConfiguration, + Net461.References.System, + Net461.References.mscorlib }); var sysNS = (NamespaceSymbol)assemblies[1].GlobalNamespace.GetMember("System"); @@ -1251,10 +1251,10 @@ public void TestAttributesOverloadedCtors() { var assemblies = MetadataTestHelpers.GetSymbolsForReferences(mrefs: new[] { - Net451.SystemData, - Net451.SystemCore, - Net451.System, - Net40.mscorlib + NetFramework.SystemData, + NetFramework.SystemCore, + NetFramework.System, + Net40.References.mscorlib }); var sysNS = (NamespaceSymbol)assemblies[0].GlobalNamespace.GetMember("System"); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingEvents.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingEvents.cs index 61852eab05639..8589ea5ad8fb3 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingEvents.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingEvents.cs @@ -12,7 +12,6 @@ using System; using System.Linq; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -24,7 +23,7 @@ public void LoadNonGenericEvents() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.Events, }); @@ -41,7 +40,7 @@ public void LoadGenericEvents() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.Events, }); @@ -58,7 +57,7 @@ public void LoadClosedGenericEvents() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.Events, }); @@ -123,7 +122,7 @@ public void LoadSignatureMismatchEvents() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.Events, }); @@ -146,7 +145,7 @@ public void LoadMissingParameterEvents() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.Events, }); @@ -169,7 +168,7 @@ public void LoadNonDelegateEvent() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.Events, }); @@ -187,7 +186,7 @@ public void TestExplicitImplementationSimple() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp, }); @@ -214,7 +213,7 @@ public void TestExplicitImplementationGeneric() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp, }); @@ -246,7 +245,7 @@ public void TestExplicitImplementationConstructed() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp, }); @@ -282,7 +281,7 @@ public void TestExplicitImplementationDefRefDef() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp, }); @@ -322,7 +321,7 @@ public void TestTypeParameterPositions() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp, }); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingFields.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingFields.cs index 5130bdd3eefc2..20cd2e71c709a 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingFields.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingFields.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -23,7 +24,7 @@ public void Test1() { TestReferences.SymbolsTests.Fields.CSFields.dll, TestReferences.SymbolsTests.Fields.VBFields.dll, - TestMetadata.Net40.mscorlib + Net40.References.mscorlib }, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal)); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingGenericTypeParameters.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingGenericTypeParameters.cs index e27c93ac304af..c47381d01c730 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingGenericTypeParameters.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingGenericTypeParameters.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -19,7 +20,7 @@ public class LoadingGenericTypeParameters : CSharpTestBase [Fact] public void Test1() { - var assembly = MetadataTestHelpers.GetSymbolForReference(TestMetadata.Net40.mscorlib); + var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.References.mscorlib); var module0 = assembly.Modules[0]; var objectType = module0.GlobalNamespace.GetMembers("System"). diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingMethods.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingMethods.cs index c3b413062e0fc..3972be3b64b64 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingMethods.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingMethods.cs @@ -13,7 +13,7 @@ using Roslyn.Test.Utilities; using Xunit; using System.Reflection; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; //test @@ -30,7 +30,7 @@ public void Test1() TestReferences.SymbolsTests.MDTestLib2, TestReferences.SymbolsTests.Methods.CSMethods, TestReferences.SymbolsTests.Methods.VBMethods, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.Methods.ByRefReturn }, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.Internal)); @@ -439,7 +439,7 @@ public void TestExplicitImplementationGeneric() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( mrefs: new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Methods.CSharp, }); @@ -475,7 +475,7 @@ public void TestExplicitImplementationConstructed() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Methods.CSharp, }); @@ -566,7 +566,7 @@ public void TestExplicitImplementationDefRefDef() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Methods.CSharp, }); @@ -659,7 +659,7 @@ public void TestExplicitImplementationOfUnrelatedGenericInterfaceMethod() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Methods.IL, }); @@ -693,7 +693,7 @@ public void TestTypeParameterPositions() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Methods.CSharp, }); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingNamespacesAndTypes.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingNamespacesAndTypes.cs index 12fe274e38b82..79751c1d8d05f 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingNamespacesAndTypes.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingNamespacesAndTypes.cs @@ -14,7 +14,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -23,7 +23,7 @@ public class LoadingNamespacesAndTypes : CSharpTestBase [Fact] public void Test1() { - var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.mscorlib); + var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.References.mscorlib); XElement dumpXML = LoadChildNamespace1(assembly.Modules[0].GlobalNamespace); var baseLine = XElement.Load(new MemoryStream(TestResources.SymbolsTests.Metadata.MscorlibNamespacesAndTypes)); @@ -37,7 +37,7 @@ public void Test1() [Fact] public void Test2() { - var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.mscorlib); + var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.References.mscorlib); XElement dumpXML = LoadChildNamespace2(assembly.Modules[0].GlobalNamespace); var baseLine = XElement.Load(new MemoryStream(TestResources.SymbolsTests.Metadata.MscorlibNamespacesAndTypes)); @@ -122,7 +122,7 @@ private static XElement LoadChildType(NamedTypeSymbol t) [Fact] public void Test3() { - var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.mscorlib); + var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.References.mscorlib); var module0 = assembly.Modules[0]; var globalNS = module0.GlobalNamespace; @@ -167,7 +167,7 @@ public void Test3() [Fact] public void Test4() { - var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.mscorlib); + var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.References.mscorlib); TestGetMembersOfName(assembly.Modules[0]); var assembly2 = MetadataTestHelpers.GetSymbolForReference(TestReferences.SymbolsTests.DifferByCase.TypeAndNamespaceDifferByCase); @@ -381,7 +381,7 @@ public void TestAssemblyNameWithSpace2() var compilation = CSharpCompilation.Create("C1", references: new[] { - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.WithSpaces }); @@ -398,7 +398,7 @@ public void TestNetModuleNameWithSpace() var compilation = CSharpCompilation.Create("C1", references: new[] { - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.WithSpacesModule }); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingProperties.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingProperties.cs index 94ec2de6001c1..c9fa1e41a322c 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingProperties.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/LoadingProperties.cs @@ -14,7 +14,6 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -49,7 +48,7 @@ public void TestExplicitImplementationGeneric() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Properties.CSharp, }); @@ -81,7 +80,7 @@ public void TestExplicitImplementationConstructed() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Properties.CSharp, }); @@ -117,7 +116,7 @@ public void TestExplicitImplementationDefRefDef() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Properties.CSharp, }); @@ -157,7 +156,7 @@ public void TestTypeParameterPositions() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Properties.CSharp, }); @@ -220,7 +219,7 @@ public void TestExplicitImplementationMultipleAndPartial() var assemblies = MetadataTestHelpers.GetSymbolsForReferences( new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Properties.IL, }); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/MissingTypeReferences.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/MissingTypeReferences.cs index 6eac76dccaf73..8acafb6e85177 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/MissingTypeReferences.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/MissingTypeReferences.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; //test @@ -29,7 +30,7 @@ public void Test1() { TestReferences.SymbolsTests.MissingTypes.MDMissingType, TestReferences.SymbolsTests.MissingTypes.MDMissingTypeLib, - TestMetadata.Net40.mscorlib + Net40.References.mscorlib }); TestMissingTypeReferencesHelper2(assemblies); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPia.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPia.cs index 57973c529c8f4..9540d538396c2 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPia.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/NoPia.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -49,7 +49,7 @@ public void LocalTypeSubstitution1() TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1 }); @@ -92,7 +92,7 @@ public void LocalTypeSubstitution1() TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib + Net40.References.mscorlib }); var localTypes1_2 = assemblies2[0]; @@ -169,7 +169,7 @@ public void LocalTypeSubstitution1() TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1 }); @@ -183,7 +183,7 @@ public void LocalTypeSubstitution1() TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia2, - Net40.mscorlib + Net40.References.mscorlib }); var localTypes1_5 = assemblies5[0]; @@ -220,7 +220,7 @@ public void LocalTypeSubstitution1() TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia3, - Net40.mscorlib + Net40.References.mscorlib }); var localTypes1_6 = assemblies6[0]; @@ -251,7 +251,7 @@ public void LocalTypeSubstitution1() TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib + Net40.References.mscorlib }); var localTypes1_7 = assemblies7[0]; @@ -283,7 +283,7 @@ public void LocalTypeSubstitution1() TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia4, TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib + Net40.References.mscorlib }); var localTypes1_8 = assemblies8[0]; @@ -316,7 +316,7 @@ public void LocalTypeSubstitution1() TestReferences.SymbolsTests.NoPia.Library1, TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib + Net40.References.mscorlib }); var library1_9 = assemblies9[0]; @@ -327,7 +327,7 @@ public void LocalTypeSubstitution1() TestReferences.SymbolsTests.NoPia.Library1, TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1 }); @@ -362,7 +362,7 @@ public void Test2(S1 x, NS1.S2 y) { } } "; - var mscorlibRef = Net40.mscorlib; + var mscorlibRef = Net40.References.mscorlib; var pia1CopyLink = TestReferences.SymbolsTests.NoPia.Pia1Copy.WithEmbedInteropTypes(true); var pia1CopyRef = TestReferences.SymbolsTests.NoPia.Pia1Copy.WithEmbedInteropTypes(false); @@ -378,7 +378,7 @@ public void Test2(S1 x, NS1.S2 y) var assemblies1 = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1, TestReferences.SymbolsTests.MDTestLib2 }, @@ -431,7 +431,7 @@ public void Test2(S1 x, NS1.S2 y) var assemblies2 = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1 }, new CSharpCompilation[] { localTypes1, localTypes2 }); @@ -462,7 +462,7 @@ public void Test2(S1 x, NS1.S2 y) var assemblies3 = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib + Net40.References.mscorlib }, new CSharpCompilation[] { localTypes1, localTypes2 }); @@ -494,7 +494,7 @@ public void Test2(S1 x, NS1.S2 y) var assemblies4 = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1, TestReferences.SymbolsTests.MDTestLib2 }, @@ -508,7 +508,7 @@ public void Test2(S1 x, NS1.S2 y) var assemblies5 = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.NoPia.Pia2, - Net40.mscorlib + Net40.References.mscorlib }, new CSharpCompilation[] { localTypes1, localTypes2 }); @@ -553,7 +553,7 @@ public void Test2(S1 x, NS1.S2 y) var assemblies6 = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.NoPia.Pia3, - Net40.mscorlib + Net40.References.mscorlib }, new CSharpCompilation[] { localTypes1, localTypes2 }); @@ -583,7 +583,7 @@ public void Test2(S1 x, NS1.S2 y) var assemblies7 = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib + Net40.References.mscorlib }, new CSharpCompilation[] { localTypes1, localTypes2 }); @@ -618,7 +618,7 @@ public void Test2(S1 x, NS1.S2 y) { TestReferences.SymbolsTests.NoPia.Pia4, TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib + Net40.References.mscorlib }, new CSharpCompilation[] { localTypes1, localTypes2 }); @@ -650,7 +650,7 @@ public void Test2(S1 x, NS1.S2 y) { TestReferences.SymbolsTests.NoPia.Library1, TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib, + Net40.References.mscorlib, new CSharpCompilationReference(localTypes1) }); @@ -662,7 +662,7 @@ public void Test2(S1 x, NS1.S2 y) var assemblies10 = MetadataTestHelpers.GetSymbolsForReferences( TestReferences.SymbolsTests.NoPia.Library1, TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1, new CSharpCompilationReference(localTypes1)); @@ -728,7 +728,7 @@ public void GenericsClosedOverLocalTypes1() { TestReferences.SymbolsTests.NoPia.LocalTypes3, TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib + Net40.References.mscorlib }); localTypes3 = assemblies[0].GlobalNamespace.GetTypeMembers("LocalTypes3").Single(); @@ -744,7 +744,7 @@ public void GenericsClosedOverLocalTypes1() [ConditionalFact(typeof(DesktopOnly))] public void GenericsClosedOverLocalTypes2() { - var mscorlibRef = Net40.mscorlib; + var mscorlibRef = Net40.References.mscorlib; var pia5Link = TestReferences.SymbolsTests.NoPia.Pia5.WithEmbedInteropTypes(true); var pia5Ref = TestReferences.SymbolsTests.NoPia.Pia5.WithEmbedInteropTypes(false); var library2Ref = TestReferences.SymbolsTests.NoPia.Library2.WithEmbedInteropTypes(false); @@ -869,7 +869,7 @@ public void GenericsClosedOverLocalTypes2() [Fact] public void GenericsClosedOverLocalTypes3() { - var varmscorlibRef = Net40.mscorlib; + var varmscorlibRef = Net40.References.mscorlib; var varALink = TestReferences.SymbolsTests.NoPia.A.WithEmbedInteropTypes(true); var varARef = TestReferences.SymbolsTests.NoPia.A.WithEmbedInteropTypes(false); var varBLink = TestReferences.SymbolsTests.NoPia.B.WithEmbedInteropTypes(true); @@ -1001,7 +1001,7 @@ public class C33 {} "; - var mscorlibRef = Net40.mscorlib; + var mscorlibRef = Net40.References.mscorlib; var pia1CopyLink = TestReferences.SymbolsTests.NoPia.Pia1Copy.WithEmbedInteropTypes(true); var pia1CopyRef = TestReferences.SymbolsTests.NoPia.Pia1Copy.WithEmbedInteropTypes(false); @@ -1028,7 +1028,7 @@ public class C33 assemblies = MetadataTestHelpers.GetSymbolsForReferences(new[] { TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib + Net40.References.mscorlib }, new CSharpCompilation[] { varC_LocalTypes3 }); @@ -1100,7 +1100,7 @@ public interface I7 } "; - var mscorlibRef = Net40.mscorlib; + var mscorlibRef = Net40.References.mscorlib; // vbc /t:library /vbruntime- Pia5.vb var varC_Pia5 = CSharpCompilation.Create("Pia5", new[] { Parse(pia5Source) }, new[] { mscorlibRef }); @@ -1262,7 +1262,7 @@ public interface I7 [Fact] public void GenericsClosedOverLocalTypes6() { - var mscorlibRef = Net40.mscorlib; + var mscorlibRef = Net40.References.mscorlib; var varC_A = CSharpCompilation.Create("A", references: new[] { mscorlibRef }); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeAccessibility.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeAccessibility.cs index 9b2ced6bdac9a..d3f305c0ff7c4 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeAccessibility.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeAccessibility.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -20,7 +20,7 @@ public class TypeAccessibility : CSharpTestBase [Fact] public void Test1() { - var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.mscorlib); + var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.References.mscorlib); TestTypeAccessibilityHelper(assembly.Modules[0]); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeForwarders.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeForwarders.cs index 0dee0fa96702a..7396ff9004b6d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeForwarders.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeForwarders.cs @@ -18,7 +18,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -32,7 +32,7 @@ public void Test1() TestReferences.SymbolsTests.TypeForwarders.TypeForwarder.dll, TestReferences.SymbolsTests.TypeForwarders.TypeForwarderLib.dll, TestReferences.SymbolsTests.TypeForwarders.TypeForwarderBase.dll, - Net40.mscorlib + Net40.References.mscorlib }); TestTypeForwarderHelper(assemblies); @@ -93,9 +93,9 @@ public void TypeInNamespace() { var compilation = CreateCompilationWithMscorlib40AndSystemCore(new SyntaxTree[0]); - var corlibAssembly = compilation.GetReferencedAssemblySymbol(Net40.mscorlib); + var corlibAssembly = compilation.GetReferencedAssemblySymbol(Net40.References.mscorlib); Assert.NotNull(corlibAssembly); - var systemCoreAssembly = compilation.GetReferencedAssemblySymbol(Net40.SystemCore); + var systemCoreAssembly = compilation.GetReferencedAssemblySymbol(Net40.References.SystemCore); Assert.NotNull(systemCoreAssembly); const string funcTypeMetadataName = "System.Func`1"; @@ -1092,7 +1092,9 @@ class Test !ns.StartsWith("System", StringComparison.Ordinal) && !ns.StartsWith("Windows", StringComparison.Ordinal) && !ns.StartsWith("FxResources", StringComparison.Ordinal) && - !ns.StartsWith("Microsoft", StringComparison.Ordinal)); + !ns.StartsWith("Microsoft", StringComparison.Ordinal) && + !ns.StartsWith("", StringComparison.Ordinal) && + !ns.StartsWith("", StringComparison.Ordinal)); var expectedNamespaces = new[] { "Ns", "Ns.Ms" }; Assert.True(actualNamespaces.SetEquals(expectedNamespaces, EqualityComparer.Default)); } @@ -1154,7 +1156,9 @@ class Test !ns.StartsWith("System", StringComparison.Ordinal) && !ns.StartsWith("Windows", StringComparison.Ordinal) && !ns.StartsWith("FxResources", StringComparison.Ordinal) && - !ns.StartsWith("Microsoft", StringComparison.Ordinal)); + !ns.StartsWith("Microsoft", StringComparison.Ordinal) && + !ns.StartsWith("", StringComparison.Ordinal) && + !ns.StartsWith("", StringComparison.Ordinal)); var expectedNamespaces = new[] { "N1", "N1.N2", "N1.N2.N3" }; Assert.True(actualNamespaces.SetEquals(expectedNamespaces, EqualityComparer.Default)); } @@ -1216,7 +1220,9 @@ class Test !ns.StartsWith("System", StringComparison.Ordinal) && !ns.StartsWith("Windows", StringComparison.Ordinal) && !ns.StartsWith("FxResources", StringComparison.Ordinal) && - !ns.StartsWith("Microsoft", StringComparison.Ordinal)); + !ns.StartsWith("Microsoft", StringComparison.Ordinal) && + !ns.StartsWith("", StringComparison.Ordinal) && + !ns.StartsWith("", StringComparison.Ordinal)); var expectedNamespaces = new[] { "N1", "N1.N2", "N1.N2.N3" }; Assert.True(actualNamespaces.SetEquals(expectedNamespaces, EqualityComparer.Default)); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeKindTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeKindTests.cs index dd36fb806f3c7..826e7f9122c5d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeKindTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Metadata/PE/TypeKindTests.cs @@ -11,7 +11,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata.PE { @@ -20,7 +20,7 @@ public class TypeKindTests : CSharpTestBase [Fact] public void Test1() { - var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.mscorlib); + var assembly = MetadataTestHelpers.GetSymbolForReference(Net40.References.mscorlib); TestTypeKindHelper(assembly); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs index 42b3d2083af4e..2bbfa4d5d2c05 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs @@ -6,11 +6,11 @@ using System; using System.Linq; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -121,7 +121,7 @@ public static void Main(string[] args) public static void Extension(this string x) {} }"; - var comp = CreateEmptyCompilation(source, new[] { Net40.mscorlib }, options: TestOptions.ReleaseDll); + var comp = CreateEmptyCompilation(source, new[] { Net40.References.mscorlib }, options: TestOptions.ReleaseDll); comp.MakeMemberMissing(WellKnownMember.System_Diagnostics_DebuggerHiddenAttribute__ctor); @@ -547,7 +547,7 @@ SpecialType.System_Runtime_CompilerServices_PreserveBaseOverridesAttribute or [WorkItem(530436, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530436")] public void AllSpecialTypeMembers() { - var comp = CreateEmptyCompilation("", new[] { MscorlibRef_v4_0_30316_17626 }); + var comp = CreateEmptyCompilation("", [Net461.References.mscorlib]); foreach (SpecialMember special in Enum.GetValues(typeof(SpecialMember))) { @@ -567,8 +567,7 @@ public void AllSpecialTypeMembers() || special == SpecialMember.System_Runtime_CompilerServices_RuntimeFeature__ByRefLikeGenerics || special == SpecialMember.System_Runtime_CompilerServices_PreserveBaseOverridesAttribute__ctor || special == SpecialMember.System_Runtime_CompilerServices_InlineArrayAttribute__ctor - || special == SpecialMember.System_ReadOnlySpan_T__ctor_Reference - || special == SpecialMember.System_Array__Empty) + || special == SpecialMember.System_ReadOnlySpan_T__ctor_Reference) { Assert.Null(symbol); // Not available } @@ -656,6 +655,7 @@ public void AllWellKnownTypes() case WellKnownType.Microsoft_CodeAnalysis_EmbeddedAttribute: case WellKnownType.System_Runtime_InteropServices_CollectionsMarshal: case WellKnownType.System_Runtime_InteropServices_ImmutableCollectionsMarshal: + case WellKnownType.System_Runtime_CompilerServices_HotReloadException: // Not always available. continue; case WellKnownType.ExtSentinel: @@ -1072,8 +1072,10 @@ public void AllWellKnownTypeMembers() case WellKnownMember.System_Span_T__CopyTo_Span_T: case WellKnownMember.System_ReadOnlySpan_T__CopyTo_Span_T: case WellKnownMember.System_Collections_Immutable_ImmutableArray_T__AsSpan: + case WellKnownMember.System_Collections_Immutable_ImmutableArray_T__Empty: case WellKnownMember.System_Span_T__ctor_ref_T: case WellKnownMember.System_ReadOnlySpan_T__ctor_ref_readonly_T: + case WellKnownMember.System_Runtime_CompilerServices_HotReloadException__ctorStringInt32: // Not always available. continue; } @@ -1129,7 +1131,7 @@ static void Main(string[] args) } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe); compilation.MakeMemberMissing(SpecialMember.System_Delegate__Combine); compilation.VerifyEmitDiagnostics( // (13,12): error CS0656: Missing compiler required member 'System.Delegate.Combine' @@ -1167,7 +1169,7 @@ public static void Main() } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T__ctor); compilation.VerifyEmitDiagnostics( // (20,19): error CS0656: Missing compiler required member 'System.Nullable`1..ctor' @@ -1208,7 +1210,7 @@ public static void Main() } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); compilation.VerifyEmitDiagnostics( // (22,19): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' @@ -1249,7 +1251,7 @@ public static void Main() } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_get_HasValue); compilation.VerifyEmitDiagnostics( // (22,19): error CS0656: Missing compiler required member 'System.Nullable`1.get_HasValue' @@ -1289,7 +1291,7 @@ public static implicit operator C(int v) } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); compilation.VerifyEmitDiagnostics( // (10,19): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' @@ -1314,7 +1316,7 @@ static void Test() Console.WriteLine(p); } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_get_Value); compilation.VerifyEmitDiagnostics( // (9,28): error CS0656: Missing compiler required member 'System.Nullable`1.get_Value' @@ -1344,7 +1346,7 @@ static void Main() static long? M_long(long? p = null) { return p; } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T__ctor); compilation.VerifyEmitDiagnostics( // (8,27): error CS0656: Missing compiler required member 'System.Nullable`1..ctor' @@ -1392,7 +1394,7 @@ public static implicit operator MyClass(decimal Value) } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T__ctor); compilation.VerifyEmitDiagnostics( // (9,21): error CS0656: Missing compiler required member 'System.Nullable`1..ctor' @@ -1476,7 +1478,7 @@ public static void Main() } "; - var compilation = CreateCompilationWithMscorlib45(source1 + source2); + var compilation = CreateCompilationWithMscorlib461(source1 + source2); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T__ctor); compilation.VerifyEmitDiagnostics( // (55,9): error CS0656: Missing compiler required member 'System.Nullable`1..ctor' @@ -1515,7 +1517,7 @@ public static implicit operator MyClass(decimal Value) } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); compilation.VerifyEmitDiagnostics( // (11,21): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' @@ -1555,7 +1557,7 @@ public static implicit operator MyClass(decimal Value) } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_get_HasValue); compilation.VerifyEmitDiagnostics( // (11,21): error CS0656: Missing compiler required member 'System.Nullable`1.get_HasValue' @@ -1596,7 +1598,7 @@ public static implicit operator S(int? s) } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); // We use more optimal `GetValueOrDefault(defaultValue)` member for this case, so no error about missing `GetValueOrDefault()` is reported @@ -1619,7 +1621,7 @@ static void Main() } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }); compilation.MakeMemberMissing(SpecialMember.System_String__ConcatObjectObject); compilation.VerifyEmitDiagnostics( // (9,51): error CS0656: Missing compiler required member 'System.String.Concat' @@ -1647,7 +1649,7 @@ static void Main() { } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_String__ConcatStringStringString); compilation.VerifyEmitDiagnostics( // (8,58): error CS0656: Missing compiler required member 'System.String.Concat' @@ -1675,7 +1677,7 @@ static void Main() { } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_String__ConcatStringStringStringString); compilation.VerifyEmitDiagnostics( // (8,58): error CS0656: Missing compiler required member 'System.String.Concat' @@ -1717,7 +1719,7 @@ static void Main() { } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_String__ConcatStringArray); compilation.VerifyEmitDiagnostics( // (8,58): error CS0656: Missing compiler required member 'System.String.Concat' @@ -1782,7 +1784,7 @@ public static void Main() } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); compilation.VerifyEmitDiagnostics( // (9,17): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' @@ -1808,7 +1810,7 @@ public static void Main() } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T__ctor); compilation.VerifyEmitDiagnostics( // (8,17): error CS0656: Missing compiler required member 'System.Nullable`1..ctor' @@ -1838,7 +1840,7 @@ static void Main() System.Console.WriteLine(object.ReferenceEquals(c, null) ? 1 : 0); } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T__ctor); compilation.VerifyEmitDiagnostics( // (11,5): error CS0656: Missing compiler required member 'System.Nullable`1..ctor' @@ -1859,7 +1861,7 @@ static void Main() Func lambda = a => { return checked(a * a); }; } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Decimal__op_Multiply); compilation.VerifyEmitDiagnostics( // (7,65): error CS0656: Missing compiler required member 'System.Decimal.op_Multiply' @@ -1891,7 +1893,7 @@ static void Main() } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); compilation.VerifyEmitDiagnostics( // (13,9): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' @@ -1923,7 +1925,7 @@ static void T(int line, bool b) } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); compilation.VerifyEmitDiagnostics( // (10,11): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' @@ -1952,7 +1954,7 @@ static void T(int line, bool b) } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T__ctor); compilation.VerifyEmitDiagnostics( // (8,18): error CS0656: Missing compiler required member 'System.Nullable`1..ctor' @@ -1995,7 +1997,7 @@ static void T(int line, bool b) } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); compilation.VerifyEmitDiagnostics( // (18,11): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' @@ -2032,7 +2034,7 @@ static void T(int line, bool b) } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T__ctor); compilation.VerifyEmitDiagnostics( // (15,12): error CS0656: Missing compiler required member 'System.Nullable`1..ctor' @@ -2063,7 +2065,7 @@ static void Main() } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T__ctor); compilation.VerifyEmitDiagnostics( // (11,21): error CS0656: Missing compiler required member 'System.Nullable`1..ctor' @@ -2094,7 +2096,7 @@ static void Main() } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); compilation.VerifyEmitDiagnostics( // (13,15): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' @@ -2129,7 +2131,7 @@ static void Main() } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_String__op_Equality); compilation.VerifyEmitDiagnostics( // (8,61): error CS0656: Missing compiler required member 'System.String.op_Equality' @@ -2162,7 +2164,7 @@ static void Where() } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_get_HasValue); compilation.VerifyEmitDiagnostics( // (17,31): error CS0656: Missing compiler required member 'System.Nullable`1.get_HasValue' @@ -2193,7 +2195,7 @@ public static void Main() Console.WriteLine(""7. {0}"", (x is bool is bool)); } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); compilation.VerifyEmitDiagnostics( // (16,38): warning CS0184: The given expression is never of the provided ('bool') type @@ -2255,7 +2257,7 @@ public static void M(object o) } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_String__op_Equality); compilation.VerifyEmitDiagnostics( // (13,18): error CS0656: Missing compiler required member 'System.String.op_Equality' @@ -2300,7 +2302,7 @@ public static bool IsB(char value) } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_String__Chars); compilation.VerifyEmitDiagnostics( // (8,9): error CS0656: Missing compiler required member 'System.String.get_Chars' @@ -2351,7 +2353,7 @@ struct X return 1; } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault); compilation.VerifyEmitDiagnostics( // (9,13): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault' @@ -2381,7 +2383,7 @@ static void Main() } } "; - var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe); + var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.ReleaseExe); compilation.MakeMemberMissing(SpecialMember.System_String__ConcatObject); compilation.VerifyEmitDiagnostics(); // We don't expect any CompileAndVerify(compilation, expectedOutput: @"O @@ -2403,7 +2405,7 @@ static void Main() } } "; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Object__ToString); compilation.VerifyEmitDiagnostics( // (9,27): error CS0656: Missing compiler required member 'System.Object.ToString' @@ -2429,7 +2431,7 @@ static void Main() } """; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Object__ToString); compilation.VerifyEmitDiagnostics( // (9,27): error CS0656: Missing compiler required member 'System.Object.ToString' @@ -2459,7 +2461,7 @@ static void Main() } """; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Object__ToString); compilation.VerifyEmitDiagnostics( // (10,27): error CS0656: Missing compiler required member 'System.Object.ToString' @@ -2492,7 +2494,7 @@ public static void Main() } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }); compilation.MakeMemberMissing(SpecialMember.System_String__ConcatStringString); compilation.VerifyEmitDiagnostics( // (10,71): error CS0656: Missing compiler required member 'System.String.Concat' @@ -2520,7 +2522,7 @@ static void Main() } } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Array__GetLowerBound); compilation.VerifyEmitDiagnostics( // (11,9): error CS0656: Missing compiler required member 'System.Array.GetLowerBound' @@ -2551,7 +2553,7 @@ static void Main() } } }"; - var compilation = CreateCompilationWithMscorlib45(source); + var compilation = CreateCompilationWithMscorlib461(source); compilation.MakeMemberMissing(SpecialMember.System_Array__GetUpperBound); compilation.VerifyEmitDiagnostics( // (11,9): error CS0656: Missing compiler required member 'System.Array.GetUpperBound' @@ -2585,7 +2587,7 @@ static void Main() Expression> testExpr = (x, y) => x ?? y; } }"; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }); compilation.MakeMemberMissing(SpecialMember.System_Decimal__op_Implicit_FromInt32); compilation.VerifyEmitDiagnostics( // (16,78): error CS0656: Missing compiler required member 'System.Decimal.op_Implicit' @@ -2607,7 +2609,7 @@ static void Main() decimal y = x; } }"; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }); compilation.MakeMemberMissing(SpecialMember.System_Decimal__op_Implicit_FromInt32); compilation.VerifyEmitDiagnostics( // (7,21): error CS0656: Missing compiler required member 'System.Decimal.op_Implicit' @@ -2629,7 +2631,7 @@ static void Main() decimal? y = x; } }"; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }); compilation.MakeMemberMissing(SpecialMember.System_Decimal__op_Implicit_FromInt32); compilation.VerifyEmitDiagnostics( // (7,22): error CS0656: Missing compiler required member 'System.Decimal.op_Implicit' @@ -2653,7 +2655,7 @@ static void Main() Expression> testExpr = (x) => x; } }"; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemCoreRef }); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemCoreRef }); compilation.MakeMemberMissing(SpecialMember.System_Decimal__op_Implicit_FromInt32); compilation.VerifyEmitDiagnostics( // (9,60): error CS0656: Missing compiler required member 'System.Decimal.op_Implicit' @@ -2678,7 +2680,7 @@ public static void Main() { } }"; - var compilation = CreateCompilationWithMscorlib45(source, new[] { SystemRef }); + var compilation = CreateCompilationWithMscorlib461(source, new[] { SystemRef }); compilation.MakeMemberMissing(SpecialMember.System_Nullable_T__ctor); compilation.VerifyEmitDiagnostics( // (10,9): error CS0656: Missing compiler required member 'System.Nullable`1..ctor' diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/OverriddenOrHiddenMembersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/OverriddenOrHiddenMembersTests.cs index 43d9407d60ae9..089ec2385c856 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/OverriddenOrHiddenMembersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/OverriddenOrHiddenMembersTests.cs @@ -522,7 +522,7 @@ public override void Method(int x) { } //this is incorrect, but doesn't break th public override ref int this[int i] { get { return ref field; } } } "; - var comp = CreateCompilationWithMscorlib45(text); + var comp = CreateCompilationWithMscorlib461(text); var global = comp.GlobalNamespace; var baseClass = (NamedTypeSymbol)global.GetMembers("BaseClass").Single(); @@ -815,7 +815,7 @@ class Base4 : Base3 { public override U Property { set { } } }"; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Base2").WithArguments("Base2", "Base.Property.get"), Diagnostic(ErrorCode.ERR_UnimplementedAbstractMethod, "Base4").WithArguments("Base4", "Base3.Method(U, V)")); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/PEParameterSymbolTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/PEParameterSymbolTests.cs index 7a3fd32a103ea..ee9513bc9db0f 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/PEParameterSymbolTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/PEParameterSymbolTests.cs @@ -89,7 +89,7 @@ public static void Main() } } "; - var compilation = CreateCompilationWithMscorlib45(source, new[] { vbComp }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); + var compilation = CreateCompilationWithMscorlib461(source, new[] { vbComp }, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular); compilation.VerifyDiagnostics( // (6,16): error CS7036: There is no argument given that corresponds to the required parameter 'x' of 'Class1.Test(out object, ref object, int)' // Class1.Test(); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs index d5f299f336a9c..b20d76e5f052d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/PartialPropertiesTests.cs @@ -924,7 +924,7 @@ .maxstack 2 Assert.True(propDefinition.IsPartialDefinition); var propImplementation = propDefinition.PartialImplementationPart!; - Assert.True(propImplementation.IsPartialImplementation); + Assert.True(propImplementation.IsPartialImplementation()); Assert.Same(propDefinition, propImplementation.PartialDefinitionPart); Assert.Null(propImplementation.PartialImplementationPart); @@ -998,7 +998,7 @@ .maxstack 1 Assert.True(propDefinition.IsPartialDefinition); var propImplementation = propDefinition.PartialImplementationPart!; - Assert.True(propImplementation.IsPartialImplementation); + Assert.True(propImplementation.IsPartialImplementation()); Assert.Same(propDefinition, propImplementation.PartialDefinitionPart); Assert.Null(propImplementation.PartialImplementationPart); @@ -1084,7 +1084,7 @@ .maxstack 1 Assert.True(propDefinition.IsPartialDefinition); var propImplementation = propDefinition.PartialImplementationPart!; - Assert.True(propImplementation.IsPartialImplementation); + Assert.True(propImplementation.IsPartialImplementation()); Assert.Same(propDefinition, propImplementation.PartialDefinitionPart); Assert.Null(propImplementation.PartialImplementationPart); @@ -1524,9 +1524,6 @@ partial class C // (11,30): error CS8799: Both partial member declarations must have identical accessibility modifiers. // partial int P1 { private get => 1; private set; } Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "get").WithLocation(11, 30), - // (11,48): error CS0501: 'C.P1.set' must declare a body because it is not marked abstract, extern, or partial - // partial int P1 { private get => 1; private set; } - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "set").WithArguments("C.P1.set").WithLocation(11, 48), // (11,48): error CS8799: Both partial member declarations must have identical accessibility modifiers. // partial int P1 { private get => 1; private set; } Diagnostic(ErrorCode.ERR_PartialMemberAccessibilityDifference, "set").WithLocation(11, 48)); @@ -3771,18 +3768,41 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,27): error CS8050: Only auto-implemented properties can have initializers. + // (3,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P1 { get; set; } = "a"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), - // (7,27): error CS8050: Only auto-implemented properties can have initializers. + // (7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P2 { get => ""; set { } } = "b"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(7, 27), - // (9,27): error CS8050: Only auto-implemented properties can have initializers. + // (9,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get; set; } = "c"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(9, 27), - // (10,27): error CS8050: Only auto-implemented properties can have initializers. + // (10,27): error CS9263: A partial property cannot have an initializer on both the definition and implementation. + // public partial string P3 { get => ""; set { } } = "d"; + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateInitializer, "P3").WithLocation(10, 27), + // (10,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get => ""; set { } } = "d"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(10, 27)); + + AssertEx.Equal([ + "System.String C.k__BackingField", + "System.String C.P1 { get; set; }", + "System.String C.P1.get", + "void C.P1.set", + "System.String C.P2 { get; set; }", + "System.String C.P2.get", + "void C.P2.set", + "System.String C.k__BackingField", + "System.String C.k__BackingField", + "System.String C.P3 { get; set; }", + "System.String C.P3.get", + "void C.P3.set", + "C..ctor()"], + comp.GetMember("C").GetMembers().SelectAsArray(m => m.ToTestDisplayString())); + + Assert.Empty(comp.GetMember("C.k__BackingField").GetAttributes()); + Assert.Empty(comp.GetMember("C.k__BackingField").GetAttributes()); + Assert.Empty(comp.GetMember("C.k__BackingField").GetAttributes()); } [Fact] @@ -3804,30 +3824,53 @@ partial class C var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( - // (3,27): error CS8050: Only auto-implemented properties can have initializers. + // (3,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P1 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(3, 27), // (3,46): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P1 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(3, 46), - // (7,27): error CS8050: Only auto-implemented properties can have initializers. + // (7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P2 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(7, 27), // (7,55): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P2 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(7, 55), - // (9,27): error CS8050: Only auto-implemented properties can have initializers. + // (9,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(9, 27), // (9,46): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P3 { get; set; } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(9, 46), - // (10,27): error CS8050: Only auto-implemented properties can have initializers. + // (10,27): error CS9263: A partial property cannot have an initializer on both the definition and implementation. + // public partial string P3 { get => ""; set { } } = ERROR; + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateInitializer, "P3").WithLocation(10, 27), + // (10,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(10, 27), // (10,55): error CS0103: The name 'ERROR' does not exist in the current context // public partial string P3 { get => ""; set { } } = ERROR; Diagnostic(ErrorCode.ERR_NameNotInContext, "ERROR").WithArguments("ERROR").WithLocation(10, 55)); + + AssertEx.Equal([ + "System.String C.k__BackingField", + "System.String C.P1 { get; set; }", + "System.String C.P1.get", + "void C.P1.set", + "System.String C.P2 { get; set; }", + "System.String C.P2.get", + "void C.P2.set", + "System.String C.k__BackingField", + "System.String C.k__BackingField", + "System.String C.P3 { get; set; }", + "System.String C.P3.get", + "void C.P3.set", + "C..ctor()"], + comp.GetMember("C").GetMembers().SelectAsArray(m => m.ToTestDisplayString())); + + Assert.Empty(comp.GetMember("C.k__BackingField").GetAttributes()); + Assert.Empty(comp.GetMember("C.k__BackingField").GetAttributes()); + Assert.Empty(comp.GetMember("C.k__BackingField").GetAttributes()); } [Fact] @@ -3862,7 +3905,7 @@ partial class C // (6,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr1] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(6, 6), - // (7,27): error CS8050: Only auto-implemented properties can have initializers. + // (7,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P1 { get; set; } = "a"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P1").WithLocation(7, 27), // (8,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. @@ -3874,19 +3917,22 @@ partial class C // (13,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr2] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(13, 6), - // (14,27): error CS8050: Only auto-implemented properties can have initializers. + // (14,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P2 { get => ""; set { } } = "b"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P2").WithLocation(14, 27), // (16,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr1] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(16, 6), - // (17,27): error CS8050: Only auto-implemented properties can have initializers. + // (17,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get; set; } = "c"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(17, 27), // (18,6): warning CS0657: 'field' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'property'. All attributes in this block will be ignored. // [field: Attr2] Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "field").WithArguments("field", "property").WithLocation(18, 6), - // (19,27): error CS8050: Only auto-implemented properties can have initializers. + // (19,27): error CS9263: A partial property cannot have an initializer on both the definition and implementation. + // public partial string P3 { get => ""; set { } } = "d"; + Diagnostic(ErrorCode.ERR_PartialPropertyDuplicateInitializer, "P3").WithLocation(19, 27), + // (19,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // public partial string P3 { get => ""; set { } } = "d"; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P3").WithLocation(19, 27)); @@ -3903,17 +3949,12 @@ partial class C "System.String C.P3 { get; set; }", "System.String C.P3.get", "void C.P3.set", - "System.String C.k__BackingField", "C..ctor()"], comp.GetMember("C").GetMembers().SelectAsArray(m => m.ToTestDisplayString())); Assert.Empty(comp.GetMember("C.k__BackingField").GetAttributes()); Assert.Empty(comp.GetMember("C.k__BackingField").GetAttributes()); - - var p3Fields = comp.GetMembers("C.k__BackingField"); - Assert.Equal(2, p3Fields.Length); - Assert.Empty(p3Fields[0].GetAttributes()); - Assert.Empty(p3Fields[1].GetAttributes()); + Assert.Empty(comp.GetMember("C.k__BackingField").GetAttributes()); } [Theory] @@ -4985,20 +5026,60 @@ partial class C { public partial int Prop1 { get; set; } public partial int Prop1 { get => 1; set; } - + public partial int Prop2 { get; set; } public partial int Prop2 { get; set { } } } """; var comp = CreateCompilation(source); - comp.VerifyEmitDiagnostics( - // (4,42): error CS0501: 'C.Prop1.set' must declare a body because it is not marked abstract, extern, or partial - // public partial int Prop1 { get => 1; set; } - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "set").WithArguments("C.Prop1.set").WithLocation(4, 42), - // (7,32): error CS0501: 'C.Prop2.get' must declare a body because it is not marked abstract, extern, or partial - // public partial int Prop2 { get; set { } } - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("C.Prop2.get").WithLocation(7, 32)); + comp.VerifyEmitDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74679")] + public void WRN_SequentialOnPartialClass_NotReportedForPartialProperty_01() + { + var source = """ + partial struct S + { + partial int I { get; } + } + + partial struct S + { + public S() => i = 42; + private readonly int i; + partial int I => i; + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74679")] + public void WRN_SequentialOnPartialClass_NotReportedForPartialProperty_02() + { + var source = """ + partial struct S + { + partial int I { get; } + } + + partial struct S + { + partial int I => i; + } + + partial struct S + { + public S() => i = 42; + private readonly int i; + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/NoPia.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/NoPia.cs index 94d6fd9ed690c..e918fcbcc4f15 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/NoPia.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/NoPia.cs @@ -7,11 +7,12 @@ using System; using System.Collections.Immutable; using System.Linq; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; -using Xunit; using Roslyn.Test.Utilities; +using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Retargeting { @@ -2637,7 +2638,7 @@ public struct Test } "; - var piaCompilation = CreateCompilationWithMscorlib45(pia, options: TestOptions.DebugDll, assemblyName: "Pia"); + var piaCompilation = CreateEmptyCompilation(pia, references: [Net40.References.mscorlib], options: TestOptions.DebugDll, assemblyName: "Pia"); string consumer1 = @" public class UsePia1 @@ -2661,11 +2662,11 @@ public static void Main() foreach (MetadataReference piaRef in new[] { piaCompilation.EmitToImageReference(), piaCompilation.ToMetadataReference() }) { - var compilation1 = CreateCompilationWithMscorlib45(consumer1, references: new[] { piaRef.WithEmbedInteropTypes(true) }); + var compilation1 = CreateEmptyCompilation(consumer1, references: [Net40.References.mscorlib, piaRef.WithEmbedInteropTypes(true)]); foreach (MetadataReference consumer1Ref in new[] { compilation1.EmitToImageReference(), compilation1.ToMetadataReference() }) { - var compilation2 = CreateCompilationWithMscorlib46(consumer2, references: new[] { piaRef, consumer1Ref }); + var compilation2 = CreateEmptyCompilation(consumer2, references: [Net461.References.mscorlib, piaRef, consumer1Ref]); compilation2.VerifyDiagnostics(); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetCustomAttributes.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetCustomAttributes.cs index 722bbe227f222..78a4be518a925 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetCustomAttributes.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetCustomAttributes.cs @@ -13,6 +13,7 @@ using Roslyn.Test.Utilities; using System.Collections.Generic; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Retargeting { @@ -160,7 +161,7 @@ private static MetadataReference OldMsCorLib { get { - return TestMetadata.Net40.mscorlib; + return Net40.References.mscorlib; } } @@ -168,7 +169,7 @@ private static MetadataReference NewMsCorLib { get { - return TestMetadata.Net451.mscorlib; + return NetFramework.mscorlib; } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetCustomModifiers.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetCustomModifiers.cs index 0edd129c020d2..41278e0ab7308 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetCustomModifiers.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetCustomModifiers.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Text; using Xunit; using Roslyn.Test.Utilities; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Retargeting { @@ -22,8 +23,8 @@ public class RetargetCustomModifiers : CSharpTestBase [Fact] public void Test1() { - var oldMsCorLib = TestMetadata.Net40.mscorlib; - var newMsCorLib = TestMetadata.Net451.mscorlib; + var oldMsCorLib = Net40.References.mscorlib; + var newMsCorLib = NetFramework.mscorlib; var c1 = CSharpCompilation.Create("C1", references: new[] { @@ -129,8 +130,8 @@ public void Test1() [Fact] public void Test2() { - var oldMsCorLib = TestMetadata.Net40.mscorlib; - var newMsCorLib = TestMetadata.Net451.mscorlib; + var oldMsCorLib = Net40.References.mscorlib; + var newMsCorLib = NetFramework.mscorlib; var source = @" public class Modifiers diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetExplicitInterfaceImplementation.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetExplicitInterfaceImplementation.cs index a2280b2325c61..346d61d314b10 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetExplicitInterfaceImplementation.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetExplicitInterfaceImplementation.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -48,7 +47,7 @@ event Delegate1 Interface1.Event4 { add { } remove { } } }, new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V1.MTTestLib1.dll, }); @@ -113,7 +112,7 @@ public class D : C }, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V2.MTTestLib1.dll, new CSharpCompilationReference(comp1) }); @@ -343,7 +342,7 @@ event System.Action Interface2.Event1 { add { } remove { } } }, new[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V1.MTTestLib1.dll, }); @@ -377,7 +376,7 @@ public class D3 : C3 }, new MetadataReference[] { - Net451.mscorlib, + NetFramework.mscorlib, TestReferences.SymbolsTests.V2.MTTestLib1.dll, new CSharpCompilationReference(comp1) }); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/BaseClassTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/BaseClassTests.cs index e96303ca35ca3..91342c3aa1ac6 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/BaseClassTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/BaseClassTests.cs @@ -2025,7 +2025,7 @@ class D : B { extern D(int x) : base(y) {} static int y; }"; - var comp = CreateCompilationWithMscorlib45(text); + var comp = CreateCompilationWithMscorlib461(text); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var baseY = tree.GetRoot().DescendantNodes().Where(n => n.ToString() == "y").OfType().First(); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ClsComplianceTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ClsComplianceTests.cs index 3a8e532ab7d36..4c5fb274f37ce 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ClsComplianceTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ClsComplianceTests.cs @@ -3152,7 +3152,7 @@ public class C }} "; - var helper = CreateCompilationWithMscorlib45(""); + var helper = CreateCompilationWithMscorlib461(""); var intType = helper.GetSpecialType(SpecialType.System_Int32); foreach (SpecialType st in Enum.GetValues(typeof(SpecialType))) @@ -3176,7 +3176,7 @@ public class C var qualifiedName = type.ToTestDisplayString(); var source = string.Format(sourceTemplate, qualifiedName); - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); switch (st) { diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs index 27b140fe6ef97..253e4c222f453 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/CustomModifierCopyTests.cs @@ -974,7 +974,7 @@ public void TupleWithCustomModifiersInInterfaceMethod() var il = @" .assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) } .assembly extern System.Core {} -.assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) .ver 4:0:1:0 } +.assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) .ver 4:0:3:0 } .assembly '<>' { } .class interface public abstract auto ansi I @@ -1092,7 +1092,7 @@ public void TupleWithCustomModifiersInInterfaceProperty() var il = @" .assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) } .assembly extern System.Core {} -.assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) .ver 4:0:1:0 } +.assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) .ver 4:0:3:0 } .assembly '<>' { } .class interface public abstract auto ansi I @@ -1189,7 +1189,7 @@ public void TupleWithCustomModifiersInOverride() var il = @" .assembly extern mscorlib { .ver 4:0:0:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89) } .assembly extern System.Core {} -.assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) .ver 4:0:1:0 } +.assembly extern System.ValueTuple { .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) .ver 4:0:3:0 } .assembly '<>' { } .class public auto ansi beforefieldinit Base diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs index 691cf8606a16d..8236a73106caa 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/DelegateTests.cs @@ -773,7 +773,7 @@ public void RefReturningDelegate() { var source = @"delegate ref int D();"; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics(); var global = comp.GlobalNamespace; @@ -790,7 +790,7 @@ public void RefReadonlyReturningDelegate() { var source = @"delegate ref readonly int D(in int arg);"; - var comp = CreateCompilationWithMscorlib45(source); + var comp = CreateCompilationWithMscorlib461(source); comp.VerifyDiagnostics(); var global = comp.GlobalNamespace; @@ -820,7 +820,7 @@ public static void Main() } }"; var tree = SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.Regular); - var compilation = CreateCompilationWithMscorlib45(new SyntaxTree[] { tree }).VerifyDiagnostics(); + var compilation = CreateCompilationWithMscorlib461(new SyntaxTree[] { tree }).VerifyDiagnostics(); var model = compilation.GetSemanticModel(tree); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExpressionBodiedMethodTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExpressionBodiedMethodTests.cs index 4f6fb82a6af09..59c3fc6eab2c0 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExpressionBodiedMethodTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExpressionBodiedMethodTests.cs @@ -67,7 +67,7 @@ class C [Fact] public void Syntax02() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public int M() {} => 1; @@ -99,7 +99,7 @@ interface C [Fact] public void Syntax04() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" abstract class C { public abstract int M() => 1; @@ -113,7 +113,7 @@ abstract class C [Fact] public void Syntax05() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public abstract int M() => 1; @@ -130,7 +130,7 @@ class C [Fact] public void Syntax06() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" abstract class C { abstract int M() => 1; @@ -148,7 +148,7 @@ abstract class C [WorkItem(1009638, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1009638")] public void Syntax07() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" public class C { public bool IsNull(T t) where T : class => t != null; }"); @@ -159,7 +159,7 @@ public class C { [WorkItem(1029117, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1029117")] public void Syntax08() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" namespace MyNamespace { public partial struct Goo @@ -176,7 +176,7 @@ public partial struct Goo [Fact] public void LambdaTest01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" using System; class C { @@ -196,7 +196,7 @@ class C public static explicit operator C(int i) => new C(); public static C operator++(C c) => (C)c.M(); }"; - var comp = CreateCompilationWithMscorlib45(text); + var comp = CreateCompilationWithMscorlib461(text); comp.VerifyDiagnostics(); var global = comp.GlobalNamespace; var c = global.GetTypeMember("C"); @@ -217,7 +217,7 @@ class C [Fact] public void Override01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class B { public virtual int M() { return 0; } @@ -231,7 +231,7 @@ class C : B [Fact] public void VoidExpression() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public void M() => System.Console.WriteLine(""goo""); @@ -241,7 +241,7 @@ class C [Fact] public void VoidExpression2() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public int M() => System.Console.WriteLine(""goo""); @@ -254,7 +254,7 @@ class C [Fact] public void InterfaceImplementation01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" interface I { int M(); @@ -307,7 +307,7 @@ class C : I, J, K [ClrOnlyFact] public void Emit01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" abstract class A { protected abstract string Z(); @@ -350,7 +350,7 @@ public static void Main() [ClrOnlyFact] public void Emit02() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public void M() { System.Console.WriteLine(""Hello""); } @@ -376,7 +376,7 @@ public static void Main() [Fact] public void RefReturningExpressionBodiedMethod() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { int field = 0; @@ -389,7 +389,7 @@ class C [CompilerTrait(CompilerFeature.ReadOnlyReferences)] public void RefReadonlyReturningExpressionBodiedMethod() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { int field = 0; diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExpressionBodiedPropertyTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExpressionBodiedPropertyTests.cs index c026c48a2251b..f4efc173efae9 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExpressionBodiedPropertyTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExpressionBodiedPropertyTests.cs @@ -30,7 +30,7 @@ class C [Fact] public void Syntax02() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public int P { get; } => 1; @@ -60,7 +60,7 @@ interface C [Fact] public void Syntax04() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" abstract class C { public abstract int P => 1; @@ -74,7 +74,7 @@ abstract class C [Fact] public void Syntax05() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public abstract int P => 1; @@ -91,7 +91,7 @@ class C [Fact] public void Syntax06() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" abstract class C { abstract int P => 1; @@ -109,7 +109,7 @@ abstract class C public void Syntax07() { // The '=' here parses as part of the expression body, not the property - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public int P => 1 = 2; @@ -123,7 +123,7 @@ class C [Fact] public void Syntax08() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" interface I { int P { get; }; @@ -136,7 +136,7 @@ interface I [Fact] public void Syntax09() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" class C { int P => 2 @@ -149,7 +149,7 @@ class C [Fact] public void Syntax10() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" interface I { int this[int i] @@ -168,7 +168,7 @@ int this[int i] [Fact] public void Syntax11() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" interface I { int this[int i]; @@ -190,7 +190,7 @@ interface I [Fact] public void Syntax12() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" interface I { int this[int i] { get; }; @@ -204,7 +204,7 @@ interface I public void Syntax13() { // End the property declaration at the semicolon after the accessor list - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" class C { int P { get; set; }; => 2; @@ -220,7 +220,7 @@ class C [Fact] public void Syntax14() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" class C { int this[int i] => 2 @@ -233,7 +233,7 @@ class C [Fact] public void LambdaTest01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" using System; class C { @@ -251,7 +251,7 @@ class C public int P => 2 * 2; public int this[int i, int j] => i * j * P; }"; - var comp = CreateCompilationWithMscorlib45(text); + var comp = CreateCompilationWithMscorlib461(text); comp.VerifyDiagnostics(); var global = comp.GlobalNamespace; var c = global.GetTypeMember("C"); @@ -281,7 +281,7 @@ class C [Fact] public void Override01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class B { public virtual int P { get; set; } @@ -295,7 +295,7 @@ class C : B [Fact] public void Override02() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" class B { public int P => 10; @@ -317,7 +317,7 @@ class C : B [Fact] public void Override03() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" class B { public virtual int P => 10; @@ -333,7 +333,7 @@ class C : B [Fact] public void VoidExpression() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public void P => System.Console.WriteLine(""goo""); @@ -346,7 +346,7 @@ class C [Fact] public void VoidExpression2() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { public int P => System.Console.WriteLine(""goo""); @@ -359,7 +359,7 @@ class C [Fact] public void InterfaceImplementation01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" interface I { int P { get; } @@ -409,7 +409,7 @@ class C : I, J, K [ClrOnlyFact] public void Emit01() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" abstract class A { protected abstract string Z { get; } @@ -455,7 +455,7 @@ public static void Main() [ClrOnlyFact] public void AccessorInheritsVisibility() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { private int P => 1; @@ -478,7 +478,7 @@ class C [Fact] public void StaticIndexer() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { static int this[int i] => i; @@ -492,7 +492,7 @@ class C [Fact] public void RefReturningExpressionBodiedProperty() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { int field = 0; @@ -515,7 +515,7 @@ class C [CompilerTrait(CompilerFeature.ReadOnlyReferences)] public void RefReadonlyReturningExpressionBodiedProperty() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { int field = 0; @@ -542,11 +542,11 @@ class C [CompilerTrait(CompilerFeature.ReadOnlyReferences)] public void RefReadonlyReturningExpressionBodiedIndexer() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { int field = 0; - public ref readonly int this[in int arg] => ref field; + public ref readonly int this[in int arg] => ref @field; }"); comp.VerifyDiagnostics(); @@ -570,11 +570,11 @@ class C [CompilerTrait(CompilerFeature.ReadOnlyReferences)] public void RefReadonlyReturningExpressionBodiedIndexer1() { - var comp = CreateCompilationWithMscorlib45(@" + var comp = CreateCompilationWithMscorlib461(@" class C { int field = 0; - public ref readonly int this[in int arg] => ref field; + public ref readonly int this[in int arg] => ref @field; }"); comp.VerifyDiagnostics(); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExternAliasTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExternAliasTests.cs index 1b282cfa41c8b..9347cfade262d 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExternAliasTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExternAliasTests.cs @@ -97,7 +97,7 @@ public void ExternAliasInScript() extern alias Bar; Bar::NS.Goo d = new Bar::NS.Goo(); "; - var comp = CreateCompilationWithMscorlib45(src, options: TestOptions.DebugExe, parseOptions: TestOptions.Script); + var comp = CreateCompilationWithMscorlib461(src, options: TestOptions.DebugExe, parseOptions: TestOptions.Script); comp = comp.AddReferences(Goo1, Goo2); comp.VerifyDiagnostics(); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs index 041e2d2e00791..e0b146f14224b 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs @@ -4373,7 +4373,7 @@ void M() } """; - var comp2 = CreateCompilation(source2, references: new[] { comp.ToMetadataReference() }, targetFramework: TargetFramework.Mscorlib45); + var comp2 = CreateCompilation(source2, references: new[] { comp.ToMetadataReference() }, targetFramework: TargetFramework.Mscorlib461); comp2.VerifyDiagnostics( // (5,9): error CS0103: The name 'C' does not exist in the current context // C.M(); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/MethodTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/MethodTests.cs index aa88b97f8efa6..d5295d0367975 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/MethodTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/MethodTests.cs @@ -398,7 +398,7 @@ ref int M(ref int i) } "; - var comp = CreateCompilationWithMscorlib45(text); + var comp = CreateCompilationWithMscorlib461(text); var global = comp.GlobalNamespace; var a = global.GetTypeMembers("A", 0).Single(); var m = a.GetMembers("M").Single() as MethodSymbol; @@ -581,7 +581,7 @@ public override void M0() { } } "; - var comp = CreateCompilationWithMscorlib45(new[] { text, text1, text2 }); + var comp = CreateCompilationWithMscorlib461(new[] { text, text1, text2 }); Assert.Equal(0, comp.GetDiagnostics().Count()); var ns = comp.GlobalNamespace.GetMembers("N1").Single() as NamespaceSymbol; var ns1 = ns.GetMembers("N2").Single() as NamespaceSymbol; @@ -752,16 +752,16 @@ public override void M0() { } } "; - var comp1 = CreateCompilationWithMscorlib45(text); + var comp1 = CreateCompilationWithMscorlib461(text); var compRef1 = new CSharpCompilationReference(comp1); - var comp2 = CreateCompilationWithMscorlib45(new string[] { text1 }, new List() { compRef1 }, assemblyName: "Test2"); + var comp2 = CreateCompilationWithMscorlib461(new string[] { text1 }, new List() { compRef1 }, assemblyName: "Test2"); //Compilation.Create(outputName: "Test2", options: CompilationOptions.Default, // syntaxTrees: new SyntaxTree[] { SyntaxTree.ParseCompilationUnit(text1) }, // references: new MetadataReference[] { compRef1, GetCorlibReference() }); var compRef2 = new CSharpCompilationReference(comp2); - var comp = CreateCompilationWithMscorlib45(new string[] { text2 }, new List() { compRef1, compRef2 }, assemblyName: "Test3"); + var comp = CreateCompilationWithMscorlib461(new string[] { text2 }, new List() { compRef1, compRef2 }, assemblyName: "Test3"); //Compilation.Create(outputName: "Test3", options: CompilationOptions.Default, // syntaxTrees: new SyntaxTree[] { SyntaxTree.ParseCompilationUnit(text2) }, // references: new MetadataReference[] { compRef1, compRef2, GetCorlibReference() }); @@ -1748,7 +1748,7 @@ class C : I } "; - var comp = CreateCompilationWithMscorlib45(text); + var comp = CreateCompilationWithMscorlib461(text); var globalNamespace = comp.GlobalNamespace; @@ -2176,7 +2176,7 @@ static ref void M() { } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,16): error CS1547: Keyword 'void' cannot be used in this context // static ref void M() { } Diagnostic(ErrorCode.ERR_NoVoidHere, "void").WithLocation(4, 16) @@ -2194,7 +2194,7 @@ static ref readonly void M() { } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,25): error CS1547: Keyword 'void' cannot be used in this context // static ref readonly void M() { } Diagnostic(ErrorCode.ERR_NoVoidHere, "void").WithLocation(4, 25) @@ -2214,7 +2214,7 @@ ref void M() { } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (6,13): error CS1547: Keyword 'void' cannot be used in this context // ref void M() { } Diagnostic(ErrorCode.ERR_NoVoidHere, "void").WithLocation(6, 13), @@ -2245,7 +2245,7 @@ static void Main() "; var parseOptions = TestOptions.Regular; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (10,22): error CS1547: Keyword 'void' cannot be used in this context // ref readonly void M2() {M1(); throw null;} Diagnostic(ErrorCode.ERR_NoVoidHere, "void").WithLocation(10, 22) @@ -2262,7 +2262,7 @@ static async ref int M() { } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,18): error CS1073: Unexpected token 'ref' // static async ref int M() { } Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(4, 18), @@ -2286,7 +2286,7 @@ static async ref readonly int M() { } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,18): error CS1073: Unexpected token 'ref' // static async ref readonly int M() { } Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(4, 18), diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ModifierTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ModifierTests.cs index d1fc1e22d6b01..f801a3810c248 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ModifierTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ModifierTests.cs @@ -108,7 +108,7 @@ private void M6() { } static void M12() { } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Script); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Script); var script = comp.ScriptClass; var m1 = script.GetMembers("M1").Single() as MethodSymbol; Assert.Equal(Accessibility.Private, m1.DeclaredAccessibility); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/NullablePublicAPITests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/NullablePublicAPITests.cs index afdf7d50836b5..8a6b68ec48a89 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/NullablePublicAPITests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/NullablePublicAPITests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; +using Roslyn.Utilities; using Xunit; using PublicNullableAnnotation = Microsoft.CodeAnalysis.NullableAnnotation; using PublicNullableFlowState = Microsoft.CodeAnalysis.NullableFlowState; @@ -5235,5 +5236,310 @@ void test(SemanticModelOptions options) Assert.Equal(PublicNullableAnnotation.None, typeInfo.Type.NullableAnnotation); } } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")] + public void CollectionExpression_NestedNullability_01() + { + var source = """ + #nullable enable + + var b = false; + var arr = b ? ["1"] : new[] { "2" }; + """; + + var comp = CreateCompilation(source); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var root = tree.GetRoot(); + var collectionExpr = root.DescendantNodes().OfType().Single(); + var typeInfo = model.GetTypeInfo(collectionExpr); + var type = (IArrayTypeSymbol)typeInfo.ConvertedType; + Assert.Equal("System.String[]", type.ToTestDisplayString()); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")] + public void CollectionExpression_NestedNullability_01_RhsTargetTyped() + { + var source = """ + #nullable enable + + var b = false; + var arr = b ? new[] { "1" } : ["2"]; + """; + + var comp = CreateCompilation(source); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var root = tree.GetRoot(); + var collectionExpr = root.DescendantNodes().OfType().Single(); + var typeInfo = model.GetTypeInfo(collectionExpr); + var type = (IArrayTypeSymbol)typeInfo.ConvertedType; + Assert.Equal("System.String[]", type.ToTestDisplayString()); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")] + public void CollectionExpression_NestedNullability_02() + { + var source = """ + #nullable enable + + using System; + using System.Collections.Generic; + using System.Linq.Expressions; + + class C + { + void M() + { + string[] x = ["1"]; + } + } + """; + + var comp = CreateCompilation(source); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var root = tree.GetRoot(); + var collectionExpr = root.DescendantNodes().OfType().Single(); + var typeInfo = model.GetTypeInfo(collectionExpr); + var type = (IArrayTypeSymbol)typeInfo.ConvertedType; + Assert.Equal("System.String[]", type.ToTestDisplayString()); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")] + public void CollectionExpression_NestedNullability_03() + { + var source = """ + #nullable enable + + var b = false; + var arr = b switch { true => ["1"], false => new[] { "2" } }; + """; + + var comp = CreateCompilation(source); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var root = tree.GetRoot(); + var collectionExpr = root.DescendantNodes().OfType().Single(); + var typeInfo = model.GetTypeInfo(collectionExpr); + var type = (IArrayTypeSymbol)typeInfo.ConvertedType; + Assert.Equal("System.String[]", type.ToTestDisplayString()); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")] + public void CollectionExpression_NestedNullability_04() + { + var source = """ + #nullable enable + + var arr = new[] { ["1"], new[] { "2" } }; + """; + + var comp = CreateCompilation(source); + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var root = tree.GetRoot(); + var collectionExpr = root.DescendantNodes().OfType().Single(); + var typeInfo = model.GetTypeInfo(collectionExpr); + var type = (IArrayTypeSymbol)typeInfo.ConvertedType; + Assert.Equal("System.String[]", type.ToTestDisplayString()); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71522")] + public void CollectionExpression_NestedNullability_05() + { + var source = """ + #nullable enable + public class C + { + public string[] M1(bool b) + { + var arr = b ? ["1"] : new[] { "2" }; + arr[0] = null; // 1 + return arr; + } + + public string[] M2(bool b) + { + var arr = new[] { "2" }; + arr = b ? ["1"] : arr; + arr[0] = null; // 2 + return arr; + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (7,18): warning CS8625: Cannot convert null literal to non-nullable reference type. + // arr[0] = null; // 1 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 18), + // (15,18): warning CS8625: Cannot convert null literal to non-nullable reference type. + // arr[0] = null; // 2 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(15, 18)); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var root = tree.GetRoot(); + var collectionExprs = root.DescendantNodes().OfType().ToArray(); + Assert.Equal(2, collectionExprs.Length); + foreach (var collectionExpr in collectionExprs) + { + var typeInfo = model.GetTypeInfo(collectionExpr); + var type = (IArrayTypeSymbol)typeInfo.ConvertedType; + Assert.Equal("System.String[]", type.ToTestDisplayString()); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.ElementNullableAnnotation); + } + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/71522")] + [WorkItem("https://github.com/dotnet/roslyn/issues/74609")] + public void CollectionExpression_NestedNullability_06() + { + var source = """ + #nullable enable + + public class C + { + public string[] M1(bool b) + { + var lam = () => + { + if (b) + return ["1"]; + + return new[] { "2" }; + }; + + var arr = lam(); + arr[0] = null; // 1 + return arr; + } + + public string[] M2(bool b) + { + var lam = () => new[] { "2" }; + var arr = lam(); + arr = b ? ["1"] : arr; + arr[0] = null; // 2 + return arr; + } + } + """; + + var comp = CreateCompilation(source); + // The expected nullable warnings are not reported here. + // https://github.com/dotnet/roslyn/issues/74609 + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var root = tree.GetRoot(); + var collectionExprs = root.DescendantNodes().OfType().ToArray(); + Assert.Equal(2, collectionExprs.Length); + foreach (var collectionExpr in collectionExprs) + { + var typeInfo = model.GetTypeInfo(collectionExpr); + var type = (IArrayTypeSymbol)typeInfo.ConvertedType; + Assert.Equal("System.String[]", type.ToTestDisplayString()); + Assert.Equal(PublicNullableAnnotation.NotAnnotated, type.NullableAnnotation); + + // The arrays have unexpected oblivious element nullability. + // https://github.com/dotnet/roslyn/issues/74609 + Assert.Equal(PublicNullableAnnotation.None, type.ElementNullableAnnotation); + } + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/71522")] + [WorkItem("https://github.com/dotnet/roslyn/issues/74693")] + public void TargetTypedExpressions_NestedNullability() + { + // Warning (2) is missing because default literals are contributing + // their initial bound type to best-type in nullable analysis. + // https://github.com/dotnet/roslyn/issues/74693 + var source = """ + #nullable enable + using System.Collections.Generic; + + public class C + { + public void M(bool b) + { + var x = b ? null! : new[] {"1"}; + x[0] = null; // 1 + } + + public void M2(bool b) + { + var x = b ? default! : new[] {"1"}; + x[0] = null; // 2 (missing) + } + + public void M3(bool b) + { + var x = b ? (b ? null! : null!) : new[] {"1"}; + x[0] = null; // 3 + } + + public void M4(bool b) + { + var x = b ? (b switch { _ => null! }) : new[] {"1"}; + x[0] = null; // 4 + } + + List MakeList(T value) => new List { value }; + + public void M5(bool b) + { + var x = b ? new() : MakeList("1"); + x[0] = null; // 5 + } + + public void M6(bool b) + { + var x = b ? default! : MakeList("1"); + x[0] = null; // 6 + } + } + """; + + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (9,16): warning CS8625: Cannot convert null literal to non-nullable reference type. + // x[0] = null; // 1 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(9, 16), + // (21,16): warning CS8625: Cannot convert null literal to non-nullable reference type. + // x[0] = null; // 3 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(21, 16), + // (27,16): warning CS8625: Cannot convert null literal to non-nullable reference type. + // x[0] = null; // 4 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(27, 16), + // (35,16): warning CS8625: Cannot convert null literal to non-nullable reference type. + // x[0] = null; // 5 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(35, 16), + // (41,16): warning CS8625: Cannot convert null literal to non-nullable reference type. + // x[0] = null; // 6 + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(41, 16)); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs index 9cb17023809c6..fc17e45995e8a 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs @@ -26,7 +26,7 @@ public void SetGetOnlyAutoPropNoExperimental() // One would think this creates an error, but it doesn't because // language version is a property of the parser and there are // no syntactical changes to the language for get-only autoprops - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" class C { public int P { get; } @@ -36,7 +36,7 @@ class C [Fact] public void SetGetOnlyAutoPropInConstructor() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" class C { public int P { get; } @@ -50,7 +50,7 @@ public C() [Fact] public void GetOnlyAutoPropBadOverride() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" class Base { @@ -83,7 +83,7 @@ public C() [Fact] public void SetGetOnlyAutoPropOutOfConstructor() { - CreateCompilationWithMscorlib45(@" + CreateCompilationWithMscorlib461(@" class C { public int P { get; } @@ -1776,7 +1776,7 @@ class C : I } "; - var comp = CreateCompilationWithMscorlib45(text); + var comp = CreateCompilationWithMscorlib461(text); var globalNamespace = comp.GlobalNamespace; @@ -2909,7 +2909,7 @@ ref int P { set { } } } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (4,17): error CS8080: Properties with by-reference returns must have a get accessor. // ref int P { set { } } Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "P").WithLocation(4, 17)); @@ -2926,14 +2926,14 @@ class C } "; - CreateCompilationWithMscorlib45(source).VerifyDiagnostics( + CreateCompilationWithMscorlib461(source).VerifyDiagnostics( // (5,48): error CS8147: Properties which return by reference cannot have set accessors // ref int P { get { return ref @field; } set { } } Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 48)); } [Fact, WorkItem(4696, "https://github.com/dotnet/roslyn/issues/4696")] - public void LangVersionAndReadonlyAutoProperty() + public void LangVersionAndReadonlyAutoProperty_01() { var source = @" public class Class1 @@ -2957,12 +2957,48 @@ interface I1 } "; - var comp = CreateCompilation(source, parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp5)); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular5); comp.GetDeclarationDiagnostics().Verify( - // (9,19): error CS8026: Feature 'readonly automatically implemented properties' is not available in C# 5. Please use language version 6 or greater. - // public string Prop1 { get; } - Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion5, "Prop1").WithArguments("readonly automatically implemented properties", "6").WithLocation(9, 19) + // (9,19): error CS8026: Feature 'readonly automatically implemented properties' is not available in C# 5. Please use language version 6 or greater. + // public string Prop1 { get; } + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion5, "Prop1").WithArguments("readonly automatically implemented properties", "6").WithLocation(9, 19) ); + + comp = CreateCompilation(source, parseOptions: TestOptions.Regular6); + comp.GetDeclarationDiagnostics().Verify(); + } + + [Fact] + public void LangVersionAndReadonlyAutoProperty_02() + { + var source = @" +public class Class1 +{ + public string Prop1 { set; } +} + +abstract class Class2 +{ + public abstract string Prop2 { set; } +} + +interface I1 +{ + string Prop3 { set; } +} +"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular5); + comp.GetDeclarationDiagnostics().Verify( + // (4,27): error CS8051: Auto-implemented properties must have get accessors. + // public string Prop1 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithLocation(4, 27)); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.GetDeclarationDiagnostics().Verify( + // (4,27): error CS8051: Auto-implemented properties must have get accessors. + // public string Prop1 { set; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithLocation(4, 27)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs index 0dde9e5f3fb67..9f2c305a4d345 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs @@ -5369,7 +5369,7 @@ interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation1.VerifyDiagnostics( // (4,26): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -5410,7 +5410,7 @@ virtual static void M01(){} "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation1.VerifyDiagnostics( // (4,26): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -5699,7 +5699,7 @@ interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); bool isChecked = op.StartsWith("checked "); @@ -5746,7 +5746,7 @@ interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); bool isChecked = op.StartsWith("checked "); @@ -5776,7 +5776,7 @@ interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_BadAbstractEqualityOperatorSignature).Verify( // (4,35): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -5825,7 +5825,7 @@ interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_BadAbstractEqualityOperatorSignature).Verify( // (4,35): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -5950,7 +5950,7 @@ interface I1 where T : I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation1.VerifyDiagnostics( // (4,39): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -6067,7 +6067,7 @@ interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation1.VerifyDiagnostics( // (4,31): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -6091,7 +6091,7 @@ interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation1.VerifyDiagnostics( // (4,31): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -6206,7 +6206,7 @@ interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation1.VerifyDiagnostics( // (4,41): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -6227,7 +6227,7 @@ interface I1 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation1.VerifyDiagnostics( // (4,41): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -8505,7 +8505,7 @@ static void M02() where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -8516,7 +8516,7 @@ static void M02() where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (12,26): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -9115,7 +9115,7 @@ static void M02(T x) where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -9126,7 +9126,7 @@ static void M02(T x) where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( // (12,32): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -9400,7 +9400,7 @@ static void M02(T x) where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -9411,7 +9411,7 @@ static void M02(T x) where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (12,35): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -9805,7 +9805,7 @@ class C var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -9816,7 +9816,7 @@ class C var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (21,35): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -12184,7 +12184,7 @@ static void M02(T x, int y) where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -12195,7 +12195,7 @@ static void M02(T x, int y) where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.ERR_CheckedOperatorNeedsMatch or (int)ErrorCode.ERR_BadAbstractEqualityOperatorSignature)).Verify( // (12,33): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -12247,7 +12247,7 @@ static void M02(T x, T y) where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); if (success) @@ -12265,7 +12265,7 @@ static void M02(T x, T y) where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); var builder = ArrayBuilder.GetInstance(); @@ -12334,7 +12334,7 @@ static void M02(T x, int y) where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -12345,7 +12345,7 @@ static void M02(T x, int y) where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( // (12,32): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -12384,7 +12384,7 @@ static void M02((int, T) x) where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -12395,7 +12395,7 @@ static void M02((int, T) x) where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (12,35): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -13439,7 +13439,7 @@ static void M02() where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -13450,7 +13450,7 @@ static void M02() where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (12,31): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -13491,7 +13491,7 @@ static void M02() where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -13502,7 +13502,7 @@ static void M02() where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (12,31): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -13543,7 +13543,7 @@ static void M02() where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -13557,7 +13557,7 @@ static void M02() where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (12,31): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -14149,7 +14149,7 @@ static void M02() where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -14160,7 +14160,7 @@ static void M02() where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (12,41): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -14198,7 +14198,7 @@ static void M02() where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -14209,7 +14209,7 @@ static void M02() where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (12,41): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -14751,7 +14751,7 @@ static void M02() where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -14762,7 +14762,7 @@ static void M02() where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (12,26): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -15157,7 +15157,7 @@ static void M02() where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -15168,7 +15168,7 @@ static void M02() where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (12,26): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -15425,7 +15425,7 @@ static void M02() where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll.WithAllowUnsafe(true), parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -15436,7 +15436,7 @@ static void M02() where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll.WithAllowUnsafe(true), parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (12,26): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -15963,7 +15963,7 @@ public static void M01() {} var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -15974,7 +15974,7 @@ public static void M01() {} var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (9,26): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -16010,7 +16010,7 @@ static void I1.M01() {} var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -16021,7 +16021,7 @@ static void I1.M01() {} var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (4,20): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -19062,7 +19062,7 @@ public interface I1 where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.ERR_CheckedOperatorNeedsMatch or (int)ErrorCode.ERR_OpTFRetType)).Verify( @@ -19073,7 +19073,7 @@ public interface I1 where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.ERR_CheckedOperatorNeedsMatch or (int)ErrorCode.ERR_OpTFRetType)).Verify( // (9,32): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -19114,7 +19114,7 @@ public interface I1 where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.ERR_CheckedOperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify( @@ -19125,7 +19125,7 @@ public interface I1 where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.ERR_CheckedOperatorNeedsMatch or (int)ErrorCode.WRN_EqualityOpWithoutEquals or (int)ErrorCode.WRN_EqualityOpWithoutGetHashCode)).Verify( // (9,32): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -19166,7 +19166,7 @@ public interface I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -19177,7 +19177,7 @@ public interface I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.ERR_OpTFRetType or (int)ErrorCode.ERR_CheckedOperatorNeedsMatch)).Verify( // (4,27): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -19221,7 +19221,7 @@ public interface I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -19232,7 +19232,7 @@ public interface I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.GetDiagnostics().Where(d => d.Code is not ((int)ErrorCode.ERR_OperatorNeedsMatch or (int)ErrorCode.ERR_CheckedOperatorNeedsMatch or (int)ErrorCode.ERR_BadAbstractEqualityOperatorSignature)).Verify( // (4,27): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -22813,7 +22813,7 @@ public interface I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -22830,7 +22830,7 @@ public interface I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (9,31): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -22869,7 +22869,7 @@ public interface I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -22880,7 +22880,7 @@ public interface I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (4,19): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -25597,7 +25597,7 @@ public static event System.Action M01 { add{} remove{} } var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -25614,7 +25614,7 @@ public static event System.Action M01 { add{} remove{} } var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (9,41): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -25650,7 +25650,7 @@ public interface I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -25661,7 +25661,7 @@ public interface I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (4,35): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -28522,7 +28522,7 @@ public partial interface I1 where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( @@ -28533,7 +28533,7 @@ public partial interface I1 where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( // (9,39): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -28574,7 +28574,7 @@ public interface I1 where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( @@ -28585,7 +28585,7 @@ public interface I1 where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( // (4,40): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -30519,7 +30519,7 @@ static int M02(T x) where T : I1 var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -30530,7 +30530,7 @@ static int M02(T x) where T : I1 var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_CheckedOperatorNeedsMatch).Verify( // (12,39): error CS8919: Target runtime doesn't support static abstract members in interfaces. @@ -30577,7 +30577,7 @@ class C var compilation2 = CreateCompilation(source2, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended, + targetFramework: TargetFramework.Mscorlib461Extended, references: new[] { compilation1.ToMetadataReference() }); compilation2.VerifyDiagnostics( @@ -30588,7 +30588,7 @@ class C var compilation3 = CreateCompilation(source2 + source1, options: TestOptions.DebugDll, parseOptions: TestOptions.RegularPreview, - targetFramework: TargetFramework.DesktopLatestExtended); + targetFramework: TargetFramework.Mscorlib461Extended); compilation3.VerifyDiagnostics( // (21,39): error CS8919: Target runtime doesn't support static abstract members in interfaces. diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index 67598be201e58..9c3566875c603 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -1760,13 +1761,13 @@ internal int P2 { static set { } } } "; CreateCompilation(text, parseOptions: TestOptions.Regular7, targetFramework: TargetFramework.NetCoreApp).VerifyDiagnostics( - // (3,23): error CS8503: The modifier 'static' is not valid for this item in C# 7. Please use language version '8.0' or greater. + // (3,23): error CS8703: The modifier 'static' is not valid for this item in C# 7.0. Please use language version '8.0' or greater. // public static int P1 { get; } Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("static", "7.0", "8.0").WithLocation(3, 23), - // (3,23): error CS8503: The modifier 'public' is not valid for this item in C# 7. Please use language version '8.0' or greater. + // (3,23): error CS8703: The modifier 'public' is not valid for this item in C# 7.0. Please use language version '8.0' or greater. // public static int P1 { get; } Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P1").WithArguments("public", "7.0", "8.0").WithLocation(3, 23), - // (4,18): error CS8503: The modifier 'abstract' is not valid for this item in C# 7. Please use language version '8.0' or greater. + // (4,18): error CS8703: The modifier 'abstract' is not valid for this item in C# 7.0. Please use language version '8.0' or greater. // abstract int P2 { static set; } Diagnostic(ErrorCode.ERR_InvalidModifierForLanguageVersion, "P2").WithArguments("abstract", "7.0", "8.0").WithLocation(4, 18), // (4,30): error CS0106: The modifier 'static' is not valid for this item @@ -1796,6 +1797,9 @@ internal int P2 { static set { } } // (14,21): error CS0106: The modifier 'sealed' is not valid for this item // int P4 { sealed get { return 0; } } Diagnostic(ErrorCode.ERR_BadMemberFlag, "get").WithArguments("sealed").WithLocation(14, 21), + // (15,31): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // protected internal object P5 { get { return null; } extern set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P5").WithArguments("field keyword").WithLocation(15, 31), // (15,64): error CS0106: The modifier 'extern' is not valid for this item // protected internal object P5 { get { return null; } extern set; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "set").WithArguments("extern").WithLocation(15, 64), @@ -8125,13 +8129,21 @@ public void CS0501ERR_ConcreteMissingBody02() protected abstract object S { set; } // no error } "; + CreateCompilation(text, parseOptions: TestOptions.Regular13).VerifyDiagnostics( + // (3,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int P { get; set { } } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P").WithArguments("field keyword").WithLocation(3, 16), + // (4,16): error CS8652: The feature 'field keyword' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int Q { get { return 0; } set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Q").WithArguments("field keyword").WithLocation(4, 16), + // (5,30): warning CS0626: Method, operator, or accessor 'C.R.get' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. + // public extern object R { get; } // no error + Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "get").WithArguments("C.R.get").WithLocation(5, 30)); + CreateCompilation(text).VerifyDiagnostics( - // (3,20): error CS0501: 'C.P.get' must declare a body because it is not marked abstract, extern, or partial - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("C.P.get"), - // (4,38): error CS0501: 'C.Q.set' must declare a body because it is not marked abstract, extern, or partial - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "set").WithArguments("C.Q.set"), // (5,30): warning CS0626: Method, operator, or accessor 'C.R.get' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. - Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "get").WithArguments("C.R.get")); + // public extern object R { get; } // no error + Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "get").WithArguments("C.R.get").WithLocation(5, 30)); } [Fact] @@ -14933,7 +14945,7 @@ class B { public static void M4(this object o) { } }"; - var compilation = CreateEmptyCompilation(source, new[] { TestMetadata.Net40.mscorlib }); + var compilation = CreateEmptyCompilation(source, new[] { Net40.References.mscorlib }); compilation.VerifyDiagnostics( // (3,27): error CS1110: Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll? Diagnostic(ErrorCode.ERR_ExtensionAttrNotFound, "this").WithArguments("System.Runtime.CompilerServices.ExtensionAttribute").WithLocation(3, 27), @@ -16832,7 +16844,7 @@ namespace N1 Diagnostic(ErrorCode.ERR_NamespaceNotAllowedInScript, "namespace").WithLocation(2, 1) }; - CreateCompilationWithMscorlib45(new[] { Parse(text, options: TestOptions.Script) }).VerifyDiagnostics(expectedDiagnostics); + CreateCompilationWithMscorlib461(new[] { Parse(text, options: TestOptions.Script) }).VerifyDiagnostics(expectedDiagnostics); } [Fact] @@ -16848,13 +16860,13 @@ public void CS8050ERR_InitializerOnNonAutoProperty() protected int P { get { throw null; } set { } } = 1; }"; CreateCompilation(source).VerifyDiagnostics( - // (5,9): error CS8050: Only auto-implemented properties can have initializers. + // (5,9): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // int I { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(5, 9), - // (6,16): error CS8050: Only auto-implemented properties can have initializers. + // (6,16): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // static int S { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "S").WithLocation(6, 16), - // (7,19): error CS8050: Only auto-implemented properties can have initializers. + // (7,19): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers. // protected int P { get { throw null; } set { } } = 1; Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P").WithLocation(7, 19) ); @@ -20437,7 +20449,7 @@ public void AbstractInScript() @"internal abstract void M(); internal abstract object P { get; } internal abstract event System.EventHandler E;"; - var compilation = CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlib461(source, parseOptions: TestOptions.Script, options: TestOptions.DebugExe); compilation.VerifyDiagnostics( // (1,24): error CS0513: 'M()' is abstract but it is contained in non-abstract type 'Script' // internal abstract void M(); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/TypeResolutionTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/TypeResolutionTests.cs index 6091777d5f6be..971f98ebbef94 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/TypeResolutionTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/TypeResolutionTests.cs @@ -16,7 +16,7 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols { @@ -49,7 +49,7 @@ public class TestClass var c1 = CSharpCompilation.Create("Test1", syntaxTrees: new[] { Parse(source1) }, - references: new[] { Net40.mscorlib }); + references: new[] { Net40.References.mscorlib }); Assert.Null(c1.GetTypeByMetadataName("DoesntExist")); Assert.Null(c1.GetTypeByMetadataName("DoesntExist`1")); @@ -66,7 +66,7 @@ public class TestClass references: new MetadataReference[] { new CSharpCompilationReference(c1), - Net40.mscorlib + Net40.References.mscorlib }); NamedTypeSymbol c2TestClass = c2.GetTypeByMetadataName("System.TestClass"); @@ -76,7 +76,7 @@ public class TestClass references: new MetadataReference[] { new CSharpCompilationReference(c2), - Net40.mscorlib + Net40.References.mscorlib }); NamedTypeSymbol c3TestClass = c3.GetTypeByMetadataName("System.TestClass"); @@ -90,7 +90,7 @@ public class TestClass { new CSharpCompilationReference(c1), new CSharpCompilationReference(c2), - Net40.mscorlib + Net40.References.mscorlib }); NamedTypeSymbol c4TestClass = c4.GetTypeByMetadataName("System.TestClass"); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/TypeTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/TypeTests.cs index 5a0a8192fcb81..3bd84ab511b83 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/TypeTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/TypeTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols { @@ -533,7 +534,7 @@ public class A { } "; - var compilation = CreateEmptyCompilation(text, new[] { TestMetadata.Net40.mscorlib }); + var compilation = CreateEmptyCompilation(text, new[] { Net40.References.mscorlib }); int[] ary = new int[2]; var globalNS = compilation.SourceModule.GlobalNamespace; diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs index a196defc664ea..47c197cb03303 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs @@ -432,7 +432,8 @@ public void WarningLevel_2() case ErrorCode.WRN_CollectionExpressionRefStructMayAllocate: case ErrorCode.WRN_CollectionExpressionRefStructSpreadMayAllocate: case ErrorCode.INF_TooManyBoundLambdas: - case ErrorCode.INF_IdentifierConflictWithContextualKeyword: + case ErrorCode.WRN_FieldIsAmbiguous: + case ErrorCode.WRN_UninitializedNonNullableBackingField: Assert.Equal(1, ErrorFacts.GetWarningLevel(errorCode)); break; case ErrorCode.WRN_InvalidVersionFormat: diff --git a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs index 6edb119c630fa..88f2342f45eec 100644 --- a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs +++ b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs @@ -121,6 +121,9 @@ private static Syntax.InternalSyntax.BaseExpressionSyntax GenerateBaseExpression private static Syntax.InternalSyntax.LiteralExpressionSyntax GenerateLiteralExpression() => InternalSyntaxFactory.LiteralExpression(SyntaxKind.ArgListExpression, InternalSyntaxFactory.Token(SyntaxKind.ArgListKeyword)); + private static Syntax.InternalSyntax.FieldExpressionSyntax GenerateFieldExpression() + => InternalSyntaxFactory.FieldExpression(InternalSyntaxFactory.Token(SyntaxKind.FieldKeyword)); + private static Syntax.InternalSyntax.MakeRefExpressionSyntax GenerateMakeRefExpression() => InternalSyntaxFactory.MakeRefExpression(InternalSyntaxFactory.Token(SyntaxKind.MakeRefKeyword), InternalSyntaxFactory.Token(SyntaxKind.OpenParenToken), GenerateIdentifierName(), InternalSyntaxFactory.Token(SyntaxKind.CloseParenToken)); @@ -1159,6 +1162,16 @@ public void TestLiteralExpressionFactoryAndProperties() AttachAndCheckDiagnostics(node); } + [Fact] + public void TestFieldExpressionFactoryAndProperties() + { + var node = GenerateFieldExpression(); + + Assert.Equal(SyntaxKind.FieldKeyword, node.Token.Kind); + + AttachAndCheckDiagnostics(node); + } + [Fact] public void TestMakeRefExpressionFactoryAndProperties() { @@ -4826,6 +4839,32 @@ public void TestLiteralExpressionIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestFieldExpressionTokenDeleteRewriter() + { + var oldNode = GenerateFieldExpression(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestFieldExpressionIdentityRewriter() + { + var oldNode = GenerateFieldExpression(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestMakeRefExpressionTokenDeleteRewriter() { @@ -10298,6 +10337,9 @@ private static BaseExpressionSyntax GenerateBaseExpression() private static LiteralExpressionSyntax GenerateLiteralExpression() => SyntaxFactory.LiteralExpression(SyntaxKind.ArgListExpression, SyntaxFactory.Token(SyntaxKind.ArgListKeyword)); + private static FieldExpressionSyntax GenerateFieldExpression() + => SyntaxFactory.FieldExpression(SyntaxFactory.Token(SyntaxKind.FieldKeyword)); + private static MakeRefExpressionSyntax GenerateMakeRefExpression() => SyntaxFactory.MakeRefExpression(SyntaxFactory.Token(SyntaxKind.MakeRefKeyword), SyntaxFactory.Token(SyntaxKind.OpenParenToken), GenerateIdentifierName(), SyntaxFactory.Token(SyntaxKind.CloseParenToken)); @@ -11336,6 +11378,16 @@ public void TestLiteralExpressionFactoryAndProperties() Assert.Equal(node, newNode); } + [Fact] + public void TestFieldExpressionFactoryAndProperties() + { + var node = GenerateFieldExpression(); + + Assert.Equal(SyntaxKind.FieldKeyword, node.Token.Kind()); + var newNode = node.WithToken(node.Token); + Assert.Equal(node, newNode); + } + [Fact] public void TestMakeRefExpressionFactoryAndProperties() { @@ -15003,6 +15055,32 @@ public void TestLiteralExpressionIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestFieldExpressionTokenDeleteRewriter() + { + var oldNode = GenerateFieldExpression(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestFieldExpressionIdentityRewriter() + { + var oldNode = GenerateFieldExpression(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestMakeRefExpressionTokenDeleteRewriter() { diff --git a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/XmlDocCommentTests.cs b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/XmlDocCommentTests.cs index 363646d645795..d75115cc11c1e 100644 --- a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/XmlDocCommentTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/XmlDocCommentTests.cs @@ -3009,6 +3009,19 @@ public void TestXmlSeeElementAndXmlSeeAlsoElement() Assert.Equal(expected, actual); } + [Fact] + [Trait("Feature", "Xml Documentation Comments")] + public void TestXmlSeeAlsoElementWithLink() + { + var docComment = SyntaxFactory.DocumentationComment( + SyntaxFactory.XmlSeeAlsoElement(new Uri("https://dotnet.microsoft.com/"), + SyntaxFactory.List(new XmlNodeSyntax[] { SyntaxFactory.XmlText(".NET") }))); + + Assert.Equal( + "/// .NET", + docComment.ToFullString()); + } + [Fact] [Trait("Feature", "Xml Documentation Comments")] public void TestXmlNewLineElement() diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs index 90944462784b9..563f7e270746e 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/AsyncParsingTests.cs @@ -1681,21 +1681,15 @@ class C { async partial implicit operator ", - // (4,11): error CS1553: Declaration is not valid; use '+ operator (...' instead + // (4,11): error CS1553: Declaration is not valid; use 'implicit operator (...' instead // async partial implicit operator - Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "partial").WithArguments("+").WithLocation(4, 11), - // (4,19): error CS1003: Syntax error, 'operator' expected + Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "partial").WithArguments("implicit").WithLocation(4, 11), + // (4,36): error CS1031: Type expected // async partial implicit operator - Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(4, 19), - // (4,19): error CS1037: Overloadable operator expected + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(4, 36), + // (4,36): error CS1003: Syntax error, '(' expected // async partial implicit operator - Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "implicit").WithLocation(4, 19), - // (4,28): error CS1003: Syntax error, '(' expected - // async partial implicit operator - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(4, 28), - // (4,28): error CS1041: Identifier expected; 'operator' is a keyword - // async partial implicit operator - Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(4, 28), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(4, 36), // (4,36): error CS1026: ) expected // async partial implicit operator Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 36), @@ -1712,15 +1706,15 @@ async partial implicit operator N(SyntaxKind.ClassKeyword); N(SyntaxKind.IdentifierToken, "C"); N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.OperatorDeclaration); + N(SyntaxKind.ConversionOperatorDeclaration); { N(SyntaxKind.AsyncKeyword); - N(SyntaxKind.IdentifierName); + N(SyntaxKind.ImplicitKeyword); + N(SyntaxKind.OperatorKeyword); + M(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "partial"); + M(SyntaxKind.IdentifierToken); } - M(SyntaxKind.OperatorKeyword); - M(SyntaxKind.PlusToken); M(SyntaxKind.ParameterList); { M(SyntaxKind.OpenParenToken); @@ -1798,21 +1792,15 @@ class C { async partial explicit operator ", - // (4,11): error CS1553: Declaration is not valid; use '+ operator (...' instead + // (4,11): error CS1553: Declaration is not valid; use 'explicit operator (...' instead // async partial explicit operator - Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "partial").WithArguments("+").WithLocation(4, 11), - // (4,19): error CS1003: Syntax error, 'operator' expected + Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "partial").WithArguments("explicit").WithLocation(4, 11), + // (4,36): error CS1031: Type expected // async partial explicit operator - Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator").WithLocation(4, 19), - // (4,19): error CS1037: Overloadable operator expected + Diagnostic(ErrorCode.ERR_TypeExpected, "").WithLocation(4, 36), + // (4,36): error CS1003: Syntax error, '(' expected // async partial explicit operator - Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "explicit").WithLocation(4, 19), - // (4,28): error CS1003: Syntax error, '(' expected - // async partial explicit operator - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(4, 28), - // (4,28): error CS1041: Identifier expected; 'operator' is a keyword - // async partial explicit operator - Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(4, 28), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(4, 36), // (4,36): error CS1026: ) expected // async partial explicit operator Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 36), @@ -1822,6 +1810,7 @@ async partial explicit operator // (4,36): error CS1513: } expected // async partial explicit operator Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 36)); + N(SyntaxKind.CompilationUnit); { N(SyntaxKind.ClassDeclaration); @@ -1829,15 +1818,15 @@ async partial explicit operator N(SyntaxKind.ClassKeyword); N(SyntaxKind.IdentifierToken, "C"); N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.OperatorDeclaration); + N(SyntaxKind.ConversionOperatorDeclaration); { N(SyntaxKind.AsyncKeyword); - N(SyntaxKind.IdentifierName); + N(SyntaxKind.ExplicitKeyword); + N(SyntaxKind.OperatorKeyword); + M(SyntaxKind.IdentifierName); { - N(SyntaxKind.IdentifierToken, "partial"); + M(SyntaxKind.IdentifierToken); } - M(SyntaxKind.OperatorKeyword); - M(SyntaxKind.PlusToken); M(SyntaxKind.ParameterList); { M(SyntaxKind.OpenParenToken); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/AwaitParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/AwaitParsingTests.cs index 3479451b547ab..41a096017dc4b 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/AwaitParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/AwaitParsingTests.cs @@ -1339,6 +1339,340 @@ public void AwaitInConditionalExpressionAfterPattern4() EOF(); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72720")] + public void AwaitInConditionalExpressionAfterPattern5() + { + UsingDeclaration(""" + void M() + { + var c = x is X ? await y : z; + } + """); + + 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.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "c"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.AwaitExpression); + { + N(SyntaxKind.AwaitKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "z"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72720")] + public void AwaitInConditionalExpressionAfterPattern6() + { + UsingDeclaration(""" + async void M() + { + var c = x is X ? await y : z; + } + """); + + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.AsyncKeyword); + 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.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "c"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.AwaitExpression); + { + N(SyntaxKind.AwaitKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "z"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72720")] + public void AwaitInConditionalExpressionAfterPattern7() + { + UsingDeclaration(""" + void M() + { + var c = x is X ? await(y) : z; + } + """); + + 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.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "c"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "await"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "z"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72720")] + public void AwaitInConditionalExpressionAfterPattern8() + { + UsingDeclaration(""" + async void M() + { + var c = x is X ? await (y) : z; + } + """); + + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.AsyncKeyword); + 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.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "c"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.AwaitExpression); + { + N(SyntaxKind.AwaitKeyword); + N(SyntaxKind.ParenthesizedExpression); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "z"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72720")] public void AwaitAsStartOfExpressionInConditional1() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs index 3532f3d25bb69..57d82e0f09cfd 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs @@ -65,7 +65,7 @@ public void TestFieldsForEqualsAndGetHashCode() "Features", "Language", "LanguageVersion", - "InterceptorsPreviewNamespaces", + "InterceptorsNamespaces", "PreprocessorSymbolNames", "PreprocessorSymbols", "SpecifiedLanguageVersion"); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/CollectionExpressionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/CollectionExpressionParsingTests.cs index 5eed36571065c..46b1fc99900ba 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/CollectionExpressionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/CollectionExpressionParsingTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests; -public class CollectionExpressionParsingTests : ParsingTests +public sealed class CollectionExpressionParsingTests : ParsingTests { public CollectionExpressionParsingTests(ITestOutputHelper output) : base(output) { } @@ -18112,4 +18112,517 @@ public enum BundleType } EOF(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] + public void CollectionExpression_ConditionalExpressionAmbiguity1() + { + UsingStatement("var v = x is Y ? [1, 2, 3] : [1];"); + + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "v"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.CollectionExpression); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.ExpressionElement); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ExpressionElement); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "2"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ExpressionElement); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "3"); + } + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.CollectionExpression); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.ExpressionElement); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + } + N(SyntaxKind.CloseBracketToken); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] + public void CollectionExpression_ConditionalExpressionAmbiguity2() + { + UsingStatement("var v = x is Y ? [] : [1];"); + + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "v"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.CollectionExpression); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.CollectionExpression); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.ExpressionElement); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + } + N(SyntaxKind.CloseBracketToken); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] + public void CollectionExpression_ConditionalExpressionAmbiguity3() + { + UsingStatement("var v = x is Y ? [];"); + + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "v"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.NullableType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + N(SyntaxKind.QuestionToken); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] + public void CollectionExpression_ConditionalExpressionAmbiguity4() + { + UsingStatement("var v = x is Y ? [,];"); + + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "v"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.NullableType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + N(SyntaxKind.QuestionToken); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] + public void CollectionExpression_ConditionalExpressionAmbiguity5() + { + UsingStatement("var v = x is Y ? [][];"); + + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "v"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.NullableType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + N(SyntaxKind.QuestionToken); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] + public void CollectionExpression_ConditionalExpressionAmbiguity6() + { + UsingStatement("var v = x is Y ? [] == Complex() : [1];"); + + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "v"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.EqualsExpression); + { + N(SyntaxKind.CollectionExpression); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.EqualsEqualsToken); + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Complex"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.CollectionExpression); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.ExpressionElement); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + } + N(SyntaxKind.CloseBracketToken); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] + public void CollectionExpression_ConditionalExpressionAmbiguity7() + { + UsingStatement("var v = x is Y ? [Goo]() => B : [Goo]() => C;"); + + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "v"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + } + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "B"); + } + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + } + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] + public void CollectionExpression_ConditionalExpressionAmbiguity_RealWorld() + { + // Ensure that even though `DayOfWeek.Friday` will be parsed as a type, that binding will understand that it + // should also be viewed as a constant pattern. + CreateCompilation(""" + using System; + + class C + { + void M() + { + int[] nextDayOffSet = DateTime.Today.DayOfWeek is DayOfWeek.Friday ? [1, 2, 3] : [1]; + } + } + """).VerifyDiagnostics(); + } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs index c49afe47196b8..f727bfd113093 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs @@ -5756,7 +5756,7 @@ static int Main() public void TestPartialEnum() { var text = @"partial enum E{}"; - CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + CreateCompilationWithMscorlib461(text).VerifyDiagnostics( // (1,14): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. // partial enum E{} Diagnostic(ErrorCode.ERR_PartialMisplaced, "E").WithLocation(1, 14)); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs index 2633665e833b8..35c676b2131ec 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs @@ -6822,5 +6822,206 @@ public void UnsignedRightShiftAssignment_04() EOF(); } } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75074")] + public void LinqQueryInConditionalExpression1() + { + var text = "x is X ? from item in collection select item : null"; + + UsingExpression(text); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.QueryExpression); + { + N(SyntaxKind.FromClause); + { + N(SyntaxKind.FromKeyword); + N(SyntaxKind.IdentifierToken, "item"); + N(SyntaxKind.InKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "collection"); + } + } + N(SyntaxKind.QueryBody); + { + N(SyntaxKind.SelectClause); + { + N(SyntaxKind.SelectKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "item"); + } + } + } + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75074")] + public void LinqQueryInConditionalExpression2() + { + var text = "x is X.Y ? from item in collection select item : null"; + + UsingExpression(text); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.QualifiedName); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.QueryExpression); + { + N(SyntaxKind.FromClause); + { + N(SyntaxKind.FromKeyword); + N(SyntaxKind.IdentifierToken, "item"); + N(SyntaxKind.InKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "collection"); + } + } + N(SyntaxKind.QueryBody); + { + N(SyntaxKind.SelectClause); + { + N(SyntaxKind.SelectKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "item"); + } + } + } + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75074")] + public void LinqQueryInConditionalExpression_Incomplete() + { + var text = "x is X.Y ? from item"; + + UsingExpression(text, + // (1,21): error CS1001: Identifier expected + // x is X.Y ? from item + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 21), + // (1,21): error CS1003: Syntax error, 'in' expected + // x is X.Y ? from item + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("in").WithLocation(1, 21), + // (1,21): error CS1733: Expected expression + // x is X.Y ? from item + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 21), + // (1,21): error CS0742: A query body must end with a select clause or a group clause + // x is X.Y ? from item + Diagnostic(ErrorCode.ERR_ExpectedSelectOrGroup, "").WithLocation(1, 21), + // (1,21): error CS1003: Syntax error, ':' expected + // x is X.Y ? from item + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 21), + // (1,21): error CS1733: Expected expression + // x is X.Y ? from item + Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 21)); + + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.QualifiedName); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.QueryExpression); + { + N(SyntaxKind.FromClause); + { + N(SyntaxKind.FromKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "item"); + } + M(SyntaxKind.IdentifierToken); + M(SyntaxKind.InKeyword); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.QueryBody); + { + M(SyntaxKind.SelectClause); + { + M(SyntaxKind.SelectKeyword); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + } + M(SyntaxKind.ColonToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + EOF(); + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FieldKeywordParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FieldKeywordParsingTests.cs new file mode 100644 index 0000000000000..9492d589e19da --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FieldKeywordParsingTests.cs @@ -0,0 +1,2008 @@ +// 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 Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public class FieldKeywordParsingTests : ParsingTests + { + public FieldKeywordParsingTests(ITestOutputHelper output) : base(output) + { + } + + private static bool IsParsedAsToken(LanguageVersion languageVersion, bool escapeIdentifier) + { + return !escapeIdentifier && languageVersion > LanguageVersion.CSharp13; + } + + private void IdentifierNameOrFieldExpression(LanguageVersion languageVersion, bool escapeIdentifier) + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier, IsParsedAsToken(languageVersion, escapeIdentifier)); + } + + private void IdentifierNameOrFieldExpression(LanguageVersion languageVersion, bool escapeIdentifier, bool isParsedAsToken) + { + if (isParsedAsToken) + { + N(SyntaxKind.FieldExpression); + { + N(SyntaxKind.FieldKeyword); + } + } + else + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, GetFieldIdentifier(escapeIdentifier)); + } + } + } + + private static string GetFieldIdentifier(bool escapeIdentifier) + { + return escapeIdentifier ? "@field" : "field"; + } + + [Theory] + [CombinatorialData] + public void Property_Initializer( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion) + { + UsingTree($$""" + class C + { + object P { get; set; } = field; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "field"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void Property_ExpressionBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion) + { + bool expectedParsedAsToken = languageVersion > LanguageVersion.CSharp13; + UsingTree($$""" + class C + { + object P => field; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier: false, expectedParsedAsToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void PropertyGet_ExpressionBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion) + { + bool expectedParsedAsToken = languageVersion > LanguageVersion.CSharp13; + UsingTree($$""" + class C + { + object P { get => field; } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier: false, expectedParsedAsToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void PropertyGet_BlockBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion) + { + bool expectedParsedAsToken = languageVersion > LanguageVersion.CSharp13; + UsingTree($$""" + class C + { + object P { get { return field; } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ReturnStatement); + { + N(SyntaxKind.ReturnKeyword); + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier: false, expectedParsedAsToken); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void PropertySet_BlockBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool useInit) + { + bool expectedParsedAsToken = languageVersion > LanguageVersion.CSharp13; + UsingTree($$""" + class C + { + object P { {{(useInit ? "init" : "set")}} { field = 0; } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(useInit ? SyntaxKind.InitAccessorDeclaration : SyntaxKind.SetAccessorDeclaration); + { + N(useInit ? SyntaxKind.InitKeyword : SyntaxKind.SetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier: false, expectedParsedAsToken); + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void Indexer_ExpressionBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion) + { + UsingTree($$""" + class C + { + object this[int i] => field; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IndexerDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.ThisKeyword); + N(SyntaxKind.BracketedParameterList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "field"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void IndexerGet_ExpressionBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion) + { + UsingTree($$""" + class C + { + object this[int i] { get => field; } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IndexerDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.ThisKeyword); + N(SyntaxKind.BracketedParameterList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "field"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void IndexerGet_BlockBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion) + { + UsingTree($$""" + class C + { + object this[int i] { get { return field; } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IndexerDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.ThisKeyword); + N(SyntaxKind.BracketedParameterList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ReturnStatement); + { + N(SyntaxKind.ReturnKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "field"); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void IndexerSet_BlockBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool useInit) + { + UsingTree($$""" + class C + { + object this[int i] { {{(useInit ? "init" : "set")}} { field = 0; } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IndexerDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.ThisKeyword); + N(SyntaxKind.BracketedParameterList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(useInit ? SyntaxKind.InitAccessorDeclaration : SyntaxKind.SetAccessorDeclaration); + { + N(useInit ? SyntaxKind.InitKeyword : SyntaxKind.SetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "field"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void EventAccessor( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool useRemove) + { + UsingTree($$""" + class C + { + event EventHandler E { {{(useRemove ? "remove" : "add")}} { field = null; } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "EventHandler"); + } + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(useRemove ? SyntaxKind.RemoveAccessorDeclaration : SyntaxKind.AddAccessorDeclaration); + { + N(useRemove ? SyntaxKind.RemoveKeyword : SyntaxKind.AddKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "field"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void ExplicitImplementation_PropertySet_BlockBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool useInit) + { + bool expectedParsedAsToken = languageVersion > LanguageVersion.CSharp13; + UsingTree($$""" + class C + { + object I.P { {{(useInit ? "init" : "set")}} { field = 0; } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.ExplicitInterfaceSpecifier); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "I"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.DotToken); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(useInit ? SyntaxKind.InitAccessorDeclaration : SyntaxKind.SetAccessorDeclaration); + { + N(useInit ? SyntaxKind.InitKeyword : SyntaxKind.SetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier: false, expectedParsedAsToken); + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void ExplicitImplementation_IndexerSet_BlockBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool useInit) + { + UsingTree($$""" + class C + { + object I.this[int i] { {{(useInit ? "init" : "set")}} { field = 0; } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IndexerDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.ExplicitInterfaceSpecifier); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "I"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.DotToken); + } + N(SyntaxKind.ThisKeyword); + N(SyntaxKind.BracketedParameterList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(useInit ? SyntaxKind.InitAccessorDeclaration : SyntaxKind.SetAccessorDeclaration); + { + N(useInit ? SyntaxKind.InitKeyword : SyntaxKind.SetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "field"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void Invocation( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + UsingTree($$""" + class C + { + object P => {{GetFieldIdentifier(escapeIdentifier)}}(); + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.InvocationExpression); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void ElementAccess( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + UsingTree($$""" + class C + { + object P => {{GetFieldIdentifier(escapeIdentifier)}}[0]; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.ElementAccessExpression); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + N(SyntaxKind.BracketedArgumentList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.CloseBracketToken); + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void PreIncrement( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + UsingTree($$""" + class C + { + object P => ++{{GetFieldIdentifier(escapeIdentifier)}}; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.PreIncrementExpression); + { + N(SyntaxKind.PlusPlusToken); + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void PostIncrement( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + UsingTree($$""" + class C + { + object P => {{GetFieldIdentifier(escapeIdentifier)}}++; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.PostIncrementExpression); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + N(SyntaxKind.PlusPlusToken); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void PointerIndirection( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + UsingTree($$""" + class C + { + object P => *{{GetFieldIdentifier(escapeIdentifier)}}; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.PointerIndirectionExpression); + { + N(SyntaxKind.AsteriskToken); + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void PointerMemberAccess( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + UsingTree($$""" + class C + { + object P => {{GetFieldIdentifier(escapeIdentifier)}}->F; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.PointerMemberAccessExpression); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + N(SyntaxKind.MinusGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F"); + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void ConditionalAccess( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + UsingTree($$""" + class C + { + object P => {{GetFieldIdentifier(escapeIdentifier)}}?.F; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.ConditionalAccessExpression); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + N(SyntaxKind.QuestionToken); + N(SyntaxKind.MemberBindingExpression); + { + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F"); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void NullableSuppression( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + UsingTree($$""" + class C + { + object P => {{GetFieldIdentifier(escapeIdentifier)}}!; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.SuppressNullableWarningExpression); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + N(SyntaxKind.ExclamationToken); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void Arguments( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + string identifier = GetFieldIdentifier(escapeIdentifier); + UsingTree($$""" + class C + { + object P => F({{identifier}}, {{identifier}}, out {{identifier}}); + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "F"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Argument); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Argument); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.OutKeyword); + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + } + N(SyntaxKind.CloseParenToken); + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void QualifiedName_01( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + string identifier = GetFieldIdentifier(escapeIdentifier); + UsingTree($$""" + class C + { + object P => {{identifier}}.B; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "B"); + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void QualifiedName_02( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + string identifier = GetFieldIdentifier(escapeIdentifier); + UsingTree($$""" + class C + { + object P => A.{{identifier}}; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, identifier); + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void AliasQualifiedName( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + string identifier = GetFieldIdentifier(escapeIdentifier); + UsingTree($$""" + class C + { + object P => {{identifier}}::A.B; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.AliasQualifiedName); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, identifier); + } + N(SyntaxKind.ColonColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "B"); + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void NameOf( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + UsingTree($$""" + class C + { + object P { set { _ = nameof({{GetFieldIdentifier(escapeIdentifier)}}); } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "_"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "nameof"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Argument); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + } + N(SyntaxKind.CloseParenToken); + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void Lvalue( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + UsingTree($$""" + class C + { + object P { set { {{GetFieldIdentifier(escapeIdentifier)}} = 0; } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void NewTypeName( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + string identifier = GetFieldIdentifier(escapeIdentifier); + UsingTree($$""" + class C + { + object P { set { _ = new {{identifier}}(); } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "_"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ObjectCreationExpression); + { + N(SyntaxKind.NewKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, identifier); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void LambdaBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + string identifier = GetFieldIdentifier(escapeIdentifier); + UsingTree($$""" + class C + { + object P => {{identifier}} => {{identifier}}; + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.SimpleLambdaExpression); + { + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, identifier); + } + N(SyntaxKind.EqualsGreaterThanToken); + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void LocalFunctionBody( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + string identifier = GetFieldIdentifier(escapeIdentifier); + UsingTree($$""" + class C + { + object P { set { void Local(object {{identifier}}) { _ = {{identifier}}; } } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "Local"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, identifier); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "_"); + } + N(SyntaxKind.EqualsToken); + IdentifierNameOrFieldExpression(languageVersion, escapeIdentifier); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [CombinatorialData] + public void CatchDeclaration( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersion.Preview)] LanguageVersion languageVersion, + bool escapeIdentifier) + { + string identifier = GetFieldIdentifier(escapeIdentifier); + UsingTree($$""" + class C + { + object P { set { try { } catch (Exception {{identifier}}) { } } } + } + """, + TestOptions.Regular.WithLanguageVersion(languageVersion)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "P"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.TryStatement); + { + N(SyntaxKind.TryKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CatchClause); + { + N(SyntaxKind.CatchKeyword); + N(SyntaxKind.CatchDeclaration); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Exception"); + } + N(SyntaxKind.IdentifierToken, identifier); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Incremental_ChangeBetweenMethodAndProperty() + { + var tree = ParseTree(""" + class C + { + object F() => field; + } + """, + TestOptions.RegularPreview); + + verifyMethod(tree); + verifyProperty(tree.WithRemoveFirst("()")); + + tree = ParseTree(""" + class C + { + object F => field; + } + """, + TestOptions.RegularPreview); + + verifyProperty(tree); + verifyMethod(tree.WithInsertBefore(" =>", "()")); + + void verifyMethod(SyntaxTree tree) + { + UsingTree(tree); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "field"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + void verifyProperty(SyntaxTree tree) + { + UsingTree(tree); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "F"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.FieldExpression); + { + N(SyntaxKind.FieldKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + } + } +} diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs index 74a9cb7d4bb64..fe1b2715e0110 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs @@ -2202,58 +2202,59 @@ public void NullableType_Is_01() EOF(); } - [Fact] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] public void NullableType_Is_02() { string source = "x is string ? [A] y"; - UsingExpression(source); + UsingExpression(source, + // (1,19): error CS1003: Syntax error, ':' expected + // x is string ? [A] y + Diagnostic(ErrorCode.ERR_SyntaxError, "y").WithArguments(":").WithLocation(1, 19)); - N(SyntaxKind.IsPatternExpression); + N(SyntaxKind.ConditionalExpression); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.IsExpression); { - N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } } - N(SyntaxKind.IsKeyword); - N(SyntaxKind.DeclarationPattern); + N(SyntaxKind.QuestionToken); + N(SyntaxKind.CollectionExpression); { - N(SyntaxKind.ArrayType); + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.ExpressionElement); { - N(SyntaxKind.NullableType); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.StringKeyword); - } - N(SyntaxKind.QuestionToken); - } - N(SyntaxKind.ArrayRankSpecifier); + N(SyntaxKind.IdentifierName); { - N(SyntaxKind.OpenBracketToken); - N(SyntaxKind.IdentifierName); - { - N(SyntaxKind.IdentifierToken, "A"); - } - N(SyntaxKind.CloseBracketToken); + N(SyntaxKind.IdentifierToken, "A"); } } - N(SyntaxKind.SingleVariableDesignation); - { - N(SyntaxKind.IdentifierToken, "y"); - } + N(SyntaxKind.CloseBracketToken); + } + M(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "y"); } } EOF(); } - [Fact] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] public void NullableType_Is_03() { string source = "_ = x is string ? [] y => y : z"; UsingExpression(source, - // (1,1): error CS1073: Unexpected token '=>' + // (1,20): error CS1001: Identifier expected // _ = x is string ? [] y => y : z - Diagnostic(ErrorCode.ERR_UnexpectedToken, "_ = x is string ? [] y").WithArguments("=>").WithLocation(1, 1)); + Diagnostic(ErrorCode.ERR_IdentifierExpected, "]").WithLocation(1, 20)); N(SyntaxKind.SimpleAssignmentExpression); { @@ -2262,53 +2263,60 @@ public void NullableType_Is_03() N(SyntaxKind.IdentifierToken, "_"); } N(SyntaxKind.EqualsToken); - N(SyntaxKind.IsPatternExpression); + N(SyntaxKind.ConditionalExpression); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.IsExpression); { - N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } } - N(SyntaxKind.IsKeyword); - N(SyntaxKind.DeclarationPattern); + N(SyntaxKind.QuestionToken); + N(SyntaxKind.SimpleLambdaExpression); { - N(SyntaxKind.ArrayType); + N(SyntaxKind.AttributeList); { - N(SyntaxKind.NullableType); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.StringKeyword); - } - N(SyntaxKind.QuestionToken); - } - N(SyntaxKind.ArrayRankSpecifier); + N(SyntaxKind.OpenBracketToken); + M(SyntaxKind.Attribute); { - N(SyntaxKind.OpenBracketToken); - N(SyntaxKind.OmittedArraySizeExpression); + M(SyntaxKind.IdentifierName); { - N(SyntaxKind.OmittedArraySizeExpressionToken); + M(SyntaxKind.IdentifierToken); } - N(SyntaxKind.CloseBracketToken); } + N(SyntaxKind.CloseBracketToken); } - N(SyntaxKind.SingleVariableDesignation); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "y"); } } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "z"); + } } } EOF(); } - [Fact] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] public void NullableType_Is_04() { string source = "_ = x is string ? [A] y => y : z"; - UsingExpression(source, - // (1,1): error CS1073: Unexpected token '=>' - // _ = x is string ? [A] y => y : z - Diagnostic(ErrorCode.ERR_UnexpectedToken, "_ = x is string ? [A] y").WithArguments("=>").WithLocation(1, 1)); + UsingExpression(source); N(SyntaxKind.SimpleAssignmentExpression); { @@ -2317,56 +2325,60 @@ public void NullableType_Is_04() N(SyntaxKind.IdentifierToken, "_"); } N(SyntaxKind.EqualsToken); - N(SyntaxKind.IsPatternExpression); + N(SyntaxKind.ConditionalExpression); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.IsExpression); { - N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } } - N(SyntaxKind.IsKeyword); - N(SyntaxKind.DeclarationPattern); + N(SyntaxKind.QuestionToken); + N(SyntaxKind.SimpleLambdaExpression); { - N(SyntaxKind.ArrayType); + N(SyntaxKind.AttributeList); { - N(SyntaxKind.NullableType); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.StringKeyword); - } - N(SyntaxKind.QuestionToken); - } - N(SyntaxKind.ArrayRankSpecifier); + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); { - N(SyntaxKind.OpenBracketToken); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "A"); } - N(SyntaxKind.CloseBracketToken); } + N(SyntaxKind.CloseBracketToken); } - N(SyntaxKind.SingleVariableDesignation); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "y"); } } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "z"); + } } } EOF(); } - [Fact] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75318")] public void NullableType_Is_05() { string source = "_ = x is string ? [return: A] y => y : z"; - UsingExpression(source, - // (1,1): error CS1073: Unexpected token '=>' - // _ = x is string ? [return: A] y => y : z - Diagnostic(ErrorCode.ERR_UnexpectedToken, "_ = x is string ? [return: A] y").WithArguments("=>").WithLocation(1, 1), - // (1,20): error CS1003: Syntax error, ',' expected - // _ = x is string ? [return: A] y => y : z - Diagnostic(ErrorCode.ERR_SyntaxError, "return").WithArguments(",").WithLocation(1, 20)); + UsingExpression(source); N(SyntaxKind.SimpleAssignmentExpression); { @@ -2375,40 +2387,55 @@ public void NullableType_Is_05() N(SyntaxKind.IdentifierToken, "_"); } N(SyntaxKind.EqualsToken); - N(SyntaxKind.IsPatternExpression); + N(SyntaxKind.ConditionalExpression); { - N(SyntaxKind.IdentifierName); + N(SyntaxKind.IsExpression); { - N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } } - N(SyntaxKind.IsKeyword); - N(SyntaxKind.DeclarationPattern); + N(SyntaxKind.QuestionToken); + N(SyntaxKind.SimpleLambdaExpression); { - N(SyntaxKind.ArrayType); + N(SyntaxKind.AttributeList); { - N(SyntaxKind.NullableType); + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.AttributeTargetSpecifier); { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.StringKeyword); - } - N(SyntaxKind.QuestionToken); + N(SyntaxKind.ReturnKeyword); + N(SyntaxKind.ColonToken); } - N(SyntaxKind.ArrayRankSpecifier); + N(SyntaxKind.Attribute); { - N(SyntaxKind.OpenBracketToken); N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "A"); } - N(SyntaxKind.CloseBracketToken); } + N(SyntaxKind.CloseBracketToken); } - N(SyntaxKind.SingleVariableDesignation); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "y"); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); { N(SyntaxKind.IdentifierToken, "y"); } } + N(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "z"); + } } } EOF(); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs index 6a8d436530645..a98c94c918dd3 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs @@ -10472,6 +10472,1944 @@ public class Class EOF(); } + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + [InlineData("class", SyntaxKind.ClassDeclaration, SyntaxKind.ClassKeyword)] + [InlineData("struct", SyntaxKind.StructDeclaration, SyntaxKind.StructKeyword)] + [InlineData("interface", SyntaxKind.InterfaceDeclaration, SyntaxKind.InterfaceKeyword)] + [InlineData("record", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record struct", SyntaxKind.RecordStructDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record class", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + public void ExtraCloseCurly_TypeWithSingleInvalidMemberFollowing(string typeKind, SyntaxKind typeSyntaxKind, SyntaxKind keywordKind) + { + var text = $$""" + namespace N + { + {{typeKind}} Type + { + } + + // One method that will move into the type above. + private void M() + { + } + } + """; + UsingTree(text, + // (5,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(5, 5), + // (11,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(11, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(typeSyntaxKind); + { + N(keywordKind); + + if (text.Contains("record struct")) + { + N(SyntaxKind.StructKeyword); + } + else if (text.Contains("record class")) + { + N(SyntaxKind.ClassKeyword); + } + + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + 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.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + [InlineData("class", SyntaxKind.ClassDeclaration, SyntaxKind.ClassKeyword)] + [InlineData("struct", SyntaxKind.StructDeclaration, SyntaxKind.StructKeyword)] + [InlineData("interface", SyntaxKind.InterfaceDeclaration, SyntaxKind.InterfaceKeyword)] + [InlineData("record", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record struct", SyntaxKind.RecordStructDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record class", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + public void ExtraCloseCurly_TypeWithMultipleInvalidMembersFollowing(string typeKind, SyntaxKind typeSyntaxKind, SyntaxKind keywordKind) + { + var text = $$""" + namespace N + { + {{typeKind}} Type + { + } + + // Two members that will move into the type above. + private void M() + { + } + + public int Prop => 0; + } + """; + UsingTree(text, + // (5,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(5, 5), + // (13,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(13, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(typeSyntaxKind); + { + N(keywordKind); + + if (text.Contains("record struct")) + { + N(SyntaxKind.StructKeyword); + } + else if (text.Contains("record class")) + { + N(SyntaxKind.ClassKeyword); + } + + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + 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.CloseBraceToken); + } + } + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Prop"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + [InlineData("class", SyntaxKind.ClassDeclaration, SyntaxKind.ClassKeyword)] + [InlineData("struct", SyntaxKind.StructDeclaration, SyntaxKind.StructKeyword)] + [InlineData("interface", SyntaxKind.InterfaceDeclaration, SyntaxKind.InterfaceKeyword)] + [InlineData("record", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record struct", SyntaxKind.RecordStructDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record class", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + public void ExtraCloseCurly_TypeWithInvalidMembersFollowing_FollowedByType(string typeKind, SyntaxKind typeSyntaxKind, SyntaxKind keywordKind) + { + var text = $$""" + namespace N + { + {{typeKind}} Type + { + } + + // Two members that will move into the type above. + private void M() + { + } + + public int Prop => 0; + + // Following type declaration + class Type + { + } + } + """; + UsingTree(text, + // (5,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(5, 5), + // (12,26): error CS1513: } expected + // public int Prop => 0; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(12, 26)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(typeSyntaxKind); + { + N(keywordKind); + + if (text.Contains("record struct")) + { + N(SyntaxKind.StructKeyword); + } + else if (text.Contains("record class")) + { + N(SyntaxKind.ClassKeyword); + } + + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + 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.CloseBraceToken); + } + } + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Prop"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + [InlineData("class", SyntaxKind.ClassDeclaration, SyntaxKind.ClassKeyword)] + [InlineData("struct", SyntaxKind.StructDeclaration, SyntaxKind.StructKeyword)] + [InlineData("interface", SyntaxKind.InterfaceDeclaration, SyntaxKind.InterfaceKeyword)] + [InlineData("record", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record struct", SyntaxKind.RecordStructDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record class", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + public void ExtraCloseCurly_MultipleTypesEachWithMultipleInvalidMembersFollowing(string typeKind, SyntaxKind typeSyntaxKind, SyntaxKind keywordKind) + { + var text = $$""" + namespace N + { + {{typeKind}} Type + { + } + + // Two members that will move into the type above. + private void M() + { + } + + public int Prop => 0; + + // Following type declaration + class Type + { + } + + private Constructor() { } + + private int field; + } + """; + UsingTree(text, + // (5,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(5, 5), + // (12,26): error CS1513: } expected + // public int Prop => 0; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(12, 26), + // (17,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(17, 5), + // (22,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(22, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(typeSyntaxKind); + { + N(keywordKind); + + if (text.Contains("record struct")) + { + N(SyntaxKind.StructKeyword); + } + else if (text.Contains("record class")) + { + N(SyntaxKind.ClassKeyword); + } + + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + 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.CloseBraceToken); + } + } + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Prop"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.IdentifierToken, "Constructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "field"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + [InlineData("class", SyntaxKind.ClassDeclaration, SyntaxKind.ClassKeyword)] + [InlineData("struct", SyntaxKind.StructDeclaration, SyntaxKind.StructKeyword)] + [InlineData("interface", SyntaxKind.InterfaceDeclaration, SyntaxKind.InterfaceKeyword)] + [InlineData("record", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record struct", SyntaxKind.RecordStructDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record class", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + public void ExtraCloseCurly_InitialInvalidMemberWithoutPrecedingType(string typeKind, SyntaxKind typeSyntaxKind, SyntaxKind keywordKind) + { + var text = $$""" + namespace N + { + // This has no type to go into. + event Action BeforeTypeEvent; + + {{typeKind}} Type + { + } + + // Two members that will move into the type above. + private void M() + { + } + + public int Prop => 0; + + // Following type declaration + class Type + { + } + + private Constructor() { } + + private int field; + } + """; + UsingTree(text, + // (8,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(8, 5), + // (15,26): error CS1513: } expected + // public int Prop => 0; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(15, 26), + // (20,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(20, 5), + // (25,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(25, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "BeforeTypeEvent"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(typeSyntaxKind); + { + N(keywordKind); + + if (text.Contains("record struct")) + { + N(SyntaxKind.StructKeyword); + } + else if (text.Contains("record class")) + { + N(SyntaxKind.ClassKeyword); + } + + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + 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.CloseBraceToken); + } + } + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Prop"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.IdentifierToken, "Constructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "field"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + [InlineData("class", SyntaxKind.ClassDeclaration, SyntaxKind.ClassKeyword)] + [InlineData("struct", SyntaxKind.StructDeclaration, SyntaxKind.StructKeyword)] + [InlineData("interface", SyntaxKind.InterfaceDeclaration, SyntaxKind.InterfaceKeyword)] + [InlineData("record", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record struct", SyntaxKind.RecordStructDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record class", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + public void ExtraCloseCurly_FileScopeNamespace(string typeKind, SyntaxKind typeSyntaxKind, SyntaxKind keywordKind) + { + var text = $$""" + namespace N; + + // This has no type to go into. + event Action BeforeTypeEvent; + + {{typeKind}} Type + { + } + + // Two members that will move into the type above. + private void M() + { + } + + public int Prop => 0; + + // Following type declaration + class Type + { + } + + private Constructor() { } + + private int field; + """; + UsingTree(text, + // (8,1): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(8, 1), + // (16,1): error CS1513: } expected + // + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(16, 1), + // (20,1): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(20, 1), + // (24,19): error CS1513: } expected + // private int field; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(24, 19)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.FileScopedNamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.SemicolonToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "BeforeTypeEvent"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(typeSyntaxKind); + { + N(keywordKind); + + if (text.Contains("record struct")) + { + N(SyntaxKind.StructKeyword); + } + else if (text.Contains("record class")) + { + N(SyntaxKind.ClassKeyword); + } + + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + 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.CloseBraceToken); + } + } + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Prop"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.IdentifierToken, "Constructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "field"); + } + } + N(SyntaxKind.SemicolonToken); + } + M(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + [InlineData("class", SyntaxKind.ClassDeclaration, SyntaxKind.ClassKeyword)] + [InlineData("struct", SyntaxKind.StructDeclaration, SyntaxKind.StructKeyword)] + [InlineData("interface", SyntaxKind.InterfaceDeclaration, SyntaxKind.InterfaceKeyword)] + [InlineData("record", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record struct", SyntaxKind.RecordStructDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record class", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + public void ExtraCloseCurly_NestedNamespaces_EachWithInvalidMembers(string typeKind, SyntaxKind typeSyntaxKind, SyntaxKind keywordKind) + { + var text = $$""" + namespace N1 + { + namespace N2 + { + {{typeKind}} Type + { + } + + // Should go into type + private void M() + { + } + + // Should become the close curly of Type initially. + } + + // Will not go into Type because N2 will initially end prior to this. + // After M joins into Type and NT finishes, this will be a child of + // N1. We could think about merging this into Type at some point. + private void N() + + // Should become the close curly of N1 + } + } + } + """; + UsingTree(text, + // (7,9): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(7, 9), + // (15,10): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(15, 10), + // (20,25): error CS1002: ; expected + // private void N() + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(20, 25), + // (24,5): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(24, 5), + // (25,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(25, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N1"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N2"); + } + N(SyntaxKind.OpenBraceToken); + N(typeSyntaxKind); + { + N(keywordKind); + + if (text.Contains("record struct")) + { + N(SyntaxKind.StructKeyword); + } + else if (text.Contains("record class")) + { + N(SyntaxKind.ClassKeyword); + } + + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + 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.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "N"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + [InlineData("class", SyntaxKind.ClassDeclaration, SyntaxKind.ClassKeyword)] + [InlineData("struct", SyntaxKind.StructDeclaration, SyntaxKind.StructKeyword)] + [InlineData("interface", SyntaxKind.InterfaceDeclaration, SyntaxKind.InterfaceKeyword)] + [InlineData("record", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record struct", SyntaxKind.RecordStructDeclaration, SyntaxKind.RecordKeyword)] + [InlineData("record class", SyntaxKind.RecordDeclaration, SyntaxKind.RecordKeyword)] + public void ExtraCloseCurly_Operators(string typeKind, SyntaxKind typeSyntaxKind, SyntaxKind keywordKind) + { + var text = $$""" + namespace N + { + // This type should be unaffected + class C + { + } + + {{typeKind}} Type + { + } + + // Two members that will move into the type above. + private void M() + { + } + + public static Type operator+(Type t1, Type t2) => default; + + // Following type declaration + class Type2 + { + } + + private static implicit operator int(Type2 t) => 0; + } + """; + UsingTree(text, + // (10,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(10, 5), + // (17,63): error CS1513: } expected + // public static Type operator+(Type t1, Type t2) => default; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(17, 63), + // (22,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(22, 5), + // (25,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(25, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(typeSyntaxKind); + { + N(keywordKind); + + if (text.Contains("record struct")) + { + N(SyntaxKind.StructKeyword); + } + else if (text.Contains("record class")) + { + N(SyntaxKind.ClassKeyword); + } + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + 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.CloseBraceToken); + } + } + N(SyntaxKind.OperatorDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.PlusToken); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "t1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "t2"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Type2"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConversionOperatorDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ImplicitKeyword); + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type2"); + } + N(SyntaxKind.IdentifierToken, "t"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + [InlineData("")] + [InlineData("// Errant close curly")] + public void ExtraCloseCurly_AllTypeDeclarationOnlyMembers_VaryingTrailingTrivia(string closeCurlyTrailingTrivia) + { + // Test all the different type-only member forms. + var text = $$""" + namespace N + { + class Type + { + } {{closeCurlyTrailingTrivia}} + + private Constructor() { } + ~Destructor() { } + private static implicit operator int(Type t) => 0; + event Action E1 { add { } remove { } } + event Action E2, E3; + private int field1, field2; + private int this[int i] => 0; + private void Method() { } + public static Type operator+(Type t1, Type t2) => default; + private int Prop => 0; + } + } + """; + UsingTree(text, + // (5,9): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(5, 9)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.IdentifierToken, "Constructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.DestructorDeclaration); + { + N(SyntaxKind.TildeToken); + N(SyntaxKind.IdentifierToken, "Destructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.ConversionOperatorDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ImplicitKeyword); + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "t"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.IdentifierToken, "E1"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddAccessorDeclaration); + { + N(SyntaxKind.AddKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.RemoveAccessorDeclaration); + { + N(SyntaxKind.RemoveKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E2"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "E3"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "field1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "field2"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.IndexerDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.ThisKeyword); + N(SyntaxKind.BracketedParameterList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "Method"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.OperatorDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.PlusToken); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "t1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "t2"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Prop"); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + [InlineData("")] + [InlineData("#if true")] + [InlineData("// comment")] + [InlineData("/// ")] + public void ExtraCloseCurly_LeadingTriviaCases(string closeCurlyLeadingTrivia) + { + // Test all the different type-only member forms. + var text = $$""" + namespace N + { + class Type + { + {{closeCurlyLeadingTrivia}} + } + + private Constructor() { } + {{(closeCurlyLeadingTrivia.Contains("#") ? "#endif" : "")}} + } + } + """; + UsingTree(text, options: CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.Parse), + // (6,9): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(6, 9)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.IdentifierToken, "Constructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + public void ExtraCloseCurly_WithSemicolon() + { + var text = $$""" + namespace N + { + class Type + { + }; + + // Will not move into type + private Constructor() { } + } + } + """; + UsingTree(text, + // (10,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(10, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.IdentifierToken, "Constructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + public void ExtraCloseCurly_WithExistingSkippedText() + { + var text = $$""" + namespace N + { + class Type + { + } \ + + // Will not move into type + private Constructor() { } + } + } + """; + UsingTree(text, + // (5,11): error CS1056: Unexpected character '\' + // } \ + Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "").WithArguments("\\").WithLocation(5, 11), + // (10,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(10, 1)); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.IdentifierToken, "Constructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + public void ExtraTypeOnlyMembers_AfterEnum() + { + // Test all the different type-only member forms. + var text = $$""" + namespace N + { + enum Type + { + } + + // This should not be sucked into the enum + private void Method() { } + } + """; + UsingTree(text); + CreateCompilation(text).VerifyDiagnostics( + // (8,18): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // private void Method() { } + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "Method").WithLocation(8, 18)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EnumDeclaration); + { + N(SyntaxKind.EnumKeyword); + N(SyntaxKind.IdentifierToken, "Type"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "Method"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + public void ExtraTypeOnlyMembers_AfterDelegate() + { + // Test all the different type-only member forms. + var text = $$""" + namespace N + { + delegate int D(); + + // This should not be sucked into the delegate + private void Method() { } + } + """; + UsingTree(text); + CreateCompilation(text).VerifyDiagnostics( + // (6,18): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // private void Method() { } + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "Method").WithLocation(6, 18)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.DelegateDeclaration); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "Method"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + public void ExtraTypeOnlyMembers_DoNotPullNextClassInEvenIfPrivate() + { + // Test all the different type-only member forms. + var text = $$""" + namespace N + { + class C + { + } + + // Will get pulled into C + void Method() + { + } + + // Not currently pulled in. But could consider it in the future. + private class T + { + } + } + """; + UsingTree(text, + // (5,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(5, 5), + // (10,6): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(10, 6)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "Method"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "T"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74482")] + public void ExtraTypeOnlyMembers_DoNotPullNextClassInEvenIfPrivate_PullLaterMembersIntoIt() + { + // Test all the different type-only member forms. + var text = $$""" + namespace N + { + class C + { + } + + // Will get pulled into C + void Method() + { + } + + // Not currently pulled in. But could consider it in the future. + private class T + { + } + + // Will get pulled into T + void Method2() + { + } + } + """; + UsingTree(text, + // (5,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(5, 5), + // (10,6): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(10, 6), + // (15,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + // } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "}").WithArguments("}").WithLocation(15, 5), + // (21,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(21, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "N"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "Method"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.PrivateKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "T"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "Method2"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + #region Missing > after generic [Fact] diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/NameParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/NameParsingTests.cs index ca6fe6ca83e6d..92adda1188dbb 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/NameParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/NameParsingTests.cs @@ -4,10 +4,8 @@ #nullable disable -using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; -using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -1435,5 +1433,62 @@ void M() // M, Y<,>>(); Diagnostic(ErrorCode.ERR_UnexpectedUnboundGenericName, "Y<,>").WithLocation(13, 16)); } + + [Fact] + public void ParseGlobalAliasQualifiedNameAfterConditionalExpression() + { + UsingExpression("x is X ? global::X.Y.Z : default"); + + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.SimpleMemberAccessExpression); + { + N(SyntaxKind.AliasQualifiedName); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.GlobalKeyword); + } + N(SyntaxKind.ColonColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Z"); + } + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.DefaultLiteralExpression); + { + N(SyntaxKind.DefaultKeyword); + } + } + EOF(); + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs index b4a43b474e4d1..be08d997f4c18 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs @@ -566,7 +566,7 @@ public static int Main() { } "; - CreateCompilationWithMscorlib45(test).VerifyDiagnostics( + CreateCompilationWithMscorlib461(test).VerifyDiagnostics( // (3,24): error CS0231: A params parameter must be the last parameter in a parameter list // public void MyMeth(params int[] values, int i) {} Diagnostic(ErrorCode.ERR_ParamsLast, "params int[] values").WithLocation(3, 24)); @@ -2853,43 +2853,18 @@ public static A operator () } }"; ParseAndValidate(test, TestOptions.Regular, - // (4,19): error CS1553: Declaration is not valid; use '+ operator (...' instead + // (4,19): error CS1553: Declaration is not valid; use 'explicit operator (...' instead // public static int explicit operator () - Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(4, 19), - // (4,23): error CS1003: Syntax error, 'operator' expected + Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("explicit").WithLocation(4, 19), + // (4,41): error CS1001: Identifier expected // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator").WithLocation(4, 23), - // (4,23): error CS1019: Overloadable unary operator expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "explicit").WithLocation(4, 23), - // (4,32): error CS1003: Syntax error, '(' expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(4, 32), - // (4,32): error CS1041: Identifier expected; 'operator' is a keyword - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(4, 32), - // (4,42): error CS8124: Tuple must contain at least two elements. - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(4, 42), - // (4,43): error CS1001: Identifier expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 43), - // (4,43): error CS1003: Syntax error, ',' expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(4, 43), - // (6,17): error CS1026: ) expected - // return 0; - Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(6, 17), + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(4, 41), // (8,30): error CS1037: Overloadable operator expected // public static A operator () Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "(").WithLocation(8, 30), // (8,31): error CS1003: Syntax error, '(' expected // public static A operator () - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(8, 31), - // (12,1): error CS1022: Type or namespace definition, or end-of-file expected - // } - Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(12, 1) - ); + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(8, 31)); } [Fact] @@ -2908,89 +2883,35 @@ public static A operator () } }"; CreateCompilation(test, parseOptions: TestOptions.Regular6).VerifyDiagnostics( - // (4,19): error CS1553: Declaration is not valid; use '+ operator (...' instead - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(4, 19), - // (4,23): error CS1003: Syntax error, 'operator' expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator").WithLocation(4, 23), - // (4,23): error CS1019: Overloadable unary operator expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "explicit").WithLocation(4, 23), - // (4,23): error CS0501: 'A.operator +((?, ?))' must declare a body because it is not marked abstract, extern, or partial - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "").WithArguments("A.operator +((?, ?))").WithLocation(4, 23), - // (4,23): error CS0562: The parameter of a unary operator must be the containing type - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_BadUnaryOperatorSignature, "").WithLocation(4, 23), - // (4,32): error CS1003: Syntax error, '(' expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(4, 32), - // (4,32): error CS1041: Identifier expected; 'operator' is a keyword - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(4, 32), - // (4,41): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7.0 or greater. + // (4,19): error CS1553: Declaration is not valid; use 'explicit operator (...' instead // public static int explicit operator () - Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "()").WithArguments("tuples", "7.0").WithLocation(4, 41), - // (4,42): error CS8124: Tuple must contain at least two elements. + Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("explicit").WithLocation(4, 19), + // (4,41): error CS1001: Identifier expected // public static int explicit operator () - Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(4, 42), - // (4,43): error CS1001: Identifier expected + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(4, 41), + // (4,41): error CS1019: Overloadable unary operator expected // public static int explicit operator () - Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 43), - // (4,43): error CS1003: Syntax error, ',' expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(4, 43), - // (6,17): error CS1026: ) expected - // return 0; - Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(6, 17), + Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "()").WithLocation(4, 41), // (8,30): error CS1037: Overloadable operator expected // public static A operator () Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "(").WithLocation(8, 30), // (8,31): error CS1003: Syntax error, '(' expected // public static A operator () - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(8, 31), - // (12,1): error CS1022: Type or namespace definition, or end-of-file expected - // } - Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(12, 1)); + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(8, 31)); ParseAndValidate(test, TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6), - // (4,19): error CS1553: Declaration is not valid; use '+ operator (...' instead - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(4, 19), - // (4,23): error CS1003: Syntax error, 'operator' expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator").WithLocation(4, 23), - // (4,23): error CS1019: Overloadable unary operator expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "explicit").WithLocation(4, 23), - // (4,32): error CS1003: Syntax error, '(' expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(4, 32), - // (4,32): error CS1041: Identifier expected; 'operator' is a keyword - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(4, 32), - // (4,41): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7.0 or greater. + // (4,19): error CS1553: Declaration is not valid; use 'explicit operator (...' instead // public static int explicit operator () - Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(4, 42), - // (4,43): error CS1001: Identifier expected + Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("explicit").WithLocation(4, 19), + // (4,41): error CS1001: Identifier expected // public static int explicit operator () - Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 43), - // (4,43): error CS1003: Syntax error, ',' expected - // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(4, 43), - // (6,17): error CS1026: ) expected - // return 0; - Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(6, 17), + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(4, 41), // (8,30): error CS1037: Overloadable operator expected // public static A operator () Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "(").WithLocation(8, 30), // (8,31): error CS1003: Syntax error, '(' expected // public static A operator () - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(8, 31), - // (12,1): error CS1022: Type or namespace definition, or end-of-file expected - // } - Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(12, 1)); + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(8, 31)); } // Preprocessor: @@ -4667,37 +4588,12 @@ public static int Main () "; ParseAndValidate(test, TestOptions.Regular, - // (3,19): error CS1553: Declaration is not valid; use '+ operator (...' instead - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(3, 19), - // (3,23): error CS1003: Syntax error, 'operator' expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(3, 23), - // (3,23): error CS1019: Overloadable unary operator expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "implicit").WithLocation(3, 23), - // (3,32): error CS1003: Syntax error, '(' expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(3, 32), - // (3,32): error CS1041: Identifier expected; 'operator' is a keyword - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(3, 32), - // (3,47): error CS8124: Tuple must contain at least two elements. + // (3,19): error CS1553: Declaration is not valid; use 'implicit operator (...' instead // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 47), - // (3,49): error CS1001: Identifier expected + Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("implicit").WithLocation(3, 19), + // (3,41): error CS1001: Identifier expected // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 49), - // (3,49): error CS1003: Syntax error, ',' expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 49), - // (3,59): error CS1026: ) expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(3, 59), - // (4,1): error CS1022: Type or namespace definition, or end-of-file expected - // } - Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1) - ); + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(3, 41)); } [Fact, WorkItem(535933, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/535933")] // ? @@ -4720,77 +4616,20 @@ public static int Main () // (2,7): warning CS8981: The type name 'goo' only contains lower-cased ascii characters. Such names may become reserved for the language. // class goo { Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "goo").WithArguments("goo").WithLocation(2, 7), - // (3,19): error CS1553: Declaration is not valid; use '+ operator (...' instead - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(3, 19), - // (3,23): error CS1003: Syntax error, 'operator' expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(3, 23), - // (3,23): error CS1019: Overloadable unary operator expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "implicit").WithLocation(3, 23), - // (3,23): error CS0501: 'goo.operator +((goo f, ?))' must declare a body because it is not marked abstract, extern, or partial - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "").WithArguments("goo.operator +((goo f, ?))").WithLocation(3, 23), - // (3,23): error CS0562: The parameter of a unary operator must be the containing type - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_BadUnaryOperatorSignature, "").WithLocation(3, 23), - // (3,32): error CS1003: Syntax error, '(' expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(3, 32), - // (3,32): error CS1041: Identifier expected; 'operator' is a keyword - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(3, 32), - // (3,41): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7.0 or greater. - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "(goo f)").WithArguments("tuples", "7.0").WithLocation(3, 41), - // (3,47): error CS8124: Tuple must contain at least two elements. - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 47), - // (3,49): error CS1001: Identifier expected + // (3,19): error CS1553: Declaration is not valid; use 'implicit operator (...' instead // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 49), - // (3,49): error CS1003: Syntax error, ',' expected + Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("implicit").WithLocation(3, 19), + // (3,41): error CS1001: Identifier expected // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 49), - // (3,59): error CS1026: ) expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(3, 59), - // (4,1): error CS1022: Type or namespace definition, or end-of-file expected - // } - Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)); + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(3, 41)); ParseAndValidate(test, TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6), - // (3,19): error CS1553: Declaration is not valid; use '+ operator (...' instead - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(3, 19), - // (3,23): error CS1003: Syntax error, 'operator' expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(3, 23), - // (3,23): error CS1019: Overloadable unary operator expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "implicit").WithLocation(3, 23), - // (3,32): error CS1003: Syntax error, '(' expected + // (3,19): error CS1553: Declaration is not valid; use 'implicit operator (...' instead // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(3, 32), - // (3,32): error CS1041: Identifier expected; 'operator' is a keyword + Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("implicit").WithLocation(3, 19), + // (3,41): error CS1001: Identifier expected // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(3, 32), - // (3,47): error CS8124: Tuple must contain at least two elements. - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 47), - // (3,49): error CS1001: Identifier expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 49), - // (3,49): error CS1003: Syntax error, ',' expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 49), - // (3,59): error CS1026: ) expected - // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(3, 59), - // (4,1): error CS1022: Type or namespace definition, or end-of-file expected - // } - Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)); + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(3, 41)); } [Fact(), WorkItem(526995, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/526995")] diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs index 82ccfd5192fb8..268b149eab6d4 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs @@ -27,47 +27,208 @@ public class ParsingErrorRecoveryTests(ITestOutputHelper helper) : ParsingTests( [InlineData("internal")] [InlineData("protected")] [InlineData("private")] + [WorkItem("https://github.com/dotnet/roslyn/pull/74484")] public void AccessibilityModifierErrorRecovery(string accessibility) { - var file = ParseTree($@" -class C -{{ - void M() - {{ - // bad visibility modifier - {accessibility} void localFunc() {{}} - }} - void M2() - {{ - typing - {accessibility} void localFunc() {{}} - }} - void M3() - {{ - // Ambiguous between local func with bad modifier and missing closing - // brace on previous method. Parsing currently assumes the former, - // assuming the tokens are parseable as a local func. - {accessibility} void M4() {{}} -}}"); + var text = $$""" + class C + { + void M() + { + // bad visibility modifier + {{accessibility}} void localFunc() {} + } + void M2() + { + typing + {{accessibility}} void localFunc() {} + } + void M3() + { + // Ambiguous between local func with bad modifier and missing closing + // brace on previous method. Parsing currently assumes the latter + {{accessibility}} void M4() {} + } + """; - Assert.NotNull(file); - file.GetDiagnostics().Verify( - // (7,9): error CS0106: The modifier '{accessibility}' is not valid for this item - // {accessibility} void localFunc() {} - Diagnostic(ErrorCode.ERR_BadMemberFlag, accessibility).WithArguments(accessibility).WithLocation(7, 9), - // (11,15): error CS1002: ; expected + UsingTree(text, + // (4,6): error CS1513: } expected + // { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 6), + // (8,5): error CS8803: Top-level statements must precede namespace and type declarations. + // void M2() + Diagnostic(ErrorCode.ERR_TopLevelStatementAfterNamespaceOrType, """ + void M2() + { + typing + + """).WithLocation(8, 5), + // (10,15): error CS1002: ; expected + // typing + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(10, 15), + // (10,15): error CS1513: } expected // typing - Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(11, 15), - // (12,9): error CS0106: The modifier '{accessibility}' is not valid for this item - // {accessibility} void localFunc() {} - Diagnostic(ErrorCode.ERR_BadMemberFlag, accessibility).WithArguments(accessibility).WithLocation(12, 9), - // (19,5): error CS0106: The modifier '{accessibility}' is not valid for this item - // {accessibility} void M4() {} - Diagnostic(ErrorCode.ERR_BadMemberFlag, accessibility).WithArguments(accessibility).WithLocation(19, 5), - // (20,2): error CS1513: } expected + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(10, 15), + // (11,9): error CS0106: The modifier 'internal' is not valid for this item + // internal void localFunc() {} + Diagnostic(ErrorCode.ERR_BadMemberFlag, $"{accessibility}").WithArguments($"{accessibility}").WithLocation(11, 9), + // (12,5): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(12, 5), + // (14,6): error CS1513: } expected + // { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(14, 6), + // (18,5): error CS0106: The modifier 'internal' is not valid for this item + // internal void M4() {} + Diagnostic(ErrorCode.ERR_BadMemberFlag, $"{accessibility}").WithArguments($"{accessibility}").WithLocation(17, 5), + // (19,1): error CS1022: Type or namespace definition, or end-of-file expected // } - Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(20, 2) - ); + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(18, 1)); + + var accessibilityKind = SyntaxFacts.GetKeywordKind(accessibility); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + 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); + M(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.MethodDeclaration); + { + N(accessibilityKind); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "localFunc"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M2"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "typing"); + } + M(SyntaxKind.SemicolonToken); + } + M(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(accessibilityKind); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "localFunc"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M3"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(accessibilityKind); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M4"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); } [Fact] diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs index 521fd20434c66..930ced6a0a2bc 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs @@ -148,9 +148,13 @@ protected SyntaxTree UsingTree(string text, params DiagnosticDescription[] expec } protected SyntaxTree UsingTree(string text, CSharpParseOptions? options, params DiagnosticDescription[] expectedErrors) + { + return UsingTree(ParseTree(text, options), expectedErrors); + } + + protected SyntaxTree UsingTree(SyntaxTree tree, params DiagnosticDescription[] expectedErrors) { VerifyEnumeratorConsumed(); - var tree = ParseTree(text, options); _node = tree.GetCompilationUnitRoot(); var actualErrors = _node.GetDiagnostics(); actualErrors.Verify(expectedErrors); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ReadOnlyStructs.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ReadOnlyStructs.cs index 0e011e20ab6fd..6a7712f950eeb 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ReadOnlyStructs.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ReadOnlyStructs.cs @@ -37,7 +37,7 @@ readonly public struct S3{} } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); comp.VerifyDiagnostics( ); @@ -74,7 +74,7 @@ readonly public struct S3{} } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (4,5): error CS8107: Feature 'readonly structs' is not available in C# 7. Please use language version 7.2 or greater. // readonly struct S1{} @@ -102,7 +102,7 @@ readonly public interface S3{} } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (4,20): error CS0106: The modifier 'readonly' is not valid for this item // readonly class S1{} @@ -146,7 +146,7 @@ unsafe readonly public ref struct S2{} } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll.WithAllowUnsafe(true)); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll.WithAllowUnsafe(true)); comp.VerifyDiagnostics( ); @@ -179,7 +179,7 @@ readonly ref partial struct S2{} } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); comp.VerifyDiagnostics( ); @@ -213,7 +213,7 @@ partial struct S3{} } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); comp.VerifyDiagnostics( ); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs index 9c0cd03df2e9d..de6dde7df3b40 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs @@ -2099,6 +2099,156 @@ public void WithParsing19() EOF(); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75074")] + public void WithParsingInConditionalExpression1() + { + var text = "x is X ? record with { } : record with { }"; + + UsingExpression(text); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "record"); + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.WithInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "record"); + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.WithInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75074")] + public void WithParsingInConditionalExpression2() + { + var text = "x is X.Y ? record with { } : record with { }"; + + UsingExpression(text); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.QualifiedName); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + N(SyntaxKind.DotToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Y"); + } + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "record"); + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.WithInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "record"); + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.WithInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75074")] + public void WithParsingInConditionalExpression_Incomplete() + { + var text = "x is X ? record with"; + + UsingExpression(text, + // (1,17): error CS1003: Syntax error, ':' expected + // x is X ? record with + Diagnostic(ErrorCode.ERR_SyntaxError, "with").WithArguments(":").WithLocation(1, 17)); + + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "record"); + } + M(SyntaxKind.ColonToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "with"); + } + } + EOF(); + } + [Fact] public void ParameterListAndBaseListOnClass() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RefReadonlyTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RefReadonlyTests.cs index 68b447b9a7476..d5c9558277130 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RefReadonlyTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RefReadonlyTests.cs @@ -42,7 +42,7 @@ static ref readonly T M() } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), options: TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (4,18): error CS8302: Feature 'readonly references' is not available in C# 7.1. Please use language version 7.2 or greater. // delegate ref readonly int D1(); @@ -87,7 +87,7 @@ static void Test1() } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), options: TestOptions.UnsafeDebugDll); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1), options: TestOptions.UnsafeDebugDll); comp.VerifyDiagnostics( // (4,19): error CS8302: Feature 'readonly references' is not available in C# 7.1. Please use language version 7.2 or greater. // static void M(in int x) @@ -185,7 +185,7 @@ static void Use(T dummy) } } "; - var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + var comp = CreateCompilationWithMscorlib461(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); comp.VerifyDiagnostics( // (9,10): error CS1073: Unexpected token 'ref' // (ref readonly int, ref readonly int Alice)? t = null; diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RefStructs.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RefStructs.cs index b8fffc5bdca7c..ac711404ee432 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RefStructs.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RefStructs.cs @@ -35,7 +35,7 @@ public ref struct S2{} } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); comp.VerifyDiagnostics(); } @@ -51,7 +51,7 @@ public ref struct S2{} } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (4,5): error CS8107: Feature 'ref structs' is not available in C# 7. Please use language version 7.2 or greater. // ref struct S1{} @@ -78,7 +78,7 @@ public ref unsafe struct S2{} } "; - var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib461(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.Latest), options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (4,9): error CS1031: Type expected // ref class S1{} diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs index 1ca8465151f27..d3e3fbbbd47b5 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs @@ -3556,21 +3556,19 @@ public void TestRunEmbeddedStatementNotFollowedBySemicolon() Assert.Equal((int)ErrorCode.ERR_SemicolonExpected, statement.Errors()[0].Code); } - [WorkItem(266237, "https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?_a=edit&id=266237")] - [Fact] + [Fact, WorkItem("https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_workitems?_a=edit&id=266237")] public void NullExceptionInLabeledStatement() { UsingStatement(@"{ label: public", - // (1,1): error CS1073: Unexpected token 'public' - // { label: public - Diagnostic(ErrorCode.ERR_UnexpectedToken, "{ label: ").WithArguments("public").WithLocation(1, 1), // (1,10): error CS1002: ; expected // { label: public Diagnostic(ErrorCode.ERR_SemicolonExpected, "public").WithLocation(1, 10), // (1,10): error CS1513: } expected // { label: public - Diagnostic(ErrorCode.ERR_RbraceExpected, "public").WithLocation(1, 10) - ); + Diagnostic(ErrorCode.ERR_RbraceExpected, "public").WithLocation(1, 10), + // (1,16): error CS1513: } expected + // { label: public + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 16)); N(SyntaxKind.Block); { @@ -5811,6 +5809,190 @@ public void TestSwitchStatementWithNullableTypeInPattern5() EOF(); } + [Fact] + public void TestYieldReturnTokensAfterPattern() + { + UsingDeclaration(""" + void M() + { + var res = x is X? yield + return res; + } + """, options: null, + // (3,28): error CS1003: Syntax error, ':' expected + // var res = x is X? yield + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(3, 28), + // (3,28): error CS1525: Invalid expression term 'return' + // var res = x is X? yield + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("return").WithLocation(3, 28), + // (3,28): error CS1002: ; expected + // var res = x is X? yield + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(3, 28)); + + 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.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "res"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "yield"); + } + M(SyntaxKind.ColonToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ReturnStatement); + { + N(SyntaxKind.ReturnKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "res"); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void TestYieldBreakTokensAfterPattern() + { + UsingDeclaration(""" + void M() + { + var res = x is X? yield + break; + } + """, options: null, + // (3,28): error CS1003: Syntax error, ':' expected + // var res = x is X? yield + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(3, 28), + // (3,28): error CS1525: Invalid expression term 'break' + // var res = x is X? yield + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("break").WithLocation(3, 28), + // (3,28): error CS1002: ; expected + // var res = x is X? yield + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(3, 28)); + + 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.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "var"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "res"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ConditionalExpression); + { + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.QuestionToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "yield"); + } + M(SyntaxKind.ColonToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.BreakStatement); + { + N(SyntaxKind.BreakKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + private sealed class TokenAndTriviaWalker : CSharpSyntaxWalker { public int Tokens; diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/FieldAndValueKeywordTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/FieldAndValueKeywordTests.cs index c75aa8c128a83..ce22d5439b0db 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/FieldAndValueKeywordTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/FieldAndValueKeywordTests.cs @@ -4,17 +4,22 @@ #nullable disable +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { - public class FieldAndValueKeywordTests : CSharpTestBase + public class FieldKeywordTests : CSharpTestBase { [Theory] [CombinatorialData] public void Field_01( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, bool escapeIdentifier) { string identifier = escapeIdentifier ? "@field" : "field"; @@ -33,93 +38,26 @@ class D2 : A { object this[int i] { get => {{identifier}}; } } class D4 : A { object this[int i] { set { {{identifier}} = 0; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - if (escapeIdentifier) - { - comp.VerifyEmitDiagnostics(); - } - else + if (!escapeIdentifier && languageVersion > LanguageVersion.CSharp13) { comp.VerifyEmitDiagnostics( - // (4,28): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. + // (4,28): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. // class C1 : A { object P => field; } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(4, 28), - // (5,34): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(4, 28), + // (5,34): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. // class C2 : A { object P { get => field; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(5, 34), - // (6,40): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(5, 34), + // (6,40): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. // class C3 : A { object P { get { return field; } } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(6, 40), - // (7,33): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(6, 40), + // (7,33): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. // class C4 : A { object P { set { field = 0; } } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(7, 33)); + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(7, 33)); + } + else + { + comp.VerifyEmitDiagnostics(); } - } - - [Theory] - [CombinatorialData] - public void Value_01( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, - bool escapeIdentifier) - { - string identifier = escapeIdentifier ? "@value" : "value"; - string source = $$""" - #pragma warning disable 649 - class A { public static int value; } - class B1 : A { int _f = {{identifier}}; } - class B2 : A { object F() => {{identifier}}; } - class C1 : A { object P => {{identifier}}; } - class C2 : A { object P { get => {{identifier}}; } } - class C3 : A { object P { get { return {{identifier}}; } } } - class C4 : A { object P { set { {{identifier}} = 0; } } } - class C5 : A { object P { get; set; } = {{identifier}}; } - class D1 : A { object this[int i] => {{identifier}}; } - class D2 : A { object this[int i] { get => {{identifier}}; } } - class D3 : A { object this[int i] { get { return {{identifier}}; } } } - class D4 : A { object this[int i] { set { {{identifier}} = 0; } } } - """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics(); - } - - [Theory] - [CombinatorialData] - public void Value_02( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, - bool escapeIdentifier) - { - string identifier = escapeIdentifier ? "@value" : "value"; - string source = $$""" - #pragma warning disable 649 - class A { public int value; } - class C1 : A { object P => this.{{identifier}}; } - class C2 : A { object P { get => this.{{identifier}}; } } - class C3 : A { object P { get { return this.{{identifier}}; } } } - class C4 : A { object P { set { this.{{identifier}} = 0; } } } - class D1 : A { object this[int i] => this.{{identifier}}; } - class D2 : A { object this[int i] { get => this.{{identifier}}; } } - class D3 : A { object this[int i] { get { return this.{{identifier}}; } } } - class D4 : A { object this[int i] { set { this.{{identifier}} = 0; } } } - """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics(); - } - - [Theory] - [CombinatorialData] - public void Value_03( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, - bool escapeIdentifier) - { - string identifier = escapeIdentifier ? "@value" : "value"; - string source = $$""" - class A - { - object P { get { return null; } set { _ = {{identifier}}; } } - object this[int i] { get { return null; } set { _ = {{identifier}}; } } - } - """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics(); } [Fact] @@ -143,55 +81,15 @@ object this[int @field] } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular13); // No diagnostics expected for field in indexers. comp.VerifyEmitDiagnostics(); } - [Fact] - public void Parameter_02() - { - string source = """ - class A - { - object this[int value] - { - get { return value; } - set { _ = value; } - } - } - class B - { - object this[int @value] - { - get { return @value; } - set { _ = @value; } - } - } - """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); - comp.VerifyEmitDiagnostics( - // (3,21): error CS0316: The parameter name 'value' conflicts with an automatically-generated parameter name - // object this[int value] - Diagnostic(ErrorCode.ERR_DuplicateGeneratedName, "value").WithArguments("value").WithLocation(3, 21), - // (6,19): error CS0229: Ambiguity between 'int value' and 'object value' - // set { _ = value; } - Diagnostic(ErrorCode.ERR_AmbigMember, "value").WithArguments("int value", "object value").WithLocation(6, 19), - // (6,19): info CS9258: 'value' is a contextual keyword in property accessors starting in language version preview. Use '@value' instead. - // set { _ = value; } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "value").WithArguments("value", "preview").WithLocation(6, 19), - // (11,21): error CS0316: The parameter name 'value' conflicts with an automatically-generated parameter name - // object this[int @value] - Diagnostic(ErrorCode.ERR_DuplicateGeneratedName, "@value").WithArguments("value").WithLocation(11, 21), - // (14,19): error CS0229: Ambiguity between 'int value' and 'object value' - // set { _ = @value; } - Diagnostic(ErrorCode.ERR_AmbigMember, "@value").WithArguments("int value", "object value").WithLocation(14, 19)); - } - [Theory] [CombinatorialData] public void Event_01( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = $$""" #pragma warning disable 649 @@ -199,22 +97,11 @@ public void Event_01( class C { static object field; - static object value; event EventHandler E1 { add { _ = field ?? @field; } remove { _ = @field ?? field; } } - event EventHandler E2 - { - add { _ = C.value ?? C.@value; } - remove { _ = C.@value ?? C.value; } - } - event EventHandler E3 - { - add { _ = value ?? @value; } - remove { _ = @value ?? value; } - } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); @@ -224,7 +111,7 @@ event EventHandler E3 [Theory] [CombinatorialData] public void ExplicitImplementation_01( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, bool escapeIdentifier) { string identifier = escapeIdentifier ? "@field" : "field"; @@ -243,51 +130,26 @@ class C : I } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - if (escapeIdentifier) - { - comp.VerifyEmitDiagnostics(); - } - else + if (!escapeIdentifier && languageVersion > LanguageVersion.CSharp13) { comp.VerifyEmitDiagnostics( - // (10,25): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. + // (10,25): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. // object I.P { get => field; set { _ = field; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(10, 25), - // (10,42): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(10, 25), + // (10,42): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. // object I.P { get => field; set { _ = field; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(10, 42)); + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(10, 42)); + } + else + { + comp.VerifyEmitDiagnostics(); } } [Theory] [CombinatorialData] public void ExplicitImplementation_02( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, - bool escapeIdentifier) - { - string identifier = escapeIdentifier ? "@value" : "value"; - string source = $$""" - #pragma warning disable 649 - interface I - { - object P { get; set; } - object this[int i] { get; set; } - } - class C : I - { - int value; - object I.P { get => this.{{identifier}}; set { _ = this.{{identifier}}; } } - object I.this[int i] { get => this.{{identifier}}; set { _ = this.{{identifier}}; } } - } - """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics(); - } - - [Theory] - [CombinatorialData] - public void ExplicitImplementation_03( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, bool escapeIdentifier) { string identifier = escapeIdentifier ? "@field" : "field"; @@ -312,11 +174,10 @@ class C : I [Theory] [CombinatorialData] public void ExplicitImplementation_04( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, - [CombinatorialValues("field", "value")] string identifier, + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, bool escapeIdentifier) { - string qualifiedIdentifier = (escapeIdentifier ? "@" : "") + identifier; + string identifier = escapeIdentifier ? "@field" : "field"; string source = $$""" #pragma warning disable 649 using System; @@ -326,11 +187,11 @@ interface I } class C : I { - int {{identifier}}; + int field; event EventHandler I.E { - add { _ = this.{{qualifiedIdentifier}}; } - remove { _ = this.{{qualifiedIdentifier}}; } + add { _ = this.{{identifier}}; } + remove { _ = this.{{identifier}}; } } } """; @@ -341,18 +202,15 @@ event EventHandler I.E [Theory] [CombinatorialData] public void IdentifierToken_IdentifierNameSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 8981 class field { } - class value { } class C { object P1 { get { return new field(); } } object P2 { get { return new @field(); } } - object P3 { set { _ = new value(); } } - object P4 { set { _ = new @value(); } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); @@ -362,18 +220,15 @@ class C [Theory] [CombinatorialData] public void IdentifierToken_GenericNameSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 8981 class field { } - class value { } class C { object P1 { get { return new field(); } } object P2 { get { return new @field(); } } - object P3 { set { _ = new value(); } } - object P4 { set { _ = new @value(); } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); @@ -383,7 +238,7 @@ class C [Theory] [CombinatorialData] public void IdentifierToken_Invocation( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 649 @@ -391,21 +246,56 @@ public void IdentifierToken_Invocation( class C { Func field; - object P1 { get { return field(); } } - object P2 { get { return @field(); } } + Func P1 { get { _ = field(); return null; } } + Func P2 { get { _ = @field(); return null; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (6,30): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. - // object P1 { get { return field(); } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(6, 30)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (6,33): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // Func P1 { get { _ = field(); return null; } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(6, 33)); + } + else + { + comp.VerifyEmitDiagnostics(); + } + } + + [Theory] + [CombinatorialData] + public void IdentifierToken_Index( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = """ + #pragma warning disable 649 + class C + { + object[] field; + object[] P1 { get { _ = field[0]; return null; } } + object[] P2 { get { _ = @field[0]; return null; } } + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (5,29): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object[] P1 { get { _ = field[0]; return null; } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(5, 29)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] public void IdentifierToken_TupleElementSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 219 @@ -422,7 +312,7 @@ class C [Theory] [CombinatorialData] public void IdentifierToken_FromClauseSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ using System.Linq; @@ -430,30 +320,26 @@ class C { object P1 { get { _ = from field in new int[0] select field; return null; } } object P2 { get { _ = from @field in new int[0] select @field; return null; } } - object P3 { set { _ = from value in new int[0] select value; } } - object P4 { set { _ = from @value in new int[0] select @value; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (4,59): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. - // object P1 { get { _ = from field in new int[0] select field; return null; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(4, 59), - // (6,32): error CS1931: The range variable 'value' conflicts with a previous declaration of 'value' - // object P3 { set { _ = from value in new int[0] select value; } } - Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "value").WithArguments("value").WithLocation(6, 32), - // (6,59): info CS9258: 'value' is a contextual keyword in property accessors starting in language version preview. Use '@value' instead. - // object P3 { set { _ = from value in new int[0] select value; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "value").WithArguments("value", "preview").WithLocation(6, 59), - // (7,32): error CS1931: The range variable 'value' conflicts with a previous declaration of 'value' - // object P4 { set { _ = from @value in new int[0] select @value; } } - Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "@value").WithArguments("value").WithLocation(7, 32)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (4,59): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P1 { get { _ = from field in new int[0] select field; return null; } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(4, 59)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] public void IdentifierToken_LetClauseSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ using System.Linq; @@ -461,30 +347,26 @@ class C { object P1 { get { _ = from i in new int[0] let field = i select field; return null; } } object P2 { get { _ = from i in new int[0] let @field = i select @field; return null; } } - object P3 { set { _ = from i in new int[0] let value = i select value; } } - object P4 { set { _ = from i in new int[0] let @value = i select @value; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (4,69): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. - // object P1 { get { _ = from i in new int[0] let field = i select field; return null; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(4, 69), - // (6,52): error CS1931: The range variable 'value' conflicts with a previous declaration of 'value' - // object P3 { set { _ = from i in new int[0] let value = i select value; } } - Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "value").WithArguments("value").WithLocation(6, 52), - // (6,69): info CS9258: 'value' is a contextual keyword in property accessors starting in language version preview. Use '@value' instead. - // object P3 { set { _ = from i in new int[0] let value = i select value; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "value").WithArguments("value", "preview").WithLocation(6, 69), - // (7,52): error CS1931: The range variable 'value' conflicts with a previous declaration of 'value' - // object P4 { set { _ = from i in new int[0] let @value = i select @value; } } - Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "@value").WithArguments("value").WithLocation(7, 52)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (4,69): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P1 { get { _ = from i in new int[0] let field = i select field; return null; } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(4, 69)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] public void IdentifierToken_JoinClauseSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ using System.Linq; @@ -492,30 +374,26 @@ class C { object P1 { get { _ = from x in new int[0] join field in new int[0] on x equals field select x; return null; } } object P2 { get { _ = from x in new int[0] join @field in new int[0] on x equals @field select x; return null; } } - object P3 { set { _ = from x in new int[0] join value in new int[0] on x equals value select x; } } - object P4 { set { _ = from x in new int[0] join @value in new int[0] on x equals @value select x; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (4,85): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. - // object P1 { get { _ = from x in new int[0] join field in new int[0] on x equals field select x; return null; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(4, 85), - // (6,53): error CS1931: The range variable 'value' conflicts with a previous declaration of 'value' - // object P3 { set { _ = from x in new int[0] join value in new int[0] on x equals value select x; } } - Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "value").WithArguments("value").WithLocation(6, 53), - // (6,85): info CS9258: 'value' is a contextual keyword in property accessors starting in language version preview. Use '@value' instead. - // object P3 { set { _ = from x in new int[0] join value in new int[0] on x equals value select x; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "value").WithArguments("value", "preview").WithLocation(6, 85), - // (7,53): error CS1931: The range variable 'value' conflicts with a previous declaration of 'value' - // object P4 { set { _ = from x in new int[0] join @value in new int[0] on x equals @value select x; } } - Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "@value").WithArguments("value").WithLocation(7, 53)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (4,85): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P1 { get { _ = from x in new int[0] join field in new int[0] on x equals field select x; return null; } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(4, 85)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] public void IdentifierToken_JoinIntoClauseSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ using System.Linq; @@ -523,30 +401,26 @@ class C { object P1 { get { _ = from x in new int[0] join y in new int[0] on x equals y into field select field; return null; } } object P2 { get { _ = from x in new int[0] join y in new int[0] on x equals y into @field select @field; return null; } } - object P3 { set { _ = from x in new int[0] join y in new int[0] on x equals y into value select value; } } - object P4 { set { _ = from x in new int[0] join y in new int[0] on x equals y into @value select @value; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (4,101): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. - // object P1 { get { _ = from x in new int[0] join y in new int[0] on x equals y into field select field; return null; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(4, 101), - // (6,88): error CS1931: The range variable 'value' conflicts with a previous declaration of 'value' - // object P3 { set { _ = from x in new int[0] join y in new int[0] on x equals y into value select value; } } - Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "value").WithArguments("value").WithLocation(6, 88), - // (6,101): info CS9258: 'value' is a contextual keyword in property accessors starting in language version preview. Use '@value' instead. - // object P3 { set { _ = from x in new int[0] join y in new int[0] on x equals y into value select value; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "value").WithArguments("value", "preview").WithLocation(6, 101), - // (7,88): error CS1931: The range variable 'value' conflicts with a previous declaration of 'value' - // object P4 { set { _ = from x in new int[0] join y in new int[0] on x equals y into @value select @value; } } - Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "@value").WithArguments("value").WithLocation(7, 88)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (4,101): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P1 { get { _ = from x in new int[0] join y in new int[0] on x equals y into field select field; return null; } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(4, 101)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] public void IdentifierToken_QueryContinuationSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ using System.Linq; @@ -554,30 +428,26 @@ class C { object P1 { get { _ = from x in new int[0] select x into field select field; return null; } } object P2 { get { _ = from x in new int[0] select x into @field select @field; return null; } } - object P3 { set { _ = from x in new int[0] select x into value select value; } } - object P4 { set { _ = from x in new int[0] select x into @value select @value; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (4,75): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. - // object P1 { get { _ = from x in new int[0] select x into field select field; return null; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(4, 75), - // (6,62): error CS1931: The range variable 'value' conflicts with a previous declaration of 'value' - // object P3 { set { _ = from x in new int[0] select x into value select value; } } - Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "value").WithArguments("value").WithLocation(6, 62), - // (6,75): info CS9258: 'value' is a contextual keyword in property accessors starting in language version preview. Use '@value' instead. - // object P3 { set { _ = from x in new int[0] select x into value select value; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "value").WithArguments("value", "preview").WithLocation(6, 75), - // (7,62): error CS1931: The range variable 'value' conflicts with a previous declaration of 'value' - // object P4 { set { _ = from x in new int[0] select x into @value select @value; } } - Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "@value").WithArguments("value").WithLocation(7, 62)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (4,75): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P1 { get { _ = from x in new int[0] select x into field select field; return null; } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(4, 75)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] public void IdentifierToken_LocalFunctionStatementSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 8321 @@ -585,24 +455,16 @@ class C { object P1 { get { object field() => null; return null; } } object P2 { get { object @field() => null; return null; } } - object P3 { set { void value() { } } } - object P4 { set { void @value() { } } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (6,28): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter - // object P3 { set { void value() { } } } - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "value").WithArguments("value").WithLocation(6, 28), - // (7,28): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter - // object P4 { set { void @value() { } } } - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "@value").WithArguments("value").WithLocation(7, 28)); + comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void IdentifierToken_VariableDeclaratorSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 219 @@ -610,24 +472,16 @@ class C { object P1 { get { int field = 0; return null; } } object P2 { get { int @field = 0; return null; } } - object P3 { set { int value = 0; } } - object P4 { set { int @value = 0; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (6,27): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter - // object P3 { set { int value = 0; } } - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "value").WithArguments("value").WithLocation(6, 27), - // (7,27): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter - // object P4 { set { int @value = 0; } } - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "@value").WithArguments("value").WithLocation(7, 27)); + comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void IdentifierToken_SingleVariableDesignationSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ class C @@ -635,26 +489,16 @@ class C static void F(out object value) { value = null; } object P1 { get { F(out var field); return null; } } object P2 { get { F(out var @field); return null; } } - object P3 { set { F(out var value); } } - object P4 { set { F(out var @value); } } - object P5 { set { F(out value); } } - object P6 { set { F(out @value); } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (6,33): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter - // object P3 { set { F(out var value); } } - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "value").WithArguments("value").WithLocation(6, 33), - // (7,33): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter - // object P4 { set { F(out var @value); } } - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "@value").WithArguments("value").WithLocation(7, 33)); + comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void IdentifierToken_LabeledStatementSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 164 @@ -662,8 +506,6 @@ class C { object P1 { get { field: return null; } } object P2 { get { @field: return null; } } - object P3 { set { value: return; } } - object P4 { set { @value: return; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); @@ -673,31 +515,23 @@ class C [Theory] [CombinatorialData] public void IdentifierToken_ForEachStatementSyntax_01( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ class C { object P1 { get { foreach (var field in new int[0]) { } return null; } } object P2 { get { foreach (var @field in new int[0]) { } return null; } } - object P3 { set { foreach (var value in new int[0]) { } } } - object P4 { set { foreach (var @value in new int[0]) { } } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (5,36): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter - // object P3 { set { foreach (var value in new int[0]) { } } } - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "value").WithArguments("value").WithLocation(5, 36), - // (6,36): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter - // object P4 { set { foreach (var @value in new int[0]) { } } } - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "@value").WithArguments("value").WithLocation(6, 36)); + comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void IdentifierToken_ForEachStatementSyntax_02( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ class C @@ -719,7 +553,7 @@ class C [Theory] [CombinatorialData] public void IdentifierToken_CatchDeclarationSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 168 @@ -728,33 +562,23 @@ class C { object P1 { get { try { } catch (Exception field) { } return null; } } object P2 { get { try { } catch (Exception @field) { } return null; } } - object P3 { set { try { } catch (Exception value) { } } } - object P4 { set { try { } catch (Exception @value) { } } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (7,48): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter - // object P3 { set { try { } catch (Exception value) { } } } - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "value").WithArguments("value").WithLocation(7, 48), - // (8,48): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter - // object P4 { set { try { } catch (Exception @value) { } } } - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "@value").WithArguments("value").WithLocation(8, 48)); + comp.VerifyEmitDiagnostics(); } [Theory] [CombinatorialData] public void IdentifierToken_TypeParameterSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 8321, 8981 class C { - object P1 { get { void F1() { } return null; } } - object P2 { get { void F2<@field>() { } return null; } } - object P3 { set { void F3() { } } } - object P4 { set { void F4<@value>() { } } } + object P1 { get { object F1() { return default(@field); } return null; } } + object P2 { get { object F2<@field>() { return default(field); } return null; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); @@ -764,7 +588,7 @@ class C [Theory] [CombinatorialData] public void IdentifierToken_ParameterSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 8321 @@ -772,24 +596,26 @@ class C { object P1 { get { object F1(object field) => field; return null; } } object P2 { get { object F2(object @field) => @field; return null; } } - object P3 { set { object F3(object value) { return value; } } } - object P4 { set { object F4(object @value) { return @value; } } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (4,50): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. - // object P1 { get { object F1(object field) => field; return null; } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(4, 50), - // (6,56): info CS9258: 'value' is a contextual keyword in property accessors starting in language version preview. Use '@value' instead. - // object P3 { set { object F3(object value) { return value; } } } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "value").WithArguments("value", "preview").WithLocation(6, 56)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (4,50): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P1 { get { object F1(object field) => field; return null; } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(4, 50)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] public void IdentifierToken_AttributeTargetSpecifierSyntax( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = $$""" #pragma warning disable 657 @@ -814,9 +640,10 @@ class C [Theory] [CombinatorialData] public void Deconstruction( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ + #pragma warning disable 168 // variable is declared but never used class C { void Deconstruct(out object x, out object y) => throw null; @@ -827,35 +654,67 @@ static object P1 object @field; object @value; (field, @value) = new C(); - (@field, value) = new C(); } } - static object P2 + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (10,20): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // object @value; + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "@value").WithArguments("value").WithLocation(10, 20), + // (11,14): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // (field, @value) = new C(); + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(11, 14)); + } + else + { + comp.VerifyEmitDiagnostics( + // (10,20): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter + // object @value; + Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "@value").WithArguments("value").WithLocation(10, 20)); + } + } + + [Theory] + [CombinatorialData] + public void Local( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = """ + class C + { + object P { set { - (value, @value) = new C(); + object field = 1; + _ = field; + _ = @field; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (9,20): error CS0136: A local or parameter named 'value' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter - // object @value; - Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "@value").WithArguments("value").WithLocation(9, 20), - // (10,14): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. - // (field, @value) = new C(); - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(10, 14), - // (11,22): info CS9258: 'value' is a contextual keyword in property accessors starting in language version preview. Use '@value' instead. - // (@field, value) = new C(); - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "value").WithArguments("value", "preview").WithLocation(11, 22)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (8,17): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // _ = field; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(8, 17)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] public void Lambda_01( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 649 @@ -863,7 +722,6 @@ public void Lambda_01( class C { static object field; - static object value; object P { set @@ -873,32 +731,34 @@ object P f = () => @field; f = () => C.field; f = () => C.@field; - f = () => value; - f = () => C.value; - f = () => @value; - f = () => C.@value; } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (12,23): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. - // f = () => field; - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(12, 23)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (11,23): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // f = () => field; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(11, 23)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] public void LocalFunction_01( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 649, 8321 class C { static object field; - static object value; object P { set @@ -907,23 +767,28 @@ object P object F2() => @field; object F3() => C.field; object F4() => C.@field; - object G1() { return value; } - object G2() { return C.value; } - object G3() { return @value; } - object G4() { return C.@value; } } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics( - // (10,28): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. - // object F1() => field; - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(10, 28)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (9,28): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object F1() => field; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(9, 28)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } - [Fact] - public void Lambda_Local() + [Theory] + [CombinatorialData] + public void Lambda_Local( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 649 @@ -935,25 +800,31 @@ object P get { Func f; - f = () => { object field = 1; return null; }; - f = () => { object @field = 2; return null; }; + f = () => { object field = 1; return field; }; + f = () => { object @field = 2; return @field; }; return null; } - set - { - Action a; - a = () => { object value = 1; }; - a = () => { object @value = 2; }; - } } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (10,50): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // f = () => { object field = 1; return field; }; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(10, 50)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } - [Fact] - public void Lambda_Parameter_01() + [Theory] + [CombinatorialData] + public void Lambda_Parameter_01( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 649 @@ -965,21 +836,25 @@ object P get { Func f; - f = field => null; - f = @field => null; + f = field => @field; + f = @field => field; return null; } - set - { - Action a; - a = value => { }; - a = @value => { }; - } } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (11,27): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // f = @field => field; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(11, 27)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Fact] @@ -1001,7 +876,7 @@ object P } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics(); } @@ -1024,12 +899,14 @@ object P } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular13); comp.VerifyEmitDiagnostics(); } - [Fact] - public void LocalFunction_Local() + [Theory] + [CombinatorialData] + public void LocalFunction_Local( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 649, 8321 @@ -1039,24 +916,31 @@ object P { get { - object F1() { object field = 1; return null; }; - object F2() { object @field = 2; return null; }; + object F1() { object field = 1; return field; }; + object F2() { object @field = 2; return @field; }; return null; } - set - { - void G1() { object value = 1; } - void G2() { object @value = 1; } - } } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (8,52): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object F1() { object field = 1; return field; }; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(8, 52)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } - [Fact] - public void LocalFunction_Parameter() + [Theory] + [CombinatorialData] + public void LocalFunction_Parameter( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { string source = """ #pragma warning disable 649, 8321 @@ -1066,94 +950,92 @@ object P { get { - object F1(object field) => null; - object F2(object @field) => null; + object F1(object field) => @field; + object F2(object @field) => field; return null; } - set - { - void G1(object value) { } - void G2(object @value) { } - } } } """; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular12); - comp.VerifyEmitDiagnostics(); + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (9,41): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object F2(object @field) => field; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(9, 41)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] - public void Attribute_01( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, bool escapeIdentifier) + public void TypeParameter( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { - string identifier = escapeIdentifier ? "@field" : "field"; - string source = $$""" - using System; - class A : Attribute + string source = """ + class C1 { - public A(string s) { } + object P1 => default(@field); } - class C + class C2<@field> { - const int field = 0; - [A(nameof({{identifier}}))] - object P - { - [A(nameof({{identifier}}))] get { return null; } - [A(nameof({{identifier}}))] set { } - } - [A(nameof({{identifier}}))] - event EventHandler E - { - [A(nameof({{identifier}}))] add { } - [A(nameof({{identifier}}))] remove { } - } + object P2 => default(field); } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics(); + comp.VerifyEmitDiagnostics( + // (1,10): warning CS8981: The type name 'field' only contains lower-cased ascii characters. Such names may become reserved for the language. + // class C1 + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "field").WithArguments("field").WithLocation(1, 10)); } [Theory] [CombinatorialData] - public void Attribute_02( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, bool escapeIdentifier) + public void ParameterDefaultValue( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) { - string identifier = escapeIdentifier ? "@value" : "value"; - string source = $$""" - using System; - class A : Attribute - { - public A(string s) { } - } + string source = """ + #pragma warning disable 649, 8321 class C { - const int value = 0; - [A(nameof({{identifier}}))] + const int field = 0; object P { - [A(nameof({{identifier}}))] get { return null; } - [A(nameof({{identifier}}))] set { } - } - [A(nameof({{identifier}}))] - event EventHandler E - { - [A(nameof({{identifier}}))] add { } - [A(nameof({{identifier}}))] remove { } + set + { + static void F1(int v = field) { } + static void F2(int v = @field) { } + } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics(); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (9,36): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // static void F1(int v = field) { } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(9, 36), + // (9,36): error CS1736: Default parameter value for 'v' must be a compile-time constant + // static void F1(int v = field) { } + Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "field").WithArguments("v").WithLocation(9, 36)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] - public void Attribute_03( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, bool escapeIdentifier) + public void Attribute_01( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, bool escapeIdentifier) { - string identifier = escapeIdentifier ? "@value" : "value"; + string identifier = escapeIdentifier ? "@field" : "field"; string source = $$""" using System; class A : Attribute @@ -1162,29 +1044,50 @@ public A(string s) { } } class C { - const int value = 0; + const int field = 0; + [A(nameof({{identifier}}))] object P { - [param: A(nameof({{identifier}}))] set { } + [A(nameof({{identifier}}))] get { return null; } + [A(nameof({{identifier}}))] set { } } + [A(nameof({{identifier}}))] event EventHandler E { - [param: A(nameof({{identifier}}))] add { } - [param: A(nameof({{identifier}}))] remove { } + [A(nameof({{identifier}}))] add { } + [A(nameof({{identifier}}))] remove { } } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); - comp.VerifyEmitDiagnostics(); + if (!escapeIdentifier && languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (12,19): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // [A(nameof(field))] get { return null; } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(12, 19), + // (12,19): error CS8081: Expression does not have a name. + // [A(nameof(field))] get { return null; } + Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "field").WithLocation(12, 19), + // (13,19): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // [A(nameof(field))] set { } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(13, 19), + // (13,19): error CS8081: Expression does not have a name. + // [A(nameof(field))] set { } + Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "field").WithLocation(13, 19)); + } + else + { + comp.VerifyEmitDiagnostics(); + } } [Theory] [CombinatorialData] public void Attribute_LocalFunction( - [CombinatorialValues(LanguageVersion.CSharp12, LanguageVersion.Preview)] LanguageVersion languageVersion, bool escapeIdentifier) + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, bool escapeIdentifier) { - string fieldIdentifier = escapeIdentifier ? "@field" : "field"; - string valueIdentifier = escapeIdentifier ? "@value" : "value"; + string identifier = escapeIdentifier ? "@field" : "field"; string source = $$""" #pragma warning disable 649, 8321 using System; @@ -1198,24 +1101,10 @@ object P1 { get { - [A(nameof({{fieldIdentifier}}))] void F1(int {{fieldIdentifier}}) { } + [A(nameof({{identifier}}))] void F1(int {{identifier}}) { } return null; } } - object P2 - { - set - { - [A(nameof({{valueIdentifier}}))] void F2(int {{valueIdentifier}}) { } - } - } - object P3 - { - set - { - [A(nameof({{valueIdentifier}}))] void F3() { } - } - } } """; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); @@ -1223,15 +1112,216 @@ object P3 { comp.VerifyEmitDiagnostics(); } - else + else if (languageVersion > LanguageVersion.CSharp13) { comp.VerifyEmitDiagnostics( - // (13,23): info CS9258: 'field' is a contextual keyword in property accessors starting in language version preview. Use '@field' instead. + // (13,23): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. // [A(nameof(field))] void F1(int field) { } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "field").WithArguments("field", "preview").WithLocation(13, 23), - // (21,23): info CS9258: 'value' is a contextual keyword in property accessors starting in language version preview. Use '@value' instead. - // [A(nameof(value))] void F2(int value) { } - Diagnostic(ErrorCode.INF_IdentifierConflictWithContextualKeyword, "value").WithArguments("value", "preview").WithLocation(21, 23)); + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(13, 23), + // (13,23): error CS8081: Expression does not have a name. + // [A(nameof(field))] void F1(int field) { } + Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "field").WithLocation(13, 23)); + } + else + { + comp.VerifyEmitDiagnostics(); + } + } + + [Fact] + public void NameOf_01() + { + string source = """ + class C + { + object P => nameof(field); + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (3,24): error CS8081: Expression does not have a name. + // object P => nameof(field); + Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "field").WithLocation(3, 24)); + } + + [Fact] + public void NameOf_02() + { + string source = """ + class C + { + object P { set { _ = nameof(field); } } + } + """; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics( + // (3,33): error CS8081: Expression does not have a name. + // object P { set { _ = nameof(field); } } + Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "field").WithLocation(3, 33)); + } + + [Theory] + [CombinatorialData] + public void NameOf_03( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string source = """ + class C + { + static int field; + object P => nameof(field); + } + """; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (3,16): warning CS0169: The field 'C.field' is never used + // static int field; + Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("C.field").WithLocation(3, 16), + // (4,24): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P => nameof(field); + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(4, 24), + // (4,24): error CS8081: Expression does not have a name. + // object P => nameof(field); + Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "field").WithLocation(4, 24)); + } + else + { + comp.VerifyEmitDiagnostics( + // (3,16): warning CS0649: Field 'C.field' is never assigned to, and will always have its default value 0 + // static int field; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "field").WithArguments("C.field", "0").WithLocation(3, 16)); + } + } + + [Theory] + [CombinatorialData] + public void BaseClassMember( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion) + { + string sourceA = """ + public class Base + { + protected string field; + } + """; + var comp = CreateCompilation(sourceA); + var refA = comp.EmitToImageReference(); + + string sourceB1 = """ + class Derived : Base + { + string P => field; // synthesized backing field + } + """; + comp = CreateCompilation(sourceB1, references: [refA], parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (3,17): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // string P => field; + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(3, 17)); + } + else + { + comp.VerifyEmitDiagnostics(); + } + verify(comp, synthesizeField: languageVersion > LanguageVersion.CSharp13); + + string sourceB2 = """ + class Derived : Base + { + string P => @field; // Base.field + } + """; + comp = CreateCompilation(sourceB2, references: [refA], parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics(); + verify(comp, synthesizeField: false); + + string sourceB3 = """ + class Derived : Base + { + string P => this.field; // Base.field + } + """; + comp = CreateCompilation(sourceB3, references: [refA], parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics(); + verify(comp, synthesizeField: false); + + string sourceB4 = """ + class Derived : Base + { + string P => base.field; // Base.field + } + """; + comp = CreateCompilation(sourceB4, references: [refA], parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics(); + verify(comp, synthesizeField: false); + + string sourceB5 = """ + class Derived : Base + { + #pragma warning disable 9258 // 'field' is a contextual keyword + string P => field; // synthesized backing field + } + """; + comp = CreateCompilation(sourceB5, references: [refA], parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion)); + comp.VerifyEmitDiagnostics(); + verify(comp, synthesizeField: languageVersion > LanguageVersion.CSharp13); + + static void verify(CSharpCompilation comp, bool synthesizeField) + { + var syntaxTree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(syntaxTree); + var expr = syntaxTree.GetRoot().DescendantNodes().OfType().Single().Expression; + + var symbolInfo = model.GetSymbolInfo(expr); + string expectedSymbol = synthesizeField ? "System.String Derived.

k__BackingField" : "System.String Base.field"; + Assert.Equal(expectedSymbol, symbolInfo.Symbol.ToTestDisplayString()); + + var actualFields = comp.GetMember("Derived").GetMembers().Where(m => m.Kind == SymbolKind.Field).ToTestDisplayStrings(); + string[] expectedFields = synthesizeField ? ["System.String Derived.

k__BackingField"] : []; + AssertEx.Equal(expectedFields, actualFields); + } + } + + [Theory] + [CombinatorialData] + public void Conditional( + [CombinatorialValues(LanguageVersion.CSharp13, LanguageVersionFacts.CSharpNext)] LanguageVersion languageVersion, + bool useDEBUG) + { + string source = """ + using System.Diagnostics; + class C + { + const int field = 0; + object P1 { get { M(field); return null; } } + object P2 { set { M(field); } } + [Conditional("DEBUG")] + static void M( object o) { } + } + """; + var parseOptions = TestOptions.Regular.WithLanguageVersion(languageVersion); + if (useDEBUG) + { + parseOptions = parseOptions.WithPreprocessorSymbols("DEBUG"); + } + var comp = CreateCompilation(source, parseOptions: parseOptions); + if (languageVersion > LanguageVersion.CSharp13) + { + comp.VerifyEmitDiagnostics( + // (5,25): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P1 { get { M(field); return null; } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(5, 25), + // (6,25): warning CS9258: In language version preview, the 'field' keyword binds to a synthesized backing field for the property. To avoid generating a synthesized backing field, and to refer to the existing member, use 'this.field' or '@field' instead. + // object P2 { set { M(field); } } + Diagnostic(ErrorCode.WRN_FieldIsAmbiguous, "field").WithArguments("preview").WithLocation(6, 25)); + } + else + { + comp.VerifyEmitDiagnostics(); } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/LambdaUtilitiesTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/LambdaUtilitiesTests.cs index 1b5005016525d..8d8eb1d70b1e8 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/LambdaUtilitiesTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/LambdaUtilitiesTests.cs @@ -40,7 +40,7 @@ void M() Assert.NotNull(span); var tree = SyntaxFactory.ParseSyntaxTree(source); - var compilation = CreateCompilationWithMscorlib45(new[] { tree }, new[] { SystemCoreRef }); + var compilation = CreateCompilationWithMscorlib461(new[] { tree }, new[] { SystemCoreRef }); compilation.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error).Verify(); var model = compilation.GetSemanticModel(tree, ignoreAccessibility: false); diff --git a/src/Compilers/CSharp/Test/WinRT/CodeGen/WinMdEventTests.cs b/src/Compilers/CSharp/Test/WinRT/CodeGen/WinMdEventTests.cs index 10b823874e0c7..a783cf06975fc 100644 --- a/src/Compilers/CSharp/Test/WinRT/CodeGen/WinMdEventTests.cs +++ b/src/Compilers/CSharp/Test/WinRT/CodeGen/WinMdEventTests.cs @@ -5,6 +5,7 @@ #nullable disable using System.Linq; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; @@ -621,7 +622,7 @@ public void Invoke() var comp1 = CreateEmptyCompilation(source1, WinRtRefs, TestOptions.ReleaseWinMD, TestOptions.Regular, "Lib"); - var serializationRef = TestMetadata.Net451.SystemRuntimeSerialization; + var serializationRef = Net461.References.SystemRuntimeSerialization; var comp2 = CreateEmptyCompilation(source2, WinRtRefs.Concat(new MetadataReference[] { new CSharpCompilationReference(comp1), serializationRef, SystemXmlRef }), TestOptions.ReleaseExe); CompileAndVerify(comp2, expectedOutput: @"A diff --git a/src/Compilers/CSharp/Test/WinRT/CodeGen/WinRTCollectionTests.cs b/src/Compilers/CSharp/Test/WinRT/CodeGen/WinRTCollectionTests.cs index 429570dcb96f4..d7b99c4c91f3d 100644 --- a/src/Compilers/CSharp/Test/WinRT/CodeGen/WinRTCollectionTests.cs +++ b/src/Compilers/CSharp/Test/WinRT/CodeGen/WinRTCollectionTests.cs @@ -11,6 +11,7 @@ using Xunit; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen { @@ -21,7 +22,7 @@ public static MetadataReference[] LegacyRefs = { AssemblyMetadata.CreateFromImage(TestResources.WinRt.Windows_Languages_WinRTTest).GetReference(display: "WinRTTest"), - AssemblyMetadata.CreateFromImage(TestMetadata.ResourcesNet451.SystemCore).GetReference(display: "SystemCore") + AssemblyMetadata.CreateFromImage(Net461.Resources.SystemCore).GetReference(display: "SystemCore") }; [Fact, WorkItem(762316, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/762316")] diff --git a/src/Compilers/CSharp/Test/WinRT/Metadata/WinMdDumpTest.cs b/src/Compilers/CSharp/Test/WinRT/Metadata/WinMdDumpTest.cs index 10a173b227b57..ad21fc4b06a2b 100644 --- a/src/Compilers/CSharp/Test/WinRT/Metadata/WinMdDumpTest.cs +++ b/src/Compilers/CSharp/Test/WinRT/Metadata/WinMdDumpTest.cs @@ -10,10 +10,10 @@ using System.Reflection; using System.Reflection.Metadata; using System.Text; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; -using Microsoft.CodeAnalysis.Test.Resources.Proprietary; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Roslyn.Utilities; @@ -24,10 +24,10 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Metadata public class WinMdDumpTest : CSharpTestBase { private readonly MetadataReference _windowsRef = MetadataReference.CreateFromImage(TestResources.WinRt.Windows.AsImmutableOrNull()); - private readonly MetadataReference _systemRuntimeRef = MetadataReference.CreateFromImage(TestMetadata.ResourcesNet451.SystemRuntime.AsImmutableOrNull()); - private readonly MetadataReference _systemObjectModelRef = MetadataReference.CreateFromImage(TestMetadata.ResourcesNet451.SystemObjectModel.AsImmutableOrNull()); - private readonly MetadataReference _windowsRuntimeUIXamlRef = MetadataReference.CreateFromImage(ProprietaryTestResources.v4_0_30319_17929.System_Runtime_WindowsRuntime_UI_Xaml.AsImmutableOrNull()); - private readonly MetadataReference _interopServicesWindowsRuntimeRef = MetadataReference.CreateFromImage(TestMetadata.ResourcesNet451.SystemRuntimeInteropServicesWindowsRuntime.AsImmutableOrNull()); + private readonly MetadataReference _systemRuntimeRef = MetadataReference.CreateFromImage(Net461.Resources.SystemRuntime.AsImmutableOrNull()); + private readonly MetadataReference _systemObjectModelRef = MetadataReference.CreateFromImage(Net461.Resources.SystemObjectModel.AsImmutableOrNull()); + private readonly MetadataReference _windowsRuntimeUIXamlRef = MetadataReference.CreateFromImage(TestResources.NetFX.WinRt.SystemRuntimeWindowsRuntimeUIXaml.AsImmutableOrNull()); + private readonly MetadataReference _interopServicesWindowsRuntimeRef = MetadataReference.CreateFromImage(Net461.Resources.SystemRuntimeInteropServicesWindowsRuntime.AsImmutableOrNull()); private void AppendMembers(StringBuilder result, NamespaceOrTypeSymbol container, string indent) { diff --git a/src/Compilers/CSharp/csc/CscCommandLine.projitems b/src/Compilers/CSharp/csc/CscCommandLine.projitems index b25a580868321..e1e8c45b3dcda 100644 --- a/src/Compilers/CSharp/csc/CscCommandLine.projitems +++ b/src/Compilers/CSharp/csc/CscCommandLine.projitems @@ -36,7 +36,7 @@ - + diff --git a/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs b/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs index 10889bc36940b..75af09d24cf11 100644 --- a/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs @@ -20,7 +20,7 @@ using Xunit.Abstractions; using Microsoft.CodeAnalysis.VisualBasic; -#if NETCOREAPP +#if NET using Roslyn.Test.Utilities.CoreClr; using System.Runtime.Loader; #else @@ -33,7 +33,7 @@ public enum AnalyzerTestKind { LoadDirect, ShadowLoad, -#if NETCOREAPP +#if NET LoadStream, #endif } @@ -93,7 +93,7 @@ public AnalyzerAssemblyLoaderTests(ITestOutputHelper testOutputHelper, AssemblyL TestFixture = testFixture; } -#if NETCOREAPP +#if NET private void Run(AnalyzerTestKind kind, Action testAction, IAnalyzerAssemblyResolver[]? externalResolvers = null, [CallerMemberName] string? memberName = null) => Run( @@ -359,7 +359,7 @@ private static void VerifyAssemblies(AnalyzerAssemblyLoader loader, IEnumerable< string getExpectedLoadPath(string path) { -#if NETCOREAPP +#if NET if (loader is AnalyzerAssemblyLoader { AnalyzerLoadOption: AnalyzerLoadOption.LoadFromStream }) { return ""; @@ -418,7 +418,7 @@ private static void VerifyDependencyAssemblies(AnalyzerAssemblyLoader loader, in { IEnumerable loadedAssemblies; -#if NETCOREAPP +#if NET // This verify only works where there is a single load context. var alcs = loader.GetDirectoryLoadContextsSnapshot(); Assert.Equal(1, alcs.Length); @@ -740,7 +740,7 @@ public void AssemblyLoading_MultipleVersions(AnalyzerTestKind kind) e.GetType().GetMethod("Write")!.Invoke(e, new object[] { sb, "Test E" }); var actual = sb.ToString(); -#if NETCOREAPP +#if NET var alcs = loader.GetDirectoryLoadContextsSnapshot(); Assert.Equal(2, alcs.Length); @@ -900,7 +900,7 @@ public void AssemblyLoading_MultipleVersions_MultipleVersionsOfSameAnalyzerItsel // 2B or not 2B? That is the question...that depends on whether we're on .NET Core or not. -#if NETCOREAPP +#if NET // On Core, we're able to load both of these into separate AssemblyLoadContexts. if (loader.AnalyzerLoadOption == AnalyzerLoadOption.LoadFromDisk) @@ -1055,7 +1055,7 @@ public void AssemblyLoading_MultipleVersions_MultipleLoaders(AnalyzerTestKind ki var e = epsilon.CreateInstance("Epsilon.E")!; e.GetType().GetMethod("Write")!.Invoke(e, new object[] { sb, "Test E" }); -#if NETCOREAPP +#if NET var alcs1 = loader1.GetDirectoryLoadContextsSnapshot(); Assert.Equal(1, alcs1.Length); @@ -1468,7 +1468,7 @@ public void AssemblyLoading_ResourcesInParent(AnalyzerTestKind kind) }); } -#if NETCOREAPP +#if NET [Theory] [CombinatorialData] diff --git a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs index ee5884433c796..700e0a6b64f8d 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs @@ -750,5 +750,6 @@ public void AddDependencyLocation(string fullPath) { } public bool IsHostAssembly(Assembly assembly) => false; public Assembly LoadFromPath(string fullPath) => throw new Exception(); public string? GetOriginalDependencyLocation(AssemblyName assembly) => throw new Exception(); + public void Dispose() { } } } diff --git a/src/Compilers/Core/CodeAnalysisTest/Collections/ImmutableSegmentedListTest.cs b/src/Compilers/Core/CodeAnalysisTest/Collections/ImmutableSegmentedListTest.cs index b153618443d3e..d2e48506b5d5e 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Collections/ImmutableSegmentedListTest.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Collections/ImmutableSegmentedListTest.cs @@ -788,7 +788,7 @@ public static void TestDebuggerAttributes_Null() Assert.IsType(tie.InnerException); } -#if NETCOREAPP +#if NET [Fact] public void UsableWithCollectibleAssemblies() { diff --git a/src/Compilers/Core/CodeAnalysisTest/CompilerAnalyzerAssemblyResolverTests.cs b/src/Compilers/Core/CodeAnalysisTest/CompilerAnalyzerAssemblyResolverTests.cs new file mode 100644 index 0000000000000..f13c9ab8131a0 --- /dev/null +++ b/src/Compilers/Core/CodeAnalysisTest/CompilerAnalyzerAssemblyResolverTests.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#if NET +using System.Runtime.Loader; +using System.Reflection; +using Xunit; + +namespace Microsoft.CodeAnalysis.UnitTests; + +public sealed class CompilerAnalyzerAssemblyResolverTests +{ + [Fact] + public void ExceptionReturnsNull() + { + var context = new AssemblyLoadContext(nameof(ExceptionReturnsNull), isCollectible: true); + var resolver = new AnalyzerAssemblyLoader.CompilerAnalyzerAssemblyResolver(context); + var name = new AssemblyName("NotARealAssembly"); + Assert.Null(resolver.ResolveAssembly(name)); + context.Unload(); + } +} +#endif diff --git a/src/Compilers/Core/CodeAnalysisTest/CryptoBlobParserTests.cs b/src/Compilers/Core/CodeAnalysisTest/CryptoBlobParserTests.cs index c3ef283b036f0..f0f8009d50a8d 100644 --- a/src/Compilers/Core/CodeAnalysisTest/CryptoBlobParserTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/CryptoBlobParserTests.cs @@ -170,24 +170,10 @@ public void TryGetPublicKeyFailsForInvalidKeyBlobs() "0602000000240000DEADBEEF" + new string('0', 136 * 2), // public key blob without magic public key }; - Assert.False(CryptoBlobParser.TryParseKey(HexToBin(invalidKeyBlobs[0]), out _, out _)); - Assert.False(CryptoBlobParser.TryParseKey(HexToBin(invalidKeyBlobs[1]), out _, out _)); - Assert.False(CryptoBlobParser.TryParseKey(HexToBin(invalidKeyBlobs[2]), out _, out _)); - Assert.False(CryptoBlobParser.TryParseKey(HexToBin(invalidKeyBlobs[3]), out _, out _)); - } - - private static ImmutableArray HexToBin(string input) - { - Assert.True(input != null && (input.Length & 1) == 0, "invalid input string."); - - var result = new byte[input.Length >> 1]; - - for (var i = 0; i < result.Length; i++) - { - result[i] = byte.Parse(input.Substring(i << 1, 2), NumberStyles.HexNumber); - } - - return ImmutableArray.Create(result); + Assert.False(CryptoBlobParser.TryParseKey(TestHelpers.HexToByte(invalidKeyBlobs[0].AsSpan()), out _, out _)); + Assert.False(CryptoBlobParser.TryParseKey(TestHelpers.HexToByte(invalidKeyBlobs[1].AsSpan()), out _, out _)); + Assert.False(CryptoBlobParser.TryParseKey(TestHelpers.HexToByte(invalidKeyBlobs[2].AsSpan()), out _, out _)); + Assert.False(CryptoBlobParser.TryParseKey(TestHelpers.HexToByte(invalidKeyBlobs[3].AsSpan()), out _, out _)); } } } diff --git a/src/Compilers/Core/CodeAnalysisTest/Emit/EmitOptionsTests.cs b/src/Compilers/Core/CodeAnalysisTest/Emit/EmitOptionsTests.cs index dacb90e7c1564..17db9893fe02c 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Emit/EmitOptionsTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Emit/EmitOptionsTests.cs @@ -138,7 +138,7 @@ public void TestCtors() tolerateErrors: true, includePrivateMembers: false, instrumentationKinds: ImmutableArray.Create(InstrumentationKind.TestCoverage), - pdbChecksumAlgorithm: HashAlgorithmName.MD5); + pdbChecksumAlgorithm: HashAlgorithmName.MD5); // CodeQL [SM02196] This is testing an algorithm that our codebase must support for PDBs Assert.Equal(options1, options2.WithInstrumentationKinds(default)); Assert.Equal(options2, options3.WithPdbChecksumAlgorithm(HashAlgorithmName.SHA256)); diff --git a/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs b/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs index ef1aae7ebd9d8..be0e35f24ebad 100644 --- a/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs +++ b/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs @@ -21,7 +21,7 @@ using Xunit.Abstractions; using Xunit.Sdk; using Microsoft.CodeAnalysis.VisualBasic; -#if NETCOREAPP +#if NET using Roslyn.Test.Utilities.CoreClr; using System.Runtime.Loader; #else @@ -31,7 +31,7 @@ namespace Microsoft.CodeAnalysis.UnitTests { -#if NETCOREAPP +#if NET public sealed class InvokeUtil { @@ -46,7 +46,7 @@ internal void Exec(ITestOutputHelper testOutputHelper, AssemblyLoadContext compi var compilerContextCount = compilerContext.Assemblies.Count(); using var tempRoot = new TempRoot(); - AnalyzerAssemblyLoader loader = kind switch + using AnalyzerAssemblyLoader loader = kind switch { AnalyzerTestKind.LoadDirect => new DefaultAnalyzerAssemblyLoader(compilerContext, AnalyzerLoadOption.LoadFromDisk, externalResolvers.ToImmutableArray()), AnalyzerTestKind.LoadStream => new DefaultAnalyzerAssemblyLoader(compilerContext, AnalyzerLoadOption.LoadFromStream, externalResolvers.ToImmutableArray()), @@ -60,7 +60,6 @@ internal void Exec(ITestOutputHelper testOutputHelper, AssemblyLoadContext compi } finally { - loader.UnloadAll(); testOutputHelper.WriteLine($"Test fixture root: {fixture.TempDirectory}"); foreach (var context in loader.GetDirectoryLoadContextsSnapshot()) diff --git a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs index a3e508c9c85c4..2bbf0ca1b969a 100644 --- a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs @@ -19,8 +19,8 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; +using Basic.Reference.Assemblies; using CS = Microsoft.CodeAnalysis.CSharp; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.UnitTests { @@ -59,7 +59,7 @@ public void CreateFrom_Errors() [Theory, CombinatorialData] public void CreateFromImage_Assembly(bool module, bool immutableArray, bool explicitProperties) { - var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : Net461.Resources.mscorlib; var properties = explicitProperties ? MetadataReferenceProperties.Assembly : default; var r = immutableArray ? MetadataReference.CreateFromImage(peImage.AsImmutable(), properties) @@ -76,7 +76,7 @@ public void CreateFromImage_Assembly(bool module, bool immutableArray, bool expl [Theory, CombinatorialData] public void CreateFromImage_Module(bool module, bool immutableArray) { - var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : Net461.Resources.mscorlib; var r = immutableArray ? MetadataReference.CreateFromImage(peImage.AsImmutable(), MetadataReferenceProperties.Module) : MetadataReference.CreateFromImage(peImage.AsEnumerable(), MetadataReferenceProperties.Module); @@ -92,7 +92,7 @@ public void CreateFromImage_Module(bool module, bool immutableArray) [Fact] public void CreateFromStream_FileStream() { - var file = Temp.CreateFile().WriteAllBytes(ResourcesNet451.mscorlib); + var file = Temp.CreateFile().WriteAllBytes(Net461.Resources.mscorlib); var stream = File.OpenRead(file.Path); var r = MetadataReference.CreateFromStream(stream); @@ -125,7 +125,7 @@ public void CreateFromStream_MemoryStream() [Theory, CombinatorialData] public void CreateFromStream_Assembly(bool module, bool explicitProperties) { - var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : Net461.Resources.mscorlib; var r = MetadataReference.CreateFromStream( new MemoryStream(peImage, writable: false), explicitProperties ? MetadataReferenceProperties.Assembly : default); @@ -141,7 +141,7 @@ public void CreateFromStream_Assembly(bool module, bool explicitProperties) [Theory, CombinatorialData] public void CreateFromStream_Module(bool module) { - var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : Net461.Resources.mscorlib; var r = MetadataReference.CreateFromStream( new MemoryStream(peImage, writable: false), MetadataReferenceProperties.Module); @@ -157,7 +157,7 @@ public void CreateFromStream_Module(bool module) [Theory, CombinatorialData] public void CreateFromFile_Assembly(bool module, bool explicitProperties) { - var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : Net461.Resources.mscorlib; var file = Temp.CreateFile().WriteAllBytes(peImage); var r = MetadataReference.CreateFromFile(file.Path, @@ -181,7 +181,7 @@ public void CreateFromFile_Assembly(bool module, bool explicitProperties) [Theory, CombinatorialData] public void CreateFromFile_Module(bool module) { - var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : ResourcesNet451.mscorlib; + var peImage = module ? TestResources.MetadataTests.NetModule01.ModuleCS00 : Net461.Resources.mscorlib; var file = Temp.CreateFile().WriteAllBytes(peImage); var r = MetadataReference.CreateFromFile(file.Path, MetadataReferenceProperties.Module); @@ -526,8 +526,8 @@ public void Equivalence() var f1 = MscorlibRef; var f2 = SystemCoreRef; - var i1 = AssemblyMetadata.CreateFromImage(ResourcesNet451.mscorlib).GetReference(display: "i1"); - var i2 = AssemblyMetadata.CreateFromImage(ResourcesNet451.mscorlib).GetReference(display: "i2"); + var i1 = AssemblyMetadata.CreateFromImage(Net461.Resources.mscorlib).GetReference(display: "i1"); + var i2 = AssemblyMetadata.CreateFromImage(Net461.Resources.mscorlib).GetReference(display: "i2"); var m1a = new MyReference(@"c:\a\goo.dll", display: "m1a"); Assert.Equal("m1a", m1a.Display); @@ -565,7 +565,7 @@ public void Equivalence() public void DocCommentProvider() { var docProvider = new TestDocumentationProvider(); - var corlib = AssemblyMetadata.CreateFromImage(ResourcesNet451.mscorlib). + var corlib = AssemblyMetadata.CreateFromImage(Net461.Resources.mscorlib). GetReference(display: "corlib", documentation: docProvider); var comp = (Compilation)CS.CSharpCompilation.Create("goo", diff --git a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/ModuleMetadataTests.cs b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/ModuleMetadataTests.cs index 870b1efd6de3b..f651881b289cb 100644 --- a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/ModuleMetadataTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/ModuleMetadataTests.cs @@ -11,6 +11,7 @@ using Xunit; using System.Collections.Generic; using System.Reflection.PortableExecutable; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.UnitTests { @@ -128,7 +129,7 @@ public void CreateFromFile() [Fact] public void Disposal() { - var md = ModuleMetadata.CreateFromImage(TestMetadata.ResourcesNet451.mscorlib); + var md = ModuleMetadata.CreateFromImage(Net461.Resources.mscorlib); md.Dispose(); Assert.Throws(() => md.Module); md.Dispose(); @@ -137,7 +138,7 @@ public void Disposal() [Fact] public void ImageOwnership() { - var m = ModuleMetadata.CreateFromImage(TestMetadata.ResourcesNet451.mscorlib); + var m = ModuleMetadata.CreateFromImage(Net461.Resources.mscorlib); var copy1 = m.Copy(); var copy2 = copy1.Copy(); diff --git a/src/Compilers/Core/CodeAnalysisTest/Text/CompositeTextTests.cs b/src/Compilers/Core/CodeAnalysisTest/Text/CompositeTextTests.cs new file mode 100644 index 0000000000000..5be719081f2be --- /dev/null +++ b/src/Compilers/Core/CodeAnalysisTest/Text/CompositeTextTests.cs @@ -0,0 +1,90 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Text; +using Xunit; + +namespace Microsoft.CodeAnalysis.UnitTests.Text; + +public sealed class CompositeTextTests +{ + [Theory] + [InlineData("abcdefghijkl")] + [InlineData(["\r\r\r\r\r\r\r\r\r\r\r\r"])] + [InlineData(["\n\n\n\n\n\n\n\n\n\n\n\n"])] + [InlineData(["\r\n\r\n\r\n\r\n\r\n\r\n"])] + [InlineData(["\n\r\n\r\n\r\n\r\n\r\n\r"])] + [InlineData(["a\r\nb\r\nc\r\nd\r\n"])] + [InlineData(["\ra\n\rb\n\rc\n\rd\n"])] + [InlineData(["\na\r\nb\r\nc\r\nd\r"])] + [InlineData(["ab\r\ncd\r\nef\r\n"])] + [InlineData(["ab\r\r\ncd\r\r\nef"])] + [InlineData(["ab\n\n\rcd\n\n\ref"])] + [InlineData(["ab\u0085cdef\u2028ijkl\u2029op"])] + [InlineData(["\u0085\u2028\u2029\u0085\u2028\u2029\u0085\u2028\u2029\u0085\u2028\u2029"])] + public void CompositeTextLinesEqualSourceTextLinesPermutations(string contents) + { + // Please try to limit the inputs to this method to around 12 chars or less, as much longer than that + // will blow up the number of potential permutations. + foreach (var (sourceText, compositeText) in CreateSourceAndCompositeTexts(contents)) + { + var sourceLinesText = GetLinesTexts(sourceText.Lines); + var compositeLinesText = GetLinesTexts(compositeText.Lines); + + Assert.True(sourceLinesText.SequenceEqual(compositeLinesText)); + + for (var i = 0; i < sourceText.Length; i++) + { + Assert.Equal(sourceText.Lines.IndexOf(i), compositeText.Lines.IndexOf(i)); + } + } + } + + private static IEnumerable GetLinesTexts(TextLineCollection textLines) + { + return textLines.Select(l => l.Text!.ToString(l.SpanIncludingLineBreak)); + } + + // Returns all possible permutations of contents into SourceText arrays of length between minSourceTextCount and maxSourceTextCount + private static IEnumerable<(SourceText, CompositeText)> CreateSourceAndCompositeTexts(string contents, int minSourceTextCount = 2, int maxSourceTextCount = 4) + { + var sourceText = SourceText.From(contents); + + for (var sourceTextCount = minSourceTextCount; sourceTextCount <= Math.Min(maxSourceTextCount, contents.Length); sourceTextCount++) + { + foreach (var sourceTexts in CreateSourceTextPermutations(contents, sourceTextCount)) + { + var sourceTextsBuilder = ArrayBuilder.GetInstance(); + sourceTextsBuilder.AddRange(sourceTexts); + + var compositeText = (CompositeText)CompositeText.ToSourceText(sourceTextsBuilder, sourceText, adjustSegments: false); + yield return (sourceText, compositeText); + } + } + } + + private static IEnumerable CreateSourceTextPermutations(string contents, int requestedSourceTextCount) + { + if (requestedSourceTextCount == 1) + { + yield return [SourceText.From(contents)]; + } + else + { + var maximalSourceTextLength = (contents.Length - requestedSourceTextCount) + 1; + for (int i = 1; i <= maximalSourceTextLength; i++) + { + var sourceText = SourceText.From(contents[..i]); + foreach (var otherSourceTexts in CreateSourceTextPermutations(contents.Substring(i), requestedSourceTextCount - 1)) + { + yield return [sourceText, .. otherSourceTexts]; + } + } + } + } +} diff --git a/src/Compilers/Core/CodeAnalysisTest/Text/SourceTextTests.cs b/src/Compilers/Core/CodeAnalysisTest/Text/SourceTextTests.cs index 43eff7c99a739..41aeabe8d4426 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Text/SourceTextTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Text/SourceTextTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.UnitTests.Text { @@ -332,13 +333,13 @@ public void IsBinary() Assert.False(SourceText.IsBinary(encoding.GetString(new byte[] { 0x81, 0x8D, 0x8F, 0x90, 0x9D }))); // Unicode string: äëïöüû Assert.False(SourceText.IsBinary("abc def baz aeiouy \u00E4\u00EB\u00EF\u00F6\u00FC\u00FB")); - Assert.True(SourceText.IsBinary(encoding.GetString(TestMetadata.ResourcesNet451.System))); + Assert.True(SourceText.IsBinary(encoding.GetString(Net461.Resources.System))); } [Fact] public void FromThrowsIfBinary() { - var bytes = TestMetadata.ResourcesNet451.System; + var bytes = Net461.Resources.System; Assert.Throws(() => SourceText.From(bytes, bytes.Length, throwIfBinaryDetected: true)); var stream = new MemoryStream(bytes); diff --git a/src/Compilers/Core/CodeAnalysisTest/Text/TextChangeTests.cs b/src/Compilers/Core/CodeAnalysisTest/Text/TextChangeTests.cs index 19b2d90213633..ba0f572cbe928 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Text/TextChangeTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Text/TextChangeTests.cs @@ -320,14 +320,14 @@ public void TestOptimizedSourceTextLinesRemoveCrLf() } [Fact] - public void TestOptimizedSourceTextLinesBrakeCrLf() + public void TestOptimizedSourceTextLinesBreakCrLf() { AssertChangedTextLinesHelper("Test\r\nMessage", new TextChange(new TextSpan(5, 0), "aaaaaa")); } [Fact] - public void TestOptimizedSourceTextLinesBrakeCrLfWithLfPrefixedAndCrSuffixed() + public void TestOptimizedSourceTextLinesBreakCrLfWithLfPrefixedAndCrSuffixed() { AssertChangedTextLinesHelper("Test\r\nMessage", new TextChange(new TextSpan(5, 0), "\naaaaaa\r")); diff --git a/src/Compilers/Core/MSBuildTask/Csc.cs b/src/Compilers/Core/MSBuildTask/Csc.cs index d4cde85cf8e7a..71e9cfc09f76e 100644 --- a/src/Compilers/Core/MSBuildTask/Csc.cs +++ b/src/Compilers/Core/MSBuildTask/Csc.cs @@ -241,7 +241,7 @@ protected override void AddResponseFileCommands(CommandLineBuilderExtension comm } AddReferencesToCommandLine(commandLine, References); - AddInterceptorsPreviewNamespaces(commandLine, InterceptorsPreviewNamespaces); + AddInterceptorsNamespaces(commandLine, InterceptorsNamespaces, InterceptorsPreviewNamespaces); base.AddResponseFileCommands(commandLine); @@ -280,19 +280,28 @@ protected override void AddResponseFileCommands(CommandLineBuilderExtension comm internal override RequestLanguage Language => RequestLanguage.CSharpCompile; - /// - /// The value of the <InterceptorsPreviewNamespaces> property. - /// - internal static void AddInterceptorsPreviewNamespaces(CommandLineBuilderExtension commandLine, string? interceptorsNamespaces) + internal static void AddInterceptorsNamespaces(CommandLineBuilderExtension commandLine, string? interceptorsNamespaces, string? interceptorsPreviewNamespaces) { - if (string.IsNullOrEmpty(interceptorsNamespaces)) + var interceptorsNamespacesIsNullOrEmpty = string.IsNullOrEmpty(interceptorsNamespaces); + var interceptorsPreviewNamespacesIsNullOrEmpty = string.IsNullOrEmpty(interceptorsPreviewNamespaces); + if (interceptorsNamespacesIsNullOrEmpty && interceptorsPreviewNamespacesIsNullOrEmpty) { return; } - commandLine.AppendSwitchIfNotNull("/features:", $"InterceptorsPreviewNamespaces={interceptorsNamespaces}"); + var featureValue = interceptorsNamespacesIsNullOrEmpty ? interceptorsPreviewNamespaces + : interceptorsPreviewNamespacesIsNullOrEmpty ? interceptorsNamespaces + : $"{interceptorsNamespaces};{interceptorsPreviewNamespaces}"; + commandLine.AppendSwitchIfNotNull("/features:", $"InterceptorsNamespaces={featureValue}"); } + public string? InterceptorsNamespaces + { + set { _store[nameof(InterceptorsNamespaces)] = value; } + get { return (string?)_store[nameof(InterceptorsNamespaces)]; } + } + + /// Alias for . public string? InterceptorsPreviewNamespaces { set { _store[nameof(InterceptorsPreviewNamespaces)] = value; } diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj b/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj index d10e76332f630..354e14077f975 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj +++ b/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj @@ -59,6 +59,8 @@ + + diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets b/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets index f2eefe23bec84..ad407778bafb0 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets +++ b/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets @@ -113,6 +113,7 @@ ErrorLog="$(ErrorLog)" ErrorReport="$(ErrorReport)" Features="$(Features)" + InterceptorsNamespaces="$(InterceptorsNamespaces)" InterceptorsPreviewNamespaces="$(InterceptorsPreviewNamespaces)" FileAlignment="$(FileAlignment)" GeneratedFilesOutputPath="$(CompilerGeneratedFilesOutputPath)" diff --git a/src/Compilers/Core/MSBuildTask/RCWForCurrentContext.cs b/src/Compilers/Core/MSBuildTask/RCWForCurrentContext.cs index 735c2429473fc..cfe9c0d725292 100644 --- a/src/Compilers/Core/MSBuildTask/RCWForCurrentContext.cs +++ b/src/Compilers/Core/MSBuildTask/RCWForCurrentContext.cs @@ -115,7 +115,7 @@ private void CleanupComObject() _shouldReleaseRCW && Marshal.IsComObject(_rcwForCurrentCtx)) { -#if NETCOREAPP +#if NET Debug.Assert(OperatingSystem.IsWindows()); #endif Marshal.ReleaseComObject(_rcwForCurrentCtx); diff --git a/src/Compilers/Core/MSBuildTaskTests/CscTests.cs b/src/Compilers/Core/MSBuildTaskTests/CscTests.cs index 7f42e7ac26575..0a434694d8179 100644 --- a/src/Compilers/Core/MSBuildTaskTests/CscTests.cs +++ b/src/Compilers/Core/MSBuildTaskTests/CscTests.cs @@ -213,13 +213,32 @@ public void Features() test(",a,,b,"); } + [Fact] + public void FeaturesInterceptors() + { + var csc = new Csc(); + csc.InterceptorsNamespaces = "NS1.NS2;NS3.NS4"; + csc.Sources = MSBuildUtil.CreateTaskItems("test.cs"); + AssertEx.Equal("""/features:"InterceptorsNamespaces=NS1.NS2;NS3.NS4" /out:test.exe test.cs""", csc.GenerateResponseFileContents()); + } + [Fact] public void FeaturesInterceptorsPreview() { var csc = new Csc(); csc.InterceptorsPreviewNamespaces = "NS1.NS2;NS3.NS4"; csc.Sources = MSBuildUtil.CreateTaskItems("test.cs"); - AssertEx.Equal("""/features:"InterceptorsPreviewNamespaces=NS1.NS2;NS3.NS4" /out:test.exe test.cs""", csc.GenerateResponseFileContents()); + AssertEx.Equal("""/features:"InterceptorsNamespaces=NS1.NS2;NS3.NS4" /out:test.exe test.cs""", csc.GenerateResponseFileContents()); + } + + [Fact] + public void FeaturesInterceptorsPreviewBoth() + { + var csc = new Csc(); + csc.InterceptorsNamespaces = "NS1.NS2;NS3.NS4"; + csc.InterceptorsPreviewNamespaces = "NS5.NS6;NS7.NS8"; + csc.Sources = MSBuildUtil.CreateTaskItems("test.cs"); + AssertEx.Equal("""/features:"InterceptorsNamespaces=NS1.NS2;NS3.NS4;NS5.NS6;NS7.NS8" /out:test.exe test.cs""", csc.GenerateResponseFileContents()); } [Fact] diff --git a/src/Compilers/Core/MSBuildTaskTests/TestUtilities/TaskTestUtil.cs b/src/Compilers/Core/MSBuildTaskTests/TestUtilities/TaskTestUtil.cs index 80521b800d154..dbc0ebba186c8 100644 --- a/src/Compilers/Core/MSBuildTaskTests/TestUtilities/TaskTestUtil.cs +++ b/src/Compilers/Core/MSBuildTaskTests/TestUtilities/TaskTestUtil.cs @@ -25,7 +25,7 @@ public static void AssertCommandLine( Assert.Equal(line, rsp); Assert.Equal(expected, task.GenerateCommandLineArgsTaskItems(rsp).Select(x => x.ItemSpec)); -#if NETCOREAPP +#if NET Assert.Equal($"exec \"{task.PathToManagedTool}\"", task.GenerateCommandLineContents().Trim()); // Can only run the Execute path on .NET Core presently. The internal workings of ToolTask diff --git a/src/Compilers/Core/Portable/CodeAnalysisResources.resx b/src/Compilers/Core/Portable/CodeAnalysisResources.resx index 44fe48cf05988..fc24b236c5a27 100644 --- a/src/Compilers/Core/Portable/CodeAnalysisResources.resx +++ b/src/Compilers/Core/Portable/CodeAnalysisResources.resx @@ -138,6 +138,9 @@ class + + attribute + constructor @@ -785,4 +788,7 @@ The temporary path for legacy file signing is unavailable. + + '{0}' type does not have the expected constructor + \ No newline at end of file diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index 0e33de83c40d4..f1b3df903e4da 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -282,7 +282,7 @@ internal Cci.IFieldReference CreateDataField(ImmutableArray data, ushort a // just use the hex value of the data hash. For other alignments, tack on a '2', '4', or '8' // accordingly. As every byte will yield two chars, the odd number of chars used for 2/4/8 // alignments will never produce a name that conflicts with names for an alignment of 1. - Debug.Assert(alignment is 1 or 2 or 4 or 8, $"Unexpected alignment: {alignment}"); + RoslynDebug.Assert(alignment is 1 or 2 or 4 or 8, $"Unexpected alignment: {alignment}"); string hex = DataToHex(key.Data); string name = alignment switch { @@ -571,7 +571,7 @@ internal sealed class ExplicitSizeStruct : DefaultTypeDef, Cci.INestedTypeDefini internal ExplicitSizeStruct(uint size, ushort alignment, PrivateImplementationDetails containingType, Cci.ITypeReference sysValueType) { - Debug.Assert(alignment is 1 or 2 or 4 or 8, $"Unexpected alignment: {alignment}"); + RoslynDebug.Assert(alignment is 1 or 2 or 4 or 8, $"Unexpected alignment: {alignment}"); _size = size; _alignment = alignment; diff --git a/src/Compilers/Core/Portable/Collections/ArrayBuilderExtensions.cs b/src/Compilers/Core/Portable/Collections/ArrayBuilderExtensions.cs index 648e0de0ed442..d9ae85979dcb6 100644 --- a/src/Compilers/Core/Portable/Collections/ArrayBuilderExtensions.cs +++ b/src/Compilers/Core/Portable/Collections/ArrayBuilderExtensions.cs @@ -271,5 +271,23 @@ public static OneOrMany ToOneOrManyAndFree(this ArrayBuilder builder) } #endif + + public static void RemoveWhere(this ArrayBuilder builder, Func filter, TArg arg) + { + var writeIndex = 0; + for (var i = 0; i < builder.Count; i++) + { + var item = builder[i]; + if (!filter(item, i, arg)) + { + if (writeIndex != i) + builder[writeIndex] = item; + + writeIndex++; + } + } + + builder.Count = writeIndex; + } } } diff --git a/src/Compilers/Core/Portable/Collections/DictionaryExtensions.cs b/src/Compilers/Core/Portable/Collections/DictionaryExtensions.cs index d206616a0ec9f..cb74f75739217 100644 --- a/src/Compilers/Core/Portable/Collections/DictionaryExtensions.cs +++ b/src/Compilers/Core/Portable/Collections/DictionaryExtensions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.Collections; @@ -36,6 +37,28 @@ public static TValue GetOrAdd( } } + ///

+ /// If the given key is not found in the dictionary, add it with the result of invoking getValue and return the value. + /// Otherwise return the existing value associated with that key. + /// + public static TValue GetOrAdd( + this Dictionary dictionary, + TKey key, + Func getValue) + where TKey : notnull + { + if (dictionary.TryGetValue(key, out var existingValue)) + { + return existingValue; + } + else + { + var value = getValue(); + dictionary.Add(key, value); + return value; + } + } + #if !NETCOREAPP public static bool TryAdd( this Dictionary dictionary, diff --git a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs index 2fbb864964308..6778fcbd7310b 100644 --- a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs +++ b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs @@ -352,14 +352,14 @@ public static async ValueTask> SelectAsArrayAsync.Empty; - var builder = ArrayBuilder.GetInstance(array.Length); + var builder = new TResult[array.Length]; - foreach (var item in array) + for (var i = 0; i < array.Length; i++) { - builder.Add(await selector(item, cancellationToken).ConfigureAwait(false)); + builder[i] = await selector(array[i], cancellationToken).ConfigureAwait(false); } - return builder.ToImmutableAndFree(); + return ImmutableCollectionsMarshal.AsImmutableArray(builder); } /// @@ -370,14 +370,14 @@ public static async ValueTask> SelectAsArrayAsync.Empty; - var builder = ArrayBuilder.GetInstance(array.Length); + var builder = new TResult[array.Length]; - foreach (var item in array) + for (var i = 0; i < array.Length; i++) { - builder.Add(await selector(item, arg, cancellationToken).ConfigureAwait(false)); + builder[i] = await selector(array[i], arg, cancellationToken).ConfigureAwait(false); } - return builder.ToImmutableAndFree(); + return ImmutableCollectionsMarshal.AsImmutableArray(builder); } public static ValueTask> SelectManyAsArrayAsync(this ImmutableArray source, Func>> selector, TArg arg, CancellationToken cancellationToken) @@ -432,13 +432,13 @@ public static ImmutableArray ZipAsArray(this Immutable return ImmutableArray.Create(map(self[0], other[0]), map(self[1], other[1]), map(self[2], other[2]), map(self[3], other[3])); default: - var builder = ArrayBuilder.GetInstance(self.Length); + var builder = new TResult[self.Length]; for (int i = 0; i < self.Length; i++) { - builder.Add(map(self[i], other[i])); + builder[i] = map(self[i], other[i]); } - return builder.ToImmutableAndFree(); + return ImmutableCollectionsMarshal.AsImmutableArray(builder); } } @@ -815,44 +815,124 @@ internal static ImmutableArray Concat(this ImmutableArray first, Immuta internal static ImmutableArray Concat(this ImmutableArray first, ImmutableArray second, ImmutableArray third) { - var builder = ArrayBuilder.GetInstance(first.Length + second.Length + third.Length); - builder.AddRange(first); - builder.AddRange(second); - builder.AddRange(third); - return builder.ToImmutableAndFree(); + var builder = new T[first.Length + second.Length + third.Length]; + var index = 0; + + foreach (var item in first) + { + builder[index++] = item; + } + + foreach (var item in second) + { + builder[index++] = item; + } + + foreach (var item in third) + { + builder[index++] = item; + } + + return ImmutableCollectionsMarshal.AsImmutableArray(builder); } internal static ImmutableArray Concat(this ImmutableArray first, ImmutableArray second, ImmutableArray third, ImmutableArray fourth) { - var builder = ArrayBuilder.GetInstance(first.Length + second.Length + third.Length + fourth.Length); - builder.AddRange(first); - builder.AddRange(second); - builder.AddRange(third); - builder.AddRange(fourth); - return builder.ToImmutableAndFree(); + var builder = new T[first.Length + second.Length + third.Length + fourth.Length]; + var index = 0; + + foreach (var item in first) + { + builder[index++] = item; + } + + foreach (var item in second) + { + builder[index++] = item; + } + + foreach (var item in third) + { + builder[index++] = item; + } + + foreach (var item in fourth) + { + builder[index++] = item; + } + + return ImmutableCollectionsMarshal.AsImmutableArray(builder); } internal static ImmutableArray Concat(this ImmutableArray first, ImmutableArray second, ImmutableArray third, ImmutableArray fourth, ImmutableArray fifth) { - var builder = ArrayBuilder.GetInstance(first.Length + second.Length + third.Length + fourth.Length + fifth.Length); - builder.AddRange(first); - builder.AddRange(second); - builder.AddRange(third); - builder.AddRange(fourth); - builder.AddRange(fifth); - return builder.ToImmutableAndFree(); + var builder = new T[first.Length + second.Length + third.Length + fourth.Length + fifth.Length]; + var index = 0; + + foreach (var item in first) + { + builder[index++] = item; + } + + foreach (var item in second) + { + builder[index++] = item; + } + + foreach (var item in third) + { + builder[index++] = item; + } + + foreach (var item in fourth) + { + builder[index++] = item; + } + + foreach (var item in fifth) + { + builder[index++] = item; + } + + return ImmutableCollectionsMarshal.AsImmutableArray(builder); } internal static ImmutableArray Concat(this ImmutableArray first, ImmutableArray second, ImmutableArray third, ImmutableArray fourth, ImmutableArray fifth, ImmutableArray sixth) { - var builder = ArrayBuilder.GetInstance(first.Length + second.Length + third.Length + fourth.Length + fifth.Length + sixth.Length); - builder.AddRange(first); - builder.AddRange(second); - builder.AddRange(third); - builder.AddRange(fourth); - builder.AddRange(fifth); - builder.AddRange(sixth); - return builder.ToImmutableAndFree(); + var builder = new T[first.Length + second.Length + third.Length + fourth.Length + fifth.Length + sixth.Length]; + var index = 0; + + foreach (var item in first) + { + builder[index++] = item; + } + + foreach (var item in second) + { + builder[index++] = item; + } + + foreach (var item in third) + { + builder[index++] = item; + } + + foreach (var item in fourth) + { + builder[index++] = item; + } + + foreach (var item in fifth) + { + builder[index++] = item; + } + + foreach (var item in sixth) + { + builder[index++] = item; + } + + return ImmutableCollectionsMarshal.AsImmutableArray(builder); } internal static ImmutableArray Concat(this ImmutableArray first, T second) @@ -872,15 +952,20 @@ internal static ImmutableArray AddRange(this ImmutableArray self, in Te return self.Add(items[0]); } - var builder = ArrayBuilder.GetInstance(self.Length + items.Count); - builder.AddRange(self); + var builder = new T[self.Length + items.Count]; + var index = 0; + + foreach (var item in self) + { + builder[index++] = item; + } foreach (var item in items) { - builder.Add(item); + builder[index++] = item; } - return builder.ToImmutableAndFree(); + return ImmutableCollectionsMarshal.AsImmutableArray(builder); } /// diff --git a/src/Compilers/Core/Portable/Collections/TemporaryArray`1.cs b/src/Compilers/Core/Portable/Collections/TemporaryArray`1.cs index 0610132c1ec72..51571b3073b43 100644 --- a/src/Compilers/Core/Portable/Collections/TemporaryArray`1.cs +++ b/src/Compilers/Core/Portable/Collections/TemporaryArray`1.cs @@ -337,7 +337,7 @@ private void MoveInlineToBuilder() { builder.Add(this[i]); -#if NETCOREAPP +#if NET if (RuntimeHelpers.IsReferenceOrContainsReferences()) #endif { diff --git a/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.cs b/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.cs index 46a89ceeaad0d..1b7276b4d1f2d 100644 --- a/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.cs +++ b/src/Compilers/Core/Portable/CommandLine/AnalyzerConfig.cs @@ -24,7 +24,7 @@ public sealed partial class AnalyzerConfig // Matches EditorConfig property such as "indent_style = space", see https://editorconfig.org for details private const string s_propertyMatcherPattern = @"^\s*([\w\.\-_]+)\s*[=:]\s*(.*?)\s*([#;].*)?$"; -#if NETCOREAPP +#if NET [GeneratedRegex(s_sectionMatcherPattern)] private static partial Regex GetSectionMatcherRegex(); diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index e5af04c78c4d1..b6a82988ee0e5 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -42,6 +42,13 @@ namespace Microsoft.CodeAnalysis /// public abstract partial class Compilation { + /// + /// Optional data collected during testing only. + /// Used for instance for nullable analysis (NullableWalker.NullableAnalysisData) + /// and inferred delegate types (InferredDelegateTypeData). + /// + internal object? TestOnlyCompilationData; + /// /// Returns true if this is a case sensitive compilation, false otherwise. Case sensitivity /// affects compilation features such as name lookup as well as choosing what names to emit @@ -3400,9 +3407,10 @@ internal static bool SerializePeToStream( return true; } + private protected abstract EmitBaseline MapToCompilation(CommonPEModuleBuilder moduleBeingBuilt); + internal EmitBaseline? SerializeToDeltaStreams( CommonPEModuleBuilder moduleBeingBuilt, - EmitBaseline baseline, DefinitionMap definitionMap, SymbolChanges changes, Stream metadataStream, @@ -3424,6 +3432,14 @@ internal static bool SerializePeToStream( using (nativePdbWriter) { var context = new EmitContext(moduleBeingBuilt, diagnostics, metadataOnly: false, includePrivateMembers: true); + var deletedMethodDefs = DeltaMetadataWriter.CreateDeletedMethodsDefs(context, changes); + + // Map the definitions from the previous compilation to the current compilation. + // This must be done after compiling since synthesized definitions (generated when compiling method bodies) + // may be required. Must also be done after determining deleted method definitions + // since doing so may synthesize HotReloadException symbol. + + var baseline = MapToCompilation(moduleBeingBuilt); var encId = Guid.NewGuid(); try @@ -3435,6 +3451,7 @@ internal static bool SerializePeToStream( encId, definitionMap, changes, + deletedMethodDefs, cancellationToken); moduleBeingBuilt.TestData?.SetMetadataWriter(writer); @@ -3468,6 +3485,13 @@ internal static bool SerializePeToStream( diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_PermissionSetAttributeFileReadError, Location.None, e.FileName, e.PropertyName, e.Message)); return null; } + finally + { + foreach (var (_, builder) in deletedMethodDefs) + { + builder.Free(); + } + } } } diff --git a/src/Compilers/Core/Portable/CryptographicHashProvider.cs b/src/Compilers/Core/Portable/CryptographicHashProvider.cs index c68e5540c77b3..c74d31e51cd04 100644 --- a/src/Compilers/Core/Portable/CryptographicHashProvider.cs +++ b/src/Compilers/Core/Portable/CryptographicHashProvider.cs @@ -82,6 +82,7 @@ internal static int GetHashSize(SourceHashAlgorithm algorithmId) switch (algorithmId) { case SourceHashAlgorithm.Sha1: + // CodeQL [SM02196] This is not enabled by default but exists as a compat option for existing builds. return SHA1.Create(); case SourceHashAlgorithm.Sha256: @@ -97,6 +98,7 @@ internal static HashAlgorithmName GetAlgorithmName(SourceHashAlgorithm algorithm switch (algorithmId) { case SourceHashAlgorithm.Sha1: + // CodeQL [SM02196] This is not enabled by default but exists as a compat option for existing builds. return HashAlgorithmName.SHA1; case SourceHashAlgorithm.Sha256: @@ -113,6 +115,7 @@ internal static HashAlgorithmName GetAlgorithmName(SourceHashAlgorithm algorithm { case AssemblyHashAlgorithm.None: case AssemblyHashAlgorithm.Sha1: + // CodeQL [SM02196] ECMA-335 requires us to support SHA-1 return SHA1.Create(); case AssemblyHashAlgorithm.Sha256: @@ -125,6 +128,7 @@ internal static HashAlgorithmName GetAlgorithmName(SourceHashAlgorithm algorithm return SHA512.Create(); case AssemblyHashAlgorithm.MD5: + // CodeQL [SM02196] This is supported by the underlying ECMA-335 APIs (System.Reflection.Metadata) and as consumers we must also support it. return MD5.Create(); default: @@ -166,6 +170,8 @@ internal static ImmutableArray ComputeSha1(Stream stream) if (stream != null) { stream.Seek(0, SeekOrigin.Begin); + + // CodeQL [SM02196] ECMA-335 requires us to use SHA-1 and there is no alternative. using (var hashProvider = SHA1.Create()) { return ImmutableArray.Create(hashProvider.ComputeHash(stream)); @@ -182,6 +188,7 @@ internal static ImmutableArray ComputeSha1(ImmutableArray bytes) internal static ImmutableArray ComputeSha1(byte[] bytes) { + // CodeQL [SM02196] ECMA-335 requires us to use SHA-1 and there is no alternative. using (var hashProvider = SHA1.Create()) { return ImmutableArray.Create(hashProvider.ComputeHash(bytes)); diff --git a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs index afca96c5e1e44..03af6e1a38996 100644 --- a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs +++ b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs @@ -241,7 +241,7 @@ public string GetIdForErrorCode(int errorCode) public abstract int ERR_TooManyUserStrings { get; } public abstract int ERR_PeWritingFailure { get; } public abstract int ERR_ModuleEmitFailure { get; } - public abstract int ERR_EncUpdateFailedMissingAttribute { get; } + public abstract int ERR_EncUpdateFailedMissingSymbol { get; } public abstract int ERR_InvalidDebugInfo { get; } public abstract int ERR_FunctionPointerTypesInAttributeNotSupported { get; } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.cs index c18b863c37250..d3c5c1b354bd2 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.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. -#if NETCOREAPP +#if NET using System; using System.Collections.Generic; @@ -13,6 +13,8 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Loader; +using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis { @@ -57,6 +59,8 @@ internal AnalyzerAssemblyLoader(AssemblyLoadContext? compilerLoadContext, Analyz public bool IsHostAssembly(Assembly assembly) { + CheckIfDisposed(); + var alc = AssemblyLoadContext.GetLoadContext(assembly); return alc == _compilerLoadContext || alc == AssemblyLoadContext.Default; } @@ -83,25 +87,37 @@ private partial bool IsMatch(AssemblyName requestedName, AssemblyName candidateN internal DirectoryLoadContext[] GetDirectoryLoadContextsSnapshot() { + CheckIfDisposed(); + lock (_guard) { return _loadContextByDirectory.Values.OrderBy(v => v.Directory).ToArray(); } } - internal void UnloadAll() + private partial void DisposeWorker() { - List contexts; + var contexts = ArrayBuilder.GetInstance(); lock (_guard) { - contexts = _loadContextByDirectory.Values.ToList(); + foreach (var (_, context) in _loadContextByDirectory) + contexts.Add(context); + _loadContextByDirectory.Clear(); } foreach (var context in contexts) { - context.Unload(); + try + { + context.Unload(); + } + catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Critical)) + { + } } + + contexts.Free(); } internal sealed class DirectoryLoadContext : AssemblyLoadContext @@ -211,7 +227,19 @@ internal sealed class CompilerAnalyzerAssemblyResolver(AssemblyLoadContext compi { private readonly AssemblyLoadContext _compilerAlc = compilerContext; - public Assembly? ResolveAssembly(AssemblyName assemblyName) => _compilerAlc.LoadFromAssemblyName(assemblyName); + public Assembly? ResolveAssembly(AssemblyName assemblyName) + { + try + { + return _compilerAlc.LoadFromAssemblyName(assemblyName); + } + catch + { + // The LoadFromAssemblyName method will throw if the assembly cannot be found. Need + // to catch this exception and return null to satisfy the interface contract. + return null; + } + } } } } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Desktop.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Desktop.cs index 75d6271100354..98bb543cdae6a 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Desktop.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Desktop.cs @@ -34,8 +34,15 @@ internal AnalyzerAssemblyLoader(ImmutableArray extern _externalResolvers = externalResolvers; } + private partial void DisposeWorker() + { + EnsureResolvedUnhooked(); + } + public bool IsHostAssembly(Assembly assembly) { + CheckIfDisposed(); + // When an assembly is loaded from the GAC then the load result would be the same if // this ran on command line compiler. So there is no consistency issue here, this // is just runtime rules expressing themselves. @@ -74,6 +81,8 @@ private partial bool IsMatch(AssemblyName requestedName, AssemblyName candidateN internal bool EnsureResolvedHooked() { + CheckIfDisposed(); + lock (_guard) { if (!_hookedAssemblyResolve) @@ -89,6 +98,8 @@ internal bool EnsureResolvedHooked() internal bool EnsureResolvedUnhooked() { + // Called from Dispose. We don't want to throw if we're disposed. + lock (_guard) { if (_hookedAssemblyResolve) diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs index 9b35df57eee87..30755244d7869 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.cs @@ -9,11 +9,12 @@ using System.IO; using System.Linq; using System.Reflection; +using Microsoft.CodeAnalysis.ErrorReporting; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { - internal interface IAnalyzerAssemblyLoaderInternal : IAnalyzerAssemblyLoader + internal interface IAnalyzerAssemblyLoaderInternal : IAnalyzerAssemblyLoader, IDisposable { /// /// Is this an that the loader considers to be part of the hosting @@ -76,6 +77,11 @@ internal abstract partial class AnalyzerAssemblyLoader : IAnalyzerAssemblyLoader /// winning. private readonly ImmutableArray _externalResolvers; + /// + /// Whether or not we're disposed. Once disposed, all functionality on this type should throw. + /// + private bool _isDisposed; + /// /// The implementation needs to load an with the specified . The /// parameter is the original path. It may be different than @@ -93,8 +99,31 @@ internal abstract partial class AnalyzerAssemblyLoader : IAnalyzerAssemblyLoader /// private partial bool IsMatch(AssemblyName requestedName, AssemblyName candidateName); + private void CheckIfDisposed() + { +#if NET + ObjectDisposedException.ThrowIf(_isDisposed, this); +#else + if (_isDisposed) + throw new ObjectDisposedException(this.GetType().FullName); +#endif + } + + public void Dispose() + { + if (_isDisposed) + return; + + _isDisposed = true; + DisposeWorker(); + } + + private partial void DisposeWorker(); + internal bool IsAnalyzerDependencyPath(string fullPath) { + CheckIfDisposed(); + lock (_guard) { return _analyzerAssemblyInfoMap.ContainsKey(fullPath); @@ -103,6 +132,8 @@ internal bool IsAnalyzerDependencyPath(string fullPath) public void AddDependencyLocation(string fullPath) { + CheckIfDisposed(); + CompilerPathUtilities.RequireAbsolutePath(fullPath, nameof(fullPath)); string simpleName = PathUtilities.GetFileName(fullPath, includeExtension: false); @@ -127,6 +158,8 @@ public void AddDependencyLocation(string fullPath) public Assembly LoadFromPath(string originalAnalyzerPath) { + CheckIfDisposed(); + CompilerPathUtilities.RequireAbsolutePath(originalAnalyzerPath, nameof(originalAnalyzerPath)); (AssemblyName? assemblyName, _) = GetAssemblyInfoForPath(originalAnalyzerPath); @@ -158,6 +191,8 @@ public Assembly LoadFromPath(string originalAnalyzerPath) /// protected (AssemblyName? AssemblyName, string RealAssemblyPath) GetAssemblyInfoForPath(string originalAnalyzerPath) { + CheckIfDisposed(); + lock (_guard) { if (!_analyzerAssemblyInfoMap.TryGetValue(originalAnalyzerPath, out var tuple)) @@ -205,6 +240,8 @@ public Assembly LoadFromPath(string originalAnalyzerPath) /// internal string? GetRealSatelliteLoadPath(string originalAnalyzerPath, CultureInfo cultureInfo) { + CheckIfDisposed(); + string? realSatelliteAssemblyPath = null; lock (_guard) @@ -250,14 +287,19 @@ public Assembly LoadFromPath(string originalAnalyzerPath) } } - public string? GetOriginalDependencyLocation(AssemblyName assemblyName) => - GetBestPath(assemblyName).BestOriginalPath; + public string? GetOriginalDependencyLocation(AssemblyName assemblyName) + { + CheckIfDisposed(); + return GetBestPath(assemblyName).BestOriginalPath; + } /// /// Return the best (original, real) path information for loading an assembly with the specified . /// protected (string? BestOriginalPath, string? BestRealPath) GetBestPath(AssemblyName requestedName) { + CheckIfDisposed(); + if (requestedName.Name is null) { return (null, null); @@ -327,6 +369,8 @@ protected static string GetSatelliteFileName(string assemblyFileName) => /// internal string GetRealAnalyzerLoadPath(string originalFullPath) { + CheckIfDisposed(); + lock (_guard) { if (!_analyzerAssemblyInfoMap.TryGetValue(originalFullPath, out var tuple)) @@ -340,6 +384,8 @@ internal string GetRealAnalyzerLoadPath(string originalFullPath) internal (string OriginalAssemblyPath, string RealAssemblyPath)[] GetPathMapSnapshot() { + CheckIfDisposed(); + lock (_guard) { return _analyzerAssemblyInfoMap @@ -357,6 +403,8 @@ internal string GetRealAnalyzerLoadPath(string originalFullPath) /// An if one of the resolvers is successful, or internal Assembly? ResolveAssemblyExternally(AssemblyName assemblyName) { + CheckIfDisposed(); + if (!_externalResolvers.IsDefaultOrEmpty) { foreach (var resolver in _externalResolvers) @@ -368,7 +416,7 @@ internal string GetRealAnalyzerLoadPath(string originalFullPath) return resolvedAssembly; } } - catch + catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Diagnostic)) { // Ignore if the external resolver throws } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs index a19a92077a15f..17eeeb262d9b7 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs @@ -189,7 +189,6 @@ internal ImmutableDictionary AnalyzerExecutionTime /// /// Executes the for the given analyzer. /// - /// Analyzer to get session wide analyzer actions. /// Session scope to store register session wide analyzer actions. /// Severity filter for analysis. /// Cancellation token. @@ -198,15 +197,15 @@ internal ImmutableDictionary AnalyzerExecutionTime /// Use API /// to get execute these actions to get the per-compilation analyzer actions. /// - public void ExecuteInitializeMethod(DiagnosticAnalyzer analyzer, HostSessionStartAnalysisScope sessionScope, SeverityFilter severityFilter, CancellationToken cancellationToken) + public void ExecuteInitializeMethod(HostSessionStartAnalysisScope sessionScope, SeverityFilter severityFilter, CancellationToken cancellationToken) { - var context = new AnalyzerAnalysisContext(analyzer, sessionScope, severityFilter); + var context = new AnalyzerAnalysisContext(sessionScope, severityFilter); // The Initialize method should be run asynchronously in case it is not well behaved, e.g. does not terminate. ExecuteAndCatchIfThrows( - analyzer, + sessionScope.Analyzer, data => data.analyzer.Initialize(data.context), - (analyzer, context), + (analyzer: sessionScope.Analyzer, context), contextInfo: null, cancellationToken); } @@ -223,7 +222,7 @@ public void ExecuteCompilationStartActions(ImmutableArray /// Symbol whose symbol start actions are to be executed. - /// Analyzer whose symbol start actions are to be executed. /// whose symbol start actions are to be executed. /// Symbol scope to store the analyzer actions. /// Flag indicating if the symbol being analyzed is generated code. /// Cancellation token. public void ExecuteSymbolStartActions( ISymbol symbol, - DiagnosticAnalyzer analyzer, ImmutableArray actions, HostSymbolStartAnalysisScope symbolScope, bool isGeneratedCodeSymbol, @@ -254,18 +251,18 @@ public void ExecuteSymbolStartActions( TextSpan? filterSpan, CancellationToken cancellationToken) { - if (isGeneratedCodeSymbol && _shouldSkipAnalysisOnGeneratedCode(analyzer) || - IsAnalyzerSuppressedForSymbol(analyzer, symbol, cancellationToken)) + if (isGeneratedCodeSymbol && _shouldSkipAnalysisOnGeneratedCode(symbolScope.Analyzer) || + IsAnalyzerSuppressedForSymbol(symbolScope.Analyzer, symbol, cancellationToken)) { return; } foreach (var startAction in actions) { - Debug.Assert(startAction.Analyzer == analyzer); + Debug.Assert(startAction.Analyzer == symbolScope.Analyzer); cancellationToken.ThrowIfCancellationRequested(); - var context = new AnalyzerSymbolStartAnalysisContext(startAction.Analyzer, symbolScope, + var context = new AnalyzerSymbolStartAnalysisContext(symbolScope, symbol, Compilation, AnalyzerOptions, isGeneratedCodeSymbol, filterTree, filterSpan, cancellationToken); ExecuteAndCatchIfThrows( @@ -799,8 +796,8 @@ private void ExecuteBlockActionsCore codeBlockStartAction) { var codeBlockEndActions = blockEndActions as PooledHashSet; - var codeBlockScope = new HostCodeBlockStartAnalysisScope(); - var blockStartContext = new AnalyzerCodeBlockStartAnalysisContext(startAction.Analyzer, + var codeBlockScope = new HostCodeBlockStartAnalysisScope(startAction.Analyzer); + var blockStartContext = new AnalyzerCodeBlockStartAnalysisContext( codeBlockScope, declaredNode, declaredSymbol, semanticModel, AnalyzerOptions, filterSpan, isGeneratedCode, cancellationToken); // Catch Exception from the start action. @@ -821,8 +818,8 @@ private void ExecuteBlockActionsCore; - var operationBlockScope = new HostOperationBlockStartAnalysisScope(); - var operationStartContext = new AnalyzerOperationBlockStartAnalysisContext(startAction.Analyzer, + var operationBlockScope = new HostOperationBlockStartAnalysisScope(startAction.Analyzer); + var operationStartContext = new AnalyzerOperationBlockStartAnalysisContext( operationBlockScope, operationBlocks, declaredSymbol, semanticModel.Compilation, AnalyzerOptions, GetControlFlowGraph, declaredNode.SyntaxTree, filterSpan, isGeneratedCode, cancellationToken); @@ -1006,7 +1003,7 @@ private void ExecuteSyntaxNodeActions( // aggregate. if (nodeActionsByKind.TryGetValue(getKind(node), out var actionsForKind)) { - Debug.Assert(!actionsForKind.IsEmpty, $"Unexpected empty action collection in {nameof(nodeActionsByKind)}"); + RoslynDebug.Assert(!actionsForKind.IsEmpty, $"Unexpected empty action collection in {nameof(nodeActionsByKind)}"); if (ShouldExecuteNode(node, analyzer, cancellationToken)) { // If analyzer hasn't registered any CodeBlockStart or SymbolStart actions, then update the filter span @@ -1106,7 +1103,7 @@ private void ExecuteOperationActions( // expensive in aggregate. if (operationActionsByKind.TryGetValue(operation.Kind, out var actionsForKind)) { - Debug.Assert(!actionsForKind.IsEmpty, $"Unexpected empty action collection in {nameof(operationActionsByKind)}"); + RoslynDebug.Assert(!actionsForKind.IsEmpty, $"Unexpected empty action collection in {nameof(operationActionsByKind)}"); if (ShouldExecuteOperation(operation, analyzer, cancellationToken)) { // If analyzer hasn't registered any OperationBlockStart or SymbolStart actions, then update diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs index cd91d39fc4a52..fbbd8f4553645 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerFileReference.cs @@ -31,7 +31,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics /// public sealed class AnalyzerFileReference : AnalyzerReference, IEquatable { - private delegate IEnumerable AttributeLanguagesFunc(PEModule module, CustomAttributeHandle attribute); + private delegate ImmutableArray AttributeLanguagesFunc(PEModule module, CustomAttributeHandle attribute); public override string FullPath { get; } @@ -224,31 +224,46 @@ private static ImmutableSortedDictionary> GetAn { using var assembly = AssemblyMetadata.CreateFromFile(fullPath); - // This is longer than strictly necessary to avoid thrashing the GC with string allocations - // in the call to GetFullyQualifiedTypeNames. Specifically, this checks for the presence of - // supported languages prior to creating the type names. - var typeNameMap = from module in assembly.GetModules() - from typeDefHandle in module.MetadataReader.TypeDefinitions - let typeDef = module.MetadataReader.GetTypeDefinition(typeDefHandle) - let supportedLanguages = GetSupportedLanguages(typeDef, module.Module, attributeType, languagesFunc) - where supportedLanguages.Any() - let typeName = GetFullyQualifiedTypeName(typeDef, module.Module) - from supportedLanguage in supportedLanguages - group typeName by supportedLanguage; - - return typeNameMap.ToImmutableSortedDictionary(g => g.Key, g => g.ToImmutableHashSet(), StringComparer.OrdinalIgnoreCase); + Dictionary.Builder> typeNameMap = new Dictionary.Builder>(StringComparer.OrdinalIgnoreCase); + + foreach (var module in assembly.GetModules()) + { + foreach (var typeDefHandle in module.MetadataReader.TypeDefinitions) + { + var typeDef = module.MetadataReader.GetTypeDefinition(typeDefHandle); + var supportedLanguages = GetSupportedLanguages(typeDef, module.Module, attributeType, languagesFunc); + + // PERF: avoid calling GetFullyQualifiedTypeName when no supported languages. + if (supportedLanguages.Length > 0) + { + var typeName = GetFullyQualifiedTypeName(typeDef, module.Module); + foreach (var supportedLanguage in supportedLanguages) + { + if (!typeNameMap.TryGetValue(supportedLanguage, out var builder)) + { + builder = ImmutableHashSet.CreateBuilder(); + typeNameMap.Add(supportedLanguage, builder); + } + + builder.Add(typeName); + } + } + } + } + + return typeNameMap.ToImmutableSortedDictionary(g => g.Key, g => g.Value.ToImmutable(), StringComparer.OrdinalIgnoreCase); } - private static IEnumerable GetSupportedLanguages(TypeDefinition typeDef, PEModule peModule, Type attributeType, AttributeLanguagesFunc languagesFunc) + private static ImmutableArray GetSupportedLanguages(TypeDefinition typeDef, PEModule peModule, Type attributeType, AttributeLanguagesFunc languagesFunc) { - IEnumerable? result = null; + ImmutableArray result = []; foreach (CustomAttributeHandle customAttrHandle in typeDef.GetCustomAttributes()) { if (peModule.IsTargetAttribute(customAttrHandle, attributeType.Namespace!, attributeType.Name, ctor: out _)) { if (languagesFunc(peModule, customAttrHandle) is { } attributeSupportedLanguages) { - if (result is null) + if (result.IsDefaultOrEmpty) { result = attributeSupportedLanguages; } @@ -256,16 +271,16 @@ private static IEnumerable GetSupportedLanguages(TypeDefinition typeDef, { // This is a slow path, but only occurs if a single type has multiple // DiagnosticAnalyzerAttribute instances applied to it. - result = result.Concat(attributeSupportedLanguages); + result = result.AddRange(attributeSupportedLanguages); } } } } - return result ?? SpecializedCollections.EmptyEnumerable(); + return result; } - private static IEnumerable GetDiagnosticsAnalyzerSupportedLanguages(PEModule peModule, CustomAttributeHandle customAttrHandle) + private static ImmutableArray GetDiagnosticsAnalyzerSupportedLanguages(PEModule peModule, CustomAttributeHandle customAttrHandle) { // The DiagnosticAnalyzerAttribute has one constructor, which has a string parameter for the // first supported language and an array parameter for additional supported languages. @@ -274,7 +289,7 @@ private static IEnumerable GetDiagnosticsAnalyzerSupportedLanguages(PEMo return ReadLanguagesFromAttribute(ref argsReader); } - private static IEnumerable GetGeneratorSupportedLanguages(PEModule peModule, CustomAttributeHandle customAttrHandle) + private static ImmutableArray GetGeneratorSupportedLanguages(PEModule peModule, CustomAttributeHandle customAttrHandle) { // The GeneratorAttribute has two constructors: one default, and one with a string parameter for the // first supported language and an array parameter for additional supported languages. @@ -293,7 +308,7 @@ private static IEnumerable GetGeneratorSupportedLanguages(PEModule peMod // https://github.com/dotnet/roslyn/issues/53994 tracks re-enabling nullable and fixing this method #nullable disable - private static IEnumerable ReadLanguagesFromAttribute(ref BlobReader argsReader) + private static ImmutableArray ReadLanguagesFromAttribute(ref BlobReader argsReader) { if (argsReader.Length > 4) { @@ -303,7 +318,7 @@ private static IEnumerable ReadLanguagesFromAttribute(ref BlobReader arg string firstLanguageName; if (!PEModule.CrackStringInAttributeValue(out firstLanguageName, ref argsReader)) { - return SpecializedCollections.EmptyEnumerable(); + return []; } ImmutableArray additionalLanguageNames; @@ -311,14 +326,14 @@ private static IEnumerable ReadLanguagesFromAttribute(ref BlobReader arg { if (additionalLanguageNames.Length == 0) { - return SpecializedCollections.SingletonEnumerable(firstLanguageName); + return [firstLanguageName]; } return additionalLanguageNames.Insert(0, firstLanguageName); } } } - return SpecializedCollections.EmptyEnumerable(); + return []; } #nullable enable diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.AnalyzerExecutionContext.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.AnalyzerExecutionContext.cs index 40acf22276ee5..d2d60be6a7c51 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.AnalyzerExecutionContext.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.AnalyzerExecutionContext.cs @@ -90,8 +90,8 @@ static Task getSessionAnalysisScopeTaskSlowAsync( { return Task.Run(() => { - var sessionScope = new HostSessionStartAnalysisScope(); - executor.ExecuteInitializeMethod(context._analyzer, sessionScope, executor.SeverityFilter, cancellationToken); + var sessionScope = new HostSessionStartAnalysisScope(context._analyzer); + executor.ExecuteInitializeMethod(sessionScope, executor.SeverityFilter, cancellationToken); return sessionScope; }, cancellationToken); } @@ -117,8 +117,9 @@ public Task GetCompilationAnalysisScopeAsync( { _lazyCompilationScopeTask = Task.Run(() => { + Debug.Assert(sessionScope.Analyzer == _analyzer); var compilationAnalysisScope = new HostCompilationStartAnalysisScope(sessionScope); - analyzerExecutor.ExecuteCompilationStartActions(sessionScope.GetAnalyzerActions(_analyzer).CompilationStartActions, compilationAnalysisScope, cancellationToken); + analyzerExecutor.ExecuteCompilationStartActions(sessionScope.GetAnalyzerActions().CompilationStartActions, compilationAnalysisScope, cancellationToken); return compilationAnalysisScope; }, cancellationToken); } @@ -157,10 +158,10 @@ public Task GetSymbolAnalysisScopeAsync( HostSymbolStartAnalysisScope getSymbolAnalysisScopeCore() { - var symbolAnalysisScope = new HostSymbolStartAnalysisScope(); - analyzerExecutor.ExecuteSymbolStartActions(symbol, _analyzer, symbolStartActions, symbolAnalysisScope, isGeneratedCodeSymbol, filterTree, filterSpan, cancellationToken); + var symbolAnalysisScope = new HostSymbolStartAnalysisScope(_analyzer); + analyzerExecutor.ExecuteSymbolStartActions(symbol, symbolStartActions, symbolAnalysisScope, isGeneratedCodeSymbol, filterTree, filterSpan, cancellationToken); - var symbolEndActions = symbolAnalysisScope.GetAnalyzerActions(_analyzer); + var symbolEndActions = symbolAnalysisScope.GetAnalyzerActions(); if (symbolEndActions.SymbolEndActionsCount > 0) { var dependentSymbols = getDependentSymbols(); @@ -203,13 +204,10 @@ void processMembers(IEnumerable members) memberSet ??= new HashSet(); memberSet.Add(member); - // Ensure that we include symbols for both parts of partial methods. - // https://github.com/dotnet/roslyn/issues/73772: also cascade to partial property implementation part - if (member is IMethodSymbol method && - !(method.PartialImplementationPart is null)) - { - memberSet.Add(method.PartialImplementationPart); - } + if (member is IMethodSymbol { PartialImplementationPart: { } methodImplementation }) + memberSet.Add(methodImplementation); + else if (member is IPropertySymbol { PartialImplementationPart: { } propertyImplementation }) + memberSet.Add(propertyImplementation); } if (member is INamedTypeSymbol typeMember) @@ -224,18 +222,18 @@ void processMembers(IEnumerable members) [Conditional("DEBUG")] private void VerifyNewEntryForPendingMemberSymbolsMap(ISymbol symbol, HashSet? dependentSymbols) { - Debug.Assert(_lazyPendingMemberSymbolsMap != null, $"{nameof(_lazyPendingMemberSymbolsMap)} was expected to be a non-null value."); + RoslynDebug.Assert(_lazyPendingMemberSymbolsMap != null, $"{nameof(_lazyPendingMemberSymbolsMap)} was expected to be a non-null value."); if (_lazyPendingMemberSymbolsMap.TryGetValue(symbol, out var existingDependentSymbols)) { if (existingDependentSymbols == null) { - Debug.Assert(dependentSymbols == null, $"{nameof(dependentSymbols)} was expected to be null."); + RoslynDebug.Assert(dependentSymbols == null, $"{nameof(dependentSymbols)} was expected to be null."); } else { - Debug.Assert(dependentSymbols != null, $"{nameof(dependentSymbols)} was expected to be a non-null value."); - Debug.Assert(existingDependentSymbols.IsSubsetOf(dependentSymbols), $"{nameof(existingDependentSymbols)} was expected to be a subset of {nameof(dependentSymbols)}"); + RoslynDebug.Assert(dependentSymbols != null, $"{nameof(dependentSymbols)} was expected to be a non-null value."); + RoslynDebug.Assert(existingDependentSymbols.IsSubsetOf(dependentSymbols), $"{nameof(existingDependentSymbols)} was expected to be a subset of {nameof(dependentSymbols)}"); } } } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.cs index d3f0816c90fc7..7d27857248c4b 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerManager.cs @@ -56,12 +56,11 @@ private Dictionary CreateAnalyzerE "https://github.com/dotnet/roslyn/issues/26778", OftenCompletesSynchronously = true)] private async ValueTask GetCompilationAnalysisScopeAsync( - DiagnosticAnalyzer analyzer, HostSessionStartAnalysisScope sessionScope, AnalyzerExecutor analyzerExecutor, CancellationToken cancellationToken) { - var analyzerExecutionContext = GetAnalyzerExecutionContext(analyzer); + var analyzerExecutionContext = GetAnalyzerExecutionContext(sessionScope.Analyzer); return await GetCompilationAnalysisScopeCoreAsync(sessionScope, analyzerExecutor, analyzerExecutionContext, cancellationToken).ConfigureAwait(false); } @@ -169,13 +168,13 @@ private async ValueTask GetSessionAnalysisScopeCo public async ValueTask GetAnalyzerActionsAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor, CancellationToken cancellationToken) { var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor, cancellationToken).ConfigureAwait(false); - if (sessionScope.GetAnalyzerActions(analyzer).CompilationStartActionsCount > 0 && analyzerExecutor.Compilation != null) + if (sessionScope.GetAnalyzerActions().CompilationStartActionsCount > 0 && analyzerExecutor.Compilation != null) { - var compilationScope = await GetCompilationAnalysisScopeAsync(analyzer, sessionScope, analyzerExecutor, cancellationToken).ConfigureAwait(false); - return compilationScope.GetAnalyzerActions(analyzer); + var compilationScope = await GetCompilationAnalysisScopeAsync(sessionScope, analyzerExecutor, cancellationToken).ConfigureAwait(false); + return compilationScope.GetAnalyzerActions(); } - return sessionScope.GetAnalyzerActions(analyzer); + return sessionScope.GetAnalyzerActions(); } /// @@ -199,7 +198,7 @@ public async ValueTask GetPerSymbolAnalyzerActionsAsync( if (filteredSymbolStartActions.Length > 0) { var symbolScope = await GetSymbolAnalysisScopeAsync(symbol, isGeneratedCodeSymbol, filterTree, filterSpan, analyzer, filteredSymbolStartActions, analyzerExecutor, cancellationToken).ConfigureAwait(false); - return symbolScope.GetAnalyzerActions(analyzer); + return symbolScope.GetAnalyzerActions(); } } @@ -234,7 +233,7 @@ ImmutableArray getFilteredActionsByKind(ImmutableArra public async Task IsConcurrentAnalyzerAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor, CancellationToken cancellationToken) { var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor, cancellationToken).ConfigureAwait(false); - return sessionScope.IsConcurrentAnalyzer(analyzer); + return sessionScope.IsConcurrentAnalyzer(); } /// @@ -244,7 +243,7 @@ public async Task IsConcurrentAnalyzerAsync(DiagnosticAnalyzer analyzer, A public async Task GetGeneratedCodeAnalysisFlagsAsync(DiagnosticAnalyzer analyzer, AnalyzerExecutor analyzerExecutor, CancellationToken cancellationToken) { var sessionScope = await GetSessionAnalysisScopeAsync(analyzer, analyzerExecutor, cancellationToken).ConfigureAwait(false); - return sessionScope.GetGeneratedCodeAnalysisFlags(analyzer); + return sessionScope.GetGeneratedCodeAnalysisFlags(); } /// diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs index a23c7ef140d3f..45e7418d5887a 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs @@ -1117,10 +1117,14 @@ static bool shouldIncludeSymbol(ISymbolInternal symbol, SyntaxTree tree, Cancell return true; } } - - // https://github.com/dotnet/roslyn/issues/73772: should we also check IPropertySymbol? - // there is no interface IPropertySymbolInternal - // where are tests for this? + else if (symbol is IPropertySymbolInternal propertySymbol) + { + if (propertySymbol.PartialDefinitionPart?.IsDefinedInSourceTree(tree, definedWithinSpan: null, cancellationToken) == true + || propertySymbol.PartialImplementationPart?.IsDefinedInSourceTree(tree, definedWithinSpan: null, cancellationToken) == true) + { + return true; + } + } return false; } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DefaultAnalyzerAssemblyLoader.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DefaultAnalyzerAssemblyLoader.cs index b6233d02a6d36..40f7afa19d91f 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DefaultAnalyzerAssemblyLoader.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DefaultAnalyzerAssemblyLoader.cs @@ -26,7 +26,7 @@ internal DefaultAnalyzerAssemblyLoader(ImmutableArray { } -#if NETCOREAPP +#if NET internal DefaultAnalyzerAssemblyLoader(System.Runtime.Loader.AssemblyLoadContext? compilerLoadContext = null, AnalyzerLoadOption loadOption = AnalyzerLoadOption.LoadFromDisk, ImmutableArray? externalResolvers = null) : base(compilerLoadContext, loadOption, externalResolvers ?? []) @@ -59,7 +59,7 @@ protected override string PrepareSatelliteAssemblyToLoad(string assemblyFilePath /// will be the base directory where shadow copy assemblies are stored. internal static IAnalyzerAssemblyLoaderInternal CreateNonLockingLoader(string windowsShadowPath, ImmutableArray? externalResolvers = null) { -#if NETCOREAPP +#if NET if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return new DefaultAnalyzerAssemblyLoader(loadOption: AnalyzerLoadOption.LoadFromStream, externalResolvers: externalResolvers); diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs index 3e91d86af62ff..fb6dcccfdfd45 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/DiagnosticStartAnalysisScope.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Concurrent; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -11,6 +10,7 @@ using Microsoft.CodeAnalysis.FlowAnalysis; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics { @@ -19,12 +19,10 @@ namespace Microsoft.CodeAnalysis.Diagnostics /// internal sealed class AnalyzerAnalysisContext : AnalysisContext { - private readonly DiagnosticAnalyzer _analyzer; private readonly HostSessionStartAnalysisScope _scope; - public AnalyzerAnalysisContext(DiagnosticAnalyzer analyzer, HostSessionStartAnalysisScope scope, SeverityFilter severityFilter) + public AnalyzerAnalysisContext(HostSessionStartAnalysisScope scope, SeverityFilter severityFilter) { - _analyzer = analyzer; _scope = scope; MinimumReportedSeverity = severityFilter.GetMinimumUnfilteredSeverity(); } @@ -32,89 +30,89 @@ public AnalyzerAnalysisContext(DiagnosticAnalyzer analyzer, HostSessionStartAnal public override void RegisterCompilationStartAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterCompilationStartAction(_analyzer, action); + _scope.RegisterCompilationStartAction(action); } public override void RegisterCompilationAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterCompilationAction(_analyzer, action); + _scope.RegisterCompilationAction(action); } public override void RegisterSyntaxTreeAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterSyntaxTreeAction(_analyzer, action); + _scope.RegisterSyntaxTreeAction(action); } public override void RegisterAdditionalFileAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterAdditionalFileAction(_analyzer, action); + _scope.RegisterAdditionalFileAction(action); } public override void RegisterSemanticModelAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterSemanticModelAction(_analyzer, action); + _scope.RegisterSemanticModelAction(action); } public override void RegisterSymbolAction(Action action, ImmutableArray symbolKinds) { DiagnosticAnalysisContextHelpers.VerifyArguments(action, symbolKinds); - _scope.RegisterSymbolAction(_analyzer, action, symbolKinds); + _scope.RegisterSymbolAction(action, symbolKinds); } public override void RegisterSymbolStartAction(Action action, SymbolKind symbolKind) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterSymbolStartAction(_analyzer, action, symbolKind); + _scope.RegisterSymbolStartAction(action, symbolKind); } public override void RegisterCodeBlockStartAction(Action> action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterCodeBlockStartAction(_analyzer, action); + _scope.RegisterCodeBlockStartAction(action); } public override void RegisterCodeBlockAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterCodeBlockAction(_analyzer, action); + _scope.RegisterCodeBlockAction(action); } public override void RegisterSyntaxNodeAction(Action action, ImmutableArray syntaxKinds) { DiagnosticAnalysisContextHelpers.VerifyArguments(action, syntaxKinds); - _scope.RegisterSyntaxNodeAction(_analyzer, action, syntaxKinds); + _scope.RegisterSyntaxNodeAction(action, syntaxKinds); } public override void RegisterOperationAction(Action action, ImmutableArray operationKinds) { DiagnosticAnalysisContextHelpers.VerifyArguments(action, operationKinds); - _scope.RegisterOperationAction(_analyzer, action, operationKinds); + _scope.RegisterOperationAction(action, operationKinds); } public override void RegisterOperationBlockStartAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterOperationBlockStartAction(_analyzer, action); + _scope.RegisterOperationBlockStartAction(action); } public override void RegisterOperationBlockAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterOperationBlockAction(_analyzer, action); + _scope.RegisterOperationBlockAction(action); } public override void EnableConcurrentExecution() { - _scope.EnableConcurrentExecution(_analyzer); + _scope.EnableConcurrentExecution(); } public override void ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags mode) { - _scope.ConfigureGeneratedCodeAnalysis(_analyzer, mode); + _scope.ConfigureGeneratedCodeAnalysis(mode); } public override DiagnosticSeverity MinimumReportedSeverity { get; } @@ -125,12 +123,10 @@ public override void ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags m /// internal sealed class AnalyzerCompilationStartAnalysisContext : CompilationStartAnalysisContext { - private readonly DiagnosticAnalyzer _analyzer; private readonly HostCompilationStartAnalysisScope _scope; private readonly CompilationAnalysisValueProviderFactory _compilationAnalysisValueProviderFactory; public AnalyzerCompilationStartAnalysisContext( - DiagnosticAnalyzer analyzer, HostCompilationStartAnalysisScope scope, Compilation compilation, AnalyzerOptions options, @@ -138,7 +134,6 @@ public AnalyzerCompilationStartAnalysisContext( CancellationToken cancellationToken) : base(compilation, options, cancellationToken) { - _analyzer = analyzer; _scope = scope; _compilationAnalysisValueProviderFactory = compilationAnalysisValueProviderFactory; } @@ -146,73 +141,73 @@ public AnalyzerCompilationStartAnalysisContext( public override void RegisterCompilationEndAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterCompilationEndAction(_analyzer, action); + _scope.RegisterCompilationEndAction(action); } public override void RegisterSyntaxTreeAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterSyntaxTreeAction(_analyzer, action); + _scope.RegisterSyntaxTreeAction(action); } public override void RegisterAdditionalFileAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterAdditionalFileAction(_analyzer, action); + _scope.RegisterAdditionalFileAction(action); } public override void RegisterSemanticModelAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterSemanticModelAction(_analyzer, action); + _scope.RegisterSemanticModelAction(action); } public override void RegisterSymbolAction(Action action, ImmutableArray symbolKinds) { DiagnosticAnalysisContextHelpers.VerifyArguments(action, symbolKinds); - _scope.RegisterSymbolAction(_analyzer, action, symbolKinds); + _scope.RegisterSymbolAction(action, symbolKinds); } public override void RegisterSymbolStartAction(Action action, SymbolKind symbolKind) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterSymbolStartAction(_analyzer, action, symbolKind); + _scope.RegisterSymbolStartAction(action, symbolKind); } public override void RegisterCodeBlockStartAction(Action> action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterCodeBlockStartAction(_analyzer, action); + _scope.RegisterCodeBlockStartAction(action); } public override void RegisterCodeBlockAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterCodeBlockAction(_analyzer, action); + _scope.RegisterCodeBlockAction(action); } public override void RegisterSyntaxNodeAction(Action action, ImmutableArray syntaxKinds) { DiagnosticAnalysisContextHelpers.VerifyArguments(action, syntaxKinds); - _scope.RegisterSyntaxNodeAction(_analyzer, action, syntaxKinds); + _scope.RegisterSyntaxNodeAction(action, syntaxKinds); } public override void RegisterOperationBlockStartAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterOperationBlockStartAction(_analyzer, action); + _scope.RegisterOperationBlockStartAction(action); } public override void RegisterOperationBlockAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterOperationBlockAction(_analyzer, action); + _scope.RegisterOperationBlockAction(action); } public override void RegisterOperationAction(Action action, ImmutableArray operationKinds) { DiagnosticAnalysisContextHelpers.VerifyArguments(action, operationKinds); - _scope.RegisterOperationAction(_analyzer, action, operationKinds); + _scope.RegisterOperationAction(action, operationKinds); } internal override bool TryGetValueCore(TKey key, AnalysisValueProvider valueProvider, [MaybeNullWhen(false)] out TValue value) @@ -227,10 +222,9 @@ internal override bool TryGetValueCore(TKey key, AnalysisValueProv /// internal sealed class AnalyzerSymbolStartAnalysisContext : SymbolStartAnalysisContext { - private readonly DiagnosticAnalyzer _analyzer; private readonly HostSymbolStartAnalysisScope _scope; - internal AnalyzerSymbolStartAnalysisContext(DiagnosticAnalyzer analyzer, + internal AnalyzerSymbolStartAnalysisContext( HostSymbolStartAnalysisScope scope, ISymbol owningSymbol, Compilation compilation, @@ -241,50 +235,49 @@ internal AnalyzerSymbolStartAnalysisContext(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken) : base(owningSymbol, compilation, options, isGeneratedCode, filterTree, filterSpan, cancellationToken) { - _analyzer = analyzer; _scope = scope; } public override void RegisterSymbolEndAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterSymbolEndAction(_analyzer, action); + _scope.RegisterSymbolEndAction(action); } public override void RegisterCodeBlockStartAction(Action> action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterCodeBlockStartAction(_analyzer, action); + _scope.RegisterCodeBlockStartAction(action); } public override void RegisterCodeBlockAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterCodeBlockAction(_analyzer, action); + _scope.RegisterCodeBlockAction(action); } public override void RegisterSyntaxNodeAction(Action action, ImmutableArray syntaxKinds) { DiagnosticAnalysisContextHelpers.VerifyArguments(action, syntaxKinds); - _scope.RegisterSyntaxNodeAction(_analyzer, action, syntaxKinds); + _scope.RegisterSyntaxNodeAction(action, syntaxKinds); } public override void RegisterOperationBlockStartAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterOperationBlockStartAction(_analyzer, action); + _scope.RegisterOperationBlockStartAction(action); } public override void RegisterOperationBlockAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterOperationBlockAction(_analyzer, action); + _scope.RegisterOperationBlockAction(action); } public override void RegisterOperationAction(Action action, ImmutableArray operationKinds) { DiagnosticAnalysisContextHelpers.VerifyArguments(action, operationKinds); - _scope.RegisterOperationAction(_analyzer, action, operationKinds); + _scope.RegisterOperationAction(action, operationKinds); } } @@ -293,10 +286,9 @@ public override void RegisterOperationAction(Action ac /// internal sealed class AnalyzerCodeBlockStartAnalysisContext : CodeBlockStartAnalysisContext where TLanguageKindEnum : struct { - private readonly DiagnosticAnalyzer _analyzer; private readonly HostCodeBlockStartAnalysisScope _scope; - internal AnalyzerCodeBlockStartAnalysisContext(DiagnosticAnalyzer analyzer, + internal AnalyzerCodeBlockStartAnalysisContext( HostCodeBlockStartAnalysisScope scope, SyntaxNode codeBlock, ISymbol owningSymbol, @@ -307,20 +299,19 @@ internal AnalyzerCodeBlockStartAnalysisContext(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken) : base(codeBlock, owningSymbol, semanticModel, options, filterSpan, isGeneratedCode, cancellationToken) { - _analyzer = analyzer; _scope = scope; } public override void RegisterCodeBlockEndAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterCodeBlockEndAction(_analyzer, action); + _scope.RegisterCodeBlockEndAction(action); } public override void RegisterSyntaxNodeAction(Action action, ImmutableArray syntaxKinds) { DiagnosticAnalysisContextHelpers.VerifyArguments(action, syntaxKinds); - _scope.RegisterSyntaxNodeAction(_analyzer, action, syntaxKinds); + _scope.RegisterSyntaxNodeAction(action, syntaxKinds); } } @@ -329,10 +320,9 @@ public override void RegisterSyntaxNodeAction(Action /// internal sealed class AnalyzerOperationBlockStartAnalysisContext : OperationBlockStartAnalysisContext { - private readonly DiagnosticAnalyzer _analyzer; private readonly HostOperationBlockStartAnalysisScope _scope; - internal AnalyzerOperationBlockStartAnalysisContext(DiagnosticAnalyzer analyzer, + internal AnalyzerOperationBlockStartAnalysisContext( HostOperationBlockStartAnalysisScope scope, ImmutableArray operationBlocks, ISymbol owningSymbol, @@ -345,57 +335,56 @@ internal AnalyzerOperationBlockStartAnalysisContext(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken) : base(operationBlocks, owningSymbol, compilation, options, getControlFlowGraph, filterTree, filterSpan, isGeneratedCode, cancellationToken) { - _analyzer = analyzer; _scope = scope; } public override void RegisterOperationBlockEndAction(Action action) { DiagnosticAnalysisContextHelpers.VerifyArguments(action); - _scope.RegisterOperationBlockEndAction(_analyzer, action); + _scope.RegisterOperationBlockEndAction(action); } public override void RegisterOperationAction(Action action, ImmutableArray operationKinds) { DiagnosticAnalysisContextHelpers.VerifyArguments(action, operationKinds); - _scope.RegisterOperationAction(_analyzer, action, operationKinds); + _scope.RegisterOperationAction(action, operationKinds); } } /// /// Scope for setting up analyzers for an entire session, capable of retrieving the actions. /// - internal sealed class HostSessionStartAnalysisScope : HostAnalysisScope + internal sealed class HostSessionStartAnalysisScope(DiagnosticAnalyzer analyzer) + : HostAnalysisScope(analyzer) { - private ImmutableHashSet _concurrentAnalyzers = ImmutableHashSet.Empty; - private readonly ConcurrentDictionary _generatedCodeConfigurationMap = new ConcurrentDictionary(); + private bool _isConcurrent; + private GeneratedCodeAnalysisFlags _generatedCodeConfiguration = AnalyzerDriver.DefaultGeneratedCodeAnalysisFlags; - public bool IsConcurrentAnalyzer(DiagnosticAnalyzer analyzer) + public bool IsConcurrentAnalyzer() { - return _concurrentAnalyzers.Contains(analyzer); + return _isConcurrent; } - public GeneratedCodeAnalysisFlags GetGeneratedCodeAnalysisFlags(DiagnosticAnalyzer analyzer) + public GeneratedCodeAnalysisFlags GetGeneratedCodeAnalysisFlags() { - GeneratedCodeAnalysisFlags mode; - return _generatedCodeConfigurationMap.TryGetValue(analyzer, out mode) ? mode : AnalyzerDriver.DefaultGeneratedCodeAnalysisFlags; + return _generatedCodeConfiguration; } - public void RegisterCompilationStartAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterCompilationStartAction(Action action) { - CompilationStartAnalyzerAction analyzerAction = new CompilationStartAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddCompilationStartAction(analyzerAction); + CompilationStartAnalyzerAction analyzerAction = new CompilationStartAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddCompilationStartAction(analyzerAction); } - public void EnableConcurrentExecution(DiagnosticAnalyzer analyzer) + public void EnableConcurrentExecution() { - _concurrentAnalyzers = _concurrentAnalyzers.Add(analyzer); - GetOrCreateAnalyzerActions(analyzer).Value.EnableConcurrentExecution(); + _isConcurrent = true; + GetOrCreateAnalyzerActions().Value.EnableConcurrentExecution(); } - public void ConfigureGeneratedCodeAnalysis(DiagnosticAnalyzer analyzer, GeneratedCodeAnalysisFlags mode) + public void ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags mode) { - _generatedCodeConfigurationMap.AddOrUpdate(analyzer, addValue: mode, updateValueFactory: (a, c) => mode); + _generatedCodeConfiguration = mode; } } @@ -407,14 +396,15 @@ internal sealed class HostCompilationStartAnalysisScope : HostAnalysisScope private readonly HostSessionStartAnalysisScope _sessionScope; public HostCompilationStartAnalysisScope(HostSessionStartAnalysisScope sessionScope) + : base(sessionScope.Analyzer) { _sessionScope = sessionScope; } - public override AnalyzerActions GetAnalyzerActions(DiagnosticAnalyzer analyzer) + public override AnalyzerActions GetAnalyzerActions() { - AnalyzerActions compilationActions = base.GetAnalyzerActions(analyzer); - AnalyzerActions sessionActions = _sessionScope.GetAnalyzerActions(analyzer); + AnalyzerActions compilationActions = base.GetAnalyzerActions(); + AnalyzerActions sessionActions = _sessionScope.GetAnalyzerActions(); if (sessionActions.IsEmpty) { @@ -433,21 +423,21 @@ public override AnalyzerActions GetAnalyzerActions(DiagnosticAnalyzer analyzer) /// /// Scope for setting up analyzers for analyzing a symbol and its members. /// - internal sealed class HostSymbolStartAnalysisScope : HostAnalysisScope + internal sealed class HostSymbolStartAnalysisScope(DiagnosticAnalyzer analyzer) + : HostAnalysisScope(analyzer) { - public HostSymbolStartAnalysisScope() - { - } } /// /// Scope for setting up analyzers for a code block, capable of retrieving the actions. /// - internal sealed class HostCodeBlockStartAnalysisScope where TLanguageKindEnum : struct + internal sealed class HostCodeBlockStartAnalysisScope(DiagnosticAnalyzer analyzer) where TLanguageKindEnum : struct { private ImmutableArray _codeBlockEndActions = ImmutableArray.Empty; private ImmutableArray> _syntaxNodeActions = ImmutableArray>.Empty; + private DiagnosticAnalyzer Analyzer { get; } = analyzer; + public ImmutableArray CodeBlockEndActions { get { return _codeBlockEndActions; } @@ -458,88 +448,84 @@ public ImmutableArray> SyntaxNodeAct get { return _syntaxNodeActions; } } - internal HostCodeBlockStartAnalysisScope() - { - } - - public void RegisterCodeBlockEndAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterCodeBlockEndAction(Action action) { - _codeBlockEndActions = _codeBlockEndActions.Add(new CodeBlockAnalyzerAction(action, analyzer)); + _codeBlockEndActions = _codeBlockEndActions.Add(new CodeBlockAnalyzerAction(action, Analyzer)); } - public void RegisterSyntaxNodeAction(DiagnosticAnalyzer analyzer, Action action, ImmutableArray syntaxKinds) + public void RegisterSyntaxNodeAction(Action action, ImmutableArray syntaxKinds) { - _syntaxNodeActions = _syntaxNodeActions.Add(new SyntaxNodeAnalyzerAction(action, syntaxKinds, analyzer)); + _syntaxNodeActions = _syntaxNodeActions.Add(new SyntaxNodeAnalyzerAction(action, syntaxKinds, Analyzer)); } } - internal sealed class HostOperationBlockStartAnalysisScope + internal sealed class HostOperationBlockStartAnalysisScope(DiagnosticAnalyzer analyzer) { private ImmutableArray _operationBlockEndActions = ImmutableArray.Empty; private ImmutableArray _operationActions = ImmutableArray.Empty; + private DiagnosticAnalyzer Analyzer { get; } = analyzer; + public ImmutableArray OperationBlockEndActions => _operationBlockEndActions; public ImmutableArray OperationActions => _operationActions; - internal HostOperationBlockStartAnalysisScope() + public void RegisterOperationBlockEndAction(Action action) { + _operationBlockEndActions = _operationBlockEndActions.Add(new OperationBlockAnalyzerAction(action, Analyzer)); } - public void RegisterOperationBlockEndAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterOperationAction(Action action, ImmutableArray operationKinds) { - _operationBlockEndActions = _operationBlockEndActions.Add(new OperationBlockAnalyzerAction(action, analyzer)); - } - - public void RegisterOperationAction(DiagnosticAnalyzer analyzer, Action action, ImmutableArray operationKinds) - { - _operationActions = _operationActions.Add(new OperationAnalyzerAction(action, operationKinds, analyzer)); + _operationActions = _operationActions.Add(new OperationAnalyzerAction(action, operationKinds, Analyzer)); } } - internal abstract class HostAnalysisScope + internal abstract class HostAnalysisScope(DiagnosticAnalyzer analyzer) { - private readonly ConcurrentDictionary> _analyzerActions = new ConcurrentDictionary>(); + private StrongBox? _analyzerActions; + + internal DiagnosticAnalyzer Analyzer { get; } = analyzer; - public virtual AnalyzerActions GetAnalyzerActions(DiagnosticAnalyzer analyzer) + public virtual AnalyzerActions GetAnalyzerActions() { - return this.GetOrCreateAnalyzerActions(analyzer).Value; + return this.GetOrCreateAnalyzerActions().Value; } - public void RegisterCompilationAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterCompilationAction(Action action) { - CompilationAnalyzerAction analyzerAction = new CompilationAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddCompilationAction(analyzerAction); + CompilationAnalyzerAction analyzerAction = new CompilationAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddCompilationAction(analyzerAction); } - public void RegisterCompilationEndAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterCompilationEndAction(Action action) { - CompilationAnalyzerAction analyzerAction = new CompilationAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddCompilationEndAction(analyzerAction); + CompilationAnalyzerAction analyzerAction = new CompilationAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddCompilationEndAction(analyzerAction); } - public void RegisterSemanticModelAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterSemanticModelAction(Action action) { - SemanticModelAnalyzerAction analyzerAction = new SemanticModelAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddSemanticModelAction(analyzerAction); + SemanticModelAnalyzerAction analyzerAction = new SemanticModelAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddSemanticModelAction(analyzerAction); } - public void RegisterSyntaxTreeAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterSyntaxTreeAction(Action action) { - SyntaxTreeAnalyzerAction analyzerAction = new SyntaxTreeAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddSyntaxTreeAction(analyzerAction); + SyntaxTreeAnalyzerAction analyzerAction = new SyntaxTreeAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddSyntaxTreeAction(analyzerAction); } - public void RegisterAdditionalFileAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterAdditionalFileAction(Action action) { - var analyzerAction = new AdditionalFileAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddAdditionalFileAction(analyzerAction); + var analyzerAction = new AdditionalFileAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddAdditionalFileAction(analyzerAction); } - public void RegisterSymbolAction(DiagnosticAnalyzer analyzer, Action action, ImmutableArray symbolKinds) + public void RegisterSymbolAction(Action action, ImmutableArray symbolKinds) { - SymbolAnalyzerAction analyzerAction = new SymbolAnalyzerAction(action, symbolKinds, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddSymbolAction(analyzerAction); + SymbolAnalyzerAction analyzerAction = new SymbolAnalyzerAction(action, symbolKinds, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddSymbolAction(analyzerAction); // The SymbolAnalyzerAction does not handle SymbolKind.Parameter because the compiler // does not make CompilationEvents for them. As a workaround, handle them specially by @@ -549,7 +535,6 @@ public void RegisterSymbolAction(DiagnosticAnalyzer analyzer, Action { ImmutableArray parameters; @@ -592,69 +577,69 @@ public void RegisterSymbolAction(DiagnosticAnalyzer analyzer, Action action, SymbolKind symbolKind) + public void RegisterSymbolStartAction(Action action, SymbolKind symbolKind) { - var analyzerAction = new SymbolStartAnalyzerAction(action, symbolKind, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddSymbolStartAction(analyzerAction); + var analyzerAction = new SymbolStartAnalyzerAction(action, symbolKind, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddSymbolStartAction(analyzerAction); } - public void RegisterSymbolEndAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterSymbolEndAction(Action action) { - var analyzerAction = new SymbolEndAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddSymbolEndAction(analyzerAction); + var analyzerAction = new SymbolEndAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddSymbolEndAction(analyzerAction); } - public void RegisterCodeBlockStartAction(DiagnosticAnalyzer analyzer, Action> action) where TLanguageKindEnum : struct + public void RegisterCodeBlockStartAction(Action> action) where TLanguageKindEnum : struct { - CodeBlockStartAnalyzerAction analyzerAction = new CodeBlockStartAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddCodeBlockStartAction(analyzerAction); + CodeBlockStartAnalyzerAction analyzerAction = new CodeBlockStartAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddCodeBlockStartAction(analyzerAction); } - public void RegisterCodeBlockEndAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterCodeBlockEndAction(Action action) { - CodeBlockAnalyzerAction analyzerAction = new CodeBlockAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddCodeBlockEndAction(analyzerAction); + CodeBlockAnalyzerAction analyzerAction = new CodeBlockAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddCodeBlockEndAction(analyzerAction); } - public void RegisterCodeBlockAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterCodeBlockAction(Action action) { - CodeBlockAnalyzerAction analyzerAction = new CodeBlockAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddCodeBlockAction(analyzerAction); + CodeBlockAnalyzerAction analyzerAction = new CodeBlockAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddCodeBlockAction(analyzerAction); } - public void RegisterSyntaxNodeAction(DiagnosticAnalyzer analyzer, Action action, ImmutableArray syntaxKinds) where TLanguageKindEnum : struct + public void RegisterSyntaxNodeAction(Action action, ImmutableArray syntaxKinds) where TLanguageKindEnum : struct { - SyntaxNodeAnalyzerAction analyzerAction = new SyntaxNodeAnalyzerAction(action, syntaxKinds, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddSyntaxNodeAction(analyzerAction); + SyntaxNodeAnalyzerAction analyzerAction = new SyntaxNodeAnalyzerAction(action, syntaxKinds, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddSyntaxNodeAction(analyzerAction); } - public void RegisterOperationBlockStartAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterOperationBlockStartAction(Action action) { - OperationBlockStartAnalyzerAction analyzerAction = new OperationBlockStartAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddOperationBlockStartAction(analyzerAction); + OperationBlockStartAnalyzerAction analyzerAction = new OperationBlockStartAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddOperationBlockStartAction(analyzerAction); } - public void RegisterOperationBlockEndAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterOperationBlockEndAction(Action action) { - OperationBlockAnalyzerAction analyzerAction = new OperationBlockAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddOperationBlockEndAction(analyzerAction); + OperationBlockAnalyzerAction analyzerAction = new OperationBlockAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddOperationBlockEndAction(analyzerAction); } - public void RegisterOperationBlockAction(DiagnosticAnalyzer analyzer, Action action) + public void RegisterOperationBlockAction(Action action) { - OperationBlockAnalyzerAction analyzerAction = new OperationBlockAnalyzerAction(action, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddOperationBlockAction(analyzerAction); + OperationBlockAnalyzerAction analyzerAction = new OperationBlockAnalyzerAction(action, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddOperationBlockAction(analyzerAction); } - public void RegisterOperationAction(DiagnosticAnalyzer analyzer, Action action, ImmutableArray operationKinds) + public void RegisterOperationAction(Action action, ImmutableArray operationKinds) { - OperationAnalyzerAction analyzerAction = new OperationAnalyzerAction(action, operationKinds, analyzer); - this.GetOrCreateAnalyzerActions(analyzer).Value.AddOperationAction(analyzerAction); + OperationAnalyzerAction analyzerAction = new OperationAnalyzerAction(action, operationKinds, Analyzer); + this.GetOrCreateAnalyzerActions().Value.AddOperationAction(analyzerAction); } - protected StrongBox GetOrCreateAnalyzerActions(DiagnosticAnalyzer analyzer) + protected StrongBox GetOrCreateAnalyzerActions() { - return _analyzerActions.GetOrAdd(analyzer, _ => new StrongBox(AnalyzerActions.Empty)); + return InterlockedOperations.Initialize(ref _analyzerActions, static () => new StrongBox(AnalyzerActions.Empty)); } } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/ShadowCopyAnalyzerAssemblyLoader.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/ShadowCopyAnalyzerAssemblyLoader.cs index 9cc9ed5b29a33..1df2f9c6b5cf7 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/ShadowCopyAnalyzerAssemblyLoader.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/ShadowCopyAnalyzerAssemblyLoader.cs @@ -12,7 +12,7 @@ using System.Collections.Immutable; using System.Reflection; -#if NETCOREAPP +#if NET using System.Runtime.Loader; #endif @@ -43,7 +43,7 @@ internal sealed class ShadowCopyAnalyzerAssemblyLoader : AnalyzerAssemblyLoader internal int CopyCount => _mvidPathMap.Count; -#if NETCOREAPP +#if NET public ShadowCopyAnalyzerAssemblyLoader(string baseDirectory, ImmutableArray? externalResolvers = null) : this(null, baseDirectory, externalResolvers) { diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index cd10a5c8a8eca..e6283ce8b07b2 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -89,6 +89,23 @@ public CommonPEModuleBuilder( /// EnC generation. 0 if the module is not an EnC delta, 1 if it is the first EnC delta, etc. /// public int CurrentGenerationOrdinal => (PreviousGeneration?.Ordinal + 1) ?? 0; + + /// + /// Creates the type definition of HotReloadException type if it has not been synthesized yet and returns its constructor. + /// + public abstract IMethodSymbolInternal GetOrCreateHotReloadExceptionConstructorDefinition(); + + /// + /// Creates the type definition of HotReloadException type if it has not been synthesized yet and the module is an EnC delta. + /// Returns the synthesized type definition or null if the module is not an EnC delta or a user-defined type is already defined in the compilation. + /// + public abstract INamedTypeSymbolInternal? TryGetOrCreateSynthesizedHotReloadExceptionType(); + + /// + /// Returns the HotReloadException type symbol if it has been used in this compilation, null otherwise. + /// + public abstract INamedTypeSymbolInternal? GetUsedSynthesizedHotReloadExceptionType(); + #nullable disable /// @@ -981,6 +998,18 @@ internal override ImmutableDictionary data, ushort alignment, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { - Debug.Assert(alignment is 1 or 2 or 4 or 8, $"Unexpected alignment: {alignment}"); + RoslynDebug.Assert(alignment is 1 or 2 or 4 or 8, $"Unexpected alignment: {alignment}"); var privateImpl = GetPrivateImplClass((TSyntaxNode)syntaxNode, diagnostics); diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs index dfdd6d5956f06..4e8e15699e126 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs @@ -291,14 +291,15 @@ protected abstract void GetStateMachineFieldMapFromMetadata( debugInfo = Baseline.DebugInformationProvider(methodHandle); localSignature = Baseline.LocalSignatureProvider(methodHandle); } - catch (Exception e) when (e is InvalidDataException or IOException) + catch (Exception e) when (e is InvalidDataException or IOException or BadImageFormatException) { diagnostics.Add(MessageProvider.CreateDiagnostic( MessageProvider.ERR_InvalidDebugInfo, method.Locations.First(), method, MetadataTokens.GetToken(methodHandle), - method.ContainingAssembly + method.ContainingAssembly, + e.Message )); return null; @@ -382,7 +383,8 @@ protected abstract void GetStateMachineFieldMapFromMetadata( method.Locations.First(), method, MetadataTokens.GetToken(localSignature), - method.ContainingAssembly + method.ContainingAssembly, + e.Message )); return null; @@ -418,9 +420,9 @@ internal MethodInstrumentation GetMethodBodyInstrumentations(IMethodSymbolIntern private void ReportMissingStateMachineAttribute(DiagnosticBag diagnostics, IMethodSymbolInternal method, string stateMachineAttributeFullName) { diagnostics.Add(MessageProvider.CreateDiagnostic( - MessageProvider.ERR_EncUpdateFailedMissingAttribute, + MessageProvider.ERR_EncUpdateFailedMissingSymbol, method.Locations.First(), - MessageProvider.GetErrorDisplayString(method.GetISymbol()), + CodeAnalysisResources.Attribute, stateMachineAttributeFullName)); } @@ -690,7 +692,7 @@ static ImmutableArray getHoistedVariableNames(ImmutableArray GetIL(EmitContext context, RuntimeRudeEdit? rudeEdit, bool isLambdaOrLocalFunction) { - var missingMethodExceptionStringStringConstructor = context.Module.CommonCompilation.CommonGetWellKnownTypeMember(WellKnownMember.System_MissingMethodException__ctorString); - Debug.Assert(missingMethodExceptionStringStringConstructor is not null); + var hotReloadExceptionCtorDef = context.Module.GetOrCreateHotReloadExceptionConstructorDefinition(); var builder = new ILBuilder((ITokenDeferral)context.Module, null, OptimizationLevel.Debug, false); - builder.EmitStringConstant(rudeEdit.HasValue - ? string.Format(CodeAnalysisResources.EncLambdaRudeEdit, rudeEdit.Value.Message) - : isLambdaOrLocalFunction - ? CodeAnalysisResources.EncDeletedLambdaInvoked - : CodeAnalysisResources.EncDeletedMethodInvoked); - - builder.EmitOpCode(ILOpCode.Newobj, 4); - builder.EmitToken(missingMethodExceptionStringStringConstructor.GetCciAdapter(), context.SyntaxNode!, context.Diagnostics); + string message; + int codeValue; + if (rudeEdit.HasValue) + { + message = string.Format(CodeAnalysisResources.EncLambdaRudeEdit, rudeEdit.Value.Message); + codeValue = rudeEdit.Value.ErrorCode; + } + else + { + var code = isLambdaOrLocalFunction ? HotReloadExceptionCode.DeletedLambdaInvoked : HotReloadExceptionCode.DeletedMethodInvoked; + message = code.GetExceptionMessage(); + codeValue = code.GetExceptionCodeValue(); + } + + builder.EmitStringConstant(message); + builder.EmitIntConstant(codeValue); + + // consumes message and code, pushes the created exception object: + builder.EmitOpCode(ILOpCode.Newobj, stackAdjustment: -1); + builder.EmitToken(hotReloadExceptionCtorDef.GetCciAdapter(), context.SyntaxNode!, context.Diagnostics); builder.EmitThrow(isRethrow: false); builder.Realize(); diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index 07673f9307922..21ebe9f2bab02 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -34,13 +34,8 @@ internal sealed class DeltaMetadataWriter : MetadataWriter /// private readonly List _changedTypeDefs; - /// - /// Cache of type definitions used in signatures of deleted members. Used so that if a method 'C M(C c)' is deleted - /// we use the same instance for the method return type, and the parameter type. - /// - private readonly Dictionary _typesUsedByDeletedMembers; - private readonly Dictionary> _deletedTypeMembers; + private readonly IReadOnlyDictionary> _deletedMethodDefs; private readonly DefinitionIndex _typeDefs; private readonly DefinitionIndex _eventDefs; @@ -80,6 +75,7 @@ public DeltaMetadataWriter( Guid encId, DefinitionMap definitionMap, SymbolChanges changes, + IReadOnlyDictionary> deletedMethodDefs, CancellationToken cancellationToken) : base(metadata: MakeTablesBuilder(previousGeneration), debugMetadataOpt: (context.Module.DebugInformationFormat == DebugInformationFormat.PortablePdb) ? new MetadataBuilder() : null, @@ -104,8 +100,8 @@ public DeltaMetadataWriter( var sizes = previousGeneration.TableSizes; _changedTypeDefs = new List(); - _typesUsedByDeletedMembers = new Dictionary(ReferenceEqualityComparer.Instance); _deletedTypeMembers = new Dictionary>(ReferenceEqualityComparer.Instance); + _deletedMethodDefs = deletedMethodDefs; _typeDefs = new DefinitionIndex(this.TryGetExistingTypeDefIndex, sizes[(int)TableIndex.TypeDef]); _eventDefs = new DefinitionIndex(this.TryGetExistingEventDefIndex, sizes[(int)TableIndex.Event]); _fieldDefs = new DefinitionIndex(this.TryGetExistingFieldDefIndex, sizes[(int)TableIndex.Field]); @@ -496,6 +492,101 @@ protected override void OnIndicesCreated() module.OnCreatedIndices(this.Context.Diagnostics); } + internal static IReadOnlyDictionary> CreateDeletedMethodsDefs(EmitContext context, SymbolChanges changes) + { + var result = new Dictionary>(ReferenceEqualityComparer.Instance); + var typesUsedByDeletedMembers = new Dictionary(ReferenceEqualityComparer.Instance); + + foreach (var typeDef in context.Module.GetTopLevelTypeDefinitions(context)) + { + recurse(typeDef); + } + + return result; + + void recurse(ITypeDefinition typeDef) + { + var deletedMethodDefs = getDeletedMethodDefs(typeDef); + if (deletedMethodDefs?.Count > 0) + { + result.Add(typeDef, deletedMethodDefs); + } + + foreach (var nestedType in typeDef.GetNestedTypes(context)) + { + recurse(nestedType); + } + } + + ArrayBuilder? getDeletedMethodDefs(ITypeDefinition typeDef) + { + if (typeDef.GetInternalSymbol() is INamedTypeSymbolInternal typeSymbol && + (changes.DeletedMembers.TryGetValue(typeSymbol, out var deletedMembers) | + changes.UpdatedMethods.TryGetValue(typeSymbol, out var updatedMethods))) + { + // create representations of the old deleted methods in this compilation: + + var newMethodDefs = ArrayBuilder.GetInstance(); + + ImmutableArray? lazyDeletedMethodIL = null; + ImmutableArray? lazyDeletedLambdaIL = null; + + foreach (var deletedMember in deletedMembers.NullToEmpty()) + { + if (deletedMember is IMethodSymbolInternal deletedMethod) + { + var deletedMethodHandle = changes.DefinitionMap.GetPreviousMethodHandle(deletedMethod); + var deletedMethodDef = (IMethodDefinition)deletedMethod.GetCciAdapter(); + + lazyDeletedMethodIL ??= DeletedMethodBody.GetIL(context, rudeEdit: null, isLambdaOrLocalFunction: false); + + newMethodDefs.Add(new DeletedSourceMethodDefinition(deletedMethodDef, deletedMethodHandle, lazyDeletedMethodIL.Value, typesUsedByDeletedMembers)); + + addDeletedClosureMethods(deletedMethod, currentLambdas: ImmutableArray.Empty, ImmutableArray.Empty); + } + } + + foreach (var (oldMethod, newMethod) in updatedMethods.NullToEmpty()) + { + var newMethodDef = (IMethodDefinition)newMethod.GetCciAdapter(); + + var (currentLambdas, rudeEdits) = (newMethodDef.HasBody && newMethodDef.GetBody(context) is { } body) ? + (body.LambdaDebugInfo, body.OrderedLambdaRuntimeRudeEdits) : + (ImmutableArray.Empty, ImmutableArray.Empty); + + addDeletedClosureMethods(oldMethod, currentLambdas, rudeEdits); + } + + void addDeletedClosureMethods(IMethodSymbolInternal oldMethod, ImmutableArray currentLambdas, ImmutableArray orderedLambdaRuntimeRudeEdits) + { + foreach (var (lambdaId, deletedClosureMethod) in changes.DefinitionMap.GetDeletedSynthesizedMethods(oldMethod, currentLambdas)) + { + var rudeEditIndex = orderedLambdaRuntimeRudeEdits.BinarySearch(lambdaId, static (rudeEdit, lambdaId) => rudeEdit.LambdaId.CompareTo(lambdaId)); + + var il = (rudeEditIndex >= 0) + ? DeletedMethodBody.GetIL(context, orderedLambdaRuntimeRudeEdits[rudeEditIndex].RudeEdit, isLambdaOrLocalFunction: true) + : lazyDeletedLambdaIL ??= DeletedMethodBody.GetIL(context, rudeEdit: null, isLambdaOrLocalFunction: true); + + if (deletedClosureMethod.MetadataToken != 0) + { + newMethodDefs.Add(new DeletedPEMethodDefinition(deletedClosureMethod, il)); + } + else + { + var deletedClosureMethodDef = (IMethodDefinition)deletedClosureMethod.GetCciAdapter(); + var deletedClosureMethodHandle = changes.DefinitionMap.GetPreviousMethodHandle(deletedClosureMethod); + newMethodDefs.Add(new DeletedSourceMethodDefinition(deletedClosureMethodDef, deletedClosureMethodHandle, il, typesUsedByDeletedMembers)); + } + } + } + + return newMethodDefs; + } + + return null; + } + } + protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) { var change = _changes.GetChange(typeDef); @@ -563,77 +654,15 @@ protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) CreateIndicesForMethod(methodDef, methodChange); } - if (typeDef.GetInternalSymbol() is INamedTypeSymbolInternal typeSymbol && - (_changes.DeletedMembers.TryGetValue(typeSymbol, out var deletedMembers) | - _changes.UpdatedMethods.TryGetValue(typeSymbol, out var updatedMethods))) + if (_deletedMethodDefs.TryGetValue(typeDef, out var newMethodDefs)) { - // create representations of the old deleted methods in this compilation: - var newMethodDefs = ArrayBuilder.GetInstance(); - - ImmutableArray? lazyDeletedMethodIL = null; - ImmutableArray? lazyDeletedLambdaIL = null; - - foreach (var deletedMember in deletedMembers.NullToEmpty()) - { - if (deletedMember is IMethodSymbolInternal deletedMethod) - { - var deletedMethodHandle = _definitionMap.GetPreviousMethodHandle(deletedMethod); - var deletedMethodDef = (IMethodDefinition)deletedMethod.GetCciAdapter(); - - lazyDeletedMethodIL ??= DeletedMethodBody.GetIL(Context, rudeEdit: null, isLambdaOrLocalFunction: false); - - newMethodDefs.Add(new DeletedSourceMethodDefinition(deletedMethodDef, deletedMethodHandle, lazyDeletedMethodIL.Value, _typesUsedByDeletedMembers)); - - addDeletedClosureMethods(deletedMethod, currentLambdas: ImmutableArray.Empty, ImmutableArray.Empty); - } - } - - foreach (var (oldMethod, newMethod) in updatedMethods.NullToEmpty()) + // Assign the deleted method and its parameters row ids in the delta metadata: + foreach (var newMethodDef in newMethodDefs) { - var newMethodDef = (IMethodDefinition)newMethod.GetCciAdapter(); - - var (currentLambdas, rudeEdits) = (newMethodDef.HasBody && newMethodDef.GetBody(Context) is { } body) ? - (body.LambdaDebugInfo, body.OrderedLambdaRuntimeRudeEdits) : - (ImmutableArray.Empty, ImmutableArray.Empty); - - addDeletedClosureMethods(oldMethod, currentLambdas, rudeEdits); + _methodDefs.AddUpdated(newMethodDef); } - void addDeletedClosureMethods(IMethodSymbolInternal oldMethod, ImmutableArray currentLambdas, ImmutableArray orderedLambdaRuntimeRudeEdits) - { - foreach (var (lambdaId, deletedClosureMethod) in _definitionMap.GetDeletedSynthesizedMethods(oldMethod, currentLambdas)) - { - var rudeEditIndex = orderedLambdaRuntimeRudeEdits.BinarySearch(lambdaId, static (rudeEdit, lambdaId) => rudeEdit.LambdaId.CompareTo(lambdaId)); - - var il = (rudeEditIndex >= 0) - ? DeletedMethodBody.GetIL(Context, orderedLambdaRuntimeRudeEdits[rudeEditIndex].RudeEdit, isLambdaOrLocalFunction: true) - : lazyDeletedLambdaIL ??= DeletedMethodBody.GetIL(Context, rudeEdit: null, isLambdaOrLocalFunction: true); - - if (deletedClosureMethod.MetadataToken != 0) - { - newMethodDefs.Add(new DeletedPEMethodDefinition(deletedClosureMethod, il)); - } - else - { - var deletedClosureMethodDef = (IMethodDefinition)deletedClosureMethod.GetCciAdapter(); - var deletedClosureMethodHandle = _definitionMap.GetPreviousMethodHandle(deletedClosureMethod); - newMethodDefs.Add(new DeletedSourceMethodDefinition(deletedClosureMethodDef, deletedClosureMethodHandle, il, _typesUsedByDeletedMembers)); - } - } - } - - if (newMethodDefs is not []) - { - // Assign the deleted method and its parameters row ids in the delta metadata: - foreach (var newMethodDef in newMethodDefs) - { - _methodDefs.AddUpdated(newMethodDef); - } - - _deletedTypeMembers.Add(typeDef, newMethodDefs.ToImmutable()); - } - - newMethodDefs.Free(); + _deletedTypeMembers.Add(typeDef, newMethodDefs.ToImmutable()); } foreach (var propertyDef in typeDef.GetProperties(this.Context)) @@ -1803,6 +1832,11 @@ public DeltaReferenceIndexer(DeltaMetadataWriter writer) public override void Visit(CommonPEModuleBuilder module) { Visit(module.GetTopLevelTypeDefinitions(metadataWriter.Context)); + + if (module.GetUsedSynthesizedHotReloadExceptionType() is { } hotReloadException) + { + Visit((INamedTypeDefinition)hotReloadException.GetCciAdapter()); + } } public override void Visit(IEventDefinition eventDefinition) diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs index 6a719124dba43..ce841a9541f89 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs @@ -318,7 +318,7 @@ public override bool TryGetPreviousClosure( // closure shape changed: closureId = default; - runtimeRudeEdit = new RuntimeRudeEdit(CodeAnalysisResources.EncLambdaRudeEdit_CapturedVariables); + runtimeRudeEdit = new RuntimeRudeEdit(HotReloadExceptionCode.UnsupportedChangeToCapturedVariables); return false; } @@ -345,7 +345,7 @@ public override bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, b // lambda closure changed: lambdaId = default; - runtimeRudeEdit = new RuntimeRudeEdit(CodeAnalysisResources.EncLambdaRudeEdit_CapturedVariables); + runtimeRudeEdit = new RuntimeRudeEdit(HotReloadExceptionCode.UnsupportedChangeToCapturedVariables); return false; } diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs index 89c2cf1fd101a..a8c2777cf8d08 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs @@ -412,9 +412,8 @@ private void CalculateChanges( var newMember = GetRequiredInternalSymbol(edit.NewSymbol); - // Partial methods are supplied as implementations but recorded + // Partial methods/properties/indexers are supplied as implementations but recorded // internally as definitions since definitions are used in emit. - // https://github.com/dotnet/roslyn/issues/73772: should we also make sure to use the definition for a partial property? if (newMember.Kind == SymbolKind.Method) { var newMethod = (IMethodSymbolInternal)newMember; @@ -438,6 +437,16 @@ private void CalculateChanges( updatedMethodsPerType.Add((oldMethod.PartialDefinitionPart ?? oldMethod, (IMethodSymbolInternal)newMember)); } } + else if (newMember.Kind == SymbolKind.Property) + { + var newProperty = (IPropertySymbolInternal)newMember; + + // Partial properties should be implementations, not definitions. + Debug.Assert(newProperty.PartialImplementationPart == null); + Debug.Assert(edit.OldSymbol == null || ((IPropertySymbol)edit.OldSymbol).PartialImplementationPart == null); + + newMember = newProperty.PartialDefinitionPart ?? newMember; + } AddContainingSymbolChanges(changesBuilder, newMember); diff --git a/src/Compilers/Core/Portable/Emit/HotReloadExceptionCode.cs b/src/Compilers/Core/Portable/Emit/HotReloadExceptionCode.cs new file mode 100644 index 0000000000000..945398d9941d2 --- /dev/null +++ b/src/Compilers/Core/Portable/Emit/HotReloadExceptionCode.cs @@ -0,0 +1,36 @@ +// 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.Emit; + +/// +/// Values of synthesized HotReloadException.Code field. +/// +internal enum HotReloadExceptionCode +{ + DeletedLambdaInvoked = 1, + DeletedMethodInvoked = 2, + CannotResumeSuspendedIteratorMethod = 3, + CannotResumeSuspendedAsyncMethod = 4, + UnsupportedChangeToCapturedVariables = 5, +} + +internal static class HotReloadExceptionCodeExtensions +{ + public static string GetExceptionMessage(this HotReloadExceptionCode code) + => code switch + { + HotReloadExceptionCode.DeletedLambdaInvoked => CodeAnalysisResources.EncDeletedLambdaInvoked, + HotReloadExceptionCode.DeletedMethodInvoked => CodeAnalysisResources.EncDeletedMethodInvoked, + HotReloadExceptionCode.CannotResumeSuspendedIteratorMethod => CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod, + HotReloadExceptionCode.CannotResumeSuspendedAsyncMethod => CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod, + HotReloadExceptionCode.UnsupportedChangeToCapturedVariables => CodeAnalysisResources.EncLambdaRudeEdit_CapturedVariables, + _ => throw ExceptionUtilities.UnexpectedValue(code) + }; + + public static int GetExceptionCodeValue(this HotReloadExceptionCode code) + => -(int)code; +} diff --git a/src/Compilers/Core/Portable/Emit/RuntimeRudeEdit.cs b/src/Compilers/Core/Portable/Emit/RuntimeRudeEdit.cs index 7c8723aa0d431..f9ead072244ad 100644 --- a/src/Compilers/Core/Portable/Emit/RuntimeRudeEdit.cs +++ b/src/Compilers/Core/Portable/Emit/RuntimeRudeEdit.cs @@ -2,16 +2,45 @@ // 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.Emit; /// /// Describes rude edit to be reported at runtime. /// -/// Error message. -public readonly struct RuntimeRudeEdit(string message) +public readonly struct RuntimeRudeEdit { - public string Message { get; } = message; + /// + /// Error message. + /// + public string Message { get; } + + /// + /// Error code. + /// + public int ErrorCode { get; } + + [Obsolete("Specify errorCode")] + public RuntimeRudeEdit(string message) + : this(message, errorCode: 0) + { + } + + public RuntimeRudeEdit(string message, int errorCode) + { + if (errorCode < 0) + { + throw new ArgumentOutOfRangeException(nameof(errorCode)); + } + + Message = message; + ErrorCode = errorCode; + } - internal bool IsDefault - => Message is null; + internal RuntimeRudeEdit(HotReloadExceptionCode code) + { + Message = code.GetExceptionMessage(); + ErrorCode = code.GetExceptionCodeValue(); + } } diff --git a/src/Compilers/Core/Portable/Emit/SemanticEdit.cs b/src/Compilers/Core/Portable/Emit/SemanticEdit.cs index 14cec150ebc50..1a55b7db49c21 100644 --- a/src/Compilers/Core/Portable/Emit/SemanticEdit.cs +++ b/src/Compilers/Core/Portable/Emit/SemanticEdit.cs @@ -142,15 +142,14 @@ public SemanticEdit(SemanticEditKind kind, ISymbol? oldSymbol, ISymbol? newSymbo } } - // https://github.com/dotnet/roslyn/issues/73772: should we also do this check for partial properties? - if (oldSymbol is IMethodSymbol { PartialImplementationPart: not null }) + if (oldSymbol is IMethodSymbol { PartialImplementationPart: not null } or IPropertySymbol { PartialImplementationPart: not null }) { - throw new ArgumentException("Partial method implementation required", nameof(oldSymbol)); + throw new ArgumentException("Partial member implementation required", nameof(oldSymbol)); } - if (newSymbol is IMethodSymbol { PartialImplementationPart: not null }) + if (newSymbol is IMethodSymbol { PartialImplementationPart: not null } or IPropertySymbol { PartialImplementationPart: not null }) { - throw new ArgumentException("Partial method implementation required", nameof(newSymbol)); + throw new ArgumentException("Partial member implementation required", nameof(newSymbol)); } if (kind == SemanticEditKind.Delete && oldSymbol is not (IMethodSymbol or IPropertySymbol or IEventSymbol)) diff --git a/src/Compilers/Core/Portable/Generated/FlowAnalysis.Generated.cs b/src/Compilers/Core/Portable/Generated/FlowAnalysis.Generated.cs index ba879b058a5d1..58caf7901843c 100644 --- a/src/Compilers/Core/Portable/Generated/FlowAnalysis.Generated.cs +++ b/src/Compilers/Core/Portable/Generated/FlowAnalysis.Generated.cs @@ -54,7 +54,7 @@ public interface IFlowCaptureReferenceOperation : IOperation /// CaptureId Id { get; } /// - /// True if this reference to the capture initializes the capture. Used when the capture is being initialized by being passed as an out parameter. + /// True if this reference to the capture initializes the capture. Used when the capture is being initialized by being passed as an parameter. /// bool IsInitialization { get; } } @@ -120,8 +120,10 @@ public interface IStaticLocalInitializationSemaphoreOperation : IOperation /// Represents an anonymous function operation in context of a . /// /// Current usage: - /// (1) C# lambda expression. - /// (2) VB anonymous delegate expression. + /// + /// C# lambda expression + /// VB anonymous delegate expression + /// /// /// A for the body of the anonymous function is available from /// the enclosing . diff --git a/src/Compilers/Core/Portable/Generated/Operations.Generated.cs b/src/Compilers/Core/Portable/Generated/Operations.Generated.cs index 3e4a2896be2fc..0e746e0226c27 100644 --- a/src/Compilers/Core/Portable/Generated/Operations.Generated.cs +++ b/src/Compilers/Core/Portable/Generated/Operations.Generated.cs @@ -19,8 +19,10 @@ namespace Microsoft.CodeAnalysis.Operations /// Represents an invalid operation with one or more child operations. /// /// Current usage: - /// (1) C# invalid expression or invalid statement. - /// (2) VB invalid expression or invalid statement. + /// + /// C# invalid expression or invalid statement + /// VB invalid expression or invalid statement + /// /// /// /// @@ -38,8 +40,10 @@ public interface IInvalidOperation : IOperation /// Represents a block containing a sequence of operations and local declarations. /// /// Current usage: - /// (1) C# "{ ... }" block statement. - /// (2) VB implicit block statement for method bodies and other block scoped statements. + /// + /// C# "{ ... }" block statement + /// VB implicit block statement for method bodies and other block scoped statements + /// /// /// /// @@ -63,16 +67,18 @@ public interface IBlockOperation : IOperation } /// /// Represents a variable declaration statement. - /// /// /// Current Usage: - /// (1) C# local declaration statement - /// (2) C# fixed statement - /// (3) C# using statement - /// (4) C# using declaration - /// (5) VB Dim statement - /// (6) VB Using statement + /// + /// C# local declaration statement + /// C# fixed statement + /// C# using statement + /// C# using declaration + /// VB Dim statement + /// VB Using statement + /// /// + /// /// /// This node is associated with the following operation kinds: /// @@ -95,8 +101,10 @@ public interface IVariableDeclarationGroupOperation : IOperation /// Represents a switch operation with a value to be switched upon and switch cases. /// /// Current usage: - /// (1) C# switch statement. - /// (2) VB Select Case statement. + /// + /// C# switch statement + /// VB Select Case statement + /// /// /// /// @@ -130,8 +138,10 @@ public interface ISwitchOperation : IOperation /// Represents a loop operation. /// /// Current usage: - /// (1) C# 'while', 'for', 'foreach' and 'do' loop statements - /// (2) VB 'While', 'ForTo', 'ForEach', 'Do While' and 'Do Until' loop statements + /// + /// C# 'while', 'for', 'foreach' and 'do' loop statements + /// VB 'While', 'ForTo', 'ForEach', 'Do While' and 'Do Until' loop statements + /// /// /// /// @@ -165,8 +175,10 @@ public interface ILoopOperation : IOperation /// Represents a for each loop. /// /// Current usage: - /// (1) C# 'foreach' loop statement - /// (2) VB 'For Each' loop statement + /// + /// C# 'foreach' loop statement + /// VB 'For Each' loop statement + /// /// /// /// @@ -198,7 +210,9 @@ public interface IForEachLoopOperation : ILoopOperation /// Represents a for loop. /// /// Current usage: - /// (1) C# 'for' loop statement + /// + /// C# 'for' loop statement + /// /// /// /// @@ -230,7 +244,9 @@ public interface IForLoopOperation : ILoopOperation /// Represents a for to loop with loop control variable and initial, limit and step values for the control variable. /// /// Current usage: - /// (1) VB 'For ... To ... Step' loop statement + /// + /// VB 'For ... To ... Step' loop statement + /// /// /// /// @@ -257,7 +273,7 @@ public interface IForToLoopOperation : ILoopOperation /// IOperation StepValue { get; } /// - /// true if arithmetic operations behind this loop are 'checked'. + /// if arithmetic operations behind this loop are 'checked'. /// bool IsChecked { get; } /// @@ -269,8 +285,10 @@ public interface IForToLoopOperation : ILoopOperation /// Represents a while or do while loop. /// /// Current usage: - /// (1) C# 'while' and 'do while' loop statements. - /// (2) VB 'While', 'Do While' and 'Do Until' loop statements. + /// + /// C# 'while' and 'do while' loop statements + /// VB 'While', 'Do While' and 'Do Until' loop statements + /// /// /// /// @@ -304,8 +322,10 @@ public interface IWhileLoopOperation : ILoopOperation /// Represents an operation with a label. /// /// Current usage: - /// (1) C# labeled statement. - /// (2) VB label statement. + /// + /// C# labeled statement + /// VB label statement + /// /// /// /// @@ -331,8 +351,10 @@ public interface ILabeledOperation : IOperation /// Represents a branch operation. /// /// Current usage: - /// (1) C# goto, break, or continue statement. - /// (2) VB GoTo, Exit ***, or Continue *** statement. + /// + /// C# goto, break, or continue statement + /// VB GoTo, Exit ***, or Continue *** statement + /// /// /// /// @@ -358,7 +380,9 @@ public interface IBranchOperation : IOperation /// Represents an empty or no-op operation. /// /// Current usage: - /// (1) C# empty statement. + /// + /// C# empty statement + /// /// /// /// @@ -376,8 +400,10 @@ public interface IEmptyOperation : IOperation /// Represents a return from the method with an optional return value. /// /// Current usage: - /// (1) C# return statement and yield statement. - /// (2) VB Return statement. + /// + /// C# return statement and yield statement + /// VB Return statement + /// /// /// /// @@ -401,8 +427,10 @@ public interface IReturnOperation : IOperation /// Represents a of operations that are executed while holding a lock onto the . /// /// Current usage: - /// (1) C# lock statement. - /// (2) VB SyncLock statement. + /// + /// C# lock statement + /// VB SyncLock statement + /// /// /// /// @@ -428,8 +456,10 @@ public interface ILockOperation : IOperation /// Represents a try operation for exception handling code with a body, catch clauses and a finally handler. /// /// Current usage: - /// (1) C# try statement. - /// (2) VB Try statement. + /// + /// C# try statement + /// VB Try statement + /// /// /// /// @@ -463,8 +493,10 @@ public interface ITryOperation : IOperation /// Represents a of operations that are executed while using disposable . /// /// Current usage: - /// (1) C# using statement. - /// (2) VB Using statement. + /// + /// C# using statement + /// VB Using statement + /// /// /// /// @@ -499,8 +531,10 @@ public interface IUsingOperation : IOperation /// Represents an operation that drops the resulting value and the type of the underlying wrapped . /// /// Current usage: - /// (1) C# expression statement. - /// (2) VB expression statement. + /// + /// C# expression statement + /// VB expression statement + /// /// /// /// @@ -522,7 +556,9 @@ public interface IExpressionStatementOperation : IOperation /// Represents a local function defined within a method. /// /// Current usage: - /// (1) C# local function statement. + /// + /// C# local function statement + /// /// /// /// @@ -558,7 +594,9 @@ public interface ILocalFunctionOperation : IOperation /// Represents an operation to stop or suspend execution of code. /// /// Current usage: - /// (1) VB Stop statement. + /// + /// VB Stop statement + /// /// /// /// @@ -576,7 +614,9 @@ public interface IStopOperation : IOperation /// Represents an operation that stops the execution of code abruptly. /// /// Current usage: - /// (1) VB End Statement. + /// + /// VB End Statement + /// /// /// /// @@ -594,7 +634,9 @@ public interface IEndOperation : IOperation /// Represents an operation for raising an event. /// /// Current usage: - /// (1) VB raise event statement. + /// + /// VB raise event statement + /// /// /// /// @@ -624,8 +666,10 @@ public interface IRaiseEventOperation : IOperation /// Represents a textual literal numeric, string, etc. /// /// Current usage: - /// (1) C# literal expression. - /// (2) VB literal expression. + /// + /// C# literal expression + /// VB literal expression + /// /// /// /// @@ -643,8 +687,10 @@ public interface ILiteralOperation : IOperation /// Represents a type conversion. /// /// Current usage: - /// (1) C# conversion expression. - /// (2) VB conversion expression. + /// + /// C# conversion expression + /// VB conversion expression + /// /// /// /// @@ -693,15 +739,25 @@ public interface IConversionOperation : IOperation /// Represents an invocation of a method. /// /// Current usage: - /// (1) C# method invocation expression. - /// (2) C# collection element initializer. - /// For example, in the following collection initializer: new C() { 1, 2, 3 }, we will have - /// 3 nodes, each of which will be a call to the corresponding Add method - /// with either 1, 2, 3 as the argument. - /// (3) VB method invocation expression. - /// (4) VB collection element initializer. - /// Similar to the C# example, New C() From {1, 2, 3} will have 3 - /// nodes with 1, 2, and 3 as their arguments, respectively. + /// + /// C# method invocation expression + /// + /// + /// C# collection element initializer. + /// For example, in the following collection initializer: new C() { 1, 2, 3 }, we will have + /// 3 nodes, each of which will be a call to the corresponding Add method + /// with either 1, 2, 3 as the argument + /// + /// + /// VB method invocation expression + /// + /// + /// VB collection element initializer. + /// Similar to the C# example, New C() From {1, 2, 3} will have 3 + /// nodes with 1, 2, and 3 as their arguments, respectively + /// + /// + /// /// /// /// @@ -744,8 +800,10 @@ public interface IInvocationOperation : IOperation /// Represents a reference to an array element. /// /// Current usage: - /// (1) C# array element reference expression. - /// (2) VB array element reference expression. + /// + /// C# array element reference expression + /// VB array element reference expression + /// /// /// /// @@ -771,8 +829,10 @@ public interface IArrayElementReferenceOperation : IOperation /// Represents a reference to a declared local variable. /// /// Current usage: - /// (1) C# local reference expression. - /// (2) VB local reference expression. + /// + /// C# local reference expression + /// VB local reference expression + /// /// /// /// @@ -799,8 +859,10 @@ public interface ILocalReferenceOperation : IOperation /// Represents a reference to a parameter. /// /// Current usage: - /// (1) C# parameter reference expression. - /// (2) VB parameter reference expression. + /// + /// C# parameter reference expression + /// VB parameter reference expression + /// /// /// /// @@ -822,8 +884,10 @@ public interface IParameterReferenceOperation : IOperation /// Represents a reference to a member of a class, struct, or interface. /// /// Current usage: - /// (1) C# member reference expression. - /// (2) VB member reference expression. + /// + /// C# member reference expression + /// VB member reference expression + /// /// /// /// @@ -850,8 +914,10 @@ public interface IMemberReferenceOperation : IOperation /// Represents a reference to a field. /// /// Current usage: - /// (1) C# field reference expression. - /// (2) VB field reference expression. + /// + /// C# field reference expression + /// VB field reference expression + /// /// /// /// @@ -881,8 +947,10 @@ public interface IFieldReferenceOperation : IMemberReferenceOperation /// Represents a reference to a method other than as the target of an invocation. /// /// Current usage: - /// (1) C# method reference expression. - /// (2) VB method reference expression. + /// + /// C# method reference expression + /// VB method reference expression + /// /// /// /// @@ -908,8 +976,10 @@ public interface IMethodReferenceOperation : IMemberReferenceOperation /// Represents a reference to a property. /// /// Current usage: - /// (1) C# property reference expression. - /// (2) VB property reference expression. + /// + /// C# property reference expression + /// VB property reference expression + /// /// /// /// @@ -939,8 +1009,10 @@ public interface IPropertyReferenceOperation : IMemberReferenceOperation /// Represents a reference to an event. /// /// Current usage: - /// (1) C# event reference expression. - /// (2) VB event reference expression. + /// + /// C# event reference expression + /// VB event reference expression + /// /// /// /// @@ -962,8 +1034,10 @@ public interface IEventReferenceOperation : IMemberReferenceOperation /// Represents an operation with one operand and a unary operator. /// /// Current usage: - /// (1) C# unary operation expression. - /// (2) VB unary operation expression. + /// + /// C# unary operation expression + /// VB unary operation expression + /// /// /// /// @@ -1010,8 +1084,10 @@ public interface IUnaryOperation : IOperation /// Represents an operation with two operands and a binary operator that produces a result with a non-null type. /// /// Current usage: - /// (1) C# binary operator expression. - /// (2) VB binary operator expression. + /// + /// C# binary operator expression + /// VB binary operator expression + /// /// /// /// @@ -1065,13 +1141,17 @@ public interface IBinaryOperation : IOperation } /// /// Represents a conditional operation with: - /// (1) to be tested, - /// (2) operation to be executed when is true and - /// (3) operation to be executed when the is false. + /// + /// to be tested + /// operation to be executed when is true and + /// operation to be executed when the is false + /// /// /// Current usage: - /// (1) C# ternary expression "a ? b : c" and if statement. - /// (2) VB ternary expression "If(a, b, c)" and If Else statement. + /// + /// C# ternary expression a ? b : c and if statement + /// VB ternary expression If(a, b, c) and If Else statement + /// /// /// /// @@ -1103,12 +1183,16 @@ public interface IConditionalOperation : IOperation } /// /// Represents a coalesce operation with two operands: - /// (1) , which is the first operand that is unconditionally evaluated and is the result of the operation if non null. - /// (2) , which is the second operand that is conditionally evaluated and is the result of the operation if is null. + /// + /// , which is the first operand that is unconditionally evaluated and is the result of the operation if non null + /// , which is the second operand that is conditionally evaluated and is the result of the operation if is null + /// /// /// Current usage: - /// (1) C# null-coalescing expression "Value ?? WhenNull". - /// (2) VB binary conditional expression "If(Value, WhenNull)". + /// + /// C# null-coalescing expression Value ?? WhenNull + /// VB binary conditional expression If(Value, WhenNull) + /// /// /// /// @@ -1141,8 +1225,10 @@ public interface ICoalesceOperation : IOperation /// Represents an anonymous function operation. /// /// Current usage: - /// (1) C# lambda expression. - /// (2) VB anonymous delegate expression. + /// + /// C# lambda expression + /// VB anonymous delegate expression + /// /// /// /// @@ -1168,8 +1254,10 @@ public interface IAnonymousFunctionOperation : IOperation /// Represents creation of an object instance. /// /// Current usage: - /// (1) C# new expression. - /// (2) VB New expression. + /// + /// C# new expression + /// VB New expression + /// /// /// /// @@ -1203,8 +1291,10 @@ public interface IObjectCreationOperation : IOperation /// Represents a creation of a type parameter object, i.e. new T(), where T is a type parameter with new constraint. /// /// Current usage: - /// (1) C# type parameter object creation expression. - /// (2) VB type parameter object creation expression. + /// + /// C# type parameter object creation expression + /// VB type parameter object creation expression + /// /// /// /// @@ -1226,8 +1316,10 @@ public interface ITypeParameterObjectCreationOperation : IOperation /// Represents the creation of an array instance. /// /// Current usage: - /// (1) C# array creation expression. - /// (2) VB array creation expression. + /// + /// C# array creation expression + /// VB array creation expression + /// /// /// /// @@ -1253,10 +1345,12 @@ public interface IArrayCreationOperation : IOperation /// Represents an implicit/explicit reference to an instance. /// /// Current usage: - /// (1) C# this or base expression. - /// (2) VB Me, MyClass, or MyBase expression. - /// (3) C# object or collection or 'with' expression initializers. - /// (4) VB With statements, object or collection initializers. + /// + /// C# this or base expression + /// VB Me, MyClass, or MyBase expression + /// C# object or collection or 'with' expression initializers + /// VB With statements, object or collection initializers + /// /// /// /// @@ -1278,8 +1372,10 @@ public interface IInstanceReferenceOperation : IOperation /// Represents an operation that tests if a value is of a specific type. /// /// Current usage: - /// (1) C# "is" operator expression. - /// (2) VB "TypeOf" and "TypeOf IsNot" expression. + /// + /// C# "is" operator expression + /// VB "TypeOf" and "TypeOf IsNot" expression + /// /// /// /// @@ -1311,8 +1407,10 @@ public interface IIsTypeOperation : IOperation /// Represents an await operation. /// /// Current usage: - /// (1) C# await expression. - /// (2) VB await expression. + /// + /// C# await expression + /// VB await expression + /// /// /// /// @@ -1334,8 +1432,10 @@ public interface IAwaitOperation : IOperation /// Represents a base interface for assignments. /// /// Current usage: - /// (1) C# simple, compound and deconstruction assignment expressions. - /// (2) VB simple and compound assignment expressions. + /// + /// C# simple, compound and deconstruction assignment expressions + /// VB simple and compound assignment expressions + /// /// /// /// @@ -1357,8 +1457,10 @@ public interface IAssignmentOperation : IOperation /// Represents a simple assignment operation. /// /// Current usage: - /// (1) C# simple assignment expression. - /// (2) VB simple assignment expression. + /// + /// C# simple assignment expression + /// VB simple assignment expression + /// /// /// /// @@ -1380,8 +1482,10 @@ public interface ISimpleAssignmentOperation : IAssignmentOperation /// Represents a compound assignment that mutates the target with the result of a binary operation. /// /// Current usage: - /// (1) C# compound assignment expression. - /// (2) VB compound assignment expression. + /// + /// C# compound assignment expression + /// VB compound assignment expression + /// /// /// /// @@ -1429,7 +1533,9 @@ public interface ICompoundAssignmentOperation : IAssignmentOperation /// Represents a parenthesized operation. /// /// Current usage: - /// (1) VB parenthesized expression. + /// + /// VB parenthesized expression + /// /// /// /// @@ -1451,8 +1557,10 @@ public interface IParenthesizedOperation : IOperation /// Represents a binding of an event. /// /// Current usage: - /// (1) C# event assignment expression. - /// (2) VB Add/Remove handler statement. + /// + /// C# event assignment expression + /// VB Add/Remove handler statement + /// /// /// /// @@ -1483,8 +1591,10 @@ public interface IEventAssignmentOperation : IOperation /// of within . /// /// Current usage: - /// (1) C# conditional access expression (? or ?. operator). - /// (2) VB conditional access expression (? or ?. operator). + /// + /// C# conditional access expression (? or ?. operator) + /// VB conditional access expression (? or ?. operator) + /// /// /// /// @@ -1512,8 +1622,10 @@ public interface IConditionalAccessOperation : IOperation /// See https://github.com/dotnet/roslyn/issues/21279#issuecomment-323153041 for more details. /// /// Current usage: - /// (1) C# conditional access instance expression. - /// (2) VB conditional access instance expression. + /// + /// C# conditional access instance expression + /// VB conditional access instance expression + /// /// /// /// @@ -1554,8 +1666,10 @@ public interface IInterpolatedStringOperation : IOperation /// Represents a creation of anonymous object. /// /// Current usage: - /// (1) C# "new { ... }" expression - /// (2) VB "New With { ... }" expression + /// + /// C# new { ... } expression + /// VB New With { ... } expression + /// /// /// /// @@ -1579,10 +1693,16 @@ public interface IAnonymousObjectCreationOperation : IOperation /// Represents an initialization for an object or collection creation. /// /// Current usage: - /// (1) C# object or collection initializer expression. - /// (2) VB object or collection initializer expression. - /// For example, object initializer "{ X = x }" within object creation "new Class() { X = x }" and - /// collection initializer "{ x, y, 3 }" within collection creation "new MyList() { x, y, 3 }". + /// + /// + /// + /// C# object or collection initializer expression. + /// For example, object initializer { X = x } within object creation new Class() { X = x } and + /// collection initializer { x, y, 3 } within collection creation new MyList() { x, y, 3 } + /// + /// + /// VB object or collection initializer expression + /// /// /// /// @@ -1604,9 +1724,16 @@ public interface IObjectOrCollectionInitializerOperation : IOperation /// Represents an initialization of member within an object initializer with a nested object or collection initializer. /// /// Current usage: - /// (1) C# nested member initializer expression. - /// For example, given an object creation with initializer "new Class() { X = x, Y = { x, y, 3 }, Z = { X = z } }", - /// member initializers for Y and Z, i.e. "Y = { x, y, 3 }", and "Z = { X = z }" are nested member initializers represented by this operation. + /// + /// + /// + /// C# nested member initializer expression. + /// For example, given an object creation with initializer new Class() { X = x, Y = { x, y, 3 }, Z = { X = z } }, + /// member initializers for Y and Z, i.e. Y = { x, y, 3 }, and Z = { X = z } are nested member initializers represented by this operation + /// + /// + /// VB object or collection initializer expression + /// /// /// /// @@ -1655,8 +1782,10 @@ public interface ICollectionElementInitializerOperation : IOperation /// Represents an operation that gets a string value for the name. /// /// Current usage: - /// (1) C# nameof expression. - /// (2) VB NameOf expression. + /// + /// C# nameof expression + /// VB NameOf expression + /// /// /// /// @@ -1678,8 +1807,10 @@ public interface INameOfOperation : IOperation /// Represents a tuple with one or more elements. /// /// Current usage: - /// (1) C# tuple expression. - /// (2) VB tuple expression. + /// + /// C# tuple expression + /// VB tuple expression + /// /// /// /// @@ -1707,8 +1838,10 @@ public interface ITupleOperation : IOperation /// Represents an object creation with a dynamically bound constructor. /// /// Current usage: - /// (1) C# "new" expression with dynamic argument(s). - /// (2) VB late bound "New" expression. + /// + /// C# new expression with dynamic argument(s) + /// VB late bound New expression + /// /// /// /// @@ -1734,8 +1867,10 @@ public interface IDynamicObjectCreationOperation : IOperation /// Represents a reference to a member of a class, struct, or module that is dynamically bound. /// /// Current usage: - /// (1) C# dynamic member reference expression. - /// (2) VB late bound member reference expression. + /// + /// C# dynamic member reference expression + /// VB late bound member reference expression + /// /// /// /// @@ -1769,15 +1904,25 @@ public interface IDynamicMemberReferenceOperation : IOperation /// Represents a invocation that is dynamically bound. /// /// Current usage: - /// (1) C# dynamic invocation expression. - /// (2) C# dynamic collection element initializer. - /// For example, in the following collection initializer: new C() { do1, do2, do3 } where - /// the doX objects are of type dynamic, we'll have 3 with do1, do2, and - /// do3 as their arguments. - /// (3) VB late bound invocation expression. - /// (4) VB dynamic collection element initializer. - /// Similar to the C# example, New C() From {do1, do2, do3} will generate 3 - /// nodes with do1, do2, and do3 as their arguments, respectively. + /// + /// C# dynamic invocation expression + /// + /// + /// C# dynamic collection element initializer. + /// For example, in the following collection initializer: new C() { do1, do2, do3 } where + /// the doX objects are of type dynamic, we'll have 3 with do1, do2, and + /// do3 as their arguments + /// + /// + /// VB late bound invocation expression + /// + /// + /// VB dynamic collection element initializer. + /// Similar to the C# example, New C() From {do1, do2, do3} will generate 3 + /// nodes with do1, do2, and do3 as their arguments, respectively + /// + /// + /// /// /// /// @@ -1803,7 +1948,9 @@ public interface IDynamicInvocationOperation : IOperation /// Represents an indexer access that is dynamically bound. /// /// Current usage: - /// (1) C# dynamic indexer access expression. + /// + /// C# dynamic indexer access expression + /// /// /// /// @@ -1834,8 +1981,10 @@ public interface IDynamicIndexerAccessOperation : IOperation /// IInvocationExpression ('From' invocation for "from x in set") /// /// Current usage: - /// (1) C# query expression. - /// (2) VB query expression. + /// + /// C# query expression + /// VB query expression + /// /// /// /// @@ -1857,8 +2006,10 @@ public interface ITranslatedQueryOperation : IOperation /// Represents a delegate creation. This is created whenever a new delegate is created. /// /// Current usage: - /// (1) C# delegate creation expression. - /// (2) VB delegate creation expression. + /// + /// C# delegate creation expression + /// VB delegate creation expression + /// /// /// /// @@ -1880,7 +2031,9 @@ public interface IDelegateCreationOperation : IOperation /// Represents a default value operation. /// /// Current usage: - /// (1) C# default value expression. + /// + /// C# default value expression + /// /// /// /// @@ -1898,8 +2051,10 @@ public interface IDefaultValueOperation : IOperation /// Represents an operation that gets for the given . /// /// Current usage: - /// (1) C# typeof expression. - /// (2) VB GetType expression. + /// + /// C# typeof expression + /// VB GetType expression + /// /// /// /// @@ -1921,7 +2076,9 @@ public interface ITypeOfOperation : IOperation /// Represents an operation to compute the size of a given type. /// /// Current usage: - /// (1) C# sizeof expression. + /// + /// C# sizeof expression + /// /// /// /// @@ -1943,7 +2100,9 @@ public interface ISizeOfOperation : IOperation /// Represents an operation that creates a pointer value by taking the address of a reference. /// /// Current usage: - /// (1) C# address of expression + /// + /// C# address of expression + /// /// /// /// @@ -1965,7 +2124,9 @@ public interface IAddressOfOperation : IOperation /// Represents an operation that tests if a value matches a specific pattern. /// /// Current usage: - /// (1) C# is pattern expression. For example, "x is int i". + /// + /// C# is pattern expression. For example, x is int i + /// /// /// /// @@ -1993,7 +2154,9 @@ public interface IIsPatternOperation : IOperation /// while unary operator expression does not mutate it's operand. /// /// Current usage: - /// (1) C# increment expression or decrement expression. + /// + /// C# increment expression or decrement expression + /// /// /// /// @@ -2040,9 +2203,11 @@ public interface IIncrementOrDecrementOperation : IOperation /// Represents an operation to throw an exception. /// /// Current usage: - /// (1) C# throw expression. - /// (2) C# throw statement. - /// (2) VB Throw statement. + /// + /// C# throw expression + /// C# throw statement + /// VB Throw statement + /// /// /// /// @@ -2064,7 +2229,9 @@ public interface IThrowOperation : IOperation /// Represents a assignment with a deconstruction. /// /// Current usage: - /// (1) C# deconstruction assignment expression. + /// + /// C# deconstruction assignment expression + /// /// /// /// @@ -2082,10 +2249,18 @@ public interface IDeconstructionAssignmentOperation : IAssignmentOperation /// Represents a declaration expression operation. Unlike a regular variable declaration and , this operation represents an "expression" declaring a variable. /// /// Current usage: - /// (1) C# declaration expression. For example, - /// (a) "var (x, y)" is a deconstruction declaration expression with variables x and y. - /// (b) "(var x, var y)" is a tuple expression with two declaration expressions. - /// (c) "M(out var x);" is an invocation expression with an out "var x" declaration expression. + /// + /// + /// + /// C# deconstruction assignment expression. For example: + /// + /// var (x, y) is a deconstruction declaration expression with variables x and y + /// (var x, var y) is a tuple expression with two declaration expressions + /// M(out var x); is an invocation expression with an out var x declaration expression + /// + /// + /// + /// /// /// /// @@ -2107,7 +2282,9 @@ public interface IDeclarationExpressionOperation : IOperation /// Represents an argument value that has been omitted in an invocation. /// /// Current usage: - /// (1) VB omitted argument in an invocation expression. + /// + /// VB omitted argument in an invocation expression + /// /// /// /// @@ -2125,8 +2302,10 @@ public interface IOmittedArgumentOperation : IOperation /// Represents an initializer for a field, property, parameter or a local variable declaration. /// /// Current usage: - /// (1) C# field, property, parameter or local variable initializer. - /// (2) VB field(s), property, parameter or local variable initializer. + /// + /// C# field, property, parameter or local variable initializer + /// VB field(s), property, parameter or local variable initializer + /// /// /// /// @@ -2148,8 +2327,10 @@ public interface ISymbolInitializerOperation : IOperation /// Represents an initialization of a field. /// /// Current usage: - /// (1) C# field initializer with equals value clause. - /// (2) VB field(s) initializer with equals value clause or AsNew clause. Multiple fields can be initialized with AsNew clause in VB. + /// + /// C# field initializer with equals value clause + /// VB field(s) initializer with equals value clause or AsNew clause. Multiple fields can be initialized with AsNew clause in VB + /// /// /// /// @@ -2171,8 +2352,10 @@ public interface IFieldInitializerOperation : ISymbolInitializerOperation /// Represents an initialization of a local variable. /// /// Current usage: - /// (1) C# local variable initializer with equals value clause. - /// (2) VB local variable initializer with equals value clause or AsNew clause. + /// + /// C# local variable initializer with equals value clause + /// VB local variable initializer with equals value clause or AsNew clause + /// /// /// /// @@ -2190,8 +2373,10 @@ public interface IVariableInitializerOperation : ISymbolInitializerOperation /// Represents an initialization of a property. /// /// Current usage: - /// (1) C# property initializer with equals value clause. - /// (2) VB property initializer with equals value clause or AsNew clause. Multiple properties can be initialized with 'WithEvents' declaration with AsNew clause in VB. + /// + /// C# property initializer with equals value clause + /// VB property initializer with equals value clause or AsNew clause. Multiple properties can be initialized with 'WithEvents' declaration with AsNew clause in VB + /// /// /// /// @@ -2213,8 +2398,10 @@ public interface IPropertyInitializerOperation : ISymbolInitializerOperation /// Represents an initialization of a parameter at the point of declaration. /// /// Current usage: - /// (1) C# parameter initializer with equals value clause. - /// (2) VB parameter initializer with equals value clause. + /// + /// C# parameter initializer with equals value clause + /// VB parameter initializer with equals value clause + /// /// /// /// @@ -2236,8 +2423,10 @@ public interface IParameterInitializerOperation : ISymbolInitializerOperation /// Represents the initialization of an array instance. /// /// Current usage: - /// (1) C# array initializer. - /// (2) VB array initializer. + /// + /// C# array initializer + /// VB array initializer + /// /// /// /// @@ -2257,14 +2446,16 @@ public interface IArrayInitializerOperation : IOperation } /// /// Represents a single variable declarator and initializer. - /// /// /// Current Usage: - /// (1) C# variable declarator - /// (2) C# catch variable declaration - /// (3) VB single variable declaration - /// (4) VB catch variable declaration + /// + /// C# variable declarator + /// C# catch variable declaration + /// VB single variable declaration + /// VB catch variable declaration + /// /// + /// /// /// In VB, the initializer for this node is only ever used for explicit array bounds initializers. This node corresponds to /// the VariableDeclaratorSyntax in C# and the ModifiedIdentifierSyntax in VB. @@ -2298,14 +2489,16 @@ public interface IVariableDeclaratorOperation : IOperation } /// /// Represents a declarator that declares multiple individual variables. - /// /// /// Current Usage: - /// (1) C# VariableDeclaration - /// (2) C# fixed declarations - /// (3) VB Dim statement declaration groups - /// (4) VB Using statement variable declarations + /// + /// C# VariableDeclaration + /// C# fixed declarations + /// VB Dim statement declaration groups + /// VB Using statement variable declarations + /// /// + /// /// /// The initializer of this node is applied to all individual declarations in . There cannot /// be initializers in both locations except in invalid code scenarios. @@ -2345,8 +2538,10 @@ public interface IVariableDeclarationOperation : IOperation /// Represents an argument to a method invocation. /// /// Current usage: - /// (1) C# argument to an invocation expression, object creation expression, etc. - /// (2) VB argument to an invocation expression, object creation expression, etc. + /// + /// C# argument to an invocation expression, object creation expression, etc. + /// VB argument to an invocation expression, object creation expression, etc. + /// /// /// /// @@ -2384,8 +2579,10 @@ public interface IArgumentOperation : IOperation /// Represents a catch clause. /// /// Current usage: - /// (1) C# catch clause. - /// (2) VB Catch clause. + /// + /// C# catch clause + /// VB Catch clause + /// /// /// /// @@ -2427,8 +2624,10 @@ public interface ICatchClauseOperation : IOperation /// Represents a switch case section with one or more case clauses to match and one or more operations to execute within the section. /// /// Current usage: - /// (1) C# switch section for one or more case clause and set of statements to execute. - /// (2) VB case block with a case statement for one or more case clause and set of statements to execute. + /// + /// C# switch section for one or more case clause and set of statements to execute + /// VB case block with a case statement for one or more case clause and set of statements to execute + /// /// /// /// @@ -2458,8 +2657,10 @@ public interface ISwitchCaseOperation : IOperation /// Represents a case clause. /// /// Current usage: - /// (1) C# case clause. - /// (2) VB Case clause. + /// + /// C# case clause + /// VB Case clause + /// /// /// /// @@ -2481,8 +2682,10 @@ public interface ICaseClauseOperation : IOperation /// Represents a default case clause. /// /// Current usage: - /// (1) C# default clause. - /// (2) VB Case Else clause. + /// + /// C# default clause + /// VB Case Else clause + /// /// /// /// @@ -2522,7 +2725,9 @@ public interface IPatternCaseClauseOperation : ICaseClauseOperation /// Represents a case clause with range of values for comparison. /// /// Current usage: - /// (1) VB range case clause of the form "Case x To y". + /// + /// VB range case clause of the form Case x To y + /// /// /// /// @@ -2544,7 +2749,9 @@ public interface IRangeCaseClauseOperation : ICaseClauseOperation /// Represents a case clause with custom relational operator for comparison. /// /// Current usage: - /// (1) VB relational case clause of the form "Case Is op x". + /// + /// VB relational case clause of the form Case Is op x + /// /// /// /// @@ -2566,8 +2773,10 @@ public interface IRelationalCaseClauseOperation : ICaseClauseOperation /// Represents a case clause with a single value for comparison. /// /// Current usage: - /// (1) C# case clause of the form "case x" - /// (2) VB case clause of the form "Case x". + /// + /// C# case clause of the form case x + /// VB case clause of the form Case x + /// /// /// /// @@ -2585,8 +2794,10 @@ public interface ISingleValueCaseClauseOperation : ICaseClauseOperation /// Represents a constituent part of an interpolated string. /// /// Current usage: - /// (1) C# interpolated string content. - /// (2) VB interpolated string content. + /// + /// C# interpolated string content + /// VB interpolated string content + /// /// /// /// @@ -2600,8 +2811,10 @@ public interface IInterpolatedStringContentOperation : IOperation /// Represents a constituent string literal part of an interpolated string operation. /// /// Current usage: - /// (1) C# interpolated string text. - /// (2) VB interpolated string text. + /// + /// C# interpolated string text + /// VB interpolated string text + /// /// /// /// @@ -2623,8 +2836,10 @@ public interface IInterpolatedStringTextOperation : IInterpolatedStringContentOp /// Represents a constituent interpolation part of an interpolated string operation. /// /// Current usage: - /// (1) C# interpolation part. - /// (2) VB interpolation part. + /// + /// C# interpolation part + /// VB interpolation part + /// /// /// /// @@ -2654,7 +2869,9 @@ public interface IInterpolationOperation : IInterpolatedStringContentOperation /// Represents a pattern matching operation. /// /// Current usage: - /// (1) C# pattern. + /// + /// C# pattern + /// /// /// /// @@ -2676,7 +2893,9 @@ public interface IPatternOperation : IOperation /// Represents a pattern with a constant value. /// /// Current usage: - /// (1) C# constant pattern. + /// + /// C# constant pattern + /// /// /// /// @@ -2698,7 +2917,9 @@ public interface IConstantPatternOperation : IPatternOperation /// Represents a pattern that declares a symbol. /// /// Current usage: - /// (1) C# declaration pattern. + /// + /// C# declaration pattern + /// /// /// /// @@ -2712,7 +2933,7 @@ public interface IConstantPatternOperation : IPatternOperation public interface IDeclarationPatternOperation : IPatternOperation { /// - /// The type explicitly specified, or null if it was inferred (e.g. using var in C#). + /// The type explicitly specified, or null if it was inferred (e.g. using in C#). /// ITypeSymbol? MatchedType { get; } /// @@ -2730,7 +2951,9 @@ public interface IDeclarationPatternOperation : IPatternOperation /// Represents a comparison of two operands that returns a bool type. /// /// Current usage: - /// (1) C# tuple binary operator expression. + /// + /// C# tuple binary operator expression + /// /// /// /// @@ -2761,7 +2984,9 @@ public interface ITupleBinaryOperation : IOperation /// Represents a method body operation. /// /// Current usage: - /// (1) C# method body + /// + /// C# method body + /// /// /// /// @@ -2783,7 +3008,9 @@ public interface IMethodBodyBaseOperation : IOperation /// Represents a method body operation. /// /// Current usage: - /// (1) C# method body for non-constructor + /// + /// C# method body for non-constructor + /// /// /// /// @@ -2802,7 +3029,9 @@ public interface IMethodBodyOperation : IMethodBodyBaseOperation /// Represents a constructor method body operation. /// /// Current usage: - /// (1) C# method body for constructor declaration + /// + /// C# method body for constructor declaration + /// /// /// /// @@ -2828,7 +3057,10 @@ public interface IConstructorBodyOperation : IMethodBodyBaseOperation /// /// Represents a discard operation. /// - /// Current usage: C# discard expressions + /// Current usage: + /// + /// C# discard expressions + /// /// /// /// @@ -2848,12 +3080,16 @@ public interface IDiscardOperation : IOperation } /// /// Represents a coalesce assignment operation with a target and a conditionally-evaluated value: - /// (1) is evaluated for null. If it is null, is evaluated and assigned to target. - /// (2) is conditionally evaluated if is null, and the result is assigned into . - /// The result of the entire expression is, which is only evaluated once. + /// + /// is evaluated for null. If it is null, is evaluated and assigned to target + /// is conditionally evaluated if is null, and the result is assigned into + /// + /// The result of the entire expression is , which is only evaluated once. /// /// Current usage: - /// (1) C# null-coalescing assignment operation Target ??= Value. + /// + /// C# null-coalescing assignment operation Target ??= Value + /// /// /// /// @@ -2871,7 +3107,9 @@ public interface ICoalesceAssignmentOperation : IAssignmentOperation /// Represents a range operation. /// /// Current usage: - /// (1) C# range expressions + /// + /// C# range expressions + /// /// /// /// @@ -2893,7 +3131,7 @@ public interface IRangeOperation : IOperation /// IOperation? RightOperand { get; } /// - /// true if this is a 'lifted' range operation. When there is an + /// if this is a 'lifted' range operation. When there is an /// operator that is defined to work on a value type, 'lifted' operators are /// created to work on the versions of those /// value types. @@ -2909,7 +3147,9 @@ public interface IRangeOperation : IOperation /// Represents the ReDim operation to re-allocate storage space for array variables. /// /// Current usage: - /// (1) VB ReDim statement. + /// + /// VB ReDim statement + /// /// /// /// @@ -2935,7 +3175,9 @@ public interface IReDimOperation : IOperation /// Represents an individual clause of an to re-allocate storage space for a single array variable. /// /// Current usage: - /// (1) VB ReDim clause. + /// + /// VB ReDim clause + /// /// /// /// @@ -2975,8 +3217,8 @@ public interface IRecursivePatternOperation : IPatternOperation /// ITypeSymbol MatchedType { get; } /// - /// The symbol, if any, used for the fetching values for subpatterns. This is either a Deconstruct - /// method, the type System.Runtime.CompilerServices.ITuple, or null (for example, in + /// The symbol, if any, used for the fetching values for subpatterns. This is either a Deconstruct + /// method, the type System.Runtime.CompilerServices.ITuple, or null (for example, in /// error cases or when matching a tuple type). /// ISymbol? DeconstructSymbol { get; } @@ -2996,7 +3238,10 @@ public interface IRecursivePatternOperation : IPatternOperation /// /// Represents a discard pattern. /// - /// Current usage: C# discard pattern + /// Current usage: + /// + /// C# discard pattern + /// /// /// /// @@ -3014,7 +3259,9 @@ public interface IDiscardPatternOperation : IPatternOperation /// Represents a switch expression. /// /// Current usage: - /// (1) C# switch expression. + /// + /// C# switch expression + /// /// /// /// @@ -3132,8 +3379,10 @@ internal interface IFixedOperation : IOperation /// Represents a creation of an instance of a NoPia interface, i.e. new I(), where I is an embedded NoPia interface. /// /// Current usage: - /// (1) C# NoPia interface instance creation expression. - /// (2) VB NoPia interface instance creation expression. + /// + /// C# NoPia interface instance creation expression + /// VB NoPia interface instance creation expression + /// /// /// /// @@ -3163,7 +3412,9 @@ internal interface IPlaceholderOperation : IOperation /// Represents a reference through a pointer. /// /// Current usage: - /// (1) C# pointer indirection reference expression. + /// + /// C# pointer indirection reference expression + /// /// /// /// @@ -3181,7 +3432,9 @@ internal interface IPointerIndirectionReferenceOperation : IOperation /// Represents a of operations that are executed with implicit reference to the for member references. /// /// Current usage: - /// (1) VB With statement. + /// + /// VB With statement + /// /// /// /// @@ -3203,8 +3456,10 @@ internal interface IWithStatementOperation : IOperation /// Represents using variable declaration, with scope spanning across the parent . /// /// Current Usage: - /// (1) C# using declaration - /// (1) C# asynchronous using declaration + /// + /// C# using declaration + /// C# asynchronous using declaration + /// /// /// /// @@ -3229,8 +3484,10 @@ public interface IUsingDeclarationOperation : IOperation /// /// Represents a negated pattern. /// - /// Current usage: - /// (1) C# negated pattern. + /// Current usage: + /// + /// C# negated pattern + /// /// /// /// @@ -3251,8 +3508,10 @@ public interface INegatedPatternOperation : IPatternOperation /// /// Represents a binary ("and" or "or") pattern. /// - /// Current usage: - /// (1) C# "and" and "or" patterns. + /// Current usage: + /// + /// C# "and" and "or" patterns + /// /// /// /// @@ -3281,8 +3540,10 @@ public interface IBinaryPatternOperation : IPatternOperation /// /// Represents a pattern comparing the input with a given type. /// - /// Current usage: - /// (1) C# type pattern. + /// Current usage: + /// + /// C# type pattern + /// /// /// /// @@ -3296,7 +3557,7 @@ public interface IBinaryPatternOperation : IPatternOperation public interface ITypePatternOperation : IPatternOperation { /// - /// The type explicitly specified, or null if it was inferred (e.g. using var in C#). + /// The type explicitly specified, or null if it was inferred (e.g. using in C#). /// ITypeSymbol MatchedType { get; } } @@ -3304,7 +3565,9 @@ public interface ITypePatternOperation : IPatternOperation /// Represents a pattern comparing the input with a constant value using a relational operator. /// /// Current usage: - /// (1) C# relational pattern. + /// + /// C# relational pattern + /// /// /// /// @@ -3329,8 +3592,10 @@ public interface IRelationalPatternOperation : IPatternOperation /// /// Represents cloning of an object instance. /// - /// Current usage: - /// (1) C# with expression. + /// Current usage: + /// + /// C# with expression + /// /// /// /// @@ -3544,8 +3809,10 @@ public interface ISlicePatternOperation : IPatternOperation /// /// Represents a reference to an implicit System.Index or System.Range indexer over a non-array type. /// - /// Current usage: - /// (1) C# implicit System.Index or System.Range indexer reference expression. + /// Current usage: + /// + /// C# implicit System.Index or System.Range indexer reference expression + /// /// /// /// @@ -3578,8 +3845,10 @@ public interface IImplicitIndexerReferenceOperation : IOperation /// /// Represents a UTF-8 encoded byte representation of a string. /// - /// Current usage: - /// (1) C# UTF-8 string literal expression. + /// Current usage: + /// + /// C# UTF-8 string literal expression + /// /// /// /// @@ -3600,9 +3869,11 @@ public interface IUtf8StringOperation : IOperation /// /// Represents the application of an attribute. /// - /// Current usage: - /// (1) C# attribute application. - /// (2) VB attribute application. + /// Current usage: + /// + /// C# attribute application + /// VB attribute application + /// /// /// /// @@ -3623,8 +3894,10 @@ public interface IAttributeOperation : IOperation /// /// Represents an element reference or a slice operation over an inline array type. /// - /// Current usage: - /// (1) C# inline array access. + /// Current usage: + /// + /// C# inline array access + /// /// /// /// @@ -3649,8 +3922,10 @@ public interface IInlineArrayAccessOperation : IOperation /// /// Represents a collection expression. /// - /// Current usage: - /// (1) C# collection expression. + /// Current usage: + /// + /// C# collection expression + /// /// /// /// @@ -3685,8 +3960,10 @@ public interface ICollectionExpressionOperation : IOperation /// /// Represents a collection expression spread element. /// - /// Current usage: - /// (1) C# spread element. + /// Current usage: + /// + /// C# spread element + /// /// /// /// diff --git a/src/Compilers/Core/Portable/Hashing/NonCryptographicHashAlgorithm.cs b/src/Compilers/Core/Portable/Hashing/NonCryptographicHashAlgorithm.cs index e4e22acd901e1..293160b7004fc 100644 --- a/src/Compilers/Core/Portable/Hashing/NonCryptographicHashAlgorithm.cs +++ b/src/Compilers/Core/Portable/Hashing/NonCryptographicHashAlgorithm.cs @@ -161,7 +161,7 @@ private async Task AppendAsyncCore(Stream stream, CancellationToken cancellation while (true) { -#if NETCOREAPP +#if NET int read = await stream.ReadAsync(buffer.AsMemory(), cancellationToken).ConfigureAwait(false); #else int read = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false); diff --git a/src/Compilers/Core/Portable/InternalUtilities/ConcurrentDictionaryExtensions.cs b/src/Compilers/Core/Portable/InternalUtilities/ConcurrentDictionaryExtensions.cs index 900003e99ea6d..e3bbd70d0acac 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/ConcurrentDictionaryExtensions.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/ConcurrentDictionaryExtensions.cs @@ -28,7 +28,7 @@ public static void Add(this ConcurrentDictionary dict, K key, V valu public static TValue GetOrAdd(this ConcurrentDictionary dictionary, TKey key, Func valueFactory, TArg factoryArgument) where TKey : notnull { -#if NETCOREAPP +#if NET return dictionary.GetOrAdd(key, valueFactory, factoryArgument); #else if (dictionary.TryGetValue(key, out var value)) @@ -49,7 +49,7 @@ public static TValue AddOrUpdate( TArg factoryArgument) where TKey : notnull { -#if NETCOREAPP +#if NET return dictionary.AddOrUpdate(key, addValueFactory, updateValueFactory, factoryArgument); #else using var _a = PooledDelegates.GetPooledFunction(addValueFactory, factoryArgument, out var pooledAddValueFactory); diff --git a/src/Compilers/Core/Portable/InternalUtilities/Debug.cs b/src/Compilers/Core/Portable/InternalUtilities/Debug.cs index d2833310c6f51..ebd3a10bf6250 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/Debug.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/Debug.cs @@ -5,6 +5,8 @@ using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Text; namespace Roslyn.Utilities { @@ -12,12 +14,22 @@ internal static class RoslynDebug { /// [Conditional("DEBUG")] - public static void Assert([DoesNotReturnIf(false)] bool b) => Debug.Assert(b); + public static void Assert([DoesNotReturnIf(false)] bool condition) => Debug.Assert(condition); /// [Conditional("DEBUG")] - public static void Assert([DoesNotReturnIf(false)] bool b, string message) - => Debug.Assert(b, message); + public static void Assert([DoesNotReturnIf(false)] bool condition, string message) + => Debug.Assert(condition, message); + + /// + [Conditional("DEBUG")] + public static void Assert([DoesNotReturnIf(false)] bool condition, [InterpolatedStringHandlerArgument(nameof(condition))] ref AssertInterpolatedStringHandler message) + { + if (!condition) + { + Debug.Fail(message.ToStringAndClear()); + } + } [Conditional("DEBUG")] public static void AssertNotNull([NotNull] T value) @@ -62,5 +74,28 @@ internal static void AssertOrFailFast([DoesNotReturnIf(false)] bool condition, s } #endif } + + [InterpolatedStringHandler] + public struct AssertInterpolatedStringHandler + { + private readonly StringBuilder? _builder; + + public AssertInterpolatedStringHandler(int literalLength, int formattedCount, bool condition, out bool shouldAppend) + { + shouldAppend = !condition; + if (shouldAppend) + { + _builder = new StringBuilder(literalLength + formattedCount); + } + } + + internal string ToStringAndClear() => _builder!.ToString(); + + public void AppendLiteral(string value) => _builder!.Append(value); + + public void AppendFormatted(T value) => _builder!.Append(value); + + public void AppendFormatted(ReadOnlySpan value) => _builder!.Append(value.ToString()); + } } } diff --git a/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs b/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs index c2d82dabb00ef..e12205daf562f 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/EnumerableExtensions.cs @@ -9,6 +9,7 @@ using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -385,11 +386,15 @@ public static ImmutableArray SelectAsArray(this IRead if (source == null) return ImmutableArray.Empty; - var builder = ArrayBuilder.GetInstance(source.Count); + var builder = new TResult[source.Count]; + var index = 0; foreach (var item in source) - builder.Add(selector(item)); + { + builder[index] = selector(item); + index++; + } - return builder.ToImmutableAndFree(); + return ImmutableCollectionsMarshal.AsImmutableArray(builder); } public static ImmutableArray SelectManyAsArray(this IEnumerable? source, Func> selector) diff --git a/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs b/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs index 492df67ae2597..a620bf64f1de7 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs @@ -147,11 +147,6 @@ public static bool ReportAndPropagateUnlessCanceled(Exception exception, Cancell return ReportAndPropagate(exception, severity); } - // Since the command line compiler has no way to catch exceptions, report them, and march on, we - // simply don't offer such a mechanism here to avoid accidental swallowing of exceptions. - -#if !COMPILERCORE - /// /// Report an error. /// Calls and doesn't pass the exception through (the method returns true). @@ -169,6 +164,11 @@ public static bool ReportAndCatch(Exception exception, ErrorSeverity severity = return true; } + // Since the command line compiler has no way to catch exceptions, report them, and march on, we + // simply don't offer such a mechanism here to avoid accidental swallowing of exceptions. + +#if !COMPILERCORE + [DebuggerHidden] public static bool ReportWithDumpAndCatch(Exception exception, ErrorSeverity severity = ErrorSeverity.Uncategorized) { diff --git a/src/Compilers/Core/Portable/InternalUtilities/MultiDictionary.cs b/src/Compilers/Core/Portable/InternalUtilities/MultiDictionary.cs index 202c0a67de6e8..4dbc9950c386b 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/MultiDictionary.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/MultiDictionary.cs @@ -238,7 +238,7 @@ public MultiDictionary(IEqualityComparer comparer) public void EnsureCapacity(int capacity) { -#if NETCOREAPP +#if NET _dictionary.EnsureCapacity(capacity); #endif } diff --git a/src/Compilers/Core/Portable/InternalUtilities/NullableAttributes.cs b/src/Compilers/Core/Portable/InternalUtilities/NullableAttributes.cs index edf8a5d49dd1b..ebe509bd420cf 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/NullableAttributes.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/NullableAttributes.cs @@ -87,7 +87,7 @@ internal sealed class DoesNotReturnIfAttribute : Attribute #endif -#if !NETCOREAPP || NETCOREAPP3_1 +#if !NETCOREAPP /// Specifies that the method or property will ensure that the listed field and property members have not-null values. [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] diff --git a/src/Compilers/Core/Portable/InternalUtilities/OneOrMany.cs b/src/Compilers/Core/Portable/InternalUtilities/OneOrMany.cs index 10856414dfe81..3bb534468d58b 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/OneOrMany.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/OneOrMany.cs @@ -10,6 +10,7 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Collections; namespace Roslyn.Utilities { diff --git a/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs b/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs index 47827c416f072..fd954a5664fdc 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs @@ -17,4 +17,7 @@ internal static class RoslynExperiments internal const string SyntaxTokenParser = "RSEXPERIMENTAL003"; internal const string SyntaxTokenParser_Url = "https://github.com/dotnet/roslyn/issues/73002"; + + internal const string GeneratorHostOutputs = "RSEXPERIMENTAL004"; + internal const string GeneratorHostOutputs_Url = "https://github.com/dotnet/roslyn/issues/74753"; } diff --git a/src/Compilers/Core/Portable/InternalUtilities/StringTable.cs b/src/Compilers/Core/Portable/InternalUtilities/StringTable.cs index 6d7bea21b1829..96518a81e3752 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/StringTable.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/StringTable.cs @@ -727,7 +727,7 @@ internal static bool TextEqualsASCII(string text, ReadOnlySpan ascii) #if DEBUG for (var i = 0; i < ascii.Length; i++) { - Debug.Assert((ascii[i] & 0x80) == 0, $"The {nameof(ascii)} input to this method must be valid ASCII."); + RoslynDebug.Assert((ascii[i] & 0x80) == 0, $"The {nameof(ascii)} input to this method must be valid ASCII."); } #endif diff --git a/src/Compilers/Core/Portable/MetadataReader/TypeAttributesExtensions.cs b/src/Compilers/Core/Portable/MetadataReader/TypeAttributesExtensions.cs index bc06dd753e261..1a2d9a056df63 100644 --- a/src/Compilers/Core/Portable/MetadataReader/TypeAttributesExtensions.cs +++ b/src/Compilers/Core/Portable/MetadataReader/TypeAttributesExtensions.cs @@ -21,11 +21,6 @@ public static bool IsWindowsRuntime(this TypeAttributes flags) return (flags & TypeAttributes.WindowsRuntime) != 0; } - public static bool IsPublic(this TypeAttributes flags) - { - return (flags & TypeAttributes.Public) != 0; - } - public static bool IsSpecialName(this TypeAttributes flags) { return (flags & TypeAttributes.SpecialName) != 0; diff --git a/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj b/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj index 99b7f038eb898..94c47e9a01e9e 100644 --- a/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj +++ b/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj @@ -30,7 +30,7 @@ Note: PrivateAssets="ContentFiles" ensures that projects referencing Microsoft.CodeAnalysis.Common package will import everything but content files from Microsoft.CodeAnalysis.Analyzers, specifically, analyzers. --> - + @@ -40,7 +40,7 @@ - + diff --git a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs index e2146c1a9d70d..5b7acff12829c 100644 --- a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs +++ b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs @@ -414,36 +414,50 @@ private string SerializeVisualBasicImportTypeReference(ITypeReference typeRefere return result.ToStringAndFree(); } - private string GetAssemblyReferenceAlias(IAssemblyReference assembly, HashSet declaredExternAliases) - { - // no extern alias defined in scope at all -> error in compiler - Debug.Assert(declaredExternAliases != null); +#nullable enable + private string GetAssemblyReferenceAlias(IAssemblyReference assembly, HashSet? declaredExternAliases) + { var allAliases = _metadataWriter.Context.Module.GetAssemblyReferenceAliases(_metadataWriter.Context); - foreach (AssemblyReferenceAlias alias in allAliases) - { - // Multiple aliases may be given to an assembly reference. - // We find one that is in scope (was imported via extern alias directive). - // If multiple are in scope then use the first one. - // NOTE: Dev12 uses the one that appeared in source, whereas we use - // the first one that COULD have appeared in source. (DevDiv #913022) - // The reason we're not just using the alias from the syntax is that - // it is non-trivial to locate. In particular, since "." may be used in - // place of "::", determining whether the first identifier in the name is - // the alias requires binding. For example, "using A.B;" could refer to - // either "A::B" or "global::A.B". + if (declaredExternAliases is not null) + { + foreach (AssemblyReferenceAlias alias in allAliases) + { + // Multiple aliases may be given to an assembly reference. + // We find one that is in scope (was imported via extern alias directive). + // If multiple are in scope then use the first one. + + // NOTE: Dev12 uses the one that appeared in source, whereas we use + // the first one that COULD have appeared in source. (DevDiv #913022) + // The reason we're not just using the alias from the syntax is that + // it is non-trivial to locate. In particular, since "." may be used in + // place of "::", determining whether the first identifier in the name is + // the alias requires binding. For example, "using A.B;" could refer to + // either "A::B" or "global::A.B". + + if (assembly == alias.Assembly && declaredExternAliases.Contains(alias.Name)) + { + return alias.Name; + } + } + } - if (assembly == alias.Assembly && declaredExternAliases.Contains(alias.Name)) + // no alias defined in scope for given assembly -> must be a 'global' using, use the first defined alias + foreach (AssemblyReferenceAlias alias in allAliases) + { + if (assembly == alias.Assembly) { return alias.Name; } } - // no alias defined in scope for given assembly -> error in compiler + // no alias defined for given assembly -> error in compiler throw ExceptionUtilities.Unreachable(); } +#nullable disable + private void DefineLocalScopes(ImmutableArray scopes, StandaloneSignatureHandle localSignatureHandleOpt) { // VB scope ranges are end-inclusive diff --git a/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs b/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs index 1d16642e7b7f9..753a206354748 100644 --- a/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs +++ b/src/Compilers/Core/Portable/Operations/ControlFlowGraphBuilder.cs @@ -1536,52 +1536,58 @@ private void VisitMethodBodies(IBlockOperation? blockBody, IBlockOperation? expr { if (operation == _currentStatement) { - if (operation.WhenFalse == null) - { - // if (condition) - // consequence; - // - // becomes - // - // GotoIfFalse condition afterif; - // consequence; - // afterif: + // if (condition) + // consequence; + // + // becomes + // + // GotoIfFalse condition afterif; + // consequence; + // afterif: - BasicBlockBuilder? afterIf = null; - VisitConditionalBranch(operation.Condition, ref afterIf, jumpIfTrue: false); - VisitStatement(operation.WhenTrue); - AppendNewBlock(afterIf); - } - else - { - // if (condition) - // consequence; - // else - // alternative - // - // becomes - // - // GotoIfFalse condition alt; - // consequence - // goto afterif; - // alt: - // alternative; - // afterif: + // if (condition) + // consequence; + // else + // alternative + // + // becomes + // + // GotoIfFalse condition alt; + // consequence + // goto afterif; + // alt: + // alternative; + // afterif: + var afterIf = new BasicBlockBuilder(BasicBlockKind.Block); + + while (true) + { BasicBlockBuilder? whenFalse = null; VisitConditionalBranch(operation.Condition, ref whenFalse, jumpIfTrue: false); - + Debug.Assert(whenFalse is { }); VisitStatement(operation.WhenTrue); - - var afterIf = new BasicBlockBuilder(BasicBlockKind.Block); UnconditionalBranch(afterIf); AppendNewBlock(whenFalse); - VisitStatement(operation.WhenFalse); - AppendNewBlock(afterIf); + if (operation.WhenFalse is IConditionalOperation nested) + { + operation = nested; + } + else + { + break; + } + } + + if (operation.WhenFalse is not null) + { + VisitStatement(operation.WhenFalse); } + AppendNewBlock(afterIf); + return null; } else @@ -6585,7 +6591,8 @@ public override IOperation VisitInstanceReference(IInstanceReferenceOperation op } else { - Debug.Fail("This code path should not be reachable."); + Debug.Assert(operation.Parent is InvocationOperation { Parent: CollectionExpressionOperation ce } && ce.HasErrors(_compilation), + "Expected to reach this only in collection expression infinite chain cases."); return MakeInvalidOperation(operation.Syntax, operation.Type, ImmutableArray.Empty); } @@ -7558,15 +7565,43 @@ public override IOperation VisitRelationalPattern(IRelationalPatternOperation op public override IOperation VisitBinaryPattern(IBinaryPatternOperation operation, int? argument) { - return new BinaryPatternOperation( - operatorKind: operation.OperatorKind, - leftPattern: (IPatternOperation)VisitRequired(operation.LeftPattern), - rightPattern: (IPatternOperation)VisitRequired(operation.RightPattern), - inputType: operation.InputType, - narrowedType: operation.NarrowedType, - semanticModel: null, - syntax: operation.Syntax, - isImplicit: IsImplicit(operation)); + if (operation.LeftPattern is not IBinaryPatternOperation) + { + return createOperation(this, operation, (IPatternOperation)VisitRequired(operation.LeftPattern)); + } + + // Use a manual stack to avoid overflowing on deeply-nested binary patterns + var stack = ArrayBuilder.GetInstance(); + IBinaryPatternOperation? current = operation; + + do + { + stack.Push(current); + current = current.LeftPattern as IBinaryPatternOperation; + } while (current != null); + + current = stack.Pop(); + var result = (IPatternOperation)VisitRequired(current.LeftPattern); + do + { + result = createOperation(this, current, result); + } while (stack.TryPop(out current)); + + stack.Free(); + return result; + + static BinaryPatternOperation createOperation(ControlFlowGraphBuilder @this, IBinaryPatternOperation operation, IPatternOperation left) + { + return new BinaryPatternOperation( + operatorKind: operation.OperatorKind, + leftPattern: left, + rightPattern: (IPatternOperation)@this.VisitRequired(operation.RightPattern), + inputType: operation.InputType, + narrowedType: operation.NarrowedType, + semanticModel: null, + syntax: operation.Syntax, + isImplicit: @this.IsImplicit(operation)); + } } public override IOperation VisitNegatedPattern(INegatedPatternOperation operation, int? argument) diff --git a/src/Compilers/Core/Portable/Operations/OperationInterfaces.xml b/src/Compilers/Core/Portable/Operations/OperationInterfaces.xml index 585317d267581..cf0d7d9c4731e 100644 --- a/src/Compilers/Core/Portable/Operations/OperationInterfaces.xml +++ b/src/Compilers/Core/Portable/Operations/OperationInterfaces.xml @@ -31,8 +31,10 @@ Represents an invalid operation with one or more child operations. Current usage: - (1) C# invalid expression or invalid statement. - (2) VB invalid expression or invalid statement. + + C# invalid expression or invalid statement + VB invalid expression or invalid statement + @@ -43,8 +45,10 @@ Represents a block containing a sequence of operations and local declarations. Current usage: - (1) C# "{ ... }" block statement. - (2) VB implicit block statement for method bodies and other block scoped statements. + + C# "{ ... }" block statement + VB implicit block statement for method bodies and other block scoped statements + @@ -61,16 +65,20 @@ - Represents a variable declaration statement. - + + Represents a variable declaration statement. + Current Usage: - (1) C# local declaration statement - (2) C# fixed statement - (3) C# using statement - (4) C# using declaration - (5) VB Dim statement - (6) VB Using statement - + + C# local declaration statement + C# fixed statement + C# using statement + C# using declaration + VB Dim statement + VB Using statement + + + @@ -87,8 +95,10 @@ Represents a switch operation with a value to be switched upon and switch cases. Current usage: - (1) C# switch statement. - (2) VB Select Case statement. + + C# switch statement + VB Select Case statement + @@ -122,8 +132,10 @@ Represents a loop operation. Current usage: - (1) C# 'while', 'for', 'foreach' and 'do' loop statements - (2) VB 'While', 'ForTo', 'ForEach', 'Do While' and 'Do Until' loop statements + + C# 'while', 'for', 'foreach' and 'do' loop statements + VB 'While', 'ForTo', 'ForEach', 'Do While' and 'Do Until' loop statements + @@ -160,8 +172,10 @@ Represents a for each loop. Current usage: - (1) C# 'foreach' loop statement - (2) VB 'For Each' loop statement + + C# 'foreach' loop statement + VB 'For Each' loop statement + @@ -200,7 +214,9 @@ Represents a for loop. Current usage: - (1) C# 'for' loop statement + + C# 'for' loop statement + @@ -236,7 +252,9 @@ Represents a for to loop with loop control variable and initial, limit and step values for the control variable. Current usage: - (1) VB 'For ... To ... Step' loop statement + + VB 'For ... To ... Step' loop statement + @@ -266,7 +284,7 @@ - true if arithmetic operations behind this loop are 'checked'. + if arithmetic operations behind this loop are 'checked'. @@ -283,8 +301,10 @@ Represents a while or do while loop. Current usage: - (1) C# 'while' and 'do while' loop statements. - (2) VB 'While', 'Do While' and 'Do Until' loop statements. + + C# 'while' and 'do while' loop statements + VB 'While', 'Do While' and 'Do Until' loop statements + @@ -323,8 +343,10 @@ Represents an operation with a label. Current usage: - (1) C# labeled statement. - (2) VB label statement. + + C# labeled statement + VB label statement + @@ -345,8 +367,10 @@ Represents a branch operation. Current usage: - (1) C# goto, break, or continue statement. - (2) VB GoTo, Exit ***, or Continue *** statement. + + C# goto, break, or continue statement + VB GoTo, Exit ***, or Continue *** statement + @@ -367,7 +391,9 @@ Represents an empty or no-op operation. Current usage: - (1) C# empty statement. + + C# empty statement + @@ -383,8 +409,10 @@ Represents a return from the method with an optional return value. Current usage: - (1) C# return statement and yield statement. - (2) VB Return statement. + + C# return statement and yield statement + VB Return statement + @@ -400,8 +428,10 @@ Represents a of operations that are executed while holding a lock onto the . Current usage: - (1) C# lock statement. - (2) VB SyncLock statement. + + C# lock statement + VB SyncLock statement + @@ -423,8 +453,10 @@ Represents a try operation for exception handling code with a body, catch clauses and a finally handler. Current usage: - (1) C# try statement. - (2) VB Try statement. + + C# try statement + VB Try statement + @@ -455,8 +487,10 @@ Represents a of operations that are executed while using disposable . Current usage: - (1) C# using statement. - (2) VB Using statement. + + C# using statement + VB Using statement + @@ -497,8 +531,10 @@ Represents an operation that drops the resulting value and the type of the underlying wrapped . Current usage: - (1) C# expression statement. - (2) VB expression statement. + + C# expression statement + VB expression statement + @@ -514,7 +550,9 @@ Represents a local function defined within a method. Current usage: - (1) C# local function statement. + + C# local function statement + @@ -542,7 +580,9 @@ Represents an operation to stop or suspend execution of code. Current usage: - (1) VB Stop statement. + + VB Stop statement + @@ -553,7 +593,9 @@ Represents an operation that stops the execution of code abruptly. Current usage: - (1) VB End Statement. + + VB End Statement + @@ -564,7 +606,9 @@ Represents an operation for raising an event. Current usage: - (1) VB raise event statement. + + VB raise event statement + @@ -589,8 +633,10 @@ Represents a textual literal numeric, string, etc. Current usage: - (1) C# literal expression. - (2) VB literal expression. + + C# literal expression + VB literal expression + @@ -601,8 +647,10 @@ Represents a type conversion. Current usage: - (1) C# conversion expression. - (2) VB conversion expression. + + C# conversion expression + VB conversion expression + @@ -654,15 +702,25 @@ Represents an invocation of a method. Current usage: - (1) C# method invocation expression. - (2) C# collection element initializer. - For example, in the following collection initializer: new C() { 1, 2, 3 }, we will have - 3 nodes, each of which will be a call to the corresponding Add method - with either 1, 2, 3 as the argument. - (3) VB method invocation expression. - (4) VB collection element initializer. - Similar to the C# example, New C() From {1, 2, 3} will have 3 - nodes with 1, 2, and 3 as their arguments, respectively. + + C# method invocation expression + + + C# collection element initializer. + For example, in the following collection initializer: new C() { 1, 2, 3 }, we will have + 3 nodes, each of which will be a call to the corresponding Add method + with either 1, 2, 3 as the argument + + + VB method invocation expression + + + VB collection element initializer. + Similar to the C# example, New C() From {1, 2, 3} will have 3 + nodes with 1, 2, and 3 as their arguments, respectively + + + @@ -705,8 +763,10 @@ Represents a reference to an array element. Current usage: - (1) C# array element reference expression. - (2) VB array element reference expression. + + C# array element reference expression + VB array element reference expression + @@ -727,8 +787,10 @@ Represents a reference to a declared local variable. Current usage: - (1) C# local reference expression. - (2) VB local reference expression. + + C# local reference expression + VB local reference expression + @@ -752,8 +814,10 @@ Represents a reference to a parameter. Current usage: - (1) C# parameter reference expression. - (2) VB parameter reference expression. + + C# parameter reference expression + VB parameter reference expression + @@ -769,8 +833,10 @@ Represents a reference to a member of a class, struct, or interface. Current usage: - (1) C# member reference expression. - (2) VB member reference expression. + + C# member reference expression + VB member reference expression + @@ -799,8 +865,10 @@ Represents a reference to a field. Current usage: - (1) C# field reference expression. - (2) VB field reference expression. + + C# field reference expression + VB field reference expression + @@ -825,8 +893,10 @@ Represents a reference to a method other than as the target of an invocation. Current usage: - (1) C# method reference expression. - (2) VB method reference expression. + + C# method reference expression + VB method reference expression + @@ -848,8 +918,10 @@ Represents a reference to a property. Current usage: - (1) C# property reference expression. - (2) VB property reference expression. + + C# property reference expression + VB property reference expression + @@ -875,8 +947,10 @@ Represents a reference to an event. Current usage: - (1) C# event reference expression. - (2) VB event reference expression. + + C# event reference expression + VB event reference expression + @@ -897,8 +971,10 @@ Represents an operation with one operand and a unary operator. Current usage: - (1) C# unary operation expression. - (2) VB unary operation expression. + + C# unary operation expression + VB unary operation expression + @@ -953,8 +1029,10 @@ Represents an operation with two operands and a binary operator that produces a result with a non-null type. Current usage: - (1) C# binary operator expression. - (2) VB binary operator expression. + + C# binary operator expression + VB binary operator expression + @@ -1024,13 +1102,17 @@ Represents a conditional operation with: - (1) to be tested, - (2) operation to be executed when is true and - (3) operation to be executed when the is false. + + to be tested + operation to be executed when is true and + operation to be executed when the is false + Current usage: - (1) C# ternary expression "a ? b : c" and if statement. - (2) VB ternary expression "If(a, b, c)" and If Else statement. + + C# ternary expression a ? b : c and if statement + VB ternary expression If(a, b, c) and If Else statement + @@ -1063,12 +1145,16 @@ Represents a coalesce operation with two operands: - (1) , which is the first operand that is unconditionally evaluated and is the result of the operation if non null. - (2) , which is the second operand that is conditionally evaluated and is the result of the operation if is null. + + , which is the first operand that is unconditionally evaluated and is the result of the operation if non null + , which is the second operand that is conditionally evaluated and is the result of the operation if is null + Current usage: - (1) C# null-coalescing expression "Value ?? WhenNull". - (2) VB binary conditional expression "If(Value, WhenNull)". + + C# null-coalescing expression Value ?? WhenNull + VB binary conditional expression If(Value, WhenNull) + @@ -1106,8 +1192,10 @@ Represents an anonymous function operation. Current usage: - (1) C# lambda expression. - (2) VB anonymous delegate expression. + + C# lambda expression + VB anonymous delegate expression + @@ -1128,8 +1216,10 @@ Represents creation of an object instance. Current usage: - (1) C# new expression. - (2) VB New expression. + + C# new expression + VB New expression + @@ -1159,8 +1249,10 @@ Represents a creation of a type parameter object, i.e. new T(), where T is a type parameter with new constraint. Current usage: - (1) C# type parameter object creation expression. - (2) VB type parameter object creation expression. + + C# type parameter object creation expression + VB type parameter object creation expression + @@ -1176,8 +1268,10 @@ Represents the creation of an array instance. Current usage: - (1) C# array creation expression. - (2) VB array creation expression. + + C# array creation expression + VB array creation expression + @@ -1198,10 +1292,12 @@ Represents an implicit/explicit reference to an instance. Current usage: - (1) C# this or base expression. - (2) VB Me, MyClass, or MyBase expression. - (3) C# object or collection or 'with' expression initializers. - (4) VB With statements, object or collection initializers. + + C# this or base expression + VB Me, MyClass, or MyBase expression + C# object or collection or 'with' expression initializers + VB With statements, object or collection initializers + @@ -1217,8 +1313,10 @@ Represents an operation that tests if a value is of a specific type. Current usage: - (1) C# "is" operator expression. - (2) VB "TypeOf" and "TypeOf IsNot" expression. + + C# "is" operator expression + VB "TypeOf" and "TypeOf IsNot" expression + @@ -1248,8 +1346,10 @@ Represents an await operation. Current usage: - (1) C# await expression. - (2) VB await expression. + + C# await expression + VB await expression + @@ -1265,8 +1365,10 @@ Represents a base interface for assignments. Current usage: - (1) C# simple, compound and deconstruction assignment expressions. - (2) VB simple and compound assignment expressions. + + C# simple, compound and deconstruction assignment expressions + VB simple and compound assignment expressions + @@ -1287,8 +1389,10 @@ Represents a simple assignment operation. Current usage: - (1) C# simple assignment expression. - (2) VB simple assignment expression. + + C# simple assignment expression + VB simple assignment expression + @@ -1304,8 +1408,10 @@ Represents a compound assignment that mutates the target with the result of a binary operation. Current usage: - (1) C# compound assignment expression. - (2) VB compound assignment expression. + + C# compound assignment expression + VB compound assignment expression + @@ -1363,7 +1469,9 @@ Represents a parenthesized operation. Current usage: - (1) VB parenthesized expression. + + VB parenthesized expression + @@ -1379,8 +1487,10 @@ Represents a binding of an event. Current usage: - (1) C# event assignment expression. - (2) VB Add/Remove handler statement. + + C# event assignment expression + VB Add/Remove handler statement + @@ -1407,8 +1517,10 @@ of within . Current usage: - (1) C# conditional access expression (? or ?. operator). - (2) VB conditional access expression (? or ?. operator). + + C# conditional access expression (? or ?. operator) + VB conditional access expression (? or ?. operator) + @@ -1433,8 +1545,10 @@ See https://github.com/dotnet/roslyn/issues/21279#issuecomment-323153041 for more details. Current usage: - (1) C# conditional access instance expression. - (2) VB conditional access instance expression. + + C# conditional access instance expression + VB conditional access instance expression + @@ -1464,8 +1578,10 @@ Represents a creation of anonymous object. Current usage: - (1) C# "new { ... }" expression - (2) VB "New With { ... }" expression + + C# new { ... } expression + VB New With { ... } expression + @@ -1485,10 +1601,16 @@ Represents an initialization for an object or collection creation. Current usage: - (1) C# object or collection initializer expression. - (2) VB object or collection initializer expression. - For example, object initializer "{ X = x }" within object creation "new Class() { X = x }" and - collection initializer "{ x, y, 3 }" within collection creation "new MyList() { x, y, 3 }". + + + + C# object or collection initializer expression. + For example, object initializer { X = x } within object creation new Class() { X = x } and + collection initializer { x, y, 3 } within collection creation new MyList() { x, y, 3 } + + + VB object or collection initializer expression + @@ -1504,9 +1626,16 @@ Represents an initialization of member within an object initializer with a nested object or collection initializer. Current usage: - (1) C# nested member initializer expression. - For example, given an object creation with initializer "new Class() { X = x, Y = { x, y, 3 }, Z = { X = z } }", - member initializers for Y and Z, i.e. "Y = { x, y, 3 }", and "Z = { X = z }" are nested member initializers represented by this operation. + + + + C# nested member initializer expression. + For example, given an object creation with initializer new Class() { X = x, Y = { x, y, 3 }, Z = { X = z } }, + member initializers for Y and Z, i.e. Y = { x, y, 3 }, and Z = { X = z } are nested member initializers represented by this operation + + + VB object or collection initializer expression + @@ -1545,8 +1674,10 @@ Represents an operation that gets a string value for the name. Current usage: - (1) C# nameof expression. - (2) VB NameOf expression. + + C# nameof expression + VB NameOf expression + @@ -1562,8 +1693,10 @@ Represents a tuple with one or more elements. Current usage: - (1) C# tuple expression. - (2) VB tuple expression. + + C# tuple expression + VB tuple expression + @@ -1588,8 +1721,10 @@ Represents an object creation with a dynamically bound constructor. Current usage: - (1) C# "new" expression with dynamic argument(s). - (2) VB late bound "New" expression. + + C# new expression with dynamic argument(s) + VB late bound New expression + @@ -1610,8 +1745,10 @@ Represents a reference to a member of a class, struct, or module that is dynamically bound. Current usage: - (1) C# dynamic member reference expression. - (2) VB late bound member reference expression. + + C# dynamic member reference expression + VB late bound member reference expression + @@ -1644,15 +1781,25 @@ Represents a invocation that is dynamically bound. Current usage: - (1) C# dynamic invocation expression. - (2) C# dynamic collection element initializer. - For example, in the following collection initializer: new C() { do1, do2, do3 } where - the doX objects are of type dynamic, we'll have 3 with do1, do2, and - do3 as their arguments. - (3) VB late bound invocation expression. - (4) VB dynamic collection element initializer. - Similar to the C# example, New C() From {do1, do2, do3} will generate 3 - nodes with do1, do2, and do3 as their arguments, respectively. + + C# dynamic invocation expression + + + C# dynamic collection element initializer. + For example, in the following collection initializer: new C() { do1, do2, do3 } where + the doX objects are of type dynamic, we'll have 3 with do1, do2, and + do3 as their arguments + + + VB late bound invocation expression + + + VB dynamic collection element initializer. + Similar to the C# example, New C() From {do1, do2, do3} will generate 3 + nodes with do1, do2, and do3 as their arguments, respectively + + + @@ -1673,7 +1820,9 @@ Represents an indexer access that is dynamically bound. Current usage: - (1) C# dynamic indexer access expression. + + C# dynamic indexer access expression + @@ -1699,8 +1848,10 @@ IInvocationExpression ('From' invocation for "from x in set") Current usage: - (1) C# query expression. - (2) VB query expression. + + C# query expression + VB query expression + @@ -1716,8 +1867,10 @@ Represents a delegate creation. This is created whenever a new delegate is created. Current usage: - (1) C# delegate creation expression. - (2) VB delegate creation expression. + + C# delegate creation expression + VB delegate creation expression + @@ -1733,7 +1886,9 @@ Represents a default value operation. Current usage: - (1) C# default value expression. + + C# default value expression + @@ -1744,8 +1899,10 @@ Represents an operation that gets for the given . Current usage: - (1) C# typeof expression. - (2) VB GetType expression. + + C# typeof expression + VB GetType expression + @@ -1761,7 +1918,9 @@ Represents an operation to compute the size of a given type. Current usage: - (1) C# sizeof expression. + + C# sizeof expression + @@ -1777,7 +1936,9 @@ Represents an operation that creates a pointer value by taking the address of a reference. Current usage: - (1) C# address of expression + + C# address of expression + @@ -1793,7 +1954,9 @@ Represents an operation that tests if a value matches a specific pattern. Current usage: - (1) C# is pattern expression. For example, "x is int i". + + C# is pattern expression. For example, x is int i + @@ -1820,7 +1983,9 @@ while unary operator expression does not mutate it's operand. Current usage: - (1) C# increment expression or decrement expression. + + C# increment expression or decrement expression + @@ -1873,9 +2038,11 @@ Represents an operation to throw an exception. Current usage: - (1) C# throw expression. - (2) C# throw statement. - (2) VB Throw statement. + + C# throw expression + C# throw statement + VB Throw statement + @@ -1891,7 +2058,9 @@ Represents a assignment with a deconstruction. Current usage: - (1) C# deconstruction assignment expression. + + C# deconstruction assignment expression + @@ -1902,10 +2071,18 @@ Represents a declaration expression operation. Unlike a regular variable declaration and , this operation represents an "expression" declaring a variable. Current usage: - (1) C# declaration expression. For example, - (a) "var (x, y)" is a deconstruction declaration expression with variables x and y. - (b) "(var x, var y)" is a tuple expression with two declaration expressions. - (c) "M(out var x);" is an invocation expression with an out "var x" declaration expression. + + + + C# deconstruction assignment expression. For example: + + var (x, y) is a deconstruction declaration expression with variables x and y + (var x, var y) is a tuple expression with two declaration expressions + M(out var x); is an invocation expression with an out var x declaration expression + + + + @@ -1921,7 +2098,9 @@ Represents an argument value that has been omitted in an invocation. Current usage: - (1) VB omitted argument in an invocation expression. + + VB omitted argument in an invocation expression + @@ -1932,8 +2111,10 @@ Represents an initializer for a field, property, parameter or a local variable declaration. Current usage: - (1) C# field, property, parameter or local variable initializer. - (2) VB field(s), property, parameter or local variable initializer. + + C# field, property, parameter or local variable initializer + VB field(s), property, parameter or local variable initializer + @@ -1956,8 +2137,10 @@ Represents an initialization of a field. Current usage: - (1) C# field initializer with equals value clause. - (2) VB field(s) initializer with equals value clause or AsNew clause. Multiple fields can be initialized with AsNew clause in VB. + + C# field initializer with equals value clause + VB field(s) initializer with equals value clause or AsNew clause. Multiple fields can be initialized with AsNew clause in VB + @@ -1973,8 +2156,10 @@ Represents an initialization of a local variable. Current usage: - (1) C# local variable initializer with equals value clause. - (2) VB local variable initializer with equals value clause or AsNew clause. + + C# local variable initializer with equals value clause + VB local variable initializer with equals value clause or AsNew clause + @@ -1985,8 +2170,10 @@ Represents an initialization of a property. Current usage: - (1) C# property initializer with equals value clause. - (2) VB property initializer with equals value clause or AsNew clause. Multiple properties can be initialized with 'WithEvents' declaration with AsNew clause in VB. + + C# property initializer with equals value clause + VB property initializer with equals value clause or AsNew clause. Multiple properties can be initialized with 'WithEvents' declaration with AsNew clause in VB + @@ -2002,8 +2189,10 @@ Represents an initialization of a parameter at the point of declaration. Current usage: - (1) C# parameter initializer with equals value clause. - (2) VB parameter initializer with equals value clause. + + C# parameter initializer with equals value clause + VB parameter initializer with equals value clause + @@ -2019,8 +2208,10 @@ Represents the initialization of an array instance. Current usage: - (1) C# array initializer. - (2) VB array initializer. + + C# array initializer + VB array initializer + @@ -2032,14 +2223,18 @@ - Represents a single variable declarator and initializer. - + + Represents a single variable declarator and initializer. + Current Usage: - (1) C# variable declarator - (2) C# catch variable declaration - (3) VB single variable declaration - (4) VB catch variable declaration - + + C# variable declarator + C# catch variable declaration + VB single variable declaration + VB catch variable declaration + + + In VB, the initializer for this node is only ever used for explicit array bounds initializers. This node corresponds to the VariableDeclaratorSyntax in C# and the ModifiedIdentifierSyntax in VB. @@ -2071,14 +2266,18 @@ - Represents a declarator that declares multiple individual variables. - + + Represents a declarator that declares multiple individual variables. + Current Usage: - (1) C# VariableDeclaration - (2) C# fixed declarations - (3) VB Dim statement declaration groups - (4) VB Using statement variable declarations - + + C# VariableDeclaration + C# fixed declarations + VB Dim statement declaration groups + VB Using statement variable declarations + + + The initializer of this node is applied to all individual declarations in . There cannot be initializers in both locations except in invalid code scenarios. @@ -2116,8 +2315,10 @@ Represents an argument to a method invocation. Current usage: - (1) C# argument to an invocation expression, object creation expression, etc. - (2) VB argument to an invocation expression, object creation expression, etc. + + C# argument to an invocation expression, object creation expression, etc. + VB argument to an invocation expression, object creation expression, etc. + @@ -2153,8 +2354,10 @@ Represents a catch clause. Current usage: - (1) C# catch clause. - (2) VB Catch clause. + + C# catch clause + VB Catch clause + @@ -2198,8 +2401,10 @@ Represents a switch case section with one or more case clauses to match and one or more operations to execute within the section. Current usage: - (1) C# switch section for one or more case clause and set of statements to execute. - (2) VB case block with a case statement for one or more case clause and set of statements to execute. + + C# switch section for one or more case clause and set of statements to execute + VB case block with a case statement for one or more case clause and set of statements to execute + @@ -2239,8 +2444,10 @@ Represents a case clause. Current usage: - (1) C# case clause. - (2) VB Case clause. + + C# case clause + VB Case clause + @@ -2262,8 +2469,10 @@ Represents a default case clause. Current usage: - (1) C# default clause. - (2) VB Case Else clause. + + C# default clause + VB Case Else clause + @@ -2305,7 +2514,9 @@ Represents a case clause with range of values for comparison. Current usage: - (1) VB range case clause of the form "Case x To y". + + VB range case clause of the form Case x To y + @@ -2327,7 +2538,9 @@ Represents a case clause with custom relational operator for comparison. Current usage: - (1) VB relational case clause of the form "Case Is op x". + + VB relational case clause of the form Case Is op x + @@ -2349,8 +2562,10 @@ Represents a case clause with a single value for comparison. Current usage: - (1) C# case clause of the form "case x" - (2) VB case clause of the form "Case x". + + C# case clause of the form case x + VB case clause of the form Case x + @@ -2366,8 +2581,10 @@ Represents a constituent part of an interpolated string. Current usage: - (1) C# interpolated string content. - (2) VB interpolated string content. + + C# interpolated string content + VB interpolated string content + @@ -2378,8 +2595,10 @@ Represents a constituent string literal part of an interpolated string operation. Current usage: - (1) C# interpolated string text. - (2) VB interpolated string text. + + C# interpolated string text + VB interpolated string text + @@ -2395,8 +2614,10 @@ Represents a constituent interpolation part of an interpolated string operation. Current usage: - (1) C# interpolation part. - (2) VB interpolation part. + + C# interpolation part + VB interpolation part + @@ -2422,7 +2643,9 @@ Represents a pattern matching operation. Current usage: - (1) C# pattern. + + C# pattern + @@ -2443,7 +2666,9 @@ Represents a pattern with a constant value. Current usage: - (1) C# constant pattern. + + C# constant pattern + @@ -2459,14 +2684,16 @@ Represents a pattern that declares a symbol. Current usage: - (1) C# declaration pattern. + + C# declaration pattern + - The type explicitly specified, or null if it was inferred (e.g. using var in C#). + The type explicitly specified, or null if it was inferred (e.g. using in C#). @@ -2495,7 +2722,9 @@ Represents a comparison of two operands that returns a bool type. Current usage: - (1) C# tuple binary operator expression. + + C# tuple binary operator expression + @@ -2521,7 +2750,9 @@ Represents a method body operation. Current usage: - (1) C# method body + + C# method body + @@ -2546,7 +2777,9 @@ Represents a method body operation. Current usage: - (1) C# method body for non-constructor + + C# method body for non-constructor + @@ -2561,7 +2794,9 @@ Represents a constructor method body operation. Current usage: - (1) C# method body for constructor declaration + + C# method body for constructor declaration + @@ -2581,7 +2816,10 @@ Represents a discard operation. - Current usage: C# discard expressions + Current usage: + + C# discard expressions + @@ -2624,7 +2862,7 @@ - True if this reference to the capture initializes the capture. Used when the capture is being initialized by being passed as an out parameter. + True if this reference to the capture initializes the capture. Used when the capture is being initialized by being passed as an parameter. @@ -2673,8 +2911,10 @@ Represents an anonymous function operation in context of a . Current usage: - (1) C# lambda expression. - (2) VB anonymous delegate expression. + + C# lambda expression + VB anonymous delegate expression + A for the body of the anonymous function is available from the enclosing . @@ -2690,12 +2930,16 @@ Represents a coalesce assignment operation with a target and a conditionally-evaluated value: - (1) is evaluated for null. If it is null, is evaluated and assigned to target. - (2) is conditionally evaluated if is null, and the result is assigned into . - The result of the entire expression is, which is only evaluated once. + + is evaluated for null. If it is null, is evaluated and assigned to target + is conditionally evaluated if is null, and the result is assigned into + + The result of the entire expression is , which is only evaluated once. Current usage: - (1) C# null-coalescing assignment operation Target ??= Value. + + C# null-coalescing assignment operation Target ??= Value + @@ -2706,7 +2950,9 @@ Represents a range operation. Current usage: - (1) C# range expressions + + C# range expressions + @@ -2723,7 +2969,7 @@ - true if this is a 'lifted' range operation. When there is an + if this is a 'lifted' range operation. When there is an operator that is defined to work on a value type, 'lifted' operators are created to work on the versions of those value types. @@ -2745,7 +2991,9 @@ Represents the ReDim operation to re-allocate storage space for array variables. Current usage: - (1) VB ReDim statement. + + VB ReDim statement + @@ -2766,7 +3014,9 @@ Represents an individual clause of an to re-allocate storage space for a single array variable. Current usage: - (1) VB ReDim clause. + + VB ReDim clause + @@ -2793,8 +3043,8 @@ - The symbol, if any, used for the fetching values for subpatterns. This is either a Deconstruct - method, the type System.Runtime.CompilerServices.ITuple, or null (for example, in + The symbol, if any, used for the fetching values for subpatterns. This is either a Deconstruct + method, the type System.Runtime.CompilerServices.ITuple, or null (for example, in error cases or when matching a tuple type). @@ -2820,7 +3070,10 @@ Represents a discard pattern. - Current usage: C# discard pattern + Current usage: + + C# discard pattern + @@ -2831,7 +3084,9 @@ Represents a switch expression. Current usage: - (1) C# switch expression. + + C# switch expression + @@ -2931,8 +3186,10 @@ Represents a creation of an instance of a NoPia interface, i.e. new I(), where I is an embedded NoPia interface. Current usage: - (1) C# NoPia interface instance creation expression. - (2) VB NoPia interface instance creation expression. + + C# NoPia interface instance creation expression + VB NoPia interface instance creation expression + @@ -2957,7 +3214,9 @@ Represents a reference through a pointer. Current usage: - (1) C# pointer indirection reference expression. + + C# pointer indirection reference expression + @@ -2973,7 +3232,9 @@ Represents a of operations that are executed with implicit reference to the for member references. Current usage: - (1) VB With statement. + + VB With statement + @@ -2994,8 +3255,10 @@ Represents using variable declaration, with scope spanning across the parent . Current Usage: - (1) C# using declaration - (1) C# asynchronous using declaration + + C# using declaration + C# asynchronous using declaration + @@ -3020,8 +3283,10 @@ Represents a negated pattern. - Current usage: - (1) C# negated pattern. + Current usage: + + C# negated pattern + @@ -3036,8 +3301,10 @@ Represents a binary ("and" or "or") pattern. - Current usage: - (1) C# "and" and "or" patterns. + Current usage: + + C# "and" and "or" patterns + @@ -3062,15 +3329,17 @@ Represents a pattern comparing the input with a given type. - Current usage: - (1) C# type pattern. + Current usage: + + C# type pattern + - The type explicitly specified, or null if it was inferred (e.g. using var in C#). + The type explicitly specified, or null if it was inferred (e.g. using in C#). @@ -3081,7 +3350,9 @@ Represents a pattern comparing the input with a constant value using a relational operator. Current usage: - (1) C# relational pattern. + + C# relational pattern + @@ -3101,8 +3372,10 @@ Represents cloning of an object instance. - Current usage: - (1) C# with expression. + Current usage: + + C# with expression + @@ -3303,8 +3576,10 @@ Represents a reference to an implicit System.Index or System.Range indexer over a non-array type. - Current usage: - (1) C# implicit System.Index or System.Range indexer reference expression. + Current usage: + + C# implicit System.Index or System.Range indexer reference expression + @@ -3338,8 +3613,10 @@ Represents a UTF-8 encoded byte representation of a string. - Current usage: - (1) C# UTF-8 string literal expression. + Current usage: + + C# UTF-8 string literal expression + @@ -3354,9 +3631,11 @@ Represents the application of an attribute. - Current usage: - (1) C# attribute application. - (2) VB attribute application. + Current usage: + + C# attribute application + VB attribute application + @@ -3371,8 +3650,10 @@ Represents an element reference or a slice operation over an inline array type. - Current usage: - (1) C# inline array access. + Current usage: + + C# inline array access + @@ -3392,8 +3673,10 @@ Represents a collection expression. - Current usage: - (1) C# collection expression. + Current usage: + + C# collection expression + @@ -3427,8 +3710,10 @@ Represents a collection expression spread element. - Current usage: - (1) C# spread element. + Current usage: + + C# spread element + diff --git a/src/Compilers/Core/Portable/Operations/OperationMapBuilder.cs b/src/Compilers/Core/Portable/Operations/OperationMapBuilder.cs index 34abe6d500ed4..c4ce6176f70fe 100644 --- a/src/Compilers/Core/Portable/Operations/OperationMapBuilder.cs +++ b/src/Compilers/Core/Portable/Operations/OperationMapBuilder.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { @@ -53,6 +54,49 @@ private sealed class Walker : OperationWalker return null; } + public override object? VisitConditional(IConditionalOperation operation, Dictionary argument) + { + while (true) + { + RecordOperation(operation, argument); + Visit(operation.Condition, argument); + Visit(operation.WhenTrue, argument); + if (operation.WhenFalse is IConditionalOperation nested) + { + operation = nested; + } + else + { + Visit(operation.WhenFalse, argument); + break; + } + } + + return null; + } + + public override object? VisitBinaryPattern(IBinaryPatternOperation operation, Dictionary argument) + { + // In order to handle very large nested patterns, we implement manual iteration here. Our operations are not order sensitive, + // so we don't need to maintain a stack, just iterate through every level. + while (true) + { + RecordOperation(operation, argument); + Visit(operation.RightPattern, argument); + if (operation.LeftPattern is IBinaryPatternOperation nested) + { + operation = nested; + } + else + { + Visit(operation.LeftPattern, argument); + break; + } + } + + return null; + } + internal override object? VisitNoneOperation(IOperation operation, Dictionary argument) { // OperationWalker skips these nodes by default, to avoid having public consumers deal with NoneOperation. @@ -65,8 +109,9 @@ private static void RecordOperation(IOperation operation, Dictionary(); + var typesToIndex = new Queue(); foreach (INamespaceTypeDefinition typeDef in module.GetTopLevelTypeDefinitions(Context)) { - this.CreateIndicesFor(typeDef, nestedTypes); + createIndices(typeDef, typesToIndex); } - while (nestedTypes.Count > 0) + if (module.GetUsedSynthesizedHotReloadExceptionType() is { } hotReloadException) { - var nestedType = nestedTypes.Dequeue(); - this.CreateIndicesFor(nestedType, nestedTypes); + createIndices((ITypeDefinition)hotReloadException.GetCciAdapter(), typesToIndex); } - } - protected virtual void OnIndicesCreated() - { - } + while (typesToIndex.Count > 0) + { + createIndices(typesToIndex.Dequeue(), typesToIndex); + } - private void CreateIndicesFor(ITypeDefinition typeDef, Queue nestedTypes) - { - _cancellationToken.ThrowIfCancellationRequested(); + void createIndices(ITypeDefinition typeDef, Queue typesToIndex) + { + _cancellationToken.ThrowIfCancellationRequested(); - this.CreateIndicesForNonTypeMembers(typeDef); + CreateIndicesForNonTypeMembers(typeDef); - // Metadata spec: - // The TypeDef table has a special ordering constraint: - // the definition of an enclosing class shall precede the definition of all classes it encloses. - foreach (var nestedType in typeDef.GetNestedTypes(Context)) - { - nestedTypes.Enqueue(nestedType); + // Metadata spec: + // The TypeDef table has a special ordering constraint: + // the definition of an enclosing class shall precede the definition of all classes it encloses. + foreach (var nestedType in typeDef.GetNestedTypes(Context)) + { + typesToIndex.Enqueue(nestedType); + } } } + protected virtual void OnIndicesCreated() + { + } + protected IEnumerable GetConsolidatedTypeParameters(ITypeDefinition typeDef) { INestedTypeDefinition nestedTypeDef = typeDef.AsNestedTypeDefinition(Context); diff --git a/src/Compilers/Core/Portable/PEWriter/SigningUtilities.cs b/src/Compilers/Core/Portable/PEWriter/SigningUtilities.cs index 57bc552a68878..d7a2f1a91d16a 100644 --- a/src/Compilers/Core/Portable/PEWriter/SigningUtilities.cs +++ b/src/Compilers/Core/Portable/PEWriter/SigningUtilities.cs @@ -19,23 +19,25 @@ internal static class SigningUtilities { internal static byte[] CalculateRsaSignature(IEnumerable content, RSAParameters privateKey) { - var hash = CalculateSha1(content); + var hash = calculateSha1(content); using (var rsa = RSA.Create()) { rsa.ImportParameters(privateKey); + // CodeQL [SM02196] ECMA-335 requires us to use SHA-1 and there is no alternative. var signature = rsa.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); Array.Reverse(signature); return signature; } - } - internal static byte[] CalculateSha1(IEnumerable content) - { - using (var hash = IncrementalHash.CreateHash(HashAlgorithmName.SHA1)) + static byte[] calculateSha1(IEnumerable content) { - hash.AppendData(content); - return hash.GetHashAndReset(); + // CodeQL [SM02196] ECMA-335 requires us to use SHA-1 and there is no alternative. + using (var hash = IncrementalHash.CreateHash(HashAlgorithmName.SHA1)) + { + hash.AppendData(content); + return hash.GetHashAndReset(); + } } } diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index daaad722b1479..c58db5b5930de 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,3 +1,5 @@ +Microsoft.CodeAnalysis.Emit.RuntimeRudeEdit.ErrorCode.get -> int +Microsoft.CodeAnalysis.Emit.RuntimeRudeEdit.RuntimeRudeEdit(string! message, int errorCode) -> void Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Func? generatorFilter, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver! Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.GeneratorDriver! @@ -6,10 +8,18 @@ Microsoft.CodeAnalysis.GeneratorFilterContext Microsoft.CodeAnalysis.GeneratorFilterContext.CancellationToken.get -> System.Threading.CancellationToken Microsoft.CodeAnalysis.GeneratorFilterContext.Generator.get -> Microsoft.CodeAnalysis.ISourceGenerator! Microsoft.CodeAnalysis.GeneratorFilterContext.GeneratorFilterContext() -> void +Microsoft.CodeAnalysis.GeneratorRunResult.HostOutputs.get -> System.Collections.Immutable.ImmutableDictionary! +Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.Host = 8 -> Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind Microsoft.CodeAnalysis.IPropertySymbol.PartialDefinitionPart.get -> Microsoft.CodeAnalysis.IPropertySymbol? Microsoft.CodeAnalysis.IPropertySymbol.PartialImplementationPart.get -> Microsoft.CodeAnalysis.IPropertySymbol? Microsoft.CodeAnalysis.IPropertySymbol.IsPartialDefinition.get -> bool Microsoft.CodeAnalysis.ITypeParameterSymbol.AllowsRefLikeType.get -> bool Microsoft.CodeAnalysis.RuntimeCapability.ByRefLikeGenerics = 8 -> Microsoft.CodeAnalysis.RuntimeCapability static Microsoft.CodeAnalysis.GeneratorExtensions.AsIncrementalGenerator(this Microsoft.CodeAnalysis.ISourceGenerator! sourceGenerator) -> Microsoft.CodeAnalysis.IIncrementalGenerator! -static Microsoft.CodeAnalysis.GeneratorExtensions.GetGeneratorType(this Microsoft.CodeAnalysis.IIncrementalGenerator! generator) -> System.Type! \ No newline at end of file +static Microsoft.CodeAnalysis.GeneratorExtensions.GetGeneratorType(this Microsoft.CodeAnalysis.IIncrementalGenerator! generator) -> System.Type! +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext.AddOutput(string! name, object! value) -> void +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext.CancellationToken.get -> System.Threading.CancellationToken +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.HostOutputProductionContext.HostOutputProductionContext() -> void +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterHostOutput(Microsoft.CodeAnalysis.IncrementalValueProvider source, System.Action! action) -> void +[RSEXPERIMENTAL004]Microsoft.CodeAnalysis.IncrementalGeneratorInitializationContext.RegisterHostOutput(Microsoft.CodeAnalysis.IncrementalValuesProvider source, System.Action! action) -> void \ No newline at end of file diff --git a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs index b80ab17f9ef03..03f90681bd0b9 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs @@ -26,8 +26,6 @@ namespace Microsoft.CodeAnalysis /// public abstract class GeneratorDriver { - internal const IncrementalGeneratorOutputKind HostKind = (IncrementalGeneratorOutputKind)0b100000; // several steps higher than IncrementalGeneratorOutputKind.Implementation - internal readonly GeneratorDriverState _state; internal GeneratorDriver(GeneratorDriverState state) @@ -323,7 +321,7 @@ internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, Diagnos try { // 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 | HostKind, new GeneratorRunStateTable.Builder(state.TrackIncrementalSteps), cancellationToken, driverStateBuilder); + var context = UpdateOutputs(generatorState.OutputNodes, IncrementalGeneratorOutputKind.Source | IncrementalGeneratorOutputKind.Implementation | IncrementalGeneratorOutputKind.Host, new GeneratorRunStateTable.Builder(state.TrackIncrementalSteps), cancellationToken, driverStateBuilder); (var sources, var generatorDiagnostics, var generatorRunStateTable, var hostOutputs) = context.ToImmutableAndFree(); generatorDiagnostics = FilterDiagnostics(compilation, generatorDiagnostics, driverDiagnostics: diagnosticsBag, cancellationToken); diff --git a/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs b/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs index c58ad9ae2fe7a..a5d9ea9091d08 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GeneratorState.cs @@ -25,7 +25,7 @@ internal readonly struct GeneratorState ImmutableArray.Empty, ImmutableDictionary>.Empty, ImmutableDictionary>.Empty, - ImmutableArray<(string, string)>.Empty, + ImmutableDictionary.Empty, exception: null, elapsedTime: TimeSpan.Zero); @@ -40,7 +40,7 @@ public GeneratorState(ImmutableArray postInitTrees, Immutab ImmutableArray.Empty, ImmutableDictionary>.Empty, ImmutableDictionary>.Empty, - ImmutableArray<(string, string)>.Empty, + ImmutableDictionary.Empty, exception: null, elapsedTime: TimeSpan.Zero) { @@ -54,7 +54,7 @@ private GeneratorState( ImmutableArray diagnostics, ImmutableDictionary> executedSteps, ImmutableDictionary> outputSteps, - ImmutableArray<(string Key, string Value)> hostOutputs, + ImmutableDictionary hostOutputs, Exception? exception, TimeSpan elapsedTime) { @@ -75,7 +75,7 @@ public GeneratorState WithResults(ImmutableArray generatedT ImmutableArray diagnostics, ImmutableDictionary> executedSteps, ImmutableDictionary> outputSteps, - ImmutableArray<(string Key, string Value)> hostOutputs, + ImmutableDictionary hostOutputs, TimeSpan elapsedTime) { return new GeneratorState(this.PostInitTrees, @@ -99,7 +99,7 @@ public GeneratorState WithError(Exception exception, Diagnostic error, TimeSpan ImmutableArray.Create(error), ImmutableDictionary>.Empty, ImmutableDictionary>.Empty, - ImmutableArray<(string, string)>.Empty, + ImmutableDictionary.Empty, exception, elapsedTime); } @@ -124,7 +124,7 @@ public GeneratorState WithError(Exception exception, Diagnostic error, TimeSpan internal ImmutableDictionary> OutputSteps { get; } - internal ImmutableArray<(string Key, string Value)> HostOutputs { get; } + internal ImmutableDictionary HostOutputs { get; } internal bool RequiresPostInitReparse(ParseOptions parseOptions) => PostInitTrees.Any(static (t, parseOptions) => t.Tree.Options != parseOptions, parseOptions); } diff --git a/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs b/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs index 48120f02a5bbd..6eac4792293d8 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/IncrementalContexts.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Text; using System.Threading; using Microsoft.CodeAnalysis.Diagnostics; @@ -14,6 +15,8 @@ using Roslyn.Utilities; using ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer; +#pragma warning disable RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + namespace Microsoft.CodeAnalysis { /// @@ -72,6 +75,12 @@ internal IncrementalValueProvider CompilationOptionsProvider public void RegisterPostInitializationOutput(Action callback) => _outputNodes.Add(new PostInitOutputNode(callback.WrapUserAction(CatchAnalyzerExceptions))); + [Experimental(RoslynExperiments.GeneratorHostOutputs, UrlFormat = RoslynExperiments.GeneratorHostOutputs_Url)] + public void RegisterHostOutput(IncrementalValueProvider source, Action action) => source.Node.RegisterOutput(new HostOutputNode(source.Node, action.WrapUserAction(CatchAnalyzerExceptions))); + + [Experimental(RoslynExperiments.GeneratorHostOutputs, UrlFormat = RoslynExperiments.GeneratorHostOutputs_Url)] + public void RegisterHostOutput(IncrementalValuesProvider source, Action action) => source.Node.RegisterOutput(new HostOutputNode(source.Node, action.WrapUserAction(CatchAnalyzerExceptions))); + private void RegisterOutput(IIncrementalGeneratorOutputNode outputNode) { if (!_outputNodes.Contains(outputNode)) @@ -198,6 +207,40 @@ internal GeneratorFilterContext(ISourceGenerator generator, CancellationToken ca public CancellationToken CancellationToken { get; } } + /// + /// Context passed to an incremental generator when it has registered an output via + /// + [Experimental(RoslynExperiments.GeneratorHostOutputs, UrlFormat = RoslynExperiments.GeneratorHostOutputs_Url)] + public readonly struct HostOutputProductionContext + { + internal readonly ArrayBuilder<(string, object)> Outputs; + + internal HostOutputProductionContext(ArrayBuilder<(string, object)> outputs, CancellationToken cancellationToken) + { + Outputs = outputs; + CancellationToken = cancellationToken; + } + + /// + /// Adds a host specific output + /// + /// The name of the output to be added. + /// The output to be added. + /// + /// A host output has no defined use. It does not contribute to the final compilation in any way. Any outputs registered + /// here are made available via the collection, and it is up the host to + /// decide how to use them. A host may also disable these outputs altogether if they are not needed. The generator driver + /// otherwise makes no guarantees about how the outputs are used, other than that they will be present if the host has + /// requested they be produced. + /// + public void AddOutput(string name, object value) => Outputs.Add((name, value)); + + /// + /// A that can be checked to see if producing the output should be cancelled. + /// + public CancellationToken CancellationToken { get; } + } + // https://github.com/dotnet/roslyn/issues/53608 right now we only support generating source + diagnostics, but actively want to support generation of other things internal readonly struct IncrementalExecutionContext { @@ -209,19 +252,19 @@ internal readonly struct IncrementalExecutionContext internal readonly GeneratorRunStateTable.Builder GeneratorRunStateBuilder; - internal readonly ArrayBuilder<(string Key, string Value)> HostOutputBuilder; + internal readonly ImmutableDictionary.Builder HostOutputBuilder; public IncrementalExecutionContext(DriverStateTable.Builder? tableBuilder, GeneratorRunStateTable.Builder generatorRunStateBuilder, AdditionalSourcesCollection sources) { TableBuilder = tableBuilder; GeneratorRunStateBuilder = generatorRunStateBuilder; Sources = sources; - HostOutputBuilder = ArrayBuilder<(string, string)>.GetInstance(); + HostOutputBuilder = ImmutableDictionary.CreateBuilder(); Diagnostics = DiagnosticBag.GetInstance(); } - internal (ImmutableArray sources, ImmutableArray diagnostics, GeneratorRunStateTable executedSteps, ImmutableArray<(string Key, string Value)> hostOutputs) ToImmutableAndFree() - => (Sources.ToImmutableAndFree(), Diagnostics.ToReadOnlyAndFree(), GeneratorRunStateBuilder.ToImmutableAndFree(), HostOutputBuilder.ToImmutableAndFree()); + internal (ImmutableArray sources, ImmutableArray diagnostics, GeneratorRunStateTable executedSteps, ImmutableDictionary hostOutputs) ToImmutableAndFree() + => (Sources.ToImmutableAndFree(), Diagnostics.ToReadOnlyAndFree(), GeneratorRunStateBuilder.ToImmutableAndFree(), HostOutputBuilder.ToImmutable()); internal void Free() { diff --git a/src/Tools/ExternalAccess/RazorCompiler/HostOutputNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/HostOutputNode.cs similarity index 58% rename from src/Tools/ExternalAccess/RazorCompiler/HostOutputNode.cs rename to src/Compilers/Core/Portable/SourceGeneration/Nodes/HostOutputNode.cs index 3ae1b7dcd296e..02cf15dc88ea5 100644 --- a/src/Tools/ExternalAccess/RazorCompiler/HostOutputNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/HostOutputNode.cs @@ -10,25 +10,27 @@ using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; -using TOutput = System.Collections.Immutable.ImmutableArray<(string, string)>; +using OutputType = System.Collections.Immutable.ImmutableArray<(string, object)>; -namespace Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler +#pragma warning disable RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + +namespace Microsoft.CodeAnalysis { - internal sealed class HostOutputNode : IIncrementalGeneratorOutputNode, IIncrementalGeneratorNode + internal sealed class HostOutputNode : IIncrementalGeneratorOutputNode, IIncrementalGeneratorNode { private readonly IIncrementalGeneratorNode _source; - private readonly Action _action; + private readonly Action _action; - public HostOutputNode(IIncrementalGeneratorNode source, Action action) + public HostOutputNode(IIncrementalGeneratorNode source, Action action) { _source = source; _action = action; } - public IncrementalGeneratorOutputKind Kind => GeneratorDriver.HostKind; + public IncrementalGeneratorOutputKind Kind => IncrementalGeneratorOutputKind.Host; - public NodeStateTable UpdateStateTable(DriverStateTable.Builder graphState, NodeStateTable? previousTable, CancellationToken cancellationToken) + public NodeStateTable UpdateStateTable(DriverStateTable.Builder graphState, NodeStateTable? previousTable, CancellationToken cancellationToken) { string stepName = "HostOutput"; var sourceTable = graphState.GetLatestStateTableForNode(_source); @@ -36,12 +38,12 @@ public NodeStateTable UpdateStateTable(DriverStateTable.Builder graphSt { if (graphState.DriverState.TrackIncrementalSteps) { - return previousTable.CreateCachedTableWithUpdatedSteps(sourceTable, stepName, EqualityComparer.Default); + return previousTable.CreateCachedTableWithUpdatedSteps(sourceTable, stepName, EqualityComparer.Default); } return previousTable; } - var nodeTable = graphState.CreateTableBuilder(previousTable, stepName, EqualityComparer.Default); + var nodeTable = graphState.CreateTableBuilder(previousTable, stepName, EqualityComparer.Default); foreach (var entry in sourceTable) { var inputs = nodeTable.TrackIncrementalSteps ? ImmutableArray.Create((entry.Step!, entry.OutputIndex)) : default; @@ -51,8 +53,8 @@ public NodeStateTable UpdateStateTable(DriverStateTable.Builder graphSt } else if (entry.State != EntryState.Cached || !nodeTable.TryUseCachedEntries(TimeSpan.Zero, inputs)) { - ArrayBuilder<(string, string)> output = ArrayBuilder<(string, string)>.GetInstance(); - HostProductionContext context = new HostProductionContext(output); + ArrayBuilder<(string, object)> output = ArrayBuilder<(string, object)>.GetInstance(); + HostOutputProductionContext context = new HostOutputProductionContext(output, cancellationToken); var stopwatch = SharedStopwatch.StartNew(); _action(context, entry.Item, cancellationToken); nodeTable.AddEntry(output.ToImmutableAndFree(), EntryState.Added, stopwatch.Elapsed, inputs, EntryState.Added); @@ -73,7 +75,17 @@ public void AppendOutputs(IncrementalExecutionContext context, CancellationToken { if (state != EntryState.Removed) { - context.HostOutputBuilder.AddRange(list); + foreach (var (key, value) in list) + { + try + { + context.HostOutputBuilder.Add(key, value); + } + catch (ArgumentException e) + { + throw new UserFunctionException(e); + } + } } } @@ -83,10 +95,10 @@ public void AppendOutputs(IncrementalExecutionContext context, CancellationToken } } - IIncrementalGeneratorNode IIncrementalGeneratorNode.WithComparer(IEqualityComparer comparer) => throw ExceptionUtilities.Unreachable(); + IIncrementalGeneratorNode IIncrementalGeneratorNode.WithComparer(IEqualityComparer comparer) => throw ExceptionUtilities.Unreachable(); - public IIncrementalGeneratorNode WithTrackingName(string name) => throw ExceptionUtilities.Unreachable(); + public IIncrementalGeneratorNode WithTrackingName(string name) => throw ExceptionUtilities.Unreachable(); - void IIncrementalGeneratorNode.RegisterOutput(IIncrementalGeneratorOutputNode output) => throw ExceptionUtilities.Unreachable(); + void IIncrementalGeneratorNode.RegisterOutput(IIncrementalGeneratorOutputNode output) => throw ExceptionUtilities.Unreachable(); } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/IIncrementalGeneratorOutputNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/IIncrementalGeneratorOutputNode.cs index 0c05c369e0bf6..e30faea8fee6f 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/IIncrementalGeneratorOutputNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/IIncrementalGeneratorOutputNode.cs @@ -48,6 +48,12 @@ public enum IncrementalGeneratorOutputKind /// An Implementation only source output, registered via /// or /// - Implementation = 0b100 + Implementation = 0b100, + + /// + /// A host specific output, registered via + /// or + /// + Host = 0b1000, } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/InputNode.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/InputNode.cs index 000c1e82c1e9b..2e7205b08793e 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/InputNode.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/InputNode.cs @@ -50,7 +50,7 @@ public NodeStateTable UpdateStateTable(DriverStateTable.Builder graphState, N // create a mutable hashset of the new items we can check against var itemsSet = (_inputComparer == EqualityComparer.Default) ? PooledHashSet.GetInstance() : new HashSet(_inputComparer); -#if NETCOREAPP +#if NET itemsSet.EnsureCapacity(inputItems.Length); #endif diff --git a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithSimpleName.cs b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithSimpleName.cs index 907119830a76f..b59fde6026e92 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithSimpleName.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/Nodes/SyntaxValueProvider_ForAttributeWithSimpleName.cs @@ -338,29 +338,34 @@ bool matchesAttributeName(string currentAttributeName, bool withAttributeSuffix) return false; seenNames.Push(currentAttributeName); - - foreach (var (aliasName, symbolName) in localAliases) + try { - // see if user wrote `[SomeAlias]`. If so, if we find a `using SomeAlias = ...` recurse using the - // ... name portion to see if it might bind to the attr name the caller is searching for. - if (matchesName(currentAttributeName, aliasName, withAttributeSuffix) && - matchesAttributeName(symbolName, withAttributeSuffix: false)) + foreach (var (aliasName, symbolName) in localAliases) { - return true; + // see if user wrote `[SomeAlias]`. If so, if we find a `using SomeAlias = ...` recurse using the + // ... name portion to see if it might bind to the attr name the caller is searching for. + if (matchesName(currentAttributeName, aliasName, withAttributeSuffix) && + matchesAttributeName(symbolName, withAttributeSuffix: false)) + { + return true; + } } - } - foreach (var (aliasName, symbolName) in globalAliases.AliasAndSymbolNames) - { - if (matchesName(currentAttributeName, aliasName, withAttributeSuffix) && - matchesAttributeName(symbolName, withAttributeSuffix: false)) + foreach (var (aliasName, symbolName) in globalAliases.AliasAndSymbolNames) { - return true; + if (matchesName(currentAttributeName, aliasName, withAttributeSuffix) && + matchesAttributeName(symbolName, withAttributeSuffix: false)) + { + return true; + } } - } - seenNames.Pop(); - return false; + return false; + } + finally + { + seenNames.Pop(); + } } } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/RunResults.cs b/src/Compilers/Core/Portable/SourceGeneration/RunResults.cs index a7f84224e6103..d0e73fc34bc0e 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/RunResults.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/RunResults.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 Microsoft.CodeAnalysis.Text; @@ -83,7 +84,7 @@ internal GeneratorRunResult( ImmutableArray diagnostics, ImmutableDictionary> namedSteps, ImmutableDictionary> outputSteps, - ImmutableArray<(string Key, string Value)> hostOutputs, + ImmutableDictionary hostOutputs, Exception? exception, TimeSpan elapsedTime) { @@ -94,7 +95,9 @@ internal GeneratorRunResult( this.Diagnostics = diagnostics; this.TrackedSteps = namedSteps; this.TrackedOutputSteps = outputSteps; +#pragma warning disable RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. this.HostOutputs = hostOutputs; +#pragma warning restore RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. this.Exception = exception; this.ElapsedTime = elapsedTime; } @@ -118,7 +121,11 @@ internal GeneratorRunResult( /// public ImmutableArray Diagnostics { get; } - internal ImmutableArray<(string Key, string Value)> HostOutputs { get; } + /// + /// A collection of items added via . + /// + [Experimental(RoslynExperiments.GeneratorHostOutputs, UrlFormat = RoslynExperiments.GeneratorHostOutputs_Url)] + public ImmutableDictionary 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/Symbols/IPropertySymbolInternal.cs b/src/Compilers/Core/Portable/Symbols/IPropertySymbolInternal.cs new file mode 100644 index 0000000000000..06ca49674b661 --- /dev/null +++ b/src/Compilers/Core/Portable/Symbols/IPropertySymbolInternal.cs @@ -0,0 +1,11 @@ +// 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.Symbols; + +internal interface IPropertySymbolInternal : ISymbolInternal +{ + IPropertySymbolInternal? PartialImplementationPart { get; } + IPropertySymbolInternal? PartialDefinitionPart { get; } +} diff --git a/src/Compilers/Core/Portable/Syntax/GreenNode.cs b/src/Compilers/Core/Portable/Syntax/GreenNode.cs index 9ef6a04ef4c59..222883bf0edb8 100644 --- a/src/Compilers/Core/Portable/Syntax/GreenNode.cs +++ b/src/Compilers/Core/Portable/Syntax/GreenNode.cs @@ -268,6 +268,7 @@ internal enum NodeFlags : ushort FactoryContextIsInAsync = 1 << 2, FactoryContextIsInQuery = 1 << 3, FactoryContextIsInIterator = FactoryContextIsInQuery, // VB does not use "InQuery", but uses "InIterator" instead + FactoryContextIsInFieldKeywordContext = 1 << 4, // Flags that are inherited upwards when building parent nodes. They should all start with "Contains" to // indicate that the information could be found on it or anywhere in its children. @@ -275,15 +276,15 @@ internal enum NodeFlags : ushort /// /// If this node, or any of its descendants has annotations attached to them. /// - ContainsAnnotations = 1 << 4, + ContainsAnnotations = 1 << 5, /// /// If this node, or any of its descendants has attributes attached to it. /// - ContainsAttributes = 1 << 5, - ContainsDiagnostics = 1 << 6, - ContainsDirectives = 1 << 7, - ContainsSkippedText = 1 << 8, - ContainsStructuredTrivia = 1 << 9, + ContainsAttributes = 1 << 6, + ContainsDiagnostics = 1 << 7, + ContainsDirectives = 1 << 8, + ContainsSkippedText = 1 << 9, + ContainsStructuredTrivia = 1 << 10, InheritMask = IsNotMissing | ContainsAnnotations | ContainsAttributes | ContainsDiagnostics | ContainsDirectives | ContainsSkippedText | ContainsStructuredTrivia, } @@ -336,6 +337,14 @@ internal bool ParsedInIterator } } + internal bool ParsedInFieldKeywordContext + { + get + { + return (this.Flags & NodeFlags.FactoryContextIsInFieldKeywordContext) != 0; + } + } + public bool ContainsSkippedText { get diff --git a/src/Compilers/Core/Portable/Text/ChangedText.cs b/src/Compilers/Core/Portable/Text/ChangedText.cs index c8f7d46b8d71d..acd1e57c4ea04 100644 --- a/src/Compilers/Core/Portable/Text/ChangedText.cs +++ b/src/Compilers/Core/Portable/Text/ChangedText.cs @@ -7,8 +7,6 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Text; -using Microsoft.CodeAnalysis.Collections; -using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Text @@ -264,108 +262,8 @@ private static ImmutableArray Merge(IReadOnlyList - /// Computes line starts faster given already computed line starts from text before the change. - /// protected override TextLineCollection GetLinesCore() - { - SourceText? oldText; - TextLineCollection? oldLineInfo; - - if (!_info.WeakOldText.TryGetTarget(out oldText) || !oldText.TryGetLines(out oldLineInfo)) - { - // no old line starts? do it the hard way. - return base.GetLinesCore(); - } - - // compute line starts given changes and line starts already computed from previous text - var lineStarts = new SegmentedList(capacity: oldLineInfo.Count) - { - 0 - }; - - // position in the original document - var position = 0; - - // delta generated by already processed changes (position in the new document = position + delta) - var delta = 0; - - // true if last segment ends with CR and we need to check for CR+LF code below assumes that both CR and LF are also line breaks alone - var endsWithCR = false; - - foreach (var change in _info.ChangeRanges) - { - // include existing line starts that occur before this change - if (change.Span.Start > position) - { - if (endsWithCR && _newText[position + delta] == '\n') - { - // remove last added line start (it was due to previous CR) - // a new line start including the LF will be added next - lineStarts.RemoveAt(lineStarts.Count - 1); - } - - var lps = oldLineInfo.GetLinePositionSpan(TextSpan.FromBounds(position, change.Span.Start)); - for (int i = lps.Start.Line + 1; i <= lps.End.Line; i++) - { - lineStarts.Add(oldLineInfo[i].Start + delta); - } - - endsWithCR = oldText[change.Span.Start - 1] == '\r'; - - // in case change is inserted between CR+LF we treat CR as line break alone, - // but this line break might be retracted and replaced with new one in case LF is inserted - if (endsWithCR && change.Span.Start < oldText.Length && oldText[change.Span.Start] == '\n') - { - lineStarts.Add(change.Span.Start + delta); - } - } - - // include line starts that occur within newly inserted text - if (change.NewLength > 0) - { - var changeStart = change.Span.Start + delta; - var text = GetSubText(new TextSpan(changeStart, change.NewLength)); - - if (endsWithCR && text[0] == '\n') - { - // remove last added line start (it was due to previous CR) - // a new line start including the LF will be added next - lineStarts.RemoveAt(lineStarts.Count - 1); - } - - // Skip first line (it is always at offset 0 and corresponds to the previous line) - for (int i = 1; i < text.Lines.Count; i++) - { - lineStarts.Add(changeStart + text.Lines[i].Start); - } - - endsWithCR = text[change.NewLength - 1] == '\r'; - } - - position = change.Span.End; - delta += (change.NewLength - change.Span.Length); - } - - // include existing line starts that occur after all changes - if (position < oldText.Length) - { - if (endsWithCR && _newText[position + delta] == '\n') - { - // remove last added line start (it was due to previous CR) - // a new line start including the LF will be added next - lineStarts.RemoveAt(lineStarts.Count - 1); - } - - var lps = oldLineInfo.GetLinePositionSpan(TextSpan.FromBounds(position, oldText.Length)); - for (int i = lps.Start.Line + 1; i <= lps.End.Line; i++) - { - lineStarts.Add(oldLineInfo[i].Start + delta); - } - } - - return new LineInfo(this, lineStarts); - } + => _newText.Lines; internal static class TestAccessor { diff --git a/src/Compilers/Core/Portable/Text/CompositeText.cs b/src/Compilers/Core/Portable/Text/CompositeText.cs index d72ccf5f8d7c9..b4fdc92beec36 100644 --- a/src/Compilers/Core/Portable/Text/CompositeText.cs +++ b/src/Compilers/Core/Portable/Text/CompositeText.cs @@ -6,8 +6,8 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -29,6 +29,7 @@ private CompositeText(ImmutableArray segments, Encoding? encoding, S : base(checksumAlgorithm: checksumAlgorithm) { Debug.Assert(!segments.IsDefaultOrEmpty); + Debug.Assert(segments.Length > 0); _segments = segments; _encoding = encoding; @@ -40,10 +41,14 @@ private CompositeText(ImmutableArray segments, Encoding? encoding, S for (int i = 0; i < _segmentOffsets.Length; i++) { _segmentOffsets[i] = offset; + Debug.Assert(_segments[i].Length > 0); offset += _segments[i].Length; } } + protected override TextLineCollection GetLinesCore() + => new CompositeTextLineInfo(this); + public override Encoding? Encoding { get { return _encoding; } @@ -182,6 +187,8 @@ internal static SourceText ToSourceText(ArrayBuilder segments, Sourc ReduceSegmentCountIfNecessary(segments); } + RemoveSplitLineBreaksAndEmptySegments(segments); + if (segments.Count == 0) { return SourceText.From(string.Empty, original.Encoding, original.ChecksumAlgorithm); @@ -196,6 +203,38 @@ internal static SourceText ToSourceText(ArrayBuilder segments, Sourc } } + private static void RemoveSplitLineBreaksAndEmptySegments(ArrayBuilder segments) + { + if (segments.Count > 1) + { + // Remove empty segments before checking for split line breaks + segments.RemoveWhere(static (s, _, _) => s.Length == 0, default(VoidResult)); + + var splitLineBreakFound = false; + for (int i = 1; i < segments.Count; i++) + { + var prevSegment = segments[i - 1]; + var curSegment = segments[i]; + if (prevSegment.Length > 0 && prevSegment[^1] == '\r' && curSegment[0] == '\n') + { + splitLineBreakFound = true; + + segments[i - 1] = prevSegment.GetSubText(new TextSpan(0, prevSegment.Length - 1)); + segments.Insert(i, SourceText.From("\r\n")); + segments[i + 1] = curSegment.GetSubText(new TextSpan(1, curSegment.Length - 1)); + i++; + } + } + + if (splitLineBreakFound) + { + // If a split line break was present, ensure there aren't any empty lines again + // due to the sourcetexts created from the GetSubText calls. + segments.RemoveWhere(static (s, _, _) => s.Length == 0, default(VoidResult)); + } + } + } + // both of these numbers are currently arbitrary. internal const int TARGET_SEGMENT_COUNT_AFTER_REDUCTION = 32; internal const int MAXIMUM_SEGMENT_COUNT_BEFORE_REDUCTION = 64; @@ -373,5 +412,161 @@ private static void TrimInaccessibleText(ArrayBuilder segments) segments.Add(writer.ToSourceText()); } } + + /// + /// Delegates to SourceTexts within the CompositeText to determine line information. + /// + private sealed class CompositeTextLineInfo : TextLineCollection + { + private readonly CompositeText _compositeText; + + /// + /// The starting line number for the correspondingly indexed SourceTexts in _compositeText.Segments. + /// Multiple consecutive entries could indicate the same line number if the corresponding + /// segments don't contain newline characters. + /// + /// + /// This will be of the same length as _compositeText.Segments + /// + private readonly ImmutableArray _segmentLineNumbers; + + // The total number of lines in our _compositeText + private readonly int _lineCount; + + public CompositeTextLineInfo(CompositeText compositeText) + { + var segmentLineNumbers = new int[compositeText.Segments.Length]; + var accumulatedLineCount = 0; + + Debug.Assert(compositeText.Segments.Length > 0); + for (int i = 0; i < compositeText.Segments.Length; i++) + { + segmentLineNumbers[i] = accumulatedLineCount; + + var segment = compositeText.Segments[i]; + + // Account for this segments lines in our accumulated lines. Subtract one as each segment + // views its line count as one greater than the number of line breaks it contains. + accumulatedLineCount += (segment.Lines.Count - 1); + + Debug.Assert(segment.Length > 0); + + // RemoveSplitLineBreaksAndEmptySegments ensured no split line breaks + Debug.Assert(i == compositeText.Segments.Length - 1 || segment[^1] != '\r' || compositeText.Segments[i + 1][0] != '\n'); + } + + _compositeText = compositeText; + _segmentLineNumbers = ImmutableCollectionsMarshal.AsImmutableArray(segmentLineNumbers); + + // Add one to the accumulatedLineCount for our stored line count (so that we maintain the + // invariant that a text's line count is one greater than the number of newlines it contains) + _lineCount = accumulatedLineCount + 1; + } + + public override int Count => _lineCount; + + /// + /// Determines the line number of a position in this CompositeText + /// + public override int IndexOf(int position) + { + if (position < 0 || position > _compositeText.Length) + { + throw new ArgumentOutOfRangeException(nameof(position)); + } + + _compositeText.GetIndexAndOffset(position, out var segmentIndex, out var segmentOffset); + + var segment = _compositeText.Segments[segmentIndex]; + var lineNumberWithinSegment = segment.Lines.IndexOf(segmentOffset); + + return _segmentLineNumbers[segmentIndex] + lineNumberWithinSegment; + } + + public override TextLine this[int lineNumber] + { + get + { + if (lineNumber < 0 || lineNumber >= _lineCount) + { + throw new ArgumentOutOfRangeException(nameof(lineNumber)); + } + + // Determine the indices for segments that contribute to our view of the requested line's contents + GetSegmentIndexRangeContainingLine(lineNumber, out var firstSegmentIndexInclusive, out var lastSegmentIndexInclusive); + Debug.Assert(firstSegmentIndexInclusive <= lastSegmentIndexInclusive); + + var firstSegmentFirstLineNumber = _segmentLineNumbers[firstSegmentIndexInclusive]; + var firstSegment = _compositeText.Segments[firstSegmentIndexInclusive]; + var firstSegmentOffset = _compositeText._segmentOffsets[firstSegmentIndexInclusive]; + var firstSegmentTextLine = firstSegment.Lines[lineNumber - firstSegmentFirstLineNumber]; + + var lineLength = firstSegmentTextLine.SpanIncludingLineBreak.Length; + + // walk forward through segments between firstSegmentIndexInclusive and lastSegmentIndexInclusive, and add their + // view of the length of this line. This loop handles all segments between firstSegmentIndexInclusive and lastSegmentIndexInclusive. + for (var nextSegmentIndex = firstSegmentIndexInclusive + 1; nextSegmentIndex < lastSegmentIndexInclusive; nextSegmentIndex++) + { + var nextSegment = _compositeText.Segments[nextSegmentIndex]; + + // Segments between firstSegmentIndexInclusive and lastSegmentIndexInclusive should have either exactly one line or + // exactly two lines and the second line being empty. + Debug.Assert((nextSegment.Lines.Count == 1) || + (nextSegment.Lines.Count == 2 && nextSegment.Lines[1].SpanIncludingLineBreak.IsEmpty)); + + lineLength += nextSegment.Lines[0].SpanIncludingLineBreak.Length; + } + + if (firstSegmentIndexInclusive != lastSegmentIndexInclusive) + { + var lastSegment = _compositeText.Segments[lastSegmentIndexInclusive]; + + // lastSegment should have at least one line. + Debug.Assert(lastSegment.Lines.Count >= 1); + + lineLength += lastSegment.Lines[0].SpanIncludingLineBreak.Length; + } + + var resultLine = TextLine.FromSpanUnsafe(_compositeText, new TextSpan(firstSegmentOffset + firstSegmentTextLine.Start, lineLength)); + + // Assert resultLine only has line breaks in the appropriate locations + Debug.Assert(resultLine.ToString().All(static c => !TextUtilities.IsAnyLineBreakCharacter(c))); + + return resultLine; + } + } + + private void GetSegmentIndexRangeContainingLine(int lineNumber, out int firstSegmentIndexInclusive, out int lastSegmentIndexInclusive) + { + var idx = _segmentLineNumbers.BinarySearch(lineNumber); + var binarySearchSegmentIndex = idx >= 0 ? idx : (~idx - 1); + + // Walk backwards starting at binarySearchSegmentIndex to find the earliest segment index that intersects this line number + for (firstSegmentIndexInclusive = binarySearchSegmentIndex; firstSegmentIndexInclusive > 0; firstSegmentIndexInclusive--) + { + if (_segmentLineNumbers[firstSegmentIndexInclusive] != lineNumber) + { + // This segment doesn't start at the requested line, no need to continue to earlier segments. + break; + } + + // No need to include the previous segment if it ends in a newline character + var previousSegment = _compositeText.Segments[firstSegmentIndexInclusive - 1]; + var previousSegmentLastChar = previousSegment[^1]; + if (TextUtilities.IsAnyLineBreakCharacter(previousSegmentLastChar)) + { + break; + } + } + + for (lastSegmentIndexInclusive = binarySearchSegmentIndex; lastSegmentIndexInclusive < _compositeText.Segments.Length - 1; lastSegmentIndexInclusive++) + { + if (_segmentLineNumbers[lastSegmentIndexInclusive + 1] != lineNumber) + { + break; + } + } + } + } } } diff --git a/src/Compilers/Core/Portable/Text/SourceHashAlgorithms.cs b/src/Compilers/Core/Portable/Text/SourceHashAlgorithms.cs index eb84be4dc4aa8..993ed5bcdd93f 100644 --- a/src/Compilers/Core/Portable/Text/SourceHashAlgorithms.cs +++ b/src/Compilers/Core/Portable/Text/SourceHashAlgorithms.cs @@ -50,6 +50,7 @@ private static HashAlgorithm CreateInstance(SourceHashAlgorithm algorithm) { return algorithm switch { + // CodeQL [SM02196] This is not enabled by default but exists as a compat option for existing builds. SourceHashAlgorithm.Sha1 => SHA1.Create(), SourceHashAlgorithm.Sha256 => SHA256.Create(), _ => throw ExceptionUtilities.UnexpectedValue(algorithm) diff --git a/src/Compilers/Core/Portable/Text/SourceText.cs b/src/Compilers/Core/Portable/Text/SourceText.cs index d58eb8d2b86e7..01a6cd19999d4 100644 --- a/src/Compilers/Core/Portable/Text/SourceText.cs +++ b/src/Compilers/Core/Portable/Text/SourceText.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.Buffers; +using System.Buffers.Binary; using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel; @@ -349,7 +349,7 @@ private static string Decode(byte[] buffer, int length, Encoding encoding, out E /// internal static bool IsBinary(ReadOnlySpan text) { -#if NETCOREAPP +#if NET // On .NET Core, Contains has an optimized vectorized implementation, much faster than a custom loop. return text.Contains("\0\0", StringComparison.Ordinal); #else @@ -642,7 +642,26 @@ ImmutableArray computeContentHash() sourceIndex: index, destination: charBuffer, destinationIndex: 0, count: charsToCopy); - hash.Append(MemoryMarshal.AsBytes(charBuffer.AsSpan(0, charsToCopy))); + var charSpan = charBuffer.AsSpan(0, charsToCopy); + + // Ensure everything is always little endian, so we get the same results across all platforms. + // This will be entirely elided by the jit on a little endian machine. + if (!BitConverter.IsLittleEndian) + { + var shortSpan = MemoryMarshal.Cast(charSpan); + +#if NET8_0_OR_GREATER + // Defer to the platform to do the reversal. It ships with a vectorized + // implementation for this on .NET 8 and above. + BinaryPrimitives.ReverseEndianness(source: shortSpan, destination: shortSpan); +#else + // Otherwise, fallback to the simple approach of reversing each pair of bytes. + for (var i = 0; i < shortSpan.Length; i++) + shortSpan[i] = BinaryPrimitives.ReverseEndianness(shortSpan[i]); +#endif + } + + hash.Append(MemoryMarshal.AsBytes(charSpan)); } // Switch this to ImmutableCollectionsMarshal.AsImmutableArray(hash.GetHashAndReset()) when we move to S.C.I v8. @@ -966,12 +985,12 @@ public override TextLine this[int index] int start = _lineStarts[index]; if (index == _lineStarts.Count - 1) { - return TextLine.FromSpan(_text, TextSpan.FromBounds(start, _text.Length)); + return TextLine.FromSpanUnsafe(_text, TextSpan.FromBounds(start, _text.Length)); } else { int end = _lineStarts[index + 1]; - return TextLine.FromSpan(_text, TextSpan.FromBounds(start, end)); + return TextLine.FromSpanUnsafe(_text, TextSpan.FromBounds(start, end)); } } } diff --git a/src/Compilers/Core/Portable/Text/SubText.cs b/src/Compilers/Core/Portable/Text/SubText.cs index 7769617224043..e0935e8cebc0d 100644 --- a/src/Compilers/Core/Portable/Text/SubText.cs +++ b/src/Compilers/Core/Portable/Text/SubText.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics; +using System.Linq; using System.Text; namespace Microsoft.CodeAnalysis.Text @@ -63,6 +65,9 @@ public override char this[int position] } } + protected override TextLineCollection GetLinesCore() + => new SubTextLineInfo(this); + public override string ToString(TextSpan span) { CheckSubSpan(span); @@ -89,5 +94,130 @@ private TextSpan GetCompositeSpan(int start, int length) int compositeEnd = Math.Min(UnderlyingText.Length, compositeStart + length); return new TextSpan(compositeStart, compositeEnd - compositeStart); } + + /// + /// Delegates to the SubText's to determine line information. + /// + private sealed class SubTextLineInfo : TextLineCollection + { + private readonly SubText _subText; + private readonly int _startLineNumberInUnderlyingText; + private readonly int _lineCount; + private readonly bool _startsWithinSplitCRLF; + private readonly bool _endsWithinSplitCRLF; + + public SubTextLineInfo(SubText subText) + { + _subText = subText; + + var startLineInUnderlyingText = _subText.UnderlyingText.Lines.GetLineFromPosition(_subText.UnderlyingSpan.Start); + var endLineInUnderlyingText = _subText.UnderlyingText.Lines.GetLineFromPosition(_subText.UnderlyingSpan.End); + + _startLineNumberInUnderlyingText = startLineInUnderlyingText.LineNumber; + _lineCount = (endLineInUnderlyingText.LineNumber - _startLineNumberInUnderlyingText) + 1; + + var underlyingSpanStart = _subText.UnderlyingSpan.Start; + if (underlyingSpanStart == startLineInUnderlyingText.End + 1 && + underlyingSpanStart == startLineInUnderlyingText.EndIncludingLineBreak - 1) + { + Debug.Assert(_subText.UnderlyingText[underlyingSpanStart - 1] == '\r' && _subText.UnderlyingText[underlyingSpanStart] == '\n'); + _startsWithinSplitCRLF = true; + } + + var underlyingSpanEnd = _subText.UnderlyingSpan.End; + if (underlyingSpanEnd == endLineInUnderlyingText.End + 1 && + underlyingSpanEnd == endLineInUnderlyingText.EndIncludingLineBreak - 1) + { + Debug.Assert(_subText.UnderlyingText[underlyingSpanEnd - 1] == '\r' && _subText.UnderlyingText[underlyingSpanEnd] == '\n'); + _endsWithinSplitCRLF = true; + + // If this subtext ends in the middle of a CR/LF, then this object should view that CR as a separate line + // whereas the UnderlyingText would not. + _lineCount += 1; + } + } + + public override TextLine this[int lineNumber] + { + get + { + if (lineNumber < 0 || lineNumber >= _lineCount) + { + throw new ArgumentOutOfRangeException(nameof(lineNumber)); + } + + if (_endsWithinSplitCRLF && lineNumber == _lineCount - 1) + { + // Special case splitting the CRLF at the end as the UnderlyingText doesn't view the position + // after between the \r and \n as on a new line whereas this subtext doesn't contain the \n + // and needs to view that position as on a new line. + return TextLine.FromSpanUnsafe(_subText, new TextSpan(_subText.UnderlyingSpan.End, 0)); + } + + var underlyingTextLine = _subText.UnderlyingText.Lines[lineNumber + _startLineNumberInUnderlyingText]; + + // Consider input "a\r\nb" where ST1 contains "\a\r" and ST2 contains "\n\b", and requested lineNumber + // per this table: + // ---------------------------------------------------------------------------------------------------------------- + // | SubText | lineNumber | underlyingTextLine | _subText | underlyingTextLine | _subText | + // | | | .Start | .UnderlyingSpan | .EndIncludingLineBreak | .UnderlyingSpan | + // | | | | .Start | | .End | + // |--------------------------------------------------------------------------------------------------------------- + // | ST1 | 0 | 0 | 0 | 3 | 2 | + // | ST2 | 0 | 0 | 2 | 3 | 4 | + // | ST2 | 1 | 3 | 2 | 4 | 4 | + // ---------------------------------------------------------------------------------------------------------------- + + // These two variables represent this subtext's view on the start/end of the requested line, + // but in the coordinate space of _subText.UnderlyingText. + var startInUnderlyingText = Math.Max(underlyingTextLine.Start, _subText.UnderlyingSpan.Start); + var endInUnderlyingText = Math.Min(underlyingTextLine.EndIncludingLineBreak, _subText.UnderlyingSpan.End); + + // This variable represent this subtext's view on start of the requested line, + // in it's coordinate space + var startInSubText = startInUnderlyingText - _subText.UnderlyingSpan.Start; + + var length = endInUnderlyingText - startInUnderlyingText; + var resultLine = TextLine.FromSpanUnsafe(_subText, new TextSpan(startInSubText, length)); + + var shouldContainLineBreak = (lineNumber != _lineCount - 1); + var resultContainsLineBreak = resultLine.EndIncludingLineBreak > resultLine.End; + + if (shouldContainLineBreak != resultContainsLineBreak) + { + throw new InvalidOperationException(); + } + + // Assert resultLine only has line breaks in the appropriate locations + Debug.Assert(resultLine.ToString().All(static c => !TextUtilities.IsAnyLineBreakCharacter(c))); + + return resultLine; + } + } + + public override int Count => _lineCount; + + /// + /// Determines the line number of a position in this SubText + /// + public override int IndexOf(int position) + { + if (position < 0 || position > _subText.UnderlyingSpan.Length) + { + throw new ArgumentOutOfRangeException(nameof(position)); + } + + var underlyingPosition = position + _subText.UnderlyingSpan.Start; + var underlyingLineNumber = _subText.UnderlyingText.Lines.IndexOf(underlyingPosition); + + if (_startsWithinSplitCRLF && position != 0) + { + // The \n contributes a line to the count in this subtext, but not in the UnderlyingText. + underlyingLineNumber += 1; + } + + return underlyingLineNumber - _startLineNumberInUnderlyingText; + } + } } } diff --git a/src/Compilers/Core/Portable/Text/TextLine.cs b/src/Compilers/Core/Portable/Text/TextLine.cs index df575962c0364..b5c34d1e58def 100644 --- a/src/Compilers/Core/Portable/Text/TextLine.cs +++ b/src/Compilers/Core/Portable/Text/TextLine.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Text @@ -81,6 +82,17 @@ public static TextLine FromSpan(SourceText text, TextSpan span) } } + // Do not use unless you are certain the span you are passing in is valid! + // This was added to allow SourceText.LineInfo's indexer to directly create TextLines + // without the performance implications of calling FromSpan. + internal static TextLine FromSpanUnsafe(SourceText text, TextSpan span) + { + Debug.Assert(span.Start == 0 || TextUtilities.IsAnyLineBreakCharacter(text[span.Start - 1])); + Debug.Assert(span.End == text.Length || TextUtilities.IsAnyLineBreakCharacter(text[span.End - 1])); + + return new TextLine(text, span.Start, span.End); + } + /// /// Gets the source text. /// diff --git a/src/Compilers/Core/Portable/WellKnownMember.cs b/src/Compilers/Core/Portable/WellKnownMember.cs index 1cdddef0d9097..2e24a7e26b353 100644 --- a/src/Compilers/Core/Portable/WellKnownMember.cs +++ b/src/Compilers/Core/Portable/WellKnownMember.cs @@ -545,8 +545,8 @@ internal enum WellKnownMember System_Runtime_CompilerServices_ITuple__get_Item, System_Runtime_CompilerServices_ITuple__get_Length, + System_Exception__ctorString, System_InvalidOperationException__ctor, - System_InvalidOperationException__ctorString, System_Runtime_CompilerServices_SwitchExpressionException__ctor, System_Runtime_CompilerServices_SwitchExpressionException__ctorObject, @@ -582,7 +582,7 @@ internal enum WellKnownMember System_NotSupportedException__ctor, System_IndexOutOfRangeException__ctor, - System_MissingMethodException__ctorString, + System_Runtime_CompilerServices_HotReloadException__ctorStringInt32, System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute__ctor, System_Collections_ICollection__Count, @@ -619,10 +619,13 @@ internal enum WellKnownMember System_Span_T__CopyTo_Span_T, System_ReadOnlySpan_T__CopyTo_Span_T, System_Collections_Immutable_ImmutableArray_T__AsSpan, + System_Collections_Immutable_ImmutableArray_T__Empty, System_Collections_Generic_List_T__AddRange, System_Runtime_CompilerServices_ParamCollectionAttribute__ctor, + System_Linq_Enumerable__ToList, + Count, // Remember to update the AllWellKnownTypeMembers tests when making changes here diff --git a/src/Compilers/Core/Portable/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index 0fd77f299f9c2..4774450d1e9c8 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -3805,20 +3805,20 @@ static WellKnownMembers() 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, // Return Type - // System_InvalidOperationException__ctor + // System_Exception__ctorString (byte)MemberFlags.Constructor, // Flags - (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_InvalidOperationException - WellKnownType.ExtSentinel), // DeclaringTypeId + (byte)WellKnownType.System_Exception, // DeclaringTypeId 0, // Arity - 0, // Method Signature + 1, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, - // System_InvalidOperationException__ctorString + // System_InvalidOperationException__ctor (byte)MemberFlags.Constructor, // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_InvalidOperationException - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity - 1, // Method Signature + 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, - (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, // System_Runtime_CompilerServices_SwitchExpressionException__ctor (byte)MemberFlags.Constructor, // Flags @@ -4033,13 +4033,14 @@ static WellKnownMembers() 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, - // System_MissingMethodException__ctorString + // System_Runtime_CompilerServices_HotReloadException_ctorStringInt32 (byte)MemberFlags.Constructor, // Flags - (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_MissingMethodException - WellKnownType.ExtSentinel), // DeclaringTypeId + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_HotReloadException - WellKnownType.ExtSentinel), // DeclaringTypeId 0, // Arity - 1, // Method Signature + 2, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, // MetadataUpdateOriginalTypeAttribute__ctor (byte)MemberFlags.Constructor, // Flags @@ -4165,11 +4166,11 @@ static WellKnownMembers() (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // System_Collections_Generic_List_T__ctorInt32 - (byte)MemberFlags.Constructor, // Flags + (byte)MemberFlags.Constructor, // Flags (byte)WellKnownType.System_Collections_Generic_List_T, // DeclaringTypeId - 0, // Arity - 1, // Method Signature - (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, + 0, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Int32, // System_Collections_Generic_List_T__Add @@ -4310,6 +4311,15 @@ static WellKnownMembers() 1, (byte)SignatureTypeCode.GenericTypeParameter, 0, + // System_Collections_Immutable_ImmutableArray_T__Empty + (byte)(MemberFlags.Field | MemberFlags.Static), // Flags + (byte)WellKnownType.System_Collections_Immutable_ImmutableArray_T, // DeclaringTypeId + 0, // Arity + (byte)SignatureTypeCode.GenericTypeInstance, // Field Signature + (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.System_Collections_Immutable_ImmutableArray_T, + 1, + (byte)SignatureTypeCode.GenericTypeParameter, 0, + // System_Collections_Generic_List_T__AddRange (byte)MemberFlags.Method, // Flags (byte)WellKnownType.System_Collections_Generic_List_T, // DeclaringTypeId @@ -4327,6 +4337,20 @@ static WellKnownMembers() 0, // Arity 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + + // System_Linq_Enumerable__ToList + (byte)(MemberFlags.Method | MemberFlags.Static), // Flags + (byte)WellKnownType.System_Linq_Enumerable, // DeclaringTypeId + 1, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.GenericTypeInstance, // Return Type + (byte)SignatureTypeCode.TypeHandle, (byte)WellKnownType.System_Collections_Generic_List_T, + 1, + (byte)SignatureTypeCode.GenericMethodParameter, 0, + (byte)SignatureTypeCode.GenericTypeInstance, + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Collections_Generic_IEnumerable_T, + 1, + (byte)SignatureTypeCode.GenericMethodParameter, 0, }; string[] allNames = new string[(int)WellKnownMember.Count] @@ -4798,8 +4822,8 @@ static WellKnownMembers() "MoveNext", // System_Runtime_CompilerServices_AsyncIteratorMethodBuilder__MoveNext_T "get_Item", // System_Runtime_CompilerServices_ITuple__get_Item "get_Length", // System_Runtime_CompilerServices_ITuple__get_Length + ".ctor", // System_Exception__ctorString ".ctor", // System_InvalidOperationException__ctor - ".ctor", // System_InvalidOperationException__ctorString ".ctor", // System_Runtime_CompilerServices_SwitchExpressionException__ctor ".ctor", // System_Runtime_CompilerServices_SwitchExpressionException__ctorObject "Equals", // System_Threading_CancellationToken__Equals @@ -4859,8 +4883,10 @@ static WellKnownMembers() "CopyTo", // System_Span_T__CopyTo_Span_T "CopyTo", // System_ReadOnlySpan_T__CopyTo_Span_T "AsSpan", // System_Collections_Immutable_ImmutableArray_T__AsSpan + "Empty", // System_Collections_Immutable_ImmutableArray_T__Empty "AddRange", // System_Collections_Generic_List_T__AddRange ".ctor", // System_Runtime_CompilerServices_ParamCollectionAttribute__ctor + "ToList", // System_Linq_Enumerable__ToList }; s_descriptors = MemberDescriptor.InitializeFromStream(new System.IO.MemoryStream(initializationBytes, writable: false), allNames); diff --git a/src/Compilers/Core/Portable/WellKnownTypes.cs b/src/Compilers/Core/Portable/WellKnownTypes.cs index c9ecb5758d173..950ce4f37ecae 100644 --- a/src/Compilers/Core/Portable/WellKnownTypes.cs +++ b/src/Compilers/Core/Portable/WellKnownTypes.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { @@ -328,7 +329,7 @@ internal enum WellKnownType System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute, System_Diagnostics_CodeAnalysis_UnscopedRefAttribute, - System_MissingMethodException, + System_Runtime_CompilerServices_HotReloadException, System_IndexOutOfRangeException, System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute, @@ -652,7 +653,7 @@ internal static class WellKnownTypes "System.MemoryExtensions", "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute", - "System.MissingMethodException", + "System.Runtime.CompilerServices.HotReloadException", "System.IndexOutOfRangeException", "System.Runtime.CompilerServices.MetadataUpdateOriginalTypeAttribute", "System.Runtime.CompilerServices.Unsafe", @@ -710,7 +711,7 @@ private static void AssertEnumAndTableInSync() typeIdName = typeIdName.Substring(0, separator); } - Debug.Assert(name == typeIdName, $"Enum name ({typeIdName}) and type name ({name}) must match at {i}"); + RoslynDebug.Assert(name == typeIdName, $"Enum name ({typeIdName}) and type name ({name}) must match at {i}"); } #if DEBUG diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf index 0106a258cfa33..e27948360035c 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf @@ -17,6 +17,11 @@ Sestavení, které obsahuje typ {0}, se odkazuje na architekturu .NET Framework, což se nepodporuje. + + attribute + attribute + + Illegal built-in operator name '{0}' Neplatný předdefinovaný název operátoru {0} @@ -268,6 +273,11 @@ Pokud jsou zadané anotace prvků řazené kolekce členů s možnou hodnotou null, musí se počet anotací shodovat s kardinalitou této řazené kolekce členů. + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. Nepodařilo se určit konkrétní příčinu selhání. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf index e988574c96d27..2f1024bd36d3f 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf @@ -17,6 +17,11 @@ Die Assembly mit dem Typ "{0}" verweist auf das .NET Framework. Dies wird nicht unterstützt. + + attribute + attribute + + Illegal built-in operator name '{0}' Unzulässiger integrierter Operator namens "{0}" @@ -268,6 +273,11 @@ Wenn Nullable-Anmerkungen für Tupelelemente angegeben werden, muss die Anzahl von Anmerkungen der Kardinalität des Tupels entsprechen. + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. Die spezifische Fehlerursache kann nicht ermittelt werden. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf index e030b5e8b4eb1..184b373347e55 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf @@ -17,6 +17,11 @@ El ensamblado que contiene el tipo "{0}" hace referencia a .NET Framework, lo cual no se admite. + + attribute + attribute + + Illegal built-in operator name '{0}' Nombre de operador integrado no válido "{0}" @@ -268,6 +273,11 @@ Si se especifican las anotaciones que aceptan valores NULL de los elementos de tupla, el número de anotaciones debe coincidir con la cardinalidad de la tupla. + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. No se puede determinar la causa específica del error. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf index 497f4a8a83a55..bc48129b024c3 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf @@ -17,6 +17,11 @@ L'assembly contenant le type '{0}' référence le .NET Framework, ce qui n'est pas pris en charge. + + attribute + attribute + + Illegal built-in operator name '{0}' Nom d’opérateur intégré '{0}' non autorisé @@ -268,6 +273,11 @@ Si des annotations de type Nullable pour des éléments de tuples sont spécifiées, le nombre d'annotations doit correspondre à la cardinalité du tuple. + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. Impossible de déterminer la cause spécifique de l'échec. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf index 324357a15bd9e..c55bd8e1bd77b 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf @@ -17,6 +17,11 @@ L'assembly che contiene il tipo '{0}' fa riferimento a .NET Framework, che non è supportato. + + attribute + attribute + + Illegal built-in operator name '{0}' Nome dell'operatore predefinito '{0}' non valido @@ -268,6 +273,11 @@ Se si specificano annotazioni nullable di elementi di tupla, il numero delle annotazioni deve corrispondere alla cardinalità della tupla. + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. Non è possibile determinare la causa specifica dell'errore. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf index 8f06782d9f1ae..348b8333d5d9d 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf @@ -17,6 +17,11 @@ 型 '{0}' を含むアセンブリが .NET Framework を参照しています。これはサポートされていません。 + + attribute + attribute + + Illegal built-in operator name '{0}' 不正な組み込み演算子名 '{0}' @@ -268,6 +273,11 @@ タプル要素の Null 許容の注釈を指定する場合、注釈の数はタプルの基数と一致する必要があります。 + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. エラーの具体的な原因を特定できません。 diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf index 6cc974a1b0cd9..6bcf6900e8733 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf @@ -17,6 +17,11 @@ '{0}' 형식을 포함하는 어셈블리가 지원되지 않는 .NET Framework를 참조합니다. + + attribute + attribute + + Illegal built-in operator name '{0}' 기본 제공 연산자 이름 '{0}'이(가) 잘못되었습니다. @@ -268,6 +273,11 @@ 튜플 요소 nullable 주석이 지정된 경우, 주석 수는 튜플의 카디널리티와 일치해야 합니다. + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. 오류의 특정 원인을 확인할 수 없습니다. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf index bb2300c32493b..17cbdb97b7166 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf @@ -17,6 +17,11 @@ Zestaw zawierający typ „{0}” odwołuje się do platformy .NET Framework, co nie jest obsługiwane. + + attribute + attribute + + Illegal built-in operator name '{0}' Niedozwolona nazwa wbudowanego operatora „{0}” @@ -268,6 +273,11 @@ Jeśli określono adnotacje elementów krotki z możliwością ustawiania wartości null, liczba adnotacji musi zgadzać się z kardynalnością krotki. + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. Nie można ustalić konkretnej przyczyny niepowodzenia. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf index ab8fa9d2378b8..9952ed99f3eb2 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf @@ -17,6 +17,11 @@ O assembly contendo o tipo '{0}' faz referência a .NET Framework, mas não há suporte para isso. + + attribute + attribute + + Illegal built-in operator name '{0}' Nome de operador interno inválido '{0}' @@ -268,6 +273,11 @@ Se as anotações anuláveis de elementos de tupla forem especificadas, o número de anotações deverá corresponder à cardinalidade da tupla. + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. Não é possível determinar a causa específica da falha. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf index e70a3e967e96f..75e0c337d706f 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf @@ -17,6 +17,11 @@ Сборка, содержащая тип "{0}", ссылается на платформу .NET Framework, которая не поддерживается. + + attribute + attribute + + Illegal built-in operator name '{0}' Недопустимое имя встроенного оператора "{0}" @@ -268,6 +273,11 @@ Если указаны аннотации элементов кортежа, допускающих значения null, то число аннотаций должно соответствовать кратности кортежа. + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. Не удается определить конкретную причину сбоя. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf index e2d8d8b981974..6b008f54f5c42 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf @@ -17,6 +17,11 @@ '{0}' türünü içeren bütünleştirilmiş kod, desteklenmeyen .NET Framework'e başvuruyor. + + attribute + attribute + + Illegal built-in operator name '{0}' Geçersiz yerleşik operatör adı '{0}' @@ -268,6 +273,11 @@ Demet öğelerine yönelik boş değer atanabilir ek açıklamalar belirtildiyse, ek açıklamaların sayısı demetin kardinalitesiyle eşleşmelidir. + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. Hatanın nedeni belirlenemiyor. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf index 8025a8ee63994..f5e63e3d44c6d 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf @@ -17,6 +17,11 @@ 包含类型“{0}”的程序集引用了 .NET Framework,而此操作不受支持。 + + attribute + attribute + + Illegal built-in operator name '{0}' 内置运算符名称“{0}”非法 @@ -268,6 +273,11 @@ 如果已指定元组元素可以为 null 的注释,则注释的数量必须与元组基数相匹配。 + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. 无法确定失败的具体原因。 diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf index 7997103691f46..57ee62adf5847 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf @@ -17,6 +17,11 @@ 包含類型 '{0}' 的組件參考了 .NET Framework,此情形不受支援。 + + attribute + attribute + + Illegal built-in operator name '{0}' 不合法的內建運算子名稱 '{0}' @@ -268,6 +273,11 @@ 如果指定元組元素可為 Null 的註釋,註釋數目就必須符合元組的基數。 + + '{0}' type does not have the expected constructor + '{0}' type does not have the expected constructor + + Unable to determine specific cause of the failure. 無法判斷失敗的具體原因。 diff --git a/src/Compilers/Extension/Roslyn.Compilers.Extension.csproj b/src/Compilers/Extension/Roslyn.Compilers.Extension.csproj index 693b57f1ffcb8..2421908a81b79 100644 --- a/src/Compilers/Extension/Roslyn.Compilers.Extension.csproj +++ b/src/Compilers/Extension/Roslyn.Compilers.Extension.csproj @@ -13,7 +13,7 @@ true true false - true + true /* strtod, strtof */ - -#include "CLibraryShim.h" - -double CLibraryShim::RealConversions::atod(String^ s) -{ - int length = s->Length; - wchar_t *chars = new wchar_t[length + 1]; - for (int i = 0; i < length; i++) chars[i] = (*s)[i]; - chars[length] = 0; - wchar_t *end = 0; - double d = wcstod(chars, &end); - delete chars; - return d; -} - -float CLibraryShim::RealConversions::atof(String^ s) -{ - int length = s->Length; - wchar_t *chars = new wchar_t[length + 1]; - for (int i = 0; i < length; i++) chars[i] = (*s)[i]; - chars[length] = 0; - wchar_t *end = 0; - float f = wcstof(chars, &end); - delete chars; - return f; -} \ No newline at end of file diff --git a/src/Compilers/RealParserTests/CLibraryShim/CLibraryShim.vcxproj b/src/Compilers/RealParserTests/CLibraryShim/CLibraryShim.vcxproj deleted file mode 100644 index aca89ed5b6449..0000000000000 --- a/src/Compilers/RealParserTests/CLibraryShim/CLibraryShim.vcxproj +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {D8C0BD38-F641-4D8E-A2E0-8F89F30531B2} - v4.5.2 - ManagedCProj - CLibraryShim - 8.1 - - - - DynamicLibrary - true - v140 - true - Unicode - - - DynamicLibrary - false - v140 - true - Unicode - - - DynamicLibrary - true - v140 - true - Unicode - - - DynamicLibrary - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - Level3 - Disabled - WIN32;_DEBUG;%(PreprocessorDefinitions) - NotUsing - - - - - true - - - - - - Level3 - Disabled - _DEBUG;%(PreprocessorDefinitions) - Use - - - true - - - - - - Level3 - WIN32;NDEBUG;%(PreprocessorDefinitions) - Use - - - true - - - - - - Level3 - NDEBUG;%(PreprocessorDefinitions) - Use - - - true - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Compilers/RealParserTests/Properties/AssemblyInfo.cs b/src/Compilers/RealParserTests/Properties/AssemblyInfo.cs deleted file mode 100644 index cf9650012e58c..0000000000000 --- a/src/Compilers/RealParserTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("RealParserTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("RealParserTests")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("315bb5ef-73a8-44dd-a6f8-c07680d1e4ff")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Compilers/RealParserTests/RandomRealParserTests.cs b/src/Compilers/RealParserTests/RandomRealParserTests.cs deleted file mode 100644 index 60085228b6504..0000000000000 --- a/src/Compilers/RealParserTests/RandomRealParserTests.cs +++ /dev/null @@ -1,77 +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.Text; -using System.Threading.Tasks; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Microsoft.CodeAnalysis; - -[TestClass] -public class RandomRealParserTests -{ - [TestMethod] - public void TestRandomDoubleStrings() - { - var start = DateTime.UtcNow; - // compare our atod on random strings against C's strtod - Parallel.For(0, 150, part => - { - Random r = new Random(start.GetHashCode() + part); - var b = new StringBuilder(); - for (int i = 0; i < 100000; i++) - { - b.Clear(); - int beforeCount = r.Next(3); - int afterCount = r.Next(1 + part % 50); - int exp = r.Next(-330, 330); - if (beforeCount == 0) b.Append('0'); - for (int j = 0; j < beforeCount; j++) b.Append((char)('0' + r.Next(10))); - b.Append('.'); - for (int j = 0; j < afterCount; j++) b.Append((char)('0' + r.Next(10))); - b.Append('e'); - if (exp >= 0 && r.Next(2) == 0) b.Append('+'); - b.Append(exp); - var s = b.ToString(); - double d1; - d1 = CLibraryShim.RealConversions.atod(s); - double d2; - if (!RealParser.TryParseDouble(s, out d2)) d2 = 1.0 / 0.0; - Assert.AreEqual(d1, d2, 0.0, $"{s} differ\n RealParser=>{d2:G17}\n atod=>{d1:G17}\n"); - } - }); - } - - [TestMethod] - public void TestRandomFloatStrings() - { - var start = DateTime.UtcNow; - // compare our atof on random strings against C's strtof - Parallel.For(0, 150, part => - { - Random r = new Random(start.GetHashCode() + part); - var b = new StringBuilder(); - for (int i = 0; i < 100000; i++) - { - b.Clear(); - int beforeCount = r.Next(3); - int afterCount = r.Next(1 + part % 50); - int exp = r.Next(-50, 40); - if (beforeCount == 0) b.Append('0'); - for (int j = 0; j < beforeCount; j++) b.Append((char)('0' + r.Next(10))); - b.Append('.'); - for (int j = 0; j < afterCount; j++) b.Append((char)('0' + r.Next(10))); - b.Append('e'); - if (exp >= 0 && r.Next(2) == 0) b.Append('+'); - b.Append(exp); - var s = b.ToString(); - float d1; - d1 = CLibraryShim.RealConversions.atof(s); - float d2; - if (!RealParser.TryParseFloat(s, out d2)) d2 = 1.0f / 0.0f; - Assert.AreEqual(d1, d2, 0.0, $"{s} differ\n RealParser=>{d2:G17}\n atof=>{d1:G17}\n"); - } - }); - } -} diff --git a/src/Compilers/RealParserTests/RealParserTests.csproj b/src/Compilers/RealParserTests/RealParserTests.csproj deleted file mode 100644 index 17b35d47bdba8..0000000000000 --- a/src/Compilers/RealParserTests/RealParserTests.csproj +++ /dev/null @@ -1,93 +0,0 @@ - - - - - Debug - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF} - Library - Properties - RealParserTests - RealParserTests - v4.5.2 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - RealParser.cs - - - - - - - {d8c0bd38-f641-4d8e-a2e0-8f89f30531b2} - CLibraryShim - - - - - - - False - - - False - - - False - - - False - - - - - - - - diff --git a/src/Compilers/RealParserTests/RealParserTests.sln b/src/Compilers/RealParserTests/RealParserTests.sln deleted file mode 100644 index c200e5c7a19b8..0000000000000 --- a/src/Compilers/RealParserTests/RealParserTests.sln +++ /dev/null @@ -1,46 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RealParserTests", "RealParserTests.csproj", "{315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CLibraryShim", "CLibraryShim\CLibraryShim.vcxproj", "{D8C0BD38-F641-4D8E-A2E0-8F89F30531B2}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Debug|x64.ActiveCfg = Debug|Any CPU - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Debug|x64.Build.0 = Debug|Any CPU - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Debug|x86.ActiveCfg = Debug|Any CPU - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Debug|x86.Build.0 = Debug|Any CPU - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Release|Any CPU.Build.0 = Release|Any CPU - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Release|x64.ActiveCfg = Release|Any CPU - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Release|x64.Build.0 = Release|Any CPU - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Release|x86.ActiveCfg = Release|Any CPU - {315BB5EF-73A8-44DD-A6F8-C07680D1E4FF}.Release|x86.Build.0 = Release|Any CPU - {D8C0BD38-F641-4D8E-A2E0-8F89F30531B2}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {D8C0BD38-F641-4D8E-A2E0-8F89F30531B2}.Debug|x64.ActiveCfg = Debug|x64 - {D8C0BD38-F641-4D8E-A2E0-8F89F30531B2}.Debug|x64.Build.0 = Debug|x64 - {D8C0BD38-F641-4D8E-A2E0-8F89F30531B2}.Debug|x86.ActiveCfg = Debug|Win32 - {D8C0BD38-F641-4D8E-A2E0-8F89F30531B2}.Debug|x86.Build.0 = Debug|Win32 - {D8C0BD38-F641-4D8E-A2E0-8F89F30531B2}.Release|Any CPU.ActiveCfg = Release|Win32 - {D8C0BD38-F641-4D8E-A2E0-8F89F30531B2}.Release|x64.ActiveCfg = Release|x64 - {D8C0BD38-F641-4D8E-A2E0-8F89F30531B2}.Release|x64.Build.0 = Release|x64 - {D8C0BD38-F641-4D8E-A2E0-8F89F30531B2}.Release|x86.ActiveCfg = Release|Win32 - {D8C0BD38-F641-4D8E-A2E0-8F89F30531B2}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/src/Compilers/Server/VBCSCompiler/VBCSCompilerCommandLine.projitems b/src/Compilers/Server/VBCSCompiler/VBCSCompilerCommandLine.projitems index 25e47648faab4..ff5baba5bec0f 100644 --- a/src/Compilers/Server/VBCSCompiler/VBCSCompilerCommandLine.projitems +++ b/src/Compilers/Server/VBCSCompiler/VBCSCompilerCommandLine.projitems @@ -56,7 +56,7 @@ - + diff --git a/src/Compilers/Server/VBCSCompiler/arm64/VBCSCompiler-arm64.csproj b/src/Compilers/Server/VBCSCompiler/arm64/VBCSCompiler-arm64.csproj index 657d47a173329..059d6817c7607 100644 --- a/src/Compilers/Server/VBCSCompiler/arm64/VBCSCompiler-arm64.csproj +++ b/src/Compilers/Server/VBCSCompiler/arm64/VBCSCompiler-arm64.csproj @@ -10,7 +10,7 @@ net472 true true - true + true diff --git a/src/Compilers/Server/VBCSCompilerTests/AnalyzerConsistencyCheckerTests.cs b/src/Compilers/Server/VBCSCompilerTests/AnalyzerConsistencyCheckerTests.cs index 8bb31b511dfb6..4c381c8dc8d4d 100644 --- a/src/Compilers/Server/VBCSCompilerTests/AnalyzerConsistencyCheckerTests.cs +++ b/src/Compilers/Server/VBCSCompilerTests/AnalyzerConsistencyCheckerTests.cs @@ -251,5 +251,6 @@ public void AddDependencyLocation(string fullPath) { } public bool IsHostAssembly(Assembly assembly) => false; public Assembly LoadFromPath(string fullPath) => throw new Exception(); public string? GetOriginalDependencyLocation(AssemblyName assembly) => throw new Exception(); + public void Dispose() { } } } diff --git a/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs b/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs index 1d1e944bd482a..e6629a1bca95d 100644 --- a/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs +++ b/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs @@ -1243,8 +1243,8 @@ public async Task Utf8Output_WithRedirecting_On_Shared_VB() [Trait(Traits.Environment, Traits.Environments.VSProductInstall)] public async Task AssemblyIdentityComparer1() { - _tempDirectory.CreateFile("mscorlib20.dll").WriteAllBytes(TestMetadata.ResourcesNet20.mscorlib); - _tempDirectory.CreateFile("mscorlib40.dll").WriteAllBytes(TestMetadata.ResourcesNet40.mscorlib); + _tempDirectory.CreateFile("mscorlib20.dll").WriteAllBytes(Net20.Resources.mscorlib); + _tempDirectory.CreateFile("mscorlib40.dll").WriteAllBytes(Net40.Resources.mscorlib); // Create DLL "lib.dll" Dictionary files = diff --git a/src/Compilers/Server/VBCSCompilerTests/NamedPipeClientConnectionHostTests.cs b/src/Compilers/Server/VBCSCompilerTests/NamedPipeClientConnectionHostTests.cs index d4b99885bb927..21709cdcc467a 100644 --- a/src/Compilers/Server/VBCSCompilerTests/NamedPipeClientConnectionHostTests.cs +++ b/src/Compilers/Server/VBCSCompilerTests/NamedPipeClientConnectionHostTests.cs @@ -57,13 +57,13 @@ public async Task CallAfterComplete() } [ConditionalFact(typeof(WindowsOrLinuxOnly), Reason = "https://github.com/dotnet/runtime/issues/40301")] - public void EndListenCancelsIncompleteTask() + public async Task EndListenCancelsIncompleteTask() { _host.BeginListening(); var task = _host.GetNextClientConnectionAsync(); _host.EndListening(); - Assert.ThrowsAsync(() => task); + await Assert.ThrowsAsync(async () => await task); } /// diff --git a/src/Compilers/Shared/RuntimeHostInfo.cs b/src/Compilers/Shared/RuntimeHostInfo.cs index 0f08c684f7ef9..28c6a9644181b 100644 --- a/src/Compilers/Shared/RuntimeHostInfo.cs +++ b/src/Compilers/Shared/RuntimeHostInfo.cs @@ -25,7 +25,7 @@ internal static class RuntimeHostInfo /// internal static (string processFilePath, string commandLineArguments, string toolFilePath) GetProcessInfo(string toolFilePathWithoutExtension, string commandLineArguments) { -#if NETCOREAPP +#if NET // First check for an app host file and return that if it's available. var appHostSuffix = PlatformInformation.IsWindows ? ".exe" : ""; var appFilePath = $"{toolFilePathWithoutExtension}{appHostSuffix}"; @@ -45,7 +45,7 @@ internal static (string processFilePath, string commandLineArguments, string too #endif } -#if NETCOREAPP +#if NET internal static bool IsCoreClrRuntime => true; diff --git a/src/Compilers/Test/Core/Assert/AssertEx.cs b/src/Compilers/Test/Core/Assert/AssertEx.cs index 244b92a4d6aa9..49a41a88e565e 100644 --- a/src/Compilers/Test/Core/Assert/AssertEx.cs +++ b/src/Compilers/Test/Core/Assert/AssertEx.cs @@ -19,6 +19,7 @@ using DiffPlex.Chunkers; using DiffPlex.DiffBuilder; using DiffPlex.DiffBuilder.Model; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; @@ -160,6 +161,12 @@ public static void AreEqual(T expected, T actual, string message = null, IEqu } } + public static void Equal(ReadOnlySpan expected, T[] actual) => + Equal(expected.ToArray(), actual); + + public static void Equal(ImmutableArray expected, IEnumerable actual) + => Equal(expected, actual, comparer: null, message: null); + public static void Equal(ImmutableArray expected, IEnumerable actual, IEqualityComparer comparer = null, string message = null) { if (actual == null || expected.IsDefault) @@ -172,6 +179,9 @@ public static void Equal(ImmutableArray expected, IEnumerable actual, I } } + public static void Equal(IEnumerable expected, ImmutableArray actual) + => Equal(expected, actual, comparer: null, message: null, itemInspector: null); + public static void Equal(IEnumerable expected, ImmutableArray actual, IEqualityComparer comparer = null, string message = null, string itemSeparator = null) { if (expected == null || actual.IsDefault) @@ -184,6 +194,9 @@ public static void Equal(IEnumerable expected, ImmutableArray actual, I } } + public static void Equal(ImmutableArray expected, ImmutableArray actual) + => Equal(expected, actual, comparer: null, message: null, itemInspector: null); + public static void Equal(ImmutableArray expected, ImmutableArray actual, IEqualityComparer comparer = null, string message = null, string itemSeparator = null) { Equal(expected, (IEnumerable)actual, comparer, message, itemSeparator); @@ -1013,5 +1026,75 @@ public static void Contains(IEnumerable collection, Predicate filter, F Fail("Filter does not match any item in the collection: " + Environment.NewLine + ToString(collection, itemSeparator ?? Environment.NewLine, itemInspector)); } + +#nullable enable + + /// + /// The xunit Assert.Equal method is not callable in Visual Basic due to the presence of + /// the unmanaged constraint. Need to indirect through C# here until we resolve this. + /// + /// https://github.com/dotnet/roslyn/issues/75063 + /// + public static void Equal(T[] expected, T[] actual) => + Assert.Equal(expected, actual); + + /// + /// The xunit Assert.Equal method is not callable in Visual Basic due to the presence of + /// the unmanaged constraint. Need to indirect through C# here until we resolve this. + /// + /// https://github.com/dotnet/roslyn/issues/75063 + /// + public static void Equal(T expected, T actual) => + Assert.Equal(expected, actual); + + /// + /// The xunit Assert.NotEqual method is not callable in Visual Basic due to the presence of + /// the unmanaged constraint. Need to indirect through C# here until we resolve this. + /// + /// https://github.com/dotnet/roslyn/issues/75063 + /// + public static void NotEqual(T expected, T actual) => + Assert.NotEqual(expected, actual); + + /// + /// This assert passes if the collection is not null and empty + /// + /// + /// The core is annotated to not accept null but many + /// of our call sites pass a potentially nullable value. + /// + public static void AssertEmpty(IEnumerable? collection) + { + Assert.NotNull(collection); + Assert.Empty(collection); + } + + /// + /// This assert passes if the collection is not null and has a single item. + /// + /// + /// The core is annotated to not accept null but many + /// of our call sites pass a potentially nullable value. + /// + public static T Single(IEnumerable? collection) + { + Assert.NotNull(collection); + return Assert.Single(collection); + } + + /// + /// Verify the collection is not null and all the items pass the action. + /// + /// + /// The core is annotated to not accept null but many + /// of our call sites pass a potentially nullable value. + /// + public static void All(IEnumerable? collection, Action action) + { + Assert.NotNull(collection); + Assert.All(collection, action); + } + +#nullable disable } } diff --git a/src/Compilers/Test/Core/Compilation/CompilationDifference.cs b/src/Compilers/Test/Core/Compilation/CompilationDifference.cs index 21cb6c15890a8..7e2c84c4e028c 100644 --- a/src/Compilers/Test/Core/Compilation/CompilationDifference.cs +++ b/src/Compilers/Test/Core/Compilation/CompilationDifference.cs @@ -15,9 +15,11 @@ using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Symbols; using Microsoft.DiaSymReader.Tools; using Microsoft.Metadata.Tools; using Roslyn.Test.Utilities; +using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Test.Utilities @@ -133,9 +135,33 @@ private static string GetTypeName(SignatureTypeCode typeCode) } public void VerifySynthesizedMembers(params string[] expectedSynthesizedTypesAndMemberCounts) + => VerifySynthesizedMembers(EmitResult.Baseline.SynthesizedMembers, displayTypeKind: false, expectedSynthesizedTypesAndMemberCounts); + + internal static void VerifySynthesizedMembers(IReadOnlyDictionary> actualMembers, bool displayTypeKind, params string[] expected) { - var actual = EmitResult.Baseline.SynthesizedMembers.Select(e => e.Key.ToString() + ": {" + string.Join(", ", e.Value.Select(v => v.Name)) + "}"); - AssertEx.SetEqual(expectedSynthesizedTypesAndMemberCounts, actual, itemSeparator: ",\r\n", itemInspector: s => $"\"{s}\""); + // Synthesized namespaces are not interesting. Explode them and display types contained in them as separate fully qualified names in the list. + var actual = new List(); + foreach (var (container, members) in actualMembers) + { + if (container is INamespaceSymbolInternal ns) + { + actual.AddRange(members + .Where(m => m is not INamespaceSymbolInternal) + .Select(m => m.GetISymbol().ToDisplayString(SymbolDisplayFormat.TestFormat))); + } + } + + foreach (var (container, members) in actualMembers) + { + if (container is not INamespaceSymbolInternal) + { + actual.Add( + $"{(displayTypeKind && container is INamedTypeSymbolInternal type ? (type.TypeKind == TypeKind.Struct ? "struct " : "class ") : "")}{container}: " + + $"{{{string.Join(", ", members.Select(v => v.Name))}}}"); + } + } + + AssertEx.SetEqual(expected, actual, itemSeparator: ",\r\n", itemInspector: s => $"\"{s}\""); } public void VerifySynthesizedFields(string typeName, params string[] expectedSynthesizedTypesAndMemberCounts) diff --git a/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs b/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs index 13978d0de4ab5..e2fdfbcc60d5b 100644 --- a/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs +++ b/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs @@ -276,10 +276,7 @@ public static void ValidateIOperations(Func createCompilation) var compilation = createCompilation(); var roots = ArrayBuilder<(IOperation operation, ISymbol associatedSymbol)>.GetInstance(); var stopWatch = new Stopwatch(); - if (!System.Diagnostics.Debugger.IsAttached) - { - stopWatch.Start(); - } + start(stopWatch); void checkTimeout() { @@ -346,13 +343,21 @@ void checkTimeout() stopWatch.Stop(); checkControlFlowGraph(root, associatedSymbol); - stopWatch.Start(); + start(stopWatch); } roots.Free(); stopWatch.Stop(); return; + static void start(Stopwatch stopWatch) + { + if (!System.Diagnostics.Debugger.IsAttached) + { + stopWatch.Start(); + } + } + void checkControlFlowGraph(IOperation root, ISymbol associatedSymbol) { switch (root) diff --git a/src/Compilers/Test/Core/CompilationVerifier.cs b/src/Compilers/Test/Core/CompilationVerifier.cs index b09d83e4f2ef9..ebc1cd681856e 100644 --- a/src/Compilers/Test/Core/CompilationVerifier.cs +++ b/src/Compilers/Test/Core/CompilationVerifier.cs @@ -272,7 +272,7 @@ public void Emit( try { testEnvironment.Verify(peVerify); -#if NETCOREAPP +#if NET ILVerify(peVerify); #endif } diff --git a/src/Compilers/Test/Core/EncodingTestHelpers.cs b/src/Compilers/Test/Core/EncodingTestHelpers.cs index d9483296c4365..eccf37fa831e6 100644 --- a/src/Compilers/Test/Core/EncodingTestHelpers.cs +++ b/src/Compilers/Test/Core/EncodingTestHelpers.cs @@ -16,7 +16,7 @@ public static class EncodingTestHelpers { public static IEnumerable GetEncodings() { -#if NETCOREAPP +#if NET Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); #endif yield return null; @@ -26,7 +26,7 @@ public static class EncodingTestHelpers yield return new UTF32Encoding(bigEndian: false, byteOrderMark: false); yield return new UnicodeEncoding(bigEndian: true, byteOrderMark: false); yield return new UnicodeEncoding(bigEndian: false, byteOrderMark: false); -#if NETCOREAPP +#if NET foreach (var info in CodePagesEncodingProvider.Instance.GetEncodings()) { yield return info.GetEncoding(); diff --git a/src/Compilers/Test/Core/Generate.ps1 b/src/Compilers/Test/Core/Generate.ps1 deleted file mode 100644 index 4d5aaefa1d440..0000000000000 --- a/src/Compilers/Test/Core/Generate.ps1 +++ /dev/null @@ -1,190 +0,0 @@ -function Add-TargetFramework($name, $packagePath, $list) -{ - $resourceTypeName = "Resources" + $name - $script:codeContent += @" - public static class $resourceTypeName - { - -"@; - - $refContent = @" - public static class $name - { - -"@ - - $refAllContent = @" - public static ReferenceInfo[] All => new[] - { - -"@ - - $name = $name.ToLower() - foreach ($dllPath in $list) - { - if ($dllPath.Contains('#')) - { - $all = $dllPath.Split('#') - $dllName = $all[0] - $dllPath = $all[1] - $dll = Split-Path -leaf $dllPath - $logicalName = "$($dllName.ToLower()).$($name).$($dll)"; - } - else - { - $dll = Split-Path -leaf $dllPath - $dllName = $dll.Substring(0, $dll.Length - 4) - $logicalName = "$($name).$($dll)"; - } - - $dllFileName = "$($dllName).dll" - $link = "Resources\ReferenceAssemblies\$name\$dll" - $script:targetsContent += @" - - $logicalName - $link - - -"@ - - $propName = $dllName.Replace(".", ""); - $fieldName = "_" + $propName - $script:codeContent += @" - private static byte[] $fieldName; - public static byte[] $propName => ResourceLoader.GetOrCreateResource(ref $fieldName, "$logicalName"); - -"@ - - $refAllContent += @" - new ReferenceInfo("$dllFileName", $propName), - -"@ - - $refContent += @" - public static PortableExecutableReference $propName { get; } = AssemblyMetadata.CreateFromImage($($resourceTypeName).$($propName)).GetReference(display: "$dll ($name)", filePath: "$dllFileName"); - -"@ - - } - - $script:codeContent += $refAllContent - $script:codeContent += @" - }; - } - -"@ - - $script:codeContent += $refContent; - $script:codeContent += @" - } - -"@ -} - -$targetsContent = @" - - - -"@; - -$codeContent = @" -// 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. - -// This is a generated file, please edit Generate.ps1 to change the contents - -#nullable disable - -using Microsoft.CodeAnalysis; - -namespace Roslyn.Test.Utilities -{ - public static class TestMetadata - { - public readonly struct ReferenceInfo - { - public string FileName { get; } - public byte[] ImageBytes { get; } - public ReferenceInfo(string fileName, byte[] imageBytes) - { - FileName = fileName; - ImageBytes = imageBytes; - } - } - -"@ - - -Add-TargetFramework "Net20" '$(PkgMicrosoft_NETFramework_ReferenceAssemblies_net20)\build\.NETFramework\v2.0' @( - 'mscorlib.dll', - 'System.dll', - 'Microsoft.VisualBasic.dll') - -Add-TargetFramework "Net35" '$(Pkgjnm2_ReferenceAssemblies_net35)\build\.NETFramework\v3.5' @( - 'System.Core.dll' -) - -Add-TargetFramework "Net40" '$(PkgMicrosoft_NETFramework_ReferenceAssemblies_net40)\build\.NETFramework\v4.0' @( - 'mscorlib.dll', - 'System.dll', - 'System.Core.dll', - 'System.Data.dll', - 'System.Xml.dll', - 'System.Xml.Linq.dll', - 'Microsoft.VisualBasic.dll', - 'Microsoft.CSharp.dll' -) - -Add-TargetFramework "Net451" '$(PkgMicrosoft_NETFramework_ReferenceAssemblies_net451)\build\.NETFramework\v4.5.1' @( - 'mscorlib.dll', - 'System.dll', - 'System.Configuration.dll', - 'System.Core.dll', - 'System.Data.dll', - 'System.Drawing.dll', - 'System.EnterpriseServices.dll', - 'System.Runtime.Serialization.dll', - 'System.Windows.Forms.dll', - 'System.Web.Services.dll', - 'System.Xml.dll', - 'System.Xml.Linq.dll', - 'Microsoft.CSharp.dll', - 'Microsoft.VisualBasic.dll', - 'Facades\System.ObjectModel.dll', - 'Facades\System.Runtime.dll', - 'Facades\System.Runtime.InteropServices.WindowsRuntime.dll', - 'Facades\System.Threading.dll', - 'Facades\System.Threading.Tasks.dll' -) - -Add-TargetFramework "MicrosoftCSharp" '$(PkgMicrosoft_CSharp)' @( - 'Netstandard10#ref\netstandard1.0\Microsoft.CSharp.dll' - 'Netstandard13Lib#lib\netstandard1.3\Microsoft.CSharp.dll' -) - -Add-TargetFramework "MicrosoftVisualBasic" '$(PkgMicrosoft_VisualBasic)\ref' @( - 'Netstandard11#netstandard1.1\Microsoft.VisualBasic.dll' -) - -Add-TargetFramework "SystemThreadingTasksExtensions" '$(PkgSystem_Threading_Tasks_Extensions)' @( - 'PortableLib#\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll', - 'NetStandard20Lib#\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll' -) - -Add-TargetFramework "BuildExtensions" '$(PkgMicrosoft_NET_Build_Extensions)\msbuildExtensions\Microsoft\Microsoft.NET.Build.Extensions' @( - 'NetStandardToNet461#net461\lib\netstandard.dll' -) - -$targetsContent += @" - - -"@; - -$codeContent += @" - } -} -"@ - -$targetsContent | Out-File "Generated.targets" -Encoding Utf8 -$codeContent | Out-File "Generated.cs" -Encoding Utf8 diff --git a/src/Compilers/Test/Core/Generated.cs b/src/Compilers/Test/Core/Generated.cs deleted file mode 100644 index 137e93e893866..0000000000000 --- a/src/Compilers/Test/Core/Generated.cs +++ /dev/null @@ -1,246 +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. - -// This is a generated file, please edit Generate.ps1 to change the contents - -#nullable disable - -using Microsoft.CodeAnalysis; - -namespace Roslyn.Test.Utilities -{ - public static class TestMetadata - { - public readonly struct ReferenceInfo - { - public string FileName { get; } - public byte[] ImageBytes { get; } - public ReferenceInfo(string fileName, byte[] imageBytes) - { - FileName = fileName; - ImageBytes = imageBytes; - } - } - public static class ResourcesNet20 - { - private static byte[] _mscorlib; - public static byte[] mscorlib => ResourceLoader.GetOrCreateResource(ref _mscorlib, "net20.mscorlib.dll"); - private static byte[] _System; - public static byte[] System => ResourceLoader.GetOrCreateResource(ref _System, "net20.System.dll"); - private static byte[] _MicrosoftVisualBasic; - public static byte[] MicrosoftVisualBasic => ResourceLoader.GetOrCreateResource(ref _MicrosoftVisualBasic, "net20.Microsoft.VisualBasic.dll"); - public static ReferenceInfo[] All => new[] - { - new ReferenceInfo("mscorlib.dll", mscorlib), - new ReferenceInfo("System.dll", System), - new ReferenceInfo("Microsoft.VisualBasic.dll", MicrosoftVisualBasic), - }; - } - public static class Net20 - { - public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet20.mscorlib).GetReference(display: "mscorlib.dll (net20)", filePath: "mscorlib.dll"); - public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet20.System).GetReference(display: "System.dll (net20)", filePath: "System.dll"); - public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet20.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (net20)", filePath: "Microsoft.VisualBasic.dll"); - } - public static class ResourcesNet35 - { - private static byte[] _SystemCore; - public static byte[] SystemCore => ResourceLoader.GetOrCreateResource(ref _SystemCore, "net35.System.Core.dll"); - public static ReferenceInfo[] All => new[] - { - new ReferenceInfo("System.Core.dll", SystemCore), - }; - } - public static class Net35 - { - public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet35.SystemCore).GetReference(display: "System.Core.dll (net35)", filePath: "System.Core.dll"); - } - public static class ResourcesNet40 - { - private static byte[] _mscorlib; - public static byte[] mscorlib => ResourceLoader.GetOrCreateResource(ref _mscorlib, "net40.mscorlib.dll"); - private static byte[] _System; - public static byte[] System => ResourceLoader.GetOrCreateResource(ref _System, "net40.System.dll"); - private static byte[] _SystemCore; - public static byte[] SystemCore => ResourceLoader.GetOrCreateResource(ref _SystemCore, "net40.System.Core.dll"); - private static byte[] _SystemData; - public static byte[] SystemData => ResourceLoader.GetOrCreateResource(ref _SystemData, "net40.System.Data.dll"); - private static byte[] _SystemXml; - public static byte[] SystemXml => ResourceLoader.GetOrCreateResource(ref _SystemXml, "net40.System.Xml.dll"); - private static byte[] _SystemXmlLinq; - public static byte[] SystemXmlLinq => ResourceLoader.GetOrCreateResource(ref _SystemXmlLinq, "net40.System.Xml.Linq.dll"); - private static byte[] _MicrosoftVisualBasic; - public static byte[] MicrosoftVisualBasic => ResourceLoader.GetOrCreateResource(ref _MicrosoftVisualBasic, "net40.Microsoft.VisualBasic.dll"); - private static byte[] _MicrosoftCSharp; - public static byte[] MicrosoftCSharp => ResourceLoader.GetOrCreateResource(ref _MicrosoftCSharp, "net40.Microsoft.CSharp.dll"); - public static ReferenceInfo[] All => new[] - { - new ReferenceInfo("mscorlib.dll", mscorlib), - new ReferenceInfo("System.dll", System), - new ReferenceInfo("System.Core.dll", SystemCore), - new ReferenceInfo("System.Data.dll", SystemData), - new ReferenceInfo("System.Xml.dll", SystemXml), - new ReferenceInfo("System.Xml.Linq.dll", SystemXmlLinq), - new ReferenceInfo("Microsoft.VisualBasic.dll", MicrosoftVisualBasic), - new ReferenceInfo("Microsoft.CSharp.dll", MicrosoftCSharp), - }; - } - public static class Net40 - { - public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.mscorlib).GetReference(display: "mscorlib.dll (net40)", filePath: "mscorlib.dll"); - public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.System).GetReference(display: "System.dll (net40)", filePath: "System.dll"); - public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemCore).GetReference(display: "System.Core.dll (net40)", filePath: "System.Core.dll"); - public static PortableExecutableReference SystemData { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemData).GetReference(display: "System.Data.dll (net40)", filePath: "System.Data.dll"); - public static PortableExecutableReference SystemXml { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemXml).GetReference(display: "System.Xml.dll (net40)", filePath: "System.Xml.dll"); - public static PortableExecutableReference SystemXmlLinq { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemXmlLinq).GetReference(display: "System.Xml.Linq.dll (net40)", filePath: "System.Xml.Linq.dll"); - public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (net40)", filePath: "Microsoft.VisualBasic.dll"); - public static PortableExecutableReference MicrosoftCSharp { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.dll (net40)", filePath: "Microsoft.CSharp.dll"); - } - public static class ResourcesNet451 - { - private static byte[] _mscorlib; - public static byte[] mscorlib => ResourceLoader.GetOrCreateResource(ref _mscorlib, "net451.mscorlib.dll"); - private static byte[] _System; - public static byte[] System => ResourceLoader.GetOrCreateResource(ref _System, "net451.System.dll"); - private static byte[] _SystemConfiguration; - public static byte[] SystemConfiguration => ResourceLoader.GetOrCreateResource(ref _SystemConfiguration, "net451.System.Configuration.dll"); - private static byte[] _SystemCore; - public static byte[] SystemCore => ResourceLoader.GetOrCreateResource(ref _SystemCore, "net451.System.Core.dll"); - private static byte[] _SystemData; - public static byte[] SystemData => ResourceLoader.GetOrCreateResource(ref _SystemData, "net451.System.Data.dll"); - private static byte[] _SystemDrawing; - public static byte[] SystemDrawing => ResourceLoader.GetOrCreateResource(ref _SystemDrawing, "net451.System.Drawing.dll"); - private static byte[] _SystemEnterpriseServices; - public static byte[] SystemEnterpriseServices => ResourceLoader.GetOrCreateResource(ref _SystemEnterpriseServices, "net451.System.EnterpriseServices.dll"); - private static byte[] _SystemRuntimeSerialization; - public static byte[] SystemRuntimeSerialization => ResourceLoader.GetOrCreateResource(ref _SystemRuntimeSerialization, "net451.System.Runtime.Serialization.dll"); - private static byte[] _SystemWindowsForms; - public static byte[] SystemWindowsForms => ResourceLoader.GetOrCreateResource(ref _SystemWindowsForms, "net451.System.Windows.Forms.dll"); - private static byte[] _SystemWebServices; - public static byte[] SystemWebServices => ResourceLoader.GetOrCreateResource(ref _SystemWebServices, "net451.System.Web.Services.dll"); - private static byte[] _SystemXml; - public static byte[] SystemXml => ResourceLoader.GetOrCreateResource(ref _SystemXml, "net451.System.Xml.dll"); - private static byte[] _SystemXmlLinq; - public static byte[] SystemXmlLinq => ResourceLoader.GetOrCreateResource(ref _SystemXmlLinq, "net451.System.Xml.Linq.dll"); - private static byte[] _MicrosoftCSharp; - public static byte[] MicrosoftCSharp => ResourceLoader.GetOrCreateResource(ref _MicrosoftCSharp, "net451.Microsoft.CSharp.dll"); - private static byte[] _MicrosoftVisualBasic; - public static byte[] MicrosoftVisualBasic => ResourceLoader.GetOrCreateResource(ref _MicrosoftVisualBasic, "net451.Microsoft.VisualBasic.dll"); - private static byte[] _SystemObjectModel; - public static byte[] SystemObjectModel => ResourceLoader.GetOrCreateResource(ref _SystemObjectModel, "net451.System.ObjectModel.dll"); - private static byte[] _SystemRuntime; - public static byte[] SystemRuntime => ResourceLoader.GetOrCreateResource(ref _SystemRuntime, "net451.System.Runtime.dll"); - private static byte[] _SystemRuntimeInteropServicesWindowsRuntime; - public static byte[] SystemRuntimeInteropServicesWindowsRuntime => ResourceLoader.GetOrCreateResource(ref _SystemRuntimeInteropServicesWindowsRuntime, "net451.System.Runtime.InteropServices.WindowsRuntime.dll"); - private static byte[] _SystemThreading; - public static byte[] SystemThreading => ResourceLoader.GetOrCreateResource(ref _SystemThreading, "net451.System.Threading.dll"); - private static byte[] _SystemThreadingTasks; - public static byte[] SystemThreadingTasks => ResourceLoader.GetOrCreateResource(ref _SystemThreadingTasks, "net451.System.Threading.Tasks.dll"); - public static ReferenceInfo[] All => new[] - { - new ReferenceInfo("mscorlib.dll", mscorlib), - new ReferenceInfo("System.dll", System), - new ReferenceInfo("System.Configuration.dll", SystemConfiguration), - new ReferenceInfo("System.Core.dll", SystemCore), - new ReferenceInfo("System.Data.dll", SystemData), - new ReferenceInfo("System.Drawing.dll", SystemDrawing), - new ReferenceInfo("System.EnterpriseServices.dll", SystemEnterpriseServices), - new ReferenceInfo("System.Runtime.Serialization.dll", SystemRuntimeSerialization), - new ReferenceInfo("System.Windows.Forms.dll", SystemWindowsForms), - new ReferenceInfo("System.Web.Services.dll", SystemWebServices), - new ReferenceInfo("System.Xml.dll", SystemXml), - new ReferenceInfo("System.Xml.Linq.dll", SystemXmlLinq), - new ReferenceInfo("Microsoft.CSharp.dll", MicrosoftCSharp), - new ReferenceInfo("Microsoft.VisualBasic.dll", MicrosoftVisualBasic), - new ReferenceInfo("System.ObjectModel.dll", SystemObjectModel), - new ReferenceInfo("System.Runtime.dll", SystemRuntime), - new ReferenceInfo("System.Runtime.InteropServices.WindowsRuntime.dll", SystemRuntimeInteropServicesWindowsRuntime), - new ReferenceInfo("System.Threading.dll", SystemThreading), - new ReferenceInfo("System.Threading.Tasks.dll", SystemThreadingTasks), - }; - } - public static class Net451 - { - public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.mscorlib).GetReference(display: "mscorlib.dll (net451)", filePath: "mscorlib.dll"); - public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.System).GetReference(display: "System.dll (net451)", filePath: "System.dll"); - public static PortableExecutableReference SystemConfiguration { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemConfiguration).GetReference(display: "System.Configuration.dll (net451)", filePath: "System.Configuration.dll"); - public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemCore).GetReference(display: "System.Core.dll (net451)", filePath: "System.Core.dll"); - public static PortableExecutableReference SystemData { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemData).GetReference(display: "System.Data.dll (net451)", filePath: "System.Data.dll"); - public static PortableExecutableReference SystemDrawing { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemDrawing).GetReference(display: "System.Drawing.dll (net451)", filePath: "System.Drawing.dll"); - public static PortableExecutableReference SystemEnterpriseServices { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemEnterpriseServices).GetReference(display: "System.EnterpriseServices.dll (net451)", filePath: "System.EnterpriseServices.dll"); - public static PortableExecutableReference SystemRuntimeSerialization { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntimeSerialization).GetReference(display: "System.Runtime.Serialization.dll (net451)", filePath: "System.Runtime.Serialization.dll"); - public static PortableExecutableReference SystemWindowsForms { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemWindowsForms).GetReference(display: "System.Windows.Forms.dll (net451)", filePath: "System.Windows.Forms.dll"); - public static PortableExecutableReference SystemWebServices { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemWebServices).GetReference(display: "System.Web.Services.dll (net451)", filePath: "System.Web.Services.dll"); - public static PortableExecutableReference SystemXml { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemXml).GetReference(display: "System.Xml.dll (net451)", filePath: "System.Xml.dll"); - public static PortableExecutableReference SystemXmlLinq { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemXmlLinq).GetReference(display: "System.Xml.Linq.dll (net451)", filePath: "System.Xml.Linq.dll"); - public static PortableExecutableReference MicrosoftCSharp { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.dll (net451)", filePath: "Microsoft.CSharp.dll"); - public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (net451)", filePath: "Microsoft.VisualBasic.dll"); - public static PortableExecutableReference SystemObjectModel { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemObjectModel).GetReference(display: "System.ObjectModel.dll (net451)", filePath: "System.ObjectModel.dll"); - public static PortableExecutableReference SystemRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntime).GetReference(display: "System.Runtime.dll (net451)", filePath: "System.Runtime.dll"); - public static PortableExecutableReference SystemRuntimeInteropServicesWindowsRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntimeInteropServicesWindowsRuntime).GetReference(display: "System.Runtime.InteropServices.WindowsRuntime.dll (net451)", filePath: "System.Runtime.InteropServices.WindowsRuntime.dll"); - public static PortableExecutableReference SystemThreading { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemThreading).GetReference(display: "System.Threading.dll (net451)", filePath: "System.Threading.dll"); - public static PortableExecutableReference SystemThreadingTasks { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemThreadingTasks).GetReference(display: "System.Threading.Tasks.dll (net451)", filePath: "System.Threading.Tasks.dll"); - } - public static class ResourcesMicrosoftCSharp - { - private static byte[] _Netstandard10; - public static byte[] Netstandard10 => ResourceLoader.GetOrCreateResource(ref _Netstandard10, "netstandard10.microsoftcsharp.Microsoft.CSharp.dll"); - private static byte[] _Netstandard13Lib; - public static byte[] Netstandard13Lib => ResourceLoader.GetOrCreateResource(ref _Netstandard13Lib, "netstandard13lib.microsoftcsharp.Microsoft.CSharp.dll"); - public static ReferenceInfo[] All => new[] - { - new ReferenceInfo("Netstandard10.dll", Netstandard10), - new ReferenceInfo("Netstandard13Lib.dll", Netstandard13Lib), - }; - } - public static class MicrosoftCSharp - { - public static PortableExecutableReference Netstandard10 { get; } = AssemblyMetadata.CreateFromImage(ResourcesMicrosoftCSharp.Netstandard10).GetReference(display: "Microsoft.CSharp.dll (microsoftcsharp)", filePath: "Netstandard10.dll"); - public static PortableExecutableReference Netstandard13Lib { get; } = AssemblyMetadata.CreateFromImage(ResourcesMicrosoftCSharp.Netstandard13Lib).GetReference(display: "Microsoft.CSharp.dll (microsoftcsharp)", filePath: "Netstandard13Lib.dll"); - } - public static class ResourcesMicrosoftVisualBasic - { - private static byte[] _Netstandard11; - public static byte[] Netstandard11 => ResourceLoader.GetOrCreateResource(ref _Netstandard11, "netstandard11.microsoftvisualbasic.Microsoft.VisualBasic.dll"); - public static ReferenceInfo[] All => new[] - { - new ReferenceInfo("Netstandard11.dll", Netstandard11), - }; - } - public static class MicrosoftVisualBasic - { - public static PortableExecutableReference Netstandard11 { get; } = AssemblyMetadata.CreateFromImage(ResourcesMicrosoftVisualBasic.Netstandard11).GetReference(display: "Microsoft.VisualBasic.dll (microsoftvisualbasic)", filePath: "Netstandard11.dll"); - } - public static class ResourcesSystemThreadingTasksExtensions - { - private static byte[] _PortableLib; - public static byte[] PortableLib => ResourceLoader.GetOrCreateResource(ref _PortableLib, "portablelib.systemthreadingtasksextensions.System.Threading.Tasks.Extensions.dll"); - private static byte[] _NetStandard20Lib; - public static byte[] NetStandard20Lib => ResourceLoader.GetOrCreateResource(ref _NetStandard20Lib, "netstandard20lib.systemthreadingtasksextensions.System.Threading.Tasks.Extensions.dll"); - public static ReferenceInfo[] All => new[] - { - new ReferenceInfo("PortableLib.dll", PortableLib), - new ReferenceInfo("NetStandard20Lib.dll", NetStandard20Lib), - }; - } - public static class SystemThreadingTasksExtensions - { - public static PortableExecutableReference PortableLib { get; } = AssemblyMetadata.CreateFromImage(ResourcesSystemThreadingTasksExtensions.PortableLib).GetReference(display: "System.Threading.Tasks.Extensions.dll (systemthreadingtasksextensions)", filePath: "PortableLib.dll"); - public static PortableExecutableReference NetStandard20Lib { get; } = AssemblyMetadata.CreateFromImage(ResourcesSystemThreadingTasksExtensions.NetStandard20Lib).GetReference(display: "System.Threading.Tasks.Extensions.dll (systemthreadingtasksextensions)", filePath: "NetStandard20Lib.dll"); - } - public static class ResourcesBuildExtensions - { - private static byte[] _NetStandardToNet461; - public static byte[] NetStandardToNet461 => ResourceLoader.GetOrCreateResource(ref _NetStandardToNet461, "netstandardtonet461.buildextensions.netstandard.dll"); - public static ReferenceInfo[] All => new[] - { - new ReferenceInfo("NetStandardToNet461.dll", NetStandardToNet461), - }; - } - public static class BuildExtensions - { - public static PortableExecutableReference NetStandardToNet461 { get; } = AssemblyMetadata.CreateFromImage(ResourcesBuildExtensions.NetStandardToNet461).GetReference(display: "netstandard.dll (buildextensions)", filePath: "NetStandardToNet461.dll"); - } - } -} diff --git a/src/Compilers/Test/Core/Generated.targets b/src/Compilers/Test/Core/Generated.targets deleted file mode 100644 index c19be55d91ac4..0000000000000 --- a/src/Compilers/Test/Core/Generated.targets +++ /dev/null @@ -1,152 +0,0 @@ - - - - net20.mscorlib.dll - Resources\ReferenceAssemblies\net20\mscorlib.dll - - - net20.System.dll - Resources\ReferenceAssemblies\net20\System.dll - - - net20.Microsoft.VisualBasic.dll - Resources\ReferenceAssemblies\net20\Microsoft.VisualBasic.dll - - - net35.System.Core.dll - Resources\ReferenceAssemblies\net35\System.Core.dll - - - net40.mscorlib.dll - Resources\ReferenceAssemblies\net40\mscorlib.dll - - - net40.System.dll - Resources\ReferenceAssemblies\net40\System.dll - - - net40.System.Core.dll - Resources\ReferenceAssemblies\net40\System.Core.dll - - - net40.System.Data.dll - Resources\ReferenceAssemblies\net40\System.Data.dll - - - net40.System.Xml.dll - Resources\ReferenceAssemblies\net40\System.Xml.dll - - - net40.System.Xml.Linq.dll - Resources\ReferenceAssemblies\net40\System.Xml.Linq.dll - - - net40.Microsoft.VisualBasic.dll - Resources\ReferenceAssemblies\net40\Microsoft.VisualBasic.dll - - - net40.Microsoft.CSharp.dll - Resources\ReferenceAssemblies\net40\Microsoft.CSharp.dll - - - net451.mscorlib.dll - Resources\ReferenceAssemblies\net451\mscorlib.dll - - - net451.System.dll - Resources\ReferenceAssemblies\net451\System.dll - - - net451.System.Configuration.dll - Resources\ReferenceAssemblies\net451\System.Configuration.dll - - - net451.System.Core.dll - Resources\ReferenceAssemblies\net451\System.Core.dll - - - net451.System.Data.dll - Resources\ReferenceAssemblies\net451\System.Data.dll - - - net451.System.Drawing.dll - Resources\ReferenceAssemblies\net451\System.Drawing.dll - - - net451.System.EnterpriseServices.dll - Resources\ReferenceAssemblies\net451\System.EnterpriseServices.dll - - - net451.System.Runtime.Serialization.dll - Resources\ReferenceAssemblies\net451\System.Runtime.Serialization.dll - - - net451.System.Windows.Forms.dll - Resources\ReferenceAssemblies\net451\System.Windows.Forms.dll - - - net451.System.Web.Services.dll - Resources\ReferenceAssemblies\net451\System.Web.Services.dll - - - net451.System.Xml.dll - Resources\ReferenceAssemblies\net451\System.Xml.dll - - - net451.System.Xml.Linq.dll - Resources\ReferenceAssemblies\net451\System.Xml.Linq.dll - - - net451.Microsoft.CSharp.dll - Resources\ReferenceAssemblies\net451\Microsoft.CSharp.dll - - - net451.Microsoft.VisualBasic.dll - Resources\ReferenceAssemblies\net451\Microsoft.VisualBasic.dll - - - net451.System.ObjectModel.dll - Resources\ReferenceAssemblies\net451\System.ObjectModel.dll - - - net451.System.Runtime.dll - Resources\ReferenceAssemblies\net451\System.Runtime.dll - - - net451.System.Runtime.InteropServices.WindowsRuntime.dll - Resources\ReferenceAssemblies\net451\System.Runtime.InteropServices.WindowsRuntime.dll - - - net451.System.Threading.dll - Resources\ReferenceAssemblies\net451\System.Threading.dll - - - net451.System.Threading.Tasks.dll - Resources\ReferenceAssemblies\net451\System.Threading.Tasks.dll - - - netstandard10.microsoftcsharp.Microsoft.CSharp.dll - Resources\ReferenceAssemblies\microsoftcsharp\Microsoft.CSharp.dll - - - netstandard13lib.microsoftcsharp.Microsoft.CSharp.dll - Resources\ReferenceAssemblies\microsoftcsharp\Microsoft.CSharp.dll - - - netstandard11.microsoftvisualbasic.Microsoft.VisualBasic.dll - Resources\ReferenceAssemblies\microsoftvisualbasic\Microsoft.VisualBasic.dll - - - portablelib.systemthreadingtasksextensions.System.Threading.Tasks.Extensions.dll - Resources\ReferenceAssemblies\systemthreadingtasksextensions\System.Threading.Tasks.Extensions.dll - - - netstandard20lib.systemthreadingtasksextensions.System.Threading.Tasks.Extensions.dll - Resources\ReferenceAssemblies\systemthreadingtasksextensions\System.Threading.Tasks.Extensions.dll - - - netstandardtonet461.buildextensions.netstandard.dll - Resources\ReferenceAssemblies\buildextensions\netstandard.dll - - - diff --git a/src/Compilers/Test/Core/Metadata/ILValidation.cs b/src/Compilers/Test/Core/Metadata/ILValidation.cs index 85d2c08062f27..0503ba220aac3 100644 --- a/src/Compilers/Test/Core/Metadata/ILValidation.cs +++ b/src/Compilers/Test/Core/Metadata/ILValidation.cs @@ -106,6 +106,7 @@ public static bool IsStreamFullSigned(Stream moduleContents) // signing implementation. Array.Reverse(reversedSignature); + // CodeQL [SM02196] ECMA-335 requires us to support SHA-1 and this is testing that support if (!rsa.VerifyHash(hash, reversedSignature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)) { return false; @@ -145,6 +146,7 @@ private static byte[] ComputeSigningHash( buffer[authenticodeOffset + i] = 0; } + // CodeQL [SM02196] ECMA-335 requires us to support SHA-1 and this is testing that support using (var hash = IncrementalHash.CreateHash(HashAlgorithmName.SHA1)) { // First hash the DOS header and PE headers diff --git a/src/Compilers/Test/Core/Metadata/IlasmUtilities.cs b/src/Compilers/Test/Core/Metadata/IlasmUtilities.cs index c67ce4bf0e343..2886ff9336a3b 100644 --- a/src/Compilers/Test/Core/Metadata/IlasmUtilities.cs +++ b/src/Compilers/Test/Core/Metadata/IlasmUtilities.cs @@ -6,6 +6,7 @@ using System; using System.IO; +using System.Runtime.InteropServices; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -22,6 +23,17 @@ public static DisposableFile CreateTempAssembly(string declarations, bool prepen return new DisposableFile(assemblyPath); } + private static string GetArchitecture() + { +#if NET8_0_OR_GREATER + return RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(); +#else + return "x64"; +#endif + } + + public static readonly string Architecture = GetArchitecture(); + private static string GetIlasmPath() { if (ExecutionConditionUtil.IsWindowsDesktop) @@ -46,7 +58,7 @@ private static string GetIlasmPath() } else if (ExecutionConditionUtil.IsLinux) { - ridName = "linux-x64"; + ridName = $"linux-{GetArchitecture()}"; } else { diff --git a/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj b/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj index 61dca0b65230b..730c518eee96b 100644 --- a/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj +++ b/src/Compilers/Test/Core/Microsoft.CodeAnalysis.Test.Utilities.csproj @@ -91,7 +91,6 @@ - @@ -106,20 +105,12 @@ - - - - - - - - - + + + - - diff --git a/src/Compilers/Test/Core/Mocks/Silverlight.cs b/src/Compilers/Test/Core/Mocks/Silverlight.cs new file mode 100644 index 0000000000000..9bfe8bc8ff200 --- /dev/null +++ b/src/Compilers/Test/Core/Mocks/Silverlight.cs @@ -0,0 +1,105 @@ +// 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.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; + +namespace Roslyn.Test.Utilities; + +/// +/// The assemblies produced here are designed to mimic the public key token structure of +/// silverlight references. This often presents challenges to the compiler because it has +/// to know that two mscorlib with different public key tokens need to be treated as the +/// identicial. The assemblies produced here have the same identity of those that come +/// from silverlight but without necessarily the same type contents. +/// +public static class Silverlight +{ + private static readonly Lazy<(byte[], byte[])> s_tuple = new Lazy<(byte[], byte[])>( + () => BuildImages(), + LazyThreadSafetyMode.PublicationOnly); + + public static byte[] Mscorlib => s_tuple.Value.Item1; + + public static byte[] System => s_tuple.Value.Item2; + + private static (byte[], byte[]) BuildImages() + { + const string corlibExtraCode = """ + using System; + using System.Reflection; + + namespace System.Reflection; + + [AttributeUsage(AttributeTargets.Assembly, Inherited = false)] + public sealed class AssemblyFileVersionAttribute : Attribute + { + public string Version { get; } + public AssemblyFileVersionAttribute(string version) + { + Version = version; + } + } + [AttributeUsage(AttributeTargets.Assembly, Inherited = false)] + public sealed class AssemblyVersionAttribute : Attribute + { + public string Version { get; } + public AssemblyVersionAttribute(string version) + { + Version = version; + } + } + """; + + const string assemblyAttributes = """ + using System.Reflection; + + [assembly: AssemblyFileVersion("5.0.5.0")] + [assembly: AssemblyVersion("5.0.5.0")] + """; + + var publicKeyText = "" + + "00240000048000009400000006020000002400005253413100040000010001008d56c76f9e8649383049f" + + "383c44be0ec204181822a6c31cf5eb7ef486944d032188ea1d3920763712ccb12d75fb77e9811149e6148" + + "e5d32fbaab37611c1878ddc19e20ef135d0cb2cff2bfec3d115810c3d9069638fe4be215dbf795861920e" + + "5ab6f7db2e2ceef136ac23d5dd2bf031700aec232f6c6b1c785b4305c123b37ab"; + var publicKey = TestHelpers.HexToByte(publicKeyText.AsSpan()); + var publicKeyToken = AssemblyIdentity.CalculatePublicKeyToken(publicKey); + Debug.Assert("7C-EC-85-D7-BE-A7-79-8E" == BitConverter.ToString(publicKeyToken.ToArray())); + + var options = new CSharpCompilationOptions( + OutputKind.DynamicallyLinkedLibrary, + cryptoPublicKey: publicKey, + optimizationLevel: OptimizationLevel.Release); + var mscorlibCompilation = CSharpCompilation.Create( + "mscorlib", + [ + CSharpSyntaxTree.ParseText(SourceText.From(TestResources.NetFX.Minimal.mincorlib_cs)), + CSharpSyntaxTree.ParseText(SourceText.From(corlibExtraCode)), + CSharpSyntaxTree.ParseText(SourceText.From(assemblyAttributes)), + ], + options: options); + + var mscorlib = mscorlibCompilation.EmitToStream(EmitOptions.Default.WithRuntimeMetadataVersion("v4.0.30319")); + + var systemCompilation = CSharpCompilation.Create( + "System", + syntaxTrees: [CSharpSyntaxTree.ParseText(SourceText.From(assemblyAttributes))], + references: [mscorlibCompilation.EmitToImageReference()], + options: options); + + var system = systemCompilation.EmitToStream(); + return (mscorlib.ToArray(), system.ToArray()); + } +} diff --git a/src/Compilers/Test/Core/Mocks/StdOle.cs b/src/Compilers/Test/Core/Mocks/StdOle.cs new file mode 100644 index 0000000000000..efad464a13c9b --- /dev/null +++ b/src/Compilers/Test/Core/Mocks/StdOle.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.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; + +namespace Roslyn.Test.Utilities; + +/// +/// This type produces stdole.dll that mimic the version used in the original Roslyn +/// interop tests. +/// +public static class StdOle +{ + public static PortableExecutableReference Build(IEnumerable references) + { + const string assemblyAttributes = """ + using System.Reflection; + using System.Runtime.InteropServices; + + [assembly: ImportedFromTypeLib("stdole")] + [assembly: Guid("00020430-0000-0000-c000-000000000046")] + [assembly: PrimaryInteropAssembly(2, 0)] + [assembly: AssemblyVersion("7.0.3300.0")] + + """; + + const string code = """ + using System.Runtime.InteropServices; + namespace stdole; + + public struct GUID + { + public uint Data1; + public ushort Data2; + public ushort Data3; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] Data4; + } + + [ComImport] + [Guid("00020400-0000-0000-C000-000000000046")] + [TypeLibType(512)] + public interface IDispatch + { + } + """; + + var publicKeyText = "" + + "002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e8" + + "4aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980" + + "957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1" + + "dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293"; + var publicKey = TestHelpers.HexToByte(publicKeyText.AsSpan()); + var publicKeyToken = AssemblyIdentity.CalculatePublicKeyToken(publicKey); + Debug.Assert("B0-3F-5F-7F-11-D5-0A-3A" == BitConverter.ToString(publicKeyToken.ToArray())); + + var options = new CSharpCompilationOptions( + OutputKind.DynamicallyLinkedLibrary, + cryptoPublicKey: publicKey, + optimizationLevel: OptimizationLevel.Release); + var compilation = CSharpCompilation.Create( + "stdole", + [ + CSharpSyntaxTree.ParseText(SourceText.From(code)), + CSharpSyntaxTree.ParseText(SourceText.From(assemblyAttributes)) + ], + references: references, + options); + + return compilation.EmitToPortableExecutableReference(); + } +} diff --git a/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs b/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs index 68c2c5c6b9937..008e2eb21e579 100644 --- a/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs +++ b/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs @@ -416,7 +416,7 @@ public override int ERR_ModuleEmitFailure } } - public override int ERR_EncUpdateFailedMissingAttribute + public override int ERR_EncUpdateFailedMissingSymbol { get { diff --git a/src/Compilers/Test/Core/Mocks/TestReferences.cs b/src/Compilers/Test/Core/Mocks/TestReferences.cs index 35b42d3633597..c338990d43864 100644 --- a/src/Compilers/Test/Core/Mocks/TestReferences.cs +++ b/src/Compilers/Test/Core/Mocks/TestReferences.cs @@ -7,9 +7,10 @@ using System; using System.IO; using System.Threading; +using Basic.Reference.Assemblies; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Test.Resources.Proprietary; using Roslyn.Test.Utilities; +using Xunit; public static class TestReferences { @@ -98,7 +99,7 @@ public static class ValueTuple public static class silverlight_v5_0_5_0 { private static readonly Lazy s_system = new Lazy( - () => AssemblyMetadata.CreateFromImage(ProprietaryTestResources.silverlight_v5_0_5_0.System_v5_0_5_0_silverlight).GetReference(display: "System.v5.0.5.0_silverlight.dll"), + () => AssemblyMetadata.CreateFromImage(Silverlight.System).GetReference(display: "System.v5.0.5.0_silverlight.dll"), LazyThreadSafetyMode.PublicationOnly); public static PortableExecutableReference System => s_system.Value; } @@ -688,10 +689,13 @@ public static class MultiTargeting public static class NoPia { - private static readonly Lazy s_stdOle = new Lazy( - () => AssemblyMetadata.CreateFromImage(ProprietaryTestResources.ProprietaryPias.stdole).GetReference(display: "stdole.dll"), - LazyThreadSafetyMode.PublicationOnly); - public static PortableExecutableReference StdOle => s_stdOle.Value; + private static readonly Lazy s_stdOleNetFramework = new Lazy( + () => StdOle.Build(NetFramework.References), LazyThreadSafetyMode.PublicationOnly); + public static PortableExecutableReference StdOleNetFramework => s_stdOleNetFramework.Value; + + private static readonly Lazy s_stdOleNet40 = new Lazy( + () => StdOle.Build(Net40.References.All), LazyThreadSafetyMode.PublicationOnly); + public static PortableExecutableReference StdOleNet40 => s_stdOleNet40.Value; private static readonly Lazy s_pia1 = new Lazy( () => AssemblyMetadata.CreateFromImage(TestResources.SymbolsTests.NoPia.Pia1).GetReference(display: "Pia1.dll"), diff --git a/src/Compilers/Test/Core/Platform/CoreClr/AssemblyLoadContextUtils.cs b/src/Compilers/Test/Core/Platform/CoreClr/AssemblyLoadContextUtils.cs index 6793697fe854e..e170a629a65a5 100644 --- a/src/Compilers/Test/Core/Platform/CoreClr/AssemblyLoadContextUtils.cs +++ b/src/Compilers/Test/Core/Platform/CoreClr/AssemblyLoadContextUtils.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. -#if NETCOREAPP +#if NET using System; using System.IO; diff --git a/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs b/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs index dbe385dd965c5..60adf41aabf89 100644 --- a/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs +++ b/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs @@ -4,7 +4,7 @@ #nullable disable -#if NETCOREAPP +#if NET using System; using System.Collections.Generic; using System.Collections.Immutable; diff --git a/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironmentFactory.cs b/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironmentFactory.cs index bf9087d1a5a1e..af266ac34958e 100644 --- a/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironmentFactory.cs +++ b/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironmentFactory.cs @@ -4,7 +4,7 @@ #nullable disable -#if NETCOREAPP +#if NET using System; using System.Collections.Generic; diff --git a/src/Compilers/Test/Core/Platform/CoreClr/SharedConsoleOutWriter.cs b/src/Compilers/Test/Core/Platform/CoreClr/SharedConsoleOutWriter.cs index 44f8fc85880c7..91a8d686b0ba8 100644 --- a/src/Compilers/Test/Core/Platform/CoreClr/SharedConsoleOutWriter.cs +++ b/src/Compilers/Test/Core/Platform/CoreClr/SharedConsoleOutWriter.cs @@ -4,7 +4,7 @@ #nullable disable -#if NETCOREAPP +#if NET using System; using System.IO; diff --git a/src/Compilers/Test/Core/Platform/CoreClr/TestExecutionLoadContext.cs b/src/Compilers/Test/Core/Platform/CoreClr/TestExecutionLoadContext.cs index 720ecd43ae3c8..6118783a645db 100644 --- a/src/Compilers/Test/Core/Platform/CoreClr/TestExecutionLoadContext.cs +++ b/src/Compilers/Test/Core/Platform/CoreClr/TestExecutionLoadContext.cs @@ -4,7 +4,7 @@ #nullable disable -#if NETCOREAPP +#if NET using System; using System.Collections.Concurrent; using System.Collections.Generic; diff --git a/src/Compilers/Test/Core/Platform/Desktop/Extensions.cs b/src/Compilers/Test/Core/Platform/Desktop/Extensions.cs index f46a3c5f4a0be..14621ca6a0e99 100644 --- a/src/Compilers/Test/Core/Platform/Desktop/Extensions.cs +++ b/src/Compilers/Test/Core/Platform/Desktop/Extensions.cs @@ -13,6 +13,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Text; using System.Threading; @@ -27,30 +28,30 @@ internal static class SerializationInfoExtensions { public static void AddArray(this SerializationInfo info, string name, ImmutableArray value) where T : class { - // we will copy the content into an array and serialize the copy - // we could serialize element-wise, but that would require serializing - // name and type for every serialized element which seems worse than creating a copy. - info.AddValue(name, value.IsDefault ? null : value.ToArray(), typeof(T[])); + // This will store the underlying T[] directly into the SerializationInfo. That is safe because it + // only ever reads from the array. This is done instead of creating a copy because it is a + // significant source of allocations in our unit tests. + info.AddValue(name, value.IsDefault ? null : ImmutableCollectionsMarshal.AsArray(value), typeof(T[])); } public static ImmutableArray GetArray(this SerializationInfo info, string name) where T : class { - var arr = (T[])info.GetValue(name, typeof(T[])); - return ImmutableArray.Create(arr); + var array = (T[])info.GetValue(name, typeof(T[])); + return ImmutableCollectionsMarshal.AsImmutableArray(array); } public static void AddByteArray(this SerializationInfo info, string name, ImmutableArray value) { - // we will copy the content into an array and serialize the copy - // we could serialize element-wise, but that would require serializing - // name and type for every serialized element which seems worse than creating a copy. - info.AddValue(name, value.IsDefault ? null : value.ToArray(), typeof(byte[])); + // This will store the underlying byte[] directly into the SerializationInfo. That is safe because it + // only ever reads from the array. This is done instead of creating a copy because it is a + // significant source of allocations in our unit tests. + info.AddValue(name, value.IsDefault ? null : ImmutableCollectionsMarshal.AsArray(value), typeof(byte[])); } public static ImmutableArray GetByteArray(this SerializationInfo info, string name) { - var arr = (byte[])info.GetValue(name, typeof(byte[])); - return ImmutableArray.Create(arr); + var array = (byte[])info.GetValue(name, typeof(byte[])); + return ImmutableCollectionsMarshal.AsImmutableArray(array); } } } diff --git a/src/Compilers/Test/Core/Platform/Desktop/TestHelpers.cs b/src/Compilers/Test/Core/Platform/Desktop/TestHelpers.cs index c00cc71683579..a58904aacffaa 100644 --- a/src/Compilers/Test/Core/Platform/Desktop/TestHelpers.cs +++ b/src/Compilers/Test/Core/Platform/Desktop/TestHelpers.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Test.Resources.Proprietary; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.Win32; diff --git a/src/Compilers/Test/Core/TargetFrameworkUtil.cs b/src/Compilers/Test/Core/TargetFrameworkUtil.cs index 592cdb613b90f..2b7ed086309ed 100644 --- a/src/Compilers/Test/Core/TargetFrameworkUtil.cs +++ b/src/Compilers/Test/Core/TargetFrameworkUtil.cs @@ -13,11 +13,10 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Test.Utilities; using Basic.Reference.Assemblies; -using static TestReferences; -using static Roslyn.Test.Utilities.TestMetadata; using Microsoft.CodeAnalysis.CodeGen; using System.Reflection; using System.Collections.Concurrent; +using static TestReferences; namespace Roslyn.Test.Utilities { @@ -68,15 +67,12 @@ public enum TargetFramework Mscorlib40Extended, Mscorlib40AndSystemCore, Mscorlib40AndVBRuntime, - Mscorlib45, - Mscorlib45Extended, - Mscorlib45AndCSharp, - Mscorlib45AndVBRuntime, Mscorlib46, Mscorlib46Extended, Mscorlib461, Mscorlib461Extended, - DesktopLatestExtended = Mscorlib461Extended, + Mscorlib461AndCSharp, + Mscorlib461AndVBRuntime, /// /// Minimal set of required types (). @@ -117,16 +113,26 @@ public static class NetCoreApp /// public static class NetFramework { + private static ImmutableArray s_references; + /// /// This is the full set of references provided by default on the .NET Framework TFM /// /// /// Need to special case tuples until we move to net472 /// - public static ImmutableArray References { get; } = - ImmutableArray - .CreateRange(Net461.References.All) - .Add(NetFx.ValueTuple.tuplelib); + public static ImmutableArray References + { + get + { + if (s_references.IsDefault) + { + s_references = [.. Net461.References.All, Net461.ExtraReferences.SystemValueTuple]; + } + + return s_references; + } + } /// /// This is a limited set of references on this .NET Framework TFM. This should be avoided in new code @@ -136,18 +142,23 @@ public static class NetFramework /// Need to special case tuples until we move to net472 /// public static ImmutableArray Standard { get; } = - ImmutableArray.Create( + [ Net461.References.mscorlib, Net461.References.System, Net461.References.SystemCore, - NetFx.ValueTuple.tuplelib, - Net461.References.SystemRuntime); + Net461.References.SystemData, + Net461.References.SystemRuntime, + Net461.ExtraReferences.SystemValueTuple + ]; public static PortableExecutableReference mscorlib { get; } = Net461.References.mscorlib; public static PortableExecutableReference System { get; } = Net461.References.System; public static PortableExecutableReference SystemRuntime { get; } = Net461.References.SystemRuntime; public static PortableExecutableReference SystemCore { get; } = Net461.References.SystemCore; + public static PortableExecutableReference SystemData { get; } = Net461.References.SystemData; public static PortableExecutableReference SystemThreadingTasks { get; } = Net461.References.SystemThreadingTasks; + public static PortableExecutableReference SystemXml { get; } = Net461.References.SystemXml; + public static PortableExecutableReference SystemValueTuple { get; } = Net461.ExtraReferences.SystemValueTuple; public static PortableExecutableReference MicrosoftCSharp { get; } = Net461.References.MicrosoftCSharp; public static PortableExecutableReference MicrosoftVisualBasic { get; } = Net461.References.MicrosoftVisualBasic; } @@ -158,8 +169,8 @@ public static class TargetFrameworkUtil public static ImmutableArray NetLatest => RuntimeUtilities.IsCoreClrRuntime ? NetCoreApp.References : NetFramework.References; public static ImmutableArray StandardReferences => RuntimeUtilities.IsCoreClrRuntime ? NetStandard20References : NetFramework.Standard; - public static MetadataReference StandardCSharpReference => RuntimeUtilities.IsCoreClrRuntime ? MicrosoftCSharp.Netstandard13Lib : NetFramework.MicrosoftCSharp; - public static MetadataReference StandardVisualBasicReference => RuntimeUtilities.IsCoreClrRuntime ? MicrosoftVisualBasic.Netstandard11 : NetFramework.MicrosoftVisualBasic; + public static MetadataReference StandardCSharpReference => RuntimeUtilities.IsCoreClrRuntime ? NetStandard20.ExtraReferences.MicrosoftCSharp : NetFramework.MicrosoftCSharp; + public static MetadataReference StandardVisualBasicReference => RuntimeUtilities.IsCoreClrRuntime ? NetStandard20.ExtraReferences.MicrosoftVisualBasic : NetFramework.MicrosoftVisualBasic; public static ImmutableArray StandardAndCSharpReferences => StandardReferences.Add(StandardCSharpReference); public static ImmutableArray StandardAndVBRuntimeReferences => StandardReferences.Add(StandardVisualBasicReference); @@ -181,62 +192,51 @@ .. TestBase.WinRtRefs [ TestBase.MinAsyncCorlibRef ]; - public static ImmutableArray Mscorlib45ExtendedReferences => + + /* + * ⚠ Dev note ⚠: TestBase properties end here. + */ + + public static ImmutableArray Mscorlib45ExtendedReferences { get; } = [ - Net451.mscorlib, - Net451.System, - Net451.SystemCore, - TestBase.ValueTupleRef, - Net451.SystemRuntime + NetFramework.mscorlib, + NetFramework.System, + NetFramework.SystemCore, + NetFramework.SystemRuntime, + NetFramework.SystemValueTuple, ]; - public static ImmutableArray Mscorlib46ExtendedReferences => + public static ImmutableArray Mscorlib46ExtendedReferences { get; } = [ Net461.References.mscorlib, Net461.References.System, Net461.References.SystemCore, - TestBase.ValueTupleRef, - Net461.References.SystemRuntime + Net461.References.SystemRuntime, + Net461.ExtraReferences.SystemValueTuple, ]; - /* - * ⚠ Dev note ⚠: TestBase properties end here. - */ - public static ImmutableArray Mscorlib40References { get; } = [ - Net40.mscorlib + Net40.References.mscorlib ]; public static ImmutableArray Mscorlib40ExtendedReferences { get; } = [ - Net40.mscorlib, - Net40.System, - Net40.SystemCore + Net40.References.mscorlib, + Net40.References.System, + Net40.References.SystemCore ]; public static ImmutableArray Mscorlib40andSystemCoreReferences { get; } = [ - Net40.mscorlib, - Net40.SystemCore + Net40.References.mscorlib, + Net40.References.SystemCore ]; public static ImmutableArray Mscorlib40andVBRuntimeReferences { get; } = [ - Net40.mscorlib, - Net40.System, - Net40.MicrosoftVisualBasic + Net40.References.mscorlib, + Net40.References.System, + Net40.References.MicrosoftVisualBasic ]; public static ImmutableArray Mscorlib45References { get; } = [ - Net451.mscorlib - ]; - public static ImmutableArray Mscorlib45AndCSharpReferences { get; } = - [ - Net451.mscorlib, - Net451.SystemCore, - Net451.MicrosoftCSharp - ]; - public static ImmutableArray Mscorlib45AndVBRuntimeReferences { get; } = - [ - Net451.mscorlib, - Net451.System, - Net451.MicrosoftVisualBasic + NetFramework.mscorlib ]; public static ImmutableArray Mscorlib46References { get; } = [ @@ -251,8 +251,20 @@ .. TestBase.WinRtRefs Net461.References.mscorlib, Net461.References.System, Net461.References.SystemCore, - NetFx.ValueTuple.tuplelib, - Net461.References.SystemRuntime + Net461.References.SystemRuntime, + Net461.ExtraReferences.SystemValueTuple, + ]; + public static ImmutableArray Mscorlib461AndCSharpReferences { get; } = + [ + Net461.References.mscorlib, + Net461.References.SystemCore, + Net461.References.MicrosoftCSharp + ]; + public static ImmutableArray Mscorlib461AndVBRuntimeReferences { get; } = + [ + Net461.References.mscorlib, + Net461.References.System, + Net461.References.MicrosoftVisualBasic ]; public static ImmutableArray NetStandard20References { get; } = [ @@ -266,10 +278,10 @@ .. TestBase.WinRtRefs ]; public static ImmutableArray DefaultVbReferences { get; } = [ - Net451.mscorlib, - Net451.System, - Net451.SystemCore, - Net451.MicrosoftVisualBasic + NetFramework.mscorlib, + NetFramework.System, + NetFramework.SystemCore, + NetFramework.MicrosoftVisualBasic ]; #if DEBUG @@ -303,14 +315,12 @@ static TargetFrameworkUtil() TargetFramework.Mscorlib40Extended => Mscorlib40ExtendedReferences, TargetFramework.Mscorlib40AndSystemCore => Mscorlib40andSystemCoreReferences, TargetFramework.Mscorlib40AndVBRuntime => Mscorlib40andVBRuntimeReferences, - TargetFramework.Mscorlib45 => Mscorlib45References, - TargetFramework.Mscorlib45Extended => Mscorlib45ExtendedReferences, - TargetFramework.Mscorlib45AndCSharp => Mscorlib45AndCSharpReferences, - TargetFramework.Mscorlib45AndVBRuntime => Mscorlib45AndVBRuntimeReferences, TargetFramework.Mscorlib46 => Mscorlib46References, TargetFramework.Mscorlib46Extended => Mscorlib46ExtendedReferences, TargetFramework.Mscorlib461 => Mscorlib46References, TargetFramework.Mscorlib461Extended => Mscorlib461ExtendedReferences, + TargetFramework.Mscorlib461AndCSharp => Mscorlib461AndCSharpReferences, + TargetFramework.Mscorlib461AndVBRuntime => Mscorlib461AndVBRuntimeReferences, TargetFramework.WinRT => WinRTReferences, TargetFramework.StandardAndCSharp => StandardAndCSharpReferences, TargetFramework.StandardAndVBRuntime => StandardAndVBRuntimeReferences, diff --git a/src/Compilers/Test/Core/TestBase.cs b/src/Compilers/Test/Core/TestBase.cs index fe864fc970d5f..0930775cc7469 100644 --- a/src/Compilers/Test/Core/TestBase.cs +++ b/src/Compilers/Test/Core/TestBase.cs @@ -14,8 +14,6 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.VisualBasic; using static TestReferences.NetFx; -using static Roslyn.Test.Utilities.TestMetadata; -using Microsoft.CodeAnalysis.Test.Resources.Proprietary; using Basic.Reference.Assemblies; using Roslyn.Utilities; using System.Globalization; @@ -81,12 +79,12 @@ public virtual void Dispose() #region Metadata References private static readonly Lazy s_lazyDefaultVbReferences = new Lazy( - () => new[] { Net40.mscorlib, Net40.System, Net40.SystemCore, Net40.MicrosoftVisualBasic }, + () => new[] { Net40.References.mscorlib, Net40.References.System, Net40.References.SystemCore, Net40.References.MicrosoftVisualBasic }, LazyThreadSafetyMode.PublicationOnly); public static MetadataReference[] DefaultVbReferences => s_lazyDefaultVbReferences.Value; private static readonly Lazy s_lazyLatestVbReferences = new Lazy( - () => new[] { Net451.mscorlib, Net451.System, Net451.SystemCore, Net451.MicrosoftVisualBasic }, + () => new[] { NetFramework.mscorlib, NetFramework.System, NetFramework.SystemCore, NetFramework.MicrosoftVisualBasic }, LazyThreadSafetyMode.PublicationOnly); public static MetadataReference[] LatestVbReferences => s_lazyLatestVbReferences.Value; @@ -104,24 +102,24 @@ public virtual void Dispose() var winmd = AssemblyMetadata.CreateFromImage(TestResources.WinRt.Windows).GetReference(display: "Windows"); var windowsruntime = - AssemblyMetadata.CreateFromImage(ProprietaryTestResources.v4_0_30319_17929.System_Runtime_WindowsRuntime).GetReference(display: "System.Runtime.WindowsRuntime.dll"); + AssemblyMetadata.CreateFromImage(TestResources.NetFX.WinRt.SystemRuntimeWindowsRuntime).GetReference(display: "System.Runtime.WindowsRuntime.dll"); var runtime = - AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntime).GetReference(display: "System.Runtime.dll"); + AssemblyMetadata.CreateFromImage(Net461.Resources.SystemRuntime).GetReference(display: "System.Runtime.dll"); var objectModel = - AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemObjectModel).GetReference(display: "System.ObjectModel.dll"); + AssemblyMetadata.CreateFromImage(Net461.Resources.SystemObjectModel).GetReference(display: "System.ObjectModel.dll"); - var uixaml = AssemblyMetadata.CreateFromImage(ProprietaryTestResources.v4_0_30319_17929.System_Runtime_WindowsRuntime_UI_Xaml). + var uixaml = AssemblyMetadata.CreateFromImage(TestResources.NetFX.WinRt.SystemRuntimeWindowsRuntimeUIXaml). GetReference(display: "System.Runtime.WindowsRuntime.UI.Xaml.dll"); - var interop = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntimeInteropServicesWindowsRuntime). + var interop = AssemblyMetadata.CreateFromImage(Net461.Resources.SystemRuntimeInteropServicesWindowsRuntime). GetReference(display: "System.Runtime.InteropServices.WindowsRuntime.dll"); //Not mentioned in the adapter doc but pointed to from System.Runtime, so we'll put it here. - var system = AssemblyMetadata.CreateFromImage(ResourcesNet451.System).GetReference(display: "System.dll"); + var system = AssemblyMetadata.CreateFromImage(Net461.Resources.System).GetReference(display: "System.dll"); - var mscor = AssemblyMetadata.CreateFromImage(ResourcesNet451.mscorlib).GetReference(display: "mscorlib"); + var mscor = AssemblyMetadata.CreateFromImage(Net461.Resources.mscorlib).GetReference(display: "mscorlib"); return new MetadataReference[] { winmd, windowsruntime, runtime, objectModel, uixaml, interop, system, mscor }; }, @@ -148,17 +146,17 @@ public virtual void Dispose() private static readonly Lazy s_systemCoreRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemCore).GetReference(display: "System.Core.v4_0_30319.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.SystemCore).GetReference(display: "System.Core.v4_0_30319.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemCoreRef => s_systemCoreRef.Value; private static readonly Lazy s_systemCoreRef_v4_0_30319_17929 = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemCore).GetReference(display: "System.Core.v4_0_30319_17929.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.SystemCore).GetReference(display: "System.Core.v4_0_30319_17929.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemCoreRef_v4_0_30319_17929 => s_systemCoreRef_v4_0_30319_17929.Value; private static readonly Lazy s_systemRuntimeSerializationRef_v4_0_30319_17929 = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntimeSerialization).GetReference(display: "System.Runtime.Serialization.v4_0_30319_17929.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.SystemRuntimeSerialization).GetReference(display: "System.Runtime.Serialization.v4_0_30319_17929.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemRuntimeSerializationRef_v4_0_30319_17929 => s_systemRuntimeSerializationRef_v4_0_30319_17929.Value; @@ -168,30 +166,25 @@ public virtual void Dispose() public static MetadataReference SystemCoreRef_v46 => s_systemCoreRef_v4_0_30319_17929.Value; private static readonly Lazy s_systemWindowsFormsRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemWindowsForms).GetReference(display: "System.Windows.Forms.v4_0_30319.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.SystemWindowsForms).GetReference(display: "System.Windows.Forms.v4_0_30319.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemWindowsFormsRef => s_systemWindowsFormsRef.Value; private static readonly Lazy s_systemDrawingRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemDrawing).GetReference(display: "System.Drawing.v4_0_30319.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.SystemDrawing).GetReference(display: "System.Drawing.v4_0_30319.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemDrawingRef => s_systemDrawingRef.Value; private static readonly Lazy s_systemDataRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemData).GetReference(display: "System.Data.v4_0_30319.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.SystemData).GetReference(display: "System.Data.v4_0_30319.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemDataRef => s_systemDataRef.Value; private static readonly Lazy s_mscorlibRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.mscorlib).GetReference(display: "mscorlib.v4_0_30319.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.mscorlib).GetReference(display: "mscorlib.v4_0_30319.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference MscorlibRef => s_mscorlibRef.Value; - private static readonly Lazy s_mscorlibRefPortable = new Lazy( - () => AssemblyMetadata.CreateFromImage(ProprietaryTestResources.v4_0_30319.mscorlib_portable).GetReference(display: "mscorlib.v4_0_30319.portable.dll"), - LazyThreadSafetyMode.PublicationOnly); - public static MetadataReference MscorlibRefPortable => s_mscorlibRefPortable.Value; - private static readonly Lazy s_aacorlibRef = new Lazy( () => { @@ -215,37 +208,42 @@ public virtual void Dispose() LazyThreadSafetyMode.PublicationOnly); public static MetadataReference AacorlibRef => s_aacorlibRef.Value; - public static MetadataReference MscorlibRef_v20 => Net20.mscorlib; + public static MetadataReference MscorlibRef_v20 => Net20.References.mscorlib; - public static MetadataReference MscorlibRef_v4_0_30316_17626 => Net451.mscorlib; + public static MetadataReference MscorlibRef_v4_0_30316_17626 => NetFramework.mscorlib; private static readonly Lazy s_mscorlibRef_v46 = new Lazy( () => AssemblyMetadata.CreateFromImage(Net461.ReferenceInfos.mscorlib.ImageBytes).GetReference(display: "mscorlib.v4_6_1038_0.dll", filePath: @"Z:\FxReferenceAssembliesUri"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference MscorlibRef_v46 => s_mscorlibRef_v46.Value; - /// - /// Reference to an mscorlib silverlight assembly in which the System.Array does not contain the special member LongLength. - /// - private static readonly Lazy s_mscorlibRef_silverlight = new Lazy( - () => AssemblyMetadata.CreateFromImage(ProprietaryTestResources.silverlight_v5_0_5_0.mscorlib_v5_0_5_0_silverlight).GetReference(display: "mscorlib.v5.0.5.0_silverlight.dll"), - LazyThreadSafetyMode.PublicationOnly); - public static MetadataReference MscorlibRefSilverlight => s_mscorlibRef_silverlight.Value; - public static MetadataReference MinCorlibRef => TestReferences.NetFx.Minimal.mincorlib; public static MetadataReference MinAsyncCorlibRef => TestReferences.NetFx.Minimal.minasynccorlib; - public static MetadataReference ValueTupleRef => TestReferences.NetFx.ValueTuple.tuplelib; + public static MetadataReference ValueTupleRef => NetFramework.SystemValueTuple; - public static MetadataReference MsvbRef => Net451.MicrosoftVisualBasic; + public static MetadataReference MsvbRef => NetFramework.MicrosoftVisualBasic; - public static MetadataReference MsvbRef_v4_0_30319_17929 => Net451.MicrosoftVisualBasic; + public static MetadataReference MsvbRef_v4_0_30319_17929 => NetFramework.MicrosoftVisualBasic; public static MetadataReference CSharpRef => CSharpDesktopRef; + /// + /// This is a legacy copy of System.ValueTuple. The origin is unclear as this does not appear to be a released + /// binary on nuget.org (possible a pre-release copy). This does have a few properties that were interesting + /// for a particular style of bug in VS that cannot be reproduced with modern TFMs. Specifically that it + /// depends on System.Runtime for parts of the impl and can't compile with only a reference to mscorlib. As + /// such this is kept around for those tests. + /// + /// Related issues + /// - https://github.com/dotnet/roslyn/issues/14888 + /// - https://github.com/dotnet/roslyn/issues/14267 + /// + public static MetadataReference ValueTupleLegacyRef => TestReferences.NetFx.ValueTuple.tuplelib; + private static readonly Lazy s_desktopCSharpRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.v4.0.30319.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.v4.0.30319.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference CSharpDesktopRef => s_desktopCSharpRef.Value; @@ -255,14 +253,8 @@ public virtual void Dispose() public static MetadataReference NetStandard20Ref => s_std20Ref.Value; - private static readonly Lazy s_46NetStandardFacade = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesBuildExtensions.NetStandardToNet461).GetReference(display: "netstandard20.netstandard.dll"), - LazyThreadSafetyMode.PublicationOnly); - - public static MetadataReference Net46StandardFacade => s_46NetStandardFacade.Value; - private static readonly Lazy s_systemRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.System).GetReference(display: "System.v4_0_30319.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.System).GetReference(display: "System.v4_0_30319.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemRef => s_systemRef.Value; @@ -272,52 +264,52 @@ public virtual void Dispose() public static MetadataReference SystemRef_v46 => s_systemRef_v46.Value; private static readonly Lazy s_systemRef_v4_0_30319_17929 = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.System).GetReference(display: "System.v4_0_30319_17929.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.System).GetReference(display: "System.v4_0_30319_17929.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemRef_v4_0_30319_17929 => s_systemRef_v4_0_30319_17929.Value; private static readonly Lazy s_systemRef_v20 = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet20.System).GetReference(display: "System.v2_0_50727.dll"), + () => AssemblyMetadata.CreateFromImage(Net20.Resources.System).GetReference(display: "System.v2_0_50727.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemRef_v20 => s_systemRef_v20.Value; private static readonly Lazy s_systemXmlRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemXml).GetReference(display: "System.Xml.v4_0_30319.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.SystemXml).GetReference(display: "System.Xml.v4_0_30319.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemXmlRef => s_systemXmlRef.Value; private static readonly Lazy s_systemXmlLinqRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemXmlLinq).GetReference(display: "System.Xml.Linq.v4_0_30319.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.SystemXmlLinq).GetReference(display: "System.Xml.Linq.v4_0_30319.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemXmlLinqRef => s_systemXmlLinqRef.Value; private static readonly Lazy s_mscorlibFacadeRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.mscorlib).GetReference(display: "mscorlib.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.mscorlib).GetReference(display: "mscorlib.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference MscorlibFacadeRef => s_mscorlibFacadeRef.Value; private static readonly Lazy s_systemRuntimeFacadeRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntime).GetReference(display: "System.Runtime.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.SystemRuntime).GetReference(display: "System.Runtime.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemRuntimeFacadeRef => s_systemRuntimeFacadeRef.Value; private static readonly Lazy s_systemThreadingFacadeRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemThreading).GetReference(display: "System.Threading.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.SystemThreading).GetReference(display: "System.Threading.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemThreadingFacadeRef => s_systemThreadingTasksFacadeRef.Value; private static readonly Lazy s_systemThreadingTasksFacadeRef = new Lazy( - () => AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemThreadingTasks).GetReference(display: "System.Threading.Tasks.dll"), + () => AssemblyMetadata.CreateFromImage(Net461.Resources.SystemThreadingTasks).GetReference(display: "System.Threading.Tasks.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemThreadingTaskFacadeRef => s_systemThreadingTasksFacadeRef.Value; private static readonly Lazy s_mscorlibPP7Ref = new Lazy( - () => AssemblyMetadata.CreateFromImage(ProprietaryTestResources.ReferenceAssemblies_PortableProfile7.mscorlib).GetReference(display: "mscorlib.dll"), + () => AssemblyMetadata.CreateFromImage(TestResources.NetFX.PortableProfile7.Mscorlib).GetReference(display: "mscorlib.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference MscorlibPP7Ref => s_mscorlibPP7Ref.Value; private static readonly Lazy s_systemRuntimePP7Ref = new Lazy( - () => AssemblyMetadata.CreateFromImage(ProprietaryTestResources.ReferenceAssemblies_PortableProfile7.System_Runtime).GetReference(display: "System.Runtime.dll"), + () => AssemblyMetadata.CreateFromImage(TestResources.NetFX.PortableProfile7.SystemRuntime).GetReference(display: "System.Runtime.dll"), LazyThreadSafetyMode.PublicationOnly); public static MetadataReference SystemRuntimePP7Ref => s_systemRuntimePP7Ref.Value; diff --git a/src/Compilers/Test/Core/TestHelpers.cs b/src/Compilers/Test/Core/TestHelpers.cs index e0cd28c75ffc4..05f8777281074 100644 --- a/src/Compilers/Test/Core/TestHelpers.cs +++ b/src/Compilers/Test/Core/TestHelpers.cs @@ -11,6 +11,7 @@ using System.Globalization; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using System.Text; using System.Xml.Linq; using Microsoft.CodeAnalysis; @@ -146,5 +147,30 @@ public static string NormalizeNewLines(XCData data) return data.Value; } + + public static ImmutableArray HexToByte(ReadOnlySpan input) + { + if (input.Length % 2 != 0) + { + throw new ArgumentException("Length of the input string must be even", nameof(input)); + } + + var bytes = new byte[input.Length >> 1]; + for (var i = 0; i < bytes.Length; i++) + { + bytes[i] = parseByte(input.Slice(i << 1, 2), NumberStyles.HexNumber); + } + + return ImmutableCollectionsMarshal.AsImmutableArray(bytes); + + byte parseByte(ReadOnlySpan input, NumberStyles numberStyle) + { +#if NET + return byte.Parse(input, numberStyle); +#else + return byte.Parse(input.ToString(), numberStyle); +#endif + } + } } } diff --git a/src/Compilers/Test/Directory.Build.props b/src/Compilers/Test/Directory.Build.props index 6eef643958f56..9dd0ddea9df26 100644 --- a/src/Compilers/Test/Directory.Build.props +++ b/src/Compilers/Test/Directory.Build.props @@ -1,6 +1,6 @@ - true + true diff --git a/src/Compilers/Test/Resources/Core/Microsoft.CodeAnalysis.Compiler.Test.Resources.csproj b/src/Compilers/Test/Resources/Core/Microsoft.CodeAnalysis.Compiler.Test.Resources.csproj index 2a0b813558582..2e52cad71d476 100644 --- a/src/Compilers/Test/Resources/Core/Microsoft.CodeAnalysis.Compiler.Test.Resources.csproj +++ b/src/Compilers/Test/Resources/Core/Microsoft.CodeAnalysis.Compiler.Test.Resources.csproj @@ -15,8 +15,7 @@ - - + @@ -85,11 +84,16 @@ + + + + + @@ -103,7 +107,6 @@ - @@ -190,6 +193,7 @@ + @@ -371,14 +375,9 @@ - - - - - @@ -386,8 +385,6 @@ - - diff --git a/src/Compilers/Test/Resources/Core/NetFX/PortableProfile7/System.Runtime.dll b/src/Compilers/Test/Resources/Core/NetFX/PortableProfile7/System.Runtime.dll new file mode 100644 index 0000000000000..0afd7a96a6308 Binary files /dev/null and b/src/Compilers/Test/Resources/Core/NetFX/PortableProfile7/System.Runtime.dll differ diff --git a/src/Compilers/Test/Resources/Core/NetFX/PortableProfile7/mscorlib.dll b/src/Compilers/Test/Resources/Core/NetFX/PortableProfile7/mscorlib.dll new file mode 100644 index 0000000000000..ce2519b1887fa Binary files /dev/null and b/src/Compilers/Test/Resources/Core/NetFX/PortableProfile7/mscorlib.dll differ diff --git a/src/Compilers/Test/Resources/Core/NetFX/WinRt/System.Runtime.WindowsRuntime.UI.Xaml.dll b/src/Compilers/Test/Resources/Core/NetFX/WinRt/System.Runtime.WindowsRuntime.UI.Xaml.dll new file mode 100644 index 0000000000000..e4bbbb5376e8f Binary files /dev/null and b/src/Compilers/Test/Resources/Core/NetFX/WinRt/System.Runtime.WindowsRuntime.UI.Xaml.dll differ diff --git a/src/Compilers/Test/Resources/Core/NetFX/WinRt/System.Runtime.WindowsRuntime.dll b/src/Compilers/Test/Resources/Core/NetFX/WinRt/System.Runtime.WindowsRuntime.dll new file mode 100644 index 0000000000000..dbd3e5ea114bc Binary files /dev/null and b/src/Compilers/Test/Resources/Core/NetFX/WinRt/System.Runtime.WindowsRuntime.dll differ diff --git a/src/Compilers/Test/Resources/Core/SymbolsTests/CustomModifiers/CppCli.cpp b/src/Compilers/Test/Resources/Core/SymbolsTests/CustomModifiers/CppCli.cpp deleted file mode 100644 index 9e35b44133e8e..0000000000000 --- a/src/Compilers/Test/Resources/Core/SymbolsTests/CustomModifiers/CppCli.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -//cl /clr:safe /LD CppCli.cpp - -using namespace System; - -namespace CppCli -{ - - public interface class CppInterface1 - { - public: - void Method1(const int x); - void Method2(const int x); - }; - - // Identical, but distinct from, CppInterface1 - public interface class CppInterface2 - { - public: - void Method1(const int x); - void Method2(const int x); - }; - - public ref class CppBase1 - { - public: - virtual void VirtualMethod(const int x) - { - Console::WriteLine("CppBase1::VirtualMethod({0})", x); - } - void NonVirtualMethod(const int x) - { - Console::WriteLine("CppBase1::NonVirtualMethod({0})", x); - } - }; - - public ref class CppBase2 - { - public: - virtual void Method1(const int x) - { - Console::WriteLine("CppBase2::Method1({0})", x); - } - void Method2(const int x) - { - Console::WriteLine("CppBase2::Method2({0})", x); - } - }; - - public interface class CppBestMatchInterface - { - public: - void Method(const int x, int y); - }; - - public ref class CppBestMatchBase1 - { - public: - virtual void Method(int x, const int y) - { - Console::WriteLine("CppBestMatchBase1::Method({0},{1})", x, y); - } - }; - - public ref class CppBestMatchBase2 : CppBestMatchBase1 - { - public: - virtual void Method(const int x, const int y) new - { - Console::WriteLine("CppBestMatchBase2::Method({0},{1})", x, y); - } - }; - - public interface class CppIndexerInterface - { - public: - property int default[const int] - { - int get(const int i); - void set(const int i, int value); - } - }; - - public ref class CppIndexerBase - { - public: - - virtual property int default[const int] - { - int get(const int i) { Console::WriteLine("CppBase1::Item.get({0})", i); return 0; } - void set(const int i, int value) { Console::WriteLine("CppBase1::Item.set({0})", i); } - } - }; -} diff --git a/src/Compilers/Test/Resources/Core/SymbolsTests/CustomModifiers/GenericMethodWithModifiers.cpp b/src/Compilers/Test/Resources/Core/SymbolsTests/CustomModifiers/GenericMethodWithModifiers.cpp deleted file mode 100644 index 906e1a102ec1b..0000000000000 --- a/src/Compilers/Test/Resources/Core/SymbolsTests/CustomModifiers/GenericMethodWithModifiers.cpp +++ /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. - -//cl /clr:safe /LD GenericMethodWithModifiers.cpp - -using namespace System; - -public ref class CL1 -{ -public: - generic where T : value class, ValueType - virtual Nullable^ Test(Nullable^ x) - { - return x; - } -}; - -public interface class I1 -{ -public: - generic where T : value class, ValueType - virtual Nullable^ Test(Nullable^ x); -}; - diff --git a/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/BadDefaultParameterValue.dll b/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/BadDefaultParameterValue.dll new file mode 100644 index 0000000000000..38a013b1a207c Binary files /dev/null and b/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/BadDefaultParameterValue.dll differ diff --git a/src/Compilers/Test/Resources/Core/TestResources.cs b/src/Compilers/Test/Resources/Core/TestResources.cs index 5a7f48629dcf9..a7fed061b198a 100644 --- a/src/Compilers/Test/Resources/Core/TestResources.cs +++ b/src/Compilers/Test/Resources/Core/TestResources.cs @@ -4,6 +4,8 @@ #nullable disable +using System; + namespace TestResources { public static class DiagnosticTests @@ -170,6 +172,9 @@ public static class Minimal private static byte[] s_mincorlib; public static byte[] mincorlib => ResourceLoader.GetOrCreateResource(ref s_mincorlib, "NetFX.Minimal.mincorlib.dll"); + private static string s_mincorlib_cs; + public static string mincorlib_cs => ResourceLoader.GetOrCreateResource(ref s_mincorlib_cs, "NetFX.Minimal.mincorlib.cs"); + private static byte[] s_minasync; public static byte[] minasync => ResourceLoader.GetOrCreateResource(ref s_minasync, "NetFX.Minimal.minasync.dll"); @@ -177,6 +182,24 @@ public static class Minimal public static byte[] minasynccorlib => ResourceLoader.GetOrCreateResource(ref s_minasynccorlib, "NetFX.Minimal.minasynccorlib.dll"); } + public static class PortableProfile7 + { + private static byte[] s_mscorlib; + public static byte[] Mscorlib => ResourceLoader.GetOrCreateResource(ref s_mscorlib, "NetFX.PortableProfile7.mscorlib.dll"); + + private static byte[] s_systemRuntime; + public static byte[] SystemRuntime => ResourceLoader.GetOrCreateResource(ref s_systemRuntime, "NetFX.PortableProfile7.System.Runtime.dll"); + } + + public static class WinRt + { + public static byte[] s_systemRuntimeWindowsRuntime; + public static byte[] SystemRuntimeWindowsRuntime => ResourceLoader.GetOrCreateResource(ref s_systemRuntimeWindowsRuntime, "NetFX.WinRt.System.Runtime.WindowsRuntime.dll"); + + public static byte[] s_systemRuntimeWindowsRuntimeUIXaml; + public static byte[] SystemRuntimeWindowsRuntimeUIXaml => ResourceLoader.GetOrCreateResource(ref s_systemRuntimeWindowsRuntimeUIXaml, "NetFX.WinRt.System.Runtime.WindowsRuntime.UI.Xaml.dll"); + } + public static class ValueTuple { private static byte[] s_tuplelib; @@ -489,6 +512,9 @@ public static class Metadata private static byte[] s_invalidPublicKey; public static byte[] InvalidPublicKey => ResourceLoader.GetOrCreateResource(ref s_invalidPublicKey, "SymbolsTests.Metadata.InvalidPublicKey.dll"); + private static byte[] s_badDefaultParameterValue; + public static byte[] BadDefaultParameterValue => ResourceLoader.GetOrCreateResource(ref s_badDefaultParameterValue, "SymbolsTests.Metadata.BadDefaultParameterValue.dll"); + private static byte[] s_MDTestAttributeApplicationLib; public static byte[] MDTestAttributeApplicationLib => ResourceLoader.GetOrCreateResource(ref s_MDTestAttributeApplicationLib, "SymbolsTests.Metadata.MDTestAttributeApplicationLib.dll"); diff --git a/src/Compilers/Test/Utilities/CSharp/AttributeValidation.cs b/src/Compilers/Test/Utilities/CSharp/AttributeValidation.cs new file mode 100644 index 0000000000000..703a6c4e25d3d --- /dev/null +++ b/src/Compilers/Test/Utilities/CSharp/AttributeValidation.cs @@ -0,0 +1,51 @@ +// 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.Linq; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +internal static class AttributeValidation +{ + internal static void AssertReferencedIsUnmanagedAttribute(Accessibility accessibility, TypeParameterSymbol typeParameter, string assemblyName) + { + var attributes = ((PEModuleSymbol)typeParameter.ContainingModule).GetCustomAttributesForToken(((PETypeParameterSymbol)typeParameter).Handle); + NamedTypeSymbol attributeType = attributes.Single().AttributeClass; + + Assert.Equal("IsUnmanagedAttribute", attributeType.Name); + Assert.Equal(assemblyName, attributeType.ContainingAssembly.Name); + Assert.Equal(accessibility, attributeType.DeclaredAccessibility); + + switch (accessibility) + { + case Accessibility.Internal: + { + var isUnmanagedTypeAttributes = attributeType.GetAttributes().OrderBy(attribute => attribute.AttributeClass.Name).ToArray(); + Assert.Equal(2, isUnmanagedTypeAttributes.Length); + + Assert.Equal(WellKnownTypes.GetMetadataName(WellKnownType.System_Runtime_CompilerServices_CompilerGeneratedAttribute), isUnmanagedTypeAttributes[0].AttributeClass.ToDisplayString()); + Assert.Equal(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName, isUnmanagedTypeAttributes[1].AttributeClass.ToDisplayString()); + break; + } + + case Accessibility.Public: + { + var refSafetyRulesAttribute = attributeType.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.RefSafetyRulesAttribute.FullName); + var embeddedAttribute = attributeType.ContainingAssembly.GetTypeByMetadataName(AttributeDescription.CodeAnalysisEmbeddedAttribute.FullName); + Assert.Equal(refSafetyRulesAttribute is null, embeddedAttribute is null); + break; + } + + default: + throw ExceptionUtilities.UnexpectedValue(accessibility); + } + + } +} diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index b187e0dcd877e..e5bc18a51842e 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -32,7 +32,6 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.Test.Utilities { @@ -887,7 +886,7 @@ internal CompilationVerifier CompileAndVerifyExperimental( Verification verify = default) { options = options ?? TestOptions.ReleaseDll.WithOutputKind((expectedOutput != null) ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary); - var compilation = CreateExperimentalCompilationWithMscorlib45(source, feature, references, options, parseOptions, assemblyName: GetUniqueName()); + var compilation = CreateExperimentalCompilationWithMscorlib461(source, feature, references, options, parseOptions, assemblyName: GetUniqueName()); return CompileAndVerify( source, @@ -1146,23 +1145,23 @@ public static CSharpCompilation CreateCompilationWithMscorlib40( string assemblyName = "", string sourceFileName = "") => CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib40, assemblyName, sourceFileName); - public static CSharpCompilation CreateCompilationWithMscorlib45( + public static CSharpCompilation CreateCompilationWithMscorlib461( CSharpTestSource source, IEnumerable references = null, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null, string assemblyName = "", string sourceFileName = "", - bool skipUsesIsNullable = false) => CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib45, assemblyName, sourceFileName, skipUsesIsNullable); + bool skipUsesIsNullable = false) => CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib461, assemblyName, sourceFileName, skipUsesIsNullable); - public static CSharpCompilation CreateCompilationWithMscorlib45( + public static CSharpCompilation CreateCompilationWithMscorlib461( string[] source, IEnumerable references = null, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null, string assemblyName = "", string sourceFileName = "", - bool skipUsesIsNullable = false) => CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib45, assemblyName, sourceFileName, skipUsesIsNullable); + bool skipUsesIsNullable = false) => CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib461, assemblyName, sourceFileName, skipUsesIsNullable); public static CSharpCompilation CreateCompilationWithMscorlib46( CSharpTestSource source, @@ -1172,7 +1171,7 @@ public static CSharpCompilation CreateCompilationWithMscorlib46( string assemblyName = "", string sourceFileName = "") => CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib46, assemblyName, sourceFileName); - internal static CSharpCompilation CreateExperimentalCompilationWithMscorlib45( + internal static CSharpCompilation CreateExperimentalCompilationWithMscorlib461( CSharpTestSource source, MessageID feature, IEnumerable references = null, @@ -1180,7 +1179,7 @@ internal static CSharpCompilation CreateExperimentalCompilationWithMscorlib45( CSharpParseOptions parseOptions = null, string assemblyName = "", string sourceFileName = "", - bool skipUsesIsNullable = false) => CreateCompilationCore(source, TargetFrameworkUtil.GetReferences(TargetFramework.Mscorlib45, references), options, parseOptions, assemblyName, sourceFileName, skipUsesIsNullable, experimentalFeature: feature); + bool skipUsesIsNullable = false) => CreateCompilationCore(source, TargetFrameworkUtil.GetReferences(TargetFramework.Mscorlib461, references), options, parseOptions, assemblyName, sourceFileName, skipUsesIsNullable, experimentalFeature: feature); public static CSharpCompilation CreateCompilationWithWinRT( CSharpTestSource source, @@ -1190,13 +1189,13 @@ public static CSharpCompilation CreateCompilationWithWinRT( string assemblyName = "", string sourceFileName = "") => CreateCompilation(source, references, options, parseOptions, TargetFramework.WinRT, assemblyName, sourceFileName); - public static CSharpCompilation CreateCompilationWithMscorlib45AndCSharp( + public static CSharpCompilation CreateCompilationWithMscorlib461AndCSharp( CSharpTestSource source, IEnumerable references = null, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null, string assemblyName = "", - string sourceFileName = "") => CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib45AndCSharp, assemblyName, sourceFileName); + string sourceFileName = "") => CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib461AndCSharp, assemblyName, sourceFileName); public static CSharpCompilation CreateCompilationWithMscorlib40AndSystemCore( CSharpTestSource source, @@ -1247,13 +1246,11 @@ public static CSharpCompilation CreateCompilationWithTasksExtensions( if (RuntimeUtilities.IsCoreClrRuntime) { - allReferences = TargetFrameworkUtil.NetStandard20References; - allReferences = allReferences.Concat(new[] { SystemThreadingTasksExtensions.NetStandard20Lib }); + allReferences = [.. NetStandard20.References.All, NetStandard20.ExtraReferences.SystemThreadingTasksExtensions]; } else { - allReferences = TargetFrameworkUtil.Mscorlib461ExtendedReferences; - allReferences = allReferences.Concat(new[] { Net461.References.SystemThreadingTasks, SystemThreadingTasksExtensions.PortableLib }); + allReferences = [.. TargetFrameworkUtil.Mscorlib461ExtendedReferences, Net461.ExtraReferences.SystemThreadingTasksExtensions]; } if (references != null) @@ -1314,7 +1311,7 @@ private static CSharpCompilation CreateCompilationCore( } Func createCompilationLambda = () => CSharpCompilation.Create( - assemblyName == "" ? GetUniqueName() : assemblyName, + string.IsNullOrEmpty(assemblyName) ? GetUniqueName() : assemblyName, syntaxTrees, references, options); @@ -2278,14 +2275,14 @@ protected static CSharpCompilation CreateCompilationWithMscorlibAndSpan(CSharpTe { var reference = CreateEmptyCompilation( TestSources.Span, - references: new List() { Net451.mscorlib, Net451.SystemCore, Net451.MicrosoftCSharp }, + references: new List() { NetFramework.mscorlib, NetFramework.SystemCore, NetFramework.MicrosoftCSharp }, options: TestOptions.UnsafeReleaseDll); reference.VerifyDiagnostics(); var comp = CreateEmptyCompilation( text, - references: new List() { Net451.mscorlib, Net451.SystemCore, Net451.MicrosoftCSharp, reference.EmitToImageReference() }, + references: new List() { NetFramework.mscorlib, NetFramework.SystemCore, NetFramework.MicrosoftCSharp, reference.EmitToImageReference() }, options: options, parseOptions: parseOptions); diff --git a/src/Compilers/Test/Utilities/CSharp/FunctionPointerUtilities.cs b/src/Compilers/Test/Utilities/CSharp/FunctionPointerUtilities.cs index 50631f1757d1a..a6fbcfafacc90 100644 --- a/src/Compilers/Test/Utilities/CSharp/FunctionPointerUtilities.cs +++ b/src/Compilers/Test/Utilities/CSharp/FunctionPointerUtilities.cs @@ -80,8 +80,8 @@ static void verifySignature(MethodSymbol symbol) Assert.False(symbol.IsDeclaredReadOnly); Assert.False(symbol.IsMetadataNewSlot(true)); Assert.False(symbol.IsMetadataNewSlot(false)); - Assert.False(symbol.IsMetadataVirtual(true)); - Assert.False(symbol.IsMetadataVirtual(false)); + Assert.False(symbol.IsMetadataVirtual(MethodSymbol.IsMetadataVirtualOption.IgnoreInterfaceImplementationChanges)); + Assert.False(symbol.IsMetadataVirtual(MethodSymbol.IsMetadataVirtualOption.None)); Assert.Equal(symbol.IsVararg, symbol.CallingConvention.IsCallingConvention(CallingConvention.ExtraArguments)); diff --git a/src/Compilers/Test/Utilities/CSharp/SemanticModelTestBase.cs b/src/Compilers/Test/Utilities/CSharp/SemanticModelTestBase.cs index 8d4066331989e..7faf243c35585 100644 --- a/src/Compilers/Test/Utilities/CSharp/SemanticModelTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/SemanticModelTestBase.cs @@ -119,7 +119,7 @@ protected CompilationUtils.SemanticInfoSummary GetSemanticInfoForTest(str internal CompilationUtils.SemanticInfoSummary GetSemanticInfoForTestExperimental(string testSrc, MessageID feature, CSharpParseOptions parseOptions = null) where TNode : SyntaxNode { - var compilation = CreateExperimentalCompilationWithMscorlib45(testSrc, feature, parseOptions: parseOptions); + var compilation = CreateExperimentalCompilationWithMscorlib461(testSrc, feature, parseOptions: parseOptions); return GetSemanticInfoForTest(compilation); } diff --git a/src/Compilers/Test/Utilities/VisualBasic/CompilationTestUtils.vb b/src/Compilers/Test/Utilities/VisualBasic/CompilationTestUtils.vb index 410cdd9e098b7..92534ab7a301f 100644 --- a/src/Compilers/Test/Utilities/VisualBasic/CompilationTestUtils.vb +++ b/src/Compilers/Test/Utilities/VisualBasic/CompilationTestUtils.vb @@ -8,12 +8,12 @@ Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices Imports System.Text Imports System.Xml.Linq +Imports Basic.Reference.Assemblies Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.Text Imports Roslyn.Test.Utilities Imports Roslyn.Test.Utilities.TestBase -Imports Roslyn.Test.Utilities.TestMetadata Imports Xunit Friend Module CompilationUtils @@ -65,7 +65,7 @@ Friend Module CompilationUtils Dim trees = source.GetSyntaxTrees(parseOptions, assemblyName) Dim createCompilationLambda = Function() Return VisualBasicCompilation.Create( - If(assemblyName, GetUniqueName()), + If(String.IsNullOrEmpty(assemblyName), GetUniqueName(), assemblyName), trees, references, options) @@ -144,22 +144,22 @@ Friend Module CompilationUtils Return CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib40, assemblyName) End Function - Public Function CreateCompilationWithMscorlib45( + Public Function CreateCompilationWithMscorlib461( source As BasicTestSource, Optional references As IEnumerable(Of MetadataReference) = Nothing, Optional options As VisualBasicCompilationOptions = Nothing, Optional parseOptions As VisualBasicParseOptions = Nothing, Optional assemblyName As String = Nothing) As VisualBasicCompilation - Return CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib45, assemblyName) + Return CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib461, assemblyName) End Function - Public Function CreateCompilationWithMscorlib45AndVBRuntime( + Public Function CreateCompilationWithMscorlib461AndVBRuntime( source As BasicTestSource, Optional references As IEnumerable(Of MetadataReference) = Nothing, Optional options As VisualBasicCompilationOptions = Nothing, Optional parseOptions As VisualBasicParseOptions = Nothing, Optional assemblyName As String = Nothing) As VisualBasicCompilation - Return CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib45AndVBRuntime, assemblyName) + Return CreateCompilation(source, references, options, parseOptions, TargetFramework.Mscorlib461AndVBRuntime, assemblyName) End Function Public Function CreateCompilationWithWinRt(source As XElement) As VisualBasicCompilation @@ -170,7 +170,7 @@ Friend Module CompilationUtils references As IEnumerable(Of MetadataReference), Optional options As VisualBasicCompilationOptions = Nothing, Optional parseOptions As VisualBasicParseOptions = Nothing) As VisualBasicCompilation - Return CreateEmptyCompilationWithReferences(source, {CType(Net40.mscorlib, MetadataReference)}.Concat(references), options, parseOptions:=parseOptions) + Return CreateEmptyCompilationWithReferences(source, {CType(Net40.References.mscorlib, MetadataReference)}.Concat(references), options, parseOptions:=parseOptions) End Function ''' @@ -186,7 +186,7 @@ Friend Module CompilationUtils Public Function CreateCompilationWithMscorlib40(source As XElement, outputKind As OutputKind, Optional parseOptions As VisualBasicParseOptions = Nothing) As VisualBasicCompilation - Return CreateEmptyCompilationWithReferences(source, {Net40.mscorlib}, New VisualBasicCompilationOptions(outputKind), parseOptions:=parseOptions) + Return CreateEmptyCompilationWithReferences(source, {Net40.References.mscorlib}, New VisualBasicCompilationOptions(outputKind), parseOptions:=parseOptions) End Function ''' @@ -207,7 +207,7 @@ Friend Module CompilationUtils Optional assemblyName As String = Nothing) As VisualBasicCompilation If additionalRefs Is Nothing Then additionalRefs = {} - Dim references = {CType(Net40.mscorlib, MetadataReference), Net40.System, Net40.MicrosoftVisualBasic}.Concat(additionalRefs) + Dim references = {CType(Net40.References.mscorlib, MetadataReference), Net40.References.System, Net40.References.MicrosoftVisualBasic}.Concat(additionalRefs) Return CreateEmptyCompilationWithReferences(source, references, options, parseOptions:=parseOptions, assemblyName:=assemblyName) End Function @@ -227,9 +227,9 @@ Friend Module CompilationUtils Public ReadOnly XmlReferences As MetadataReference() = {SystemRef, SystemCoreRef, SystemXmlRef, SystemXmlLinqRef} - Public ReadOnly Net40XmlReferences As MetadataReference() = {Net40.SystemCore, Net40.SystemXml, Net40.SystemXmlLinq} + Public ReadOnly Net40XmlReferences As MetadataReference() = {Net40.References.SystemCore, Net40.References.SystemXml, Net40.References.SystemXmlLinq} - Public ReadOnly Net451XmlReferences As MetadataReference() = {Net451.SystemCore, Net451.SystemXml, Net451.SystemXmlLinq} + Public ReadOnly Net461XmlReferences As MetadataReference() = {Net461.References.SystemCore, Net461.References.SystemXml, Net461.References.SystemXmlLinq} ''' ''' @@ -248,7 +248,7 @@ Friend Module CompilationUtils Optional parseOptions As VisualBasicParseOptions = Nothing) As VisualBasicCompilation If references Is Nothing Then references = {} - Dim allReferences = {CType(Net40.mscorlib, MetadataReference), Net40.System, Net40.MicrosoftVisualBasic}.Concat(references) + Dim allReferences = {CType(Net40.References.mscorlib, MetadataReference), Net40.References.System, Net40.References.MicrosoftVisualBasic}.Concat(references) If parseOptions Is Nothing AndAlso options IsNot Nothing Then parseOptions = options.ParseOptions End If diff --git a/src/Compilers/VisualBasic/BasicAnalyzerDriver/BasicAnalyzerDriver.shproj b/src/Compilers/VisualBasic/BasicAnalyzerDriver/BasicAnalyzerDriver.shproj index b6c4ed3cc4a8a..d0155ff59ea76 100644 --- a/src/Compilers/VisualBasic/BasicAnalyzerDriver/BasicAnalyzerDriver.shproj +++ b/src/Compilers/VisualBasic/BasicAnalyzerDriver/BasicAnalyzerDriver.shproj @@ -4,7 +4,7 @@ e8f0baa5-7327-43d1-9a51-644e81ae55f1 14.0 - true + true diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/ResumableStateMachineStateAllocator.vb b/src/Compilers/VisualBasic/Portable/CodeGen/ResumableStateMachineStateAllocator.vb index 7c53690ddc6d9..54940c9cc9903 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/ResumableStateMachineStateAllocator.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/ResumableStateMachineStateAllocator.vb @@ -5,6 +5,8 @@ Imports System Imports System.Diagnostics Imports Microsoft.CodeAnalysis.CodeGen +Imports Microsoft.CodeAnalysis.Emit +Imports Microsoft.CodeAnalysis.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -15,7 +17,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Friend NotInheritable Class ResumableStateMachineStateAllocator Private ReadOnly _slotAllocator As VariableSlotAllocator Private ReadOnly _increasing As Boolean - Private ReadOnly _firstState As Integer + Private ReadOnly _firstState As StateMachineState ''' ''' The number of the next generated resumable state (i.e. state that resumes execution of the state machine after await expression or yield return). @@ -71,7 +73,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property - Public Function GenerateThrowMissingStateDispatch(f As SyntheticBoundNodeFactory, cachedState As BoundExpression, message As String) As BoundStatement + Public Function GenerateThrowMissingStateDispatch(f As SyntheticBoundNodeFactory, cachedState As BoundExpression, errorCode As HotReloadExceptionCode) As BoundStatement + Debug.Assert(f.CompilationState IsNot Nothing) + Debug.Assert(f.CompilationState.ModuleBuilderOpt IsNot Nothing) + If Not HasMissingStates Then Return Nothing End If @@ -84,8 +89,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic f.Literal(_firstState)), f.Throw( f.[New]( - f.WellKnownMember(Of MethodSymbol)(WellKnownMember.System_InvalidOperationException__ctorString), - f.StringLiteral(ConstantValue.Create(message))))) + DirectCast(f.CompilationState.ModuleBuilderOpt.GetOrCreateHotReloadExceptionConstructorDefinition(), MethodSymbol), + f.StringLiteral(ConstantValue.Create(errorCode.GetExceptionMessage())), + f.Literal(errorCode.GetExceptionCodeValue())))) End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCompiler.vb b/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCompiler.vb index c43521edbc5ac..7d5a888b72909 100644 --- a/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCompiler.vb @@ -298,7 +298,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Sub Private Protected Overrides Function CreateGeneratorDriver(baseDirectory As String, parseOptions As ParseOptions, generators As ImmutableArray(Of ISourceGenerator), analyzerConfigOptionsProvider As AnalyzerConfigOptionsProvider, additionalTexts As ImmutableArray(Of AdditionalText)) As GeneratorDriver - Return VisualBasicGeneratorDriver.Create(generators, additionalTexts, DirectCast(parseOptions, VisualBasicParseOptions), analyzerConfigOptionsProvider, driverOptions:=New GeneratorDriverOptions() With {.BaseDirectory = baseDirectory}) + Return VisualBasicGeneratorDriver.Create(generators, additionalTexts, DirectCast(parseOptions, VisualBasicParseOptions), analyzerConfigOptionsProvider, driverOptions:=New GeneratorDriverOptions(disabledOutputs:=IncrementalGeneratorOutputKind.Host) With {.BaseDirectory = baseDirectory}) End Function Private Protected Overrides Sub DiagnoseBadAccesses(consoleOutput As TextWriter, errorLogger As ErrorLogger, compilation As Compilation, diagnostics As ImmutableArray(Of Diagnostic)) diff --git a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb index 8d42d722dc96b..a05d444058945 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb @@ -255,6 +255,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic compiler.CompileSynthesizedMethods(additionalTypes) End If + ' Create and compile HotReloadException type if emitting deltas even if it is not used. + ' We might need to use it for deleted members, which we determine when indexing metadata. + Dim hotReloadException = moduleBeingBuiltOpt.TryGetOrCreateSynthesizedHotReloadExceptionType() + If hotReloadException IsNot Nothing Then + compiler.CompileSynthesizedMethods(ImmutableArray.Create(DirectCast(hotReloadException, NamedTypeSymbol))) + End If + compilation.AnonymousTypeManager.AssignTemplatesNamesAndCompile(compiler, moduleBeingBuiltOpt, diagnostics) compiler.WaitForWorkers() diff --git a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb index 166fdb3d7da14..51525fd134e32 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb @@ -2523,6 +2523,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return True End Function + Private Protected Overrides Function MapToCompilation(moduleBeingBuilt As CommonPEModuleBuilder) As EmitBaseline + Return EmitHelpers.MapToCompilation(Me, DirectCast(moduleBeingBuilt, PEDeltaAssemblyBuilder)) + End Function + Friend Overrides Function GenerateResources( moduleBuilder As CommonPEModuleBuilder, win32Resources As Stream, diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb index 03863dbc8ee5f..11f3d1c93a873 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb @@ -5,11 +5,13 @@ Imports System.Collections.Immutable Imports System.IO Imports System.Reflection.Metadata +Imports System.Runtime.InteropServices Imports System.Threading -Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeGen Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Namespace Microsoft.CodeAnalysis.VisualBasic.Emit @@ -34,17 +36,60 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Dim serializationProperties = compilation.ConstructModuleSerializationProperties(emitOpts, runtimeMDVersion, baseline.ModuleVersionId) Dim manifestResources = SpecializedCollections.EmptyEnumerable(Of ResourceDescription)() + Dim predefinedHotReloadExceptionConstructor As MethodSymbol = Nothing + If Not GetPredefinedHotReloadExceptionTypeConstructor(compilation, diagnostics, predefinedHotReloadExceptionConstructor) Then + Return New EmitDifferenceResult( + success:=False, + diagnostics:=diagnostics.ToReadOnlyAndFree(), + baseline:=Nothing, + updatedMethods:=ImmutableArray(Of MethodDefinitionHandle).Empty, + changedTypes:=ImmutableArray(Of TypeDefinitionHandle).Empty) + End If + + Dim changes As VisualBasicSymbolChanges + Dim definitionMap As VisualBasicDefinitionMap Dim moduleBeingBuilt As PEDeltaAssemblyBuilder Try + Dim sourceAssembly = compilation.SourceAssembly + Dim initialBaseline = baseline.InitialBaseline + Dim previousSourceAssembly = DirectCast(baseline.Compilation, VisualBasicCompilation).SourceAssembly + + ' Hydrate symbols from initial metadata. Once we do so it is important to reuse these symbols across all generations, + ' in order for the symbol matcher to be able to use reference equality once it maps symbols to initial metadata. + Dim metadataSymbols = PEDeltaAssemblyBuilder.GetOrCreateMetadataSymbols(initialBaseline, sourceAssembly.DeclaringCompilation) + + Dim metadataDecoder = DirectCast(metadataSymbols.MetadataDecoder, MetadataDecoder) + Dim metadataAssembly = DirectCast(metadataDecoder.ModuleSymbol.ContainingAssembly, PEAssemblySymbol) + Dim matchToMetadata = New VisualBasicSymbolMatcher(initialBaseline.LazyMetadataSymbols.SynthesizedTypes, sourceAssembly, metadataAssembly) + + Dim previousSourceToMetadata = New VisualBasicSymbolMatcher( + metadataSymbols.SynthesizedTypes, + previousSourceAssembly, + metadataAssembly) + + Dim previousSourceToCurrentSource As VisualBasicSymbolMatcher = Nothing + If baseline.Ordinal > 0 Then + Debug.Assert(baseline.PEModuleBuilder IsNot Nothing) + + previousSourceToCurrentSource = New VisualBasicSymbolMatcher( + sourceAssembly:=sourceAssembly, + otherAssembly:=previousSourceAssembly, + baseline.SynthesizedTypes, + otherSynthesizedMembersOpt:=baseline.SynthesizedMembers, + otherDeletedMembersOpt:=baseline.DeletedMembers) + End If + + definitionMap = New VisualBasicDefinitionMap(edits, metadataDecoder, previousSourceToMetadata, matchToMetadata, previousSourceToCurrentSource, baseline) + changes = New VisualBasicSymbolChanges(definitionMap, edits, isAddedSymbol) + moduleBeingBuilt = New PEDeltaAssemblyBuilder( compilation.SourceAssembly, - emitOptions:=emitOpts, - outputKind:=compilation.Options.OutputKind, - serializationProperties:=serializationProperties, - manifestResources:=manifestResources, - previousGeneration:=baseline, - edits:=edits, - isAddedSymbol:=isAddedSymbol) + changes, + emitOpts, + compilation.Options.OutputKind, + serializationProperties, + manifestResources, + predefinedHotReloadExceptionConstructor) Catch e As NotSupportedException ' TODO: https://github.com/dotnet/roslyn/issues/9004 diagnostics.Add(ERRID.ERR_ModuleEmitFailure, NoLocation.Singleton, compilation.AssemblyName, e.Message) @@ -60,9 +105,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit moduleBeingBuilt.SetTestData(testData) End If - Dim definitionMap = moduleBeingBuilt.PreviousDefinitions - Dim changes = moduleBeingBuilt.EncSymbolChanges - Dim newBaseline As EmitBaseline = Nothing Dim updatedMethods = ArrayBuilder(Of MethodDefinitionHandle).GetInstance() Dim changedTypes = ArrayBuilder(Of TypeDefinitionHandle).GetInstance() @@ -73,14 +115,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit filterOpt:=Function(s) changes.RequiresCompilation(s), cancellationToken:=cancellationToken) Then - ' Map the definitions from the previous compilation to the current compilation. - ' This must be done after compiling above since synthesized definitions - ' (generated when compiling method bodies) may be required. - Dim mappedBaseline = MapToCompilation(compilation, moduleBeingBuilt) - newBaseline = compilation.SerializeToDeltaStreams( moduleBeingBuilt, - mappedBaseline, definitionMap, changes, metadataStream, @@ -102,6 +138,30 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit changedTypes:=changedTypes.ToImmutableAndFree()) End Function + ''' + ''' Returns true if the correct constructor is found or if the type is not defined at all, in which case it can be synthesized. + ''' + Private Function GetPredefinedHotReloadExceptionTypeConstructor(compilation As VisualBasicCompilation, diagnostics As DiagnosticBag, ByRef constructor As MethodSymbol) As Boolean + constructor = TryCast(compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_HotReloadException__ctorStringInt32), MethodSymbol) + If constructor IsNot Nothing Then + Return True + End If + + Dim type = compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_HotReloadException) + If type.Kind = SymbolKind.ErrorType Then + ' type is missing and will be synthesized + Return True + End If + + diagnostics.Add( + ERRID.ERR_ModuleEmitFailure, + NoLocation.Singleton, + compilation.AssemblyName, + String.Format(CodeAnalysisResources.Type0DoesNotHaveExpectedConstructor, type.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat))) + + Return False + End Function + Friend Function MapToCompilation( compilation As VisualBasicCompilation, moduleBeingBuilt As PEDeltaAssemblyBuilder) As EmitBaseline @@ -121,10 +181,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Dim currentDeletedMembers = moduleBeingBuilt.EncSymbolChanges.DeletedMembers ' Mapping from previous compilation to the current. - Dim sourceAssembly = DirectCast(previousGeneration.Compilation, VisualBasicCompilation).SourceAssembly + Dim previousSourceAssembly = DirectCast(previousGeneration.Compilation, VisualBasicCompilation).SourceAssembly Dim matcher = New VisualBasicSymbolMatcher( - sourceAssembly, + previousSourceAssembly, compilation.SourceAssembly, synthesizedTypes, currentSynthesizedMembers, @@ -135,7 +195,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit ' TODO can we reuse some data from the previous matcher? Dim matcherWithAllSynthesizedMembers = New VisualBasicSymbolMatcher( - sourceAssembly, + previousSourceAssembly, compilation.SourceAssembly, synthesizedTypes, mappedSynthesizedMembers, diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb index 8895c2787004c..955d149b98831 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb @@ -6,6 +6,7 @@ Imports System.Collections.Immutable Imports System.Globalization Imports System.Reflection.Metadata Imports System.Runtime.InteropServices +Imports System.Threading Imports Microsoft.Cci Imports Microsoft.CodeAnalysis.CodeGen Imports Microsoft.CodeAnalysis.Collections @@ -21,50 +22,38 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Inherits PEAssemblyBuilderBase Implements IPEDeltaAssemblyBuilder - Private ReadOnly _previousDefinitions As VisualBasicDefinitionMap Private ReadOnly _changes As SymbolChanges Private ReadOnly _deepTranslator As VisualBasicSymbolMatcher.DeepTranslator + Private ReadOnly _predefinedHotReloadExceptionConstructor As MethodSymbol + + ''' + ''' HotReloadException type. May be created even if not used. We might find out + ''' we need it late in the emit phase only after all types and members have been compiled. + ''' indicates if the type is actually used in the delta. + ''' + Private _lazyHotReloadExceptionType As SynthesizedHotReloadExceptionSymbol + + ''' + ''' True if usage of HotReloadException type symbol has been observed and shouldn't be changed anymore. + ''' + Private _freezeHotReloadExceptionTypeUsage As Boolean + + ''' + ''' True if HotReloadException type is actually used in the delta. + ''' + Private _isHotReloadExceptionTypeUsed As Boolean Public Sub New(sourceAssembly As SourceAssemblySymbol, + changes As VisualBasicSymbolChanges, emitOptions As EmitOptions, outputKind As OutputKind, serializationProperties As ModulePropertiesForSerialization, manifestResources As IEnumerable(Of ResourceDescription), - previousGeneration As EmitBaseline, - edits As IEnumerable(Of SemanticEdit), - isAddedSymbol As Func(Of ISymbol, Boolean)) + predefinedHotReloadExceptionConstructor As MethodSymbol) MyBase.New(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, additionalTypes:=ImmutableArray(Of NamedTypeSymbol).Empty) - Dim initialBaseline = previousGeneration.InitialBaseline - Dim previousSourceAssembly = DirectCast(previousGeneration.Compilation, VisualBasicCompilation).SourceAssembly - - ' Hydrate symbols from initial metadata. Once we do so it is important to reuse these symbols across all generations, - ' in order for the symbol matcher to be able to use reference equality once it maps symbols to initial metadata. - Dim metadataSymbols = GetOrCreateMetadataSymbols(initialBaseline, sourceAssembly.DeclaringCompilation) - - Dim metadataDecoder = DirectCast(metadataSymbols.MetadataDecoder, MetadataDecoder) - Dim metadataAssembly = DirectCast(metadataDecoder.ModuleSymbol.ContainingAssembly, PEAssemblySymbol) - Dim matchToMetadata = New VisualBasicSymbolMatcher(initialBaseline.LazyMetadataSymbols.SynthesizedTypes, sourceAssembly, metadataAssembly) - - Dim previousSourceToMetadata = New VisualBasicSymbolMatcher( - metadataSymbols.SynthesizedTypes, - previousSourceAssembly, - metadataAssembly) - - Dim matchToPrevious As VisualBasicSymbolMatcher = Nothing - If previousGeneration.Ordinal > 0 Then - - matchToPrevious = New VisualBasicSymbolMatcher( - sourceAssembly:=sourceAssembly, - otherAssembly:=previousSourceAssembly, - previousGeneration.SynthesizedTypes, - otherSynthesizedMembersOpt:=previousGeneration.SynthesizedMembers, - otherDeletedMembersOpt:=previousGeneration.DeletedMembers) - End If - - _previousDefinitions = New VisualBasicDefinitionMap(edits, metadataDecoder, previousSourceToMetadata, matchToMetadata, matchToPrevious, previousGeneration) - _changes = New VisualBasicSymbolChanges(_previousDefinitions, edits, isAddedSymbol) + _changes = changes ' Workaround for https://github.com/dotnet/roslyn/issues/3192. ' When compiling state machine we stash types of awaiters and state-machine hoisted variables, @@ -79,6 +68,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit ' In order to get the fully lowered form we run the type symbols of stashed variables through a deep translator ' that translates the symbol recursively. _deepTranslator = New VisualBasicSymbolMatcher.DeepTranslator(sourceAssembly.GetSpecialType(SpecialType.System_Object)) + + _predefinedHotReloadExceptionConstructor = predefinedHotReloadExceptionConstructor End Sub Friend Overrides Function EncTranslateLocalVariableType(type As TypeSymbol, diagnostics As DiagnosticBag) As ITypeReference @@ -97,11 +88,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Public Overrides ReadOnly Property PreviousGeneration As EmitBaseline Get - Return _previousDefinitions.Baseline + Return _changes.DefinitionMap.Baseline End Get End Property - Private Shared Function GetOrCreateMetadataSymbols(initialBaseline As EmitBaseline, compilation As VisualBasicCompilation) As EmitBaseline.MetadataSymbols + Friend Shared Function GetOrCreateMetadataSymbols(initialBaseline As EmitBaseline, compilation As VisualBasicCompilation) As EmitBaseline.MetadataSymbols If initialBaseline.LazyMetadataSymbols IsNot Nothing Then Return initialBaseline.LazyMetadataSymbols End If @@ -221,7 +212,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Friend ReadOnly Property PreviousDefinitions As VisualBasicDefinitionMap Get - Return _previousDefinitions + Return DirectCast(_changes.DefinitionMap, VisualBasicDefinitionMap) End Get End Property @@ -239,11 +230,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Function Friend Overrides Function TryCreateVariableSlotAllocator(method As MethodSymbol, topLevelMethod As MethodSymbol, diagnostics As DiagnosticBag) As VariableSlotAllocator - Return _previousDefinitions.TryCreateVariableSlotAllocator(Compilation, method, topLevelMethod, diagnostics) + Return _changes.DefinitionMap.TryCreateVariableSlotAllocator(Compilation, method, topLevelMethod, diagnostics) End Function Friend Overrides Function GetMethodBodyInstrumentations(method As MethodSymbol) As MethodInstrumentation - Return _previousDefinitions.GetMethodBodyInstrumentations(method) + Return _changes.DefinitionMap.GetMethodBodyInstrumentations(method) End Function Friend Overrides Function GetPreviousAnonymousTypes() As ImmutableArray(Of AnonymousTypeKey) @@ -256,7 +247,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Friend Overrides Function TryGetAnonymousTypeName(template As AnonymousTypeManager.AnonymousTypeOrDelegateTemplateSymbol, ByRef name As String, ByRef index As Integer) As Boolean Debug.Assert(Compilation Is template.DeclaringCompilation) - Return _previousDefinitions.TryGetAnonymousTypeName(template, name, index) + Return PreviousDefinitions.TryGetAnonymousTypeName(template, name, index) End Function Public Overrides Function GetTopLevelTypeDefinitions(context As EmitContext) As IEnumerable(Of Cci.INamespaceTypeDefinition) @@ -289,5 +280,45 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Return SpecializedCollections.EmptyEnumerable(Of String)() End Get End Property + + Public Overrides Function TryGetOrCreateSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal + Return If(_predefinedHotReloadExceptionConstructor Is Nothing, GetOrCreateHotReloadExceptionType(), Nothing) + End Function + + Public Overrides Function GetOrCreateHotReloadExceptionConstructorDefinition() As IMethodSymbolInternal + If _predefinedHotReloadExceptionConstructor IsNot Nothing Then + Return _predefinedHotReloadExceptionConstructor + End If + + If _freezeHotReloadExceptionTypeUsage Then + ' the type shouldn't be used after usage has been frozen. + Throw ExceptionUtilities.Unreachable() + End If + + _isHotReloadExceptionTypeUsed = True + Return GetOrCreateHotReloadExceptionType().Constructor + End Function + + Public Overrides Function GetUsedSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal + _freezeHotReloadExceptionTypeUsage = True + Return If(_isHotReloadExceptionTypeUsed, _lazyHotReloadExceptionType, Nothing) + End Function + + Private Function GetOrCreateHotReloadExceptionType() As SynthesizedHotReloadExceptionSymbol + Dim symbol = _lazyHotReloadExceptionType + If symbol IsNot Nothing Then + Return symbol + End If + + Dim exceptionType = Compilation.GetWellKnownType(WellKnownType.System_Exception) + Dim stringType = Compilation.GetSpecialType(SpecialType.System_String) + Dim intType = Compilation.GetSpecialType(SpecialType.System_Int32) + + Dim containingNamespace = GetOrSynthesizeNamespace(SynthesizedHotReloadExceptionSymbol.NamespaceName) + symbol = New SynthesizedHotReloadExceptionSymbol(containingNamespace, exceptionType, stringType, intType) + + Interlocked.CompareExchange(_lazyHotReloadExceptionType, symbol, comparand:=Nothing) + Return _lazyHotReloadExceptionType + End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb index 05450b24291de..1d5113737f581 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb @@ -22,36 +22,36 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Private ReadOnly _metadataDecoder As MetadataDecoder Private ReadOnly _previousSourceToMetadata As VisualBasicSymbolMatcher - Private ReadOnly _mapToMetadata As VisualBasicSymbolMatcher - Private ReadOnly _mapToPrevious As VisualBasicSymbolMatcher + Private ReadOnly _sourceToMetadata As VisualBasicSymbolMatcher + Private ReadOnly _sourceToPrevious As VisualBasicSymbolMatcher Public Sub New(edits As IEnumerable(Of SemanticEdit), metadataDecoder As MetadataDecoder, previousSourceToMetadata As VisualBasicSymbolMatcher, - mapToMetadata As VisualBasicSymbolMatcher, - mapToPrevious As VisualBasicSymbolMatcher, + sourceToMetadata As VisualBasicSymbolMatcher, + sourceToPreviousSource As VisualBasicSymbolMatcher, baseline As EmitBaseline) MyBase.New(edits, baseline) Debug.Assert(metadataDecoder IsNot Nothing) - Debug.Assert(mapToMetadata IsNot Nothing) + Debug.Assert(sourceToMetadata IsNot Nothing) _metadataDecoder = metadataDecoder _previousSourceToMetadata = previousSourceToMetadata - _mapToMetadata = mapToMetadata - _mapToPrevious = If(mapToPrevious, mapToMetadata) + _sourceToMetadata = sourceToMetadata + _sourceToPrevious = If(sourceToPreviousSource, sourceToMetadata) End Sub Public Overrides ReadOnly Property SourceToMetadataSymbolMatcher As SymbolMatcher Get - Return _mapToMetadata + Return _sourceToMetadata End Get End Property Public Overrides ReadOnly Property SourceToPreviousSymbolMatcher As SymbolMatcher Get - Return _mapToPrevious + Return _sourceToPrevious End Get End Property @@ -80,7 +80,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Function Friend Function TryGetAnonymousTypeName(template As AnonymousTypeManager.AnonymousTypeOrDelegateTemplateSymbol, ByRef name As String, ByRef index As Integer) As Boolean - Return _mapToPrevious.TryGetAnonymousTypeName(template, name, index) + Return _sourceToPrevious.TryGetAnonymousTypeName(template, name, index) End Function Protected Overrides Function TryGetStateMachineType(methodHandle As MethodDefinitionHandle) As ITypeSymbolInternal diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb index c61089ae5b1dd..d8c88417719c5 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb @@ -4,6 +4,8 @@ Imports System.Collections.Immutable Imports System.Reflection +Imports System.Threading +Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Symbols @@ -147,6 +149,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Return m_SourceAssembly.AssemblyVersionPattern End Get End Property + + Protected Function GetOrSynthesizeNamespace(namespaceFullName As String) As NamespaceSymbol + Dim result = SourceModule.GlobalNamespace + + For Each partName In namespaceFullName.Split("."c) + Dim subnamespace = DirectCast(result.GetMembers(partName).FirstOrDefault(Function(m) m.Kind = SymbolKind.Namespace), NamespaceSymbol) + If subnamespace Is Nothing Then + subnamespace = New SynthesizedNamespaceSymbol(result, partName) + AddSynthesizedDefinition(result, subnamespace) + End If + + result = subnamespace + Next + + Return result + End Function End Class Friend NotInheritable Class PEAssemblyBuilder @@ -179,5 +197,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Return Nothing End Get End Property + + Public Overrides Function TryGetOrCreateSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal + Return Nothing + End Function + + Public Overrides Function GetOrCreateHotReloadExceptionConstructorDefinition() As IMethodSymbolInternal + ' Should only be called when compiling EnC delta + Throw ExceptionUtilities.Unreachable + End Function + + Public Overrides Function GetUsedSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal + Return Nothing + End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Emit/PENetModuleBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PENetModuleBuilder.vb index 737b993764bb9..aad6b5c1be55e 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PENetModuleBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PENetModuleBuilder.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable +Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Symbols @@ -44,6 +45,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Get End Property + Public Overrides Function TryGetOrCreateSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal + Return Nothing + End Function + + Public Overrides Function GetOrCreateHotReloadExceptionConstructorDefinition() As IMethodSymbolInternal + ' Should only be called when compiling EnC delta. EnC does not support emitting netmodules. + Throw ExceptionUtilities.Unreachable + End Function + + Public Overrides Function GetUsedSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal + Return Nothing + End Function + Public Overrides Function GetFiles(context As EmitContext) As IEnumerable(Of Cci.IFileReference) Return SpecializedCollections.EmptyEnumerable(Of Cci.IFileReference)() End Function diff --git a/src/Compilers/VisualBasic/Portable/Emit/SynthesizedNamespaceSymbol.vb b/src/Compilers/VisualBasic/Portable/Emit/SynthesizedNamespaceSymbol.vb new file mode 100644 index 0000000000000..83b6abd911994 --- /dev/null +++ b/src/Compilers/VisualBasic/Portable/Emit/SynthesizedNamespaceSymbol.vb @@ -0,0 +1,94 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Collections.Immutable +Imports Microsoft.CodeAnalysis.Emit +Imports Microsoft.CodeAnalysis.PooledObjects + +Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols + ''' + ''' Synthesized namespace that contains synthesized types or subnamespaces. + ''' All its members are stored in a table on . + ''' + Friend NotInheritable Class SynthesizedNamespaceSymbol + Inherits NamespaceSymbol + + Private ReadOnly _containingNamespace As NamespaceSymbol + + Public Overrides ReadOnly Property Name As String + + Sub New(containingNamespace As NamespaceSymbol, name As String) + _containingNamespace = containingNamespace + Me.Name = name + End Sub + + Public Overrides ReadOnly Property ContainingAssembly As AssemblySymbol + Get + Return _containingNamespace.ContainingAssembly + End Get + End Property + + Public Overrides ReadOnly Property ContainingSymbol As Symbol + Get + Return _containingNamespace + End Get + End Property + + Public Overrides ReadOnly Property Locations As ImmutableArray(Of Location) + Get + Return ImmutableArray(Of Location).Empty + End Get + End Property + + Public Overrides ReadOnly Property DeclaringSyntaxReferences As ImmutableArray(Of SyntaxReference) + Get + Return ImmutableArray(Of SyntaxReference).Empty + End Get + End Property + + Friend Overrides ReadOnly Property Extent As NamespaceExtent + Get + Return _containingNamespace.Extent + End Get + End Property + + Friend Overrides ReadOnly Property DeclaredAccessibilityOfMostAccessibleDescendantType As Accessibility + Get + Return Accessibility.Friend + End Get + End Property + + Friend Overrides ReadOnly Property TypesToCheckForExtensionMethods As ImmutableArray(Of NamedTypeSymbol) + Get + Return ImmutableArray(Of NamedTypeSymbol).Empty + End Get + End Property + + Friend Overrides Sub AppendProbableExtensionMethods(name As String, methods As ArrayBuilder(Of MethodSymbol)) + End Sub + + Friend Overrides Sub AddExtensionMethodLookupSymbolsInfo(nameSet As LookupSymbolsInfo, options As LookupOptions, originalBinder As Binder, appendThrough As NamespaceSymbol) + End Sub + + Public Overrides Function GetModuleMembers() As ImmutableArray(Of NamedTypeSymbol) + Return ImmutableArray(Of NamedTypeSymbol).Empty + End Function + + Public Overrides Function GetMembers() As ImmutableArray(Of Symbol) + Return ImmutableArray(Of Symbol).Empty + End Function + + Public Overrides Function GetMembers(name As String) As ImmutableArray(Of Symbol) + Return ImmutableArray(Of Symbol).Empty + End Function + + Public Overrides Function GetTypeMembers() As ImmutableArray(Of NamedTypeSymbol) + Return ImmutableArray(Of NamedTypeSymbol).Empty + End Function + + Public Overrides Function GetTypeMembers(name As String) As ImmutableArray(Of NamedTypeSymbol) + Return ImmutableArray(Of NamedTypeSymbol).Empty + End Function + End Class +End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb b/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb index 5c5ad85915fff..90324908c2390 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb @@ -1235,7 +1235,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERRID.ERR_PublicKeyFileFailure, ERRID.ERR_PublicKeyContainerFailure, ERRID.ERR_InvalidAssemblyCulture, - ERRID.ERR_EncUpdateFailedMissingAttribute, + ERRID.ERR_EncUpdateFailedMissingSymbol, ERRID.ERR_CantAwaitAsyncSub1, ERRID.ERR_ResumableLambdaInExpressionTree, ERRID.ERR_DllImportOnResumableMethod, @@ -1365,6 +1365,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERRID.ERR_NewConstraintCannotHaveRequiredMembers, ERRID.ERR_DoNotUseRequiredMember, ERRID.ERR_UnsupportedRefReturningCallInWithStatement, + ERRID.ERR_TypeReserved, ERRID.ERR_NextAvailable, ERRID.WRN_UseOfObsoleteSymbol2, ERRID.WRN_InvalidOverrideDueToTupleNames2, diff --git a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb index 149175d4e7713..337adb8b5246a 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb @@ -1611,7 +1611,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERR_PublicKeyContainerFailure = 36981 ERR_InvalidAssemblyCulture = 36982 - ERR_EncUpdateFailedMissingAttribute = 36983 + ERR_EncUpdateFailedMissingSymbol = 36983 ERR_CantAwaitAsyncSub1 = 37001 ERR_ResumableLambdaInExpressionTree = 37050 @@ -1780,8 +1780,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERR_LockTypeUnsupported = 37329 ERR_InvalidVersionFormatDeterministic = 37330 + ERR_TypeReserved = 37331 - ERR_NextAvailable = 37331 + ERR_NextAvailable = 37332 '// WARNINGS BEGIN HERE WRN_UseOfObsoleteSymbol2 = 40000 diff --git a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb index 74e2e9902beaa..c600c952fafeb 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb @@ -570,9 +570,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property - Public Overrides ReadOnly Property ERR_EncUpdateFailedMissingAttribute As Integer + Public Overrides ReadOnly Property ERR_EncUpdateFailedMissingSymbol As Integer Get - Return ERRID.ERR_EncUpdateFailedMissingAttribute + Return ERRID.ERR_EncUpdateFailedMissingSymbol End Get End Property diff --git a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb index 54eb8ed834cff..d36d0c84fe65c 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.CodeGen +Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -94,9 +95,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property - Protected Overrides ReadOnly Property EncMissingStateMessage As String + Protected Overrides ReadOnly Property EncMissingStateErrorCode As HotReloadExceptionCode Get - Return CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + Return HotReloadExceptionCode.CannotResumeSuspendedAsyncMethod End Get End Property diff --git a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb index 448fc24891d65..0c1489a25069c 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.CodeGen +Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -44,9 +45,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property - Protected Overrides ReadOnly Property EncMissingStateMessage As String + Protected Overrides ReadOnly Property EncMissingStateErrorCode As HotReloadExceptionCode Get - Return CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod + Return HotReloadExceptionCode.CannotResumeSuspendedIteratorMethod End Get End Property diff --git a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb index ac6abf1726dac..666c9889da573 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.CodeGen +Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -107,7 +108,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Sub Protected MustOverride ReadOnly Property FirstIncreasingResumableState As StateMachineState - Protected MustOverride ReadOnly Property EncMissingStateMessage As String + Protected MustOverride ReadOnly Property EncMissingStateErrorCode As HotReloadExceptionCode ''' ''' Implementation-specific name for labels to mark state machine resume points. @@ -222,7 +223,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Function Private Function GenerateMissingStateDispatch() As BoundStatement - Return _resumableStateAllocator.GenerateThrowMissingStateDispatch(F, F.Local(CachedState, isLValue:=False), EncMissingStateMessage) + Return _resumableStateAllocator.GenerateThrowMissingStateDispatch(F, F.Local(CachedState, isLValue:=False), EncMissingStateErrorCode) End Function #Region "Visitors" diff --git a/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb b/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb index 57598e4c1b7a6..7facf7ebbae31 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/SyntheticBoundNodeFactory.vb @@ -180,8 +180,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return boundNode End Function - Public Function Parameter(p As ParameterSymbol) As BoundParameter - Dim boundNode = New BoundParameter(_syntax, p, p.Type) + Public Function Parameter(p As ParameterSymbol, Optional isLValue As Boolean = True) As BoundParameter + Dim boundNode = New BoundParameter(_syntax, p, isLValue, p.Type) boundNode.SetWasCompilerGenerated() Return boundNode End Function diff --git a/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb index 08f8394987164..f210191c622de 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/AssemblySymbol.vb @@ -764,7 +764,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Private ReadOnly Property IAssemblySymbol_Modules As IEnumerable(Of IModuleSymbol) Implements IAssemblySymbol.Modules Get - Return Me.Modules + Return ImmutableArray(Of IModuleSymbol).CastUp(Me.Modules) End Get End Property diff --git a/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb index c3e8138ec3749..e88c3d0b985a6 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb @@ -2,12 +2,10 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Generic Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.PooledObjects -Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' @@ -15,7 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' Friend MustInherit Class PropertySymbol Inherits Symbol - Implements IPropertySymbol + Implements IPropertySymbol, IPropertySymbolInternal ' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ' Changes to the public interface of this class should remain synchronized with the C# version. @@ -642,6 +640,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Public ReadOnly Property IPropertySymbolInternal_PartialImplementationPart As IPropertySymbolInternal Implements IPropertySymbolInternal.PartialImplementationPart + Get + ' Feature not supported in VB + Return Nothing + End Get + End Property + + Public ReadOnly Property IPropertySymbolInternal_PartialDefinitionPart As IPropertySymbolInternal Implements IPropertySymbolInternal.PartialDefinitionPart + Get + ' Feature not supported in VB + Return Nothing + End Get + End Property + Public Overrides Sub Accept(visitor As SymbolVisitor) visitor.VisitProperty(Me) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedHotReloadExceptionConstructorSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedHotReloadExceptionConstructorSymbol.vb new file mode 100644 index 0000000000000..dd3c088a917fc --- /dev/null +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedHotReloadExceptionConstructorSymbol.vb @@ -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. + +Imports System.Collections.Immutable +Imports System.Runtime.InteropServices +Imports Microsoft.CodeAnalysis.Emit + +Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols + + Friend NotInheritable Class SynthesizedHotReloadExceptionConstructorSymbol + Inherits SynthesizedConstructorBase + + Private ReadOnly _parameters As ImmutableArray(Of ParameterSymbol) + + Public Sub New(container As NamedTypeSymbol, stringType As TypeSymbol, intType As TypeSymbol) + MyBase.New(VisualBasicSyntaxTree.DummyReference, container, isShared:=False, binder:=Nothing, diagnostics:=Nothing) + + _parameters = ImmutableArray.Create(Of ParameterSymbol)( + New SynthesizedParameterSymbol(Me, stringType, ordinal:=0, isByRef:=False), + New SynthesizedParameterSymbol(Me, intType, ordinal:=1, isByRef:=False)) + End Sub + + ''' + ''' Exception message. + ''' + Public ReadOnly Property MessageParameter As ParameterSymbol + Get + Return _parameters(0) + End Get + End Property + + ''' + ''' Integer value of . + ''' + Public ReadOnly Property CodeParameter As ParameterSymbol + Get + Return _parameters(1) + End Get + End Property + + Friend Overrides ReadOnly Property ParameterCount As Integer + Get + Return _parameters.Length + End Get + End Property + + Public Overrides ReadOnly Property Parameters As ImmutableArray(Of ParameterSymbol) + Get + Return _parameters + End Get + End Property + + Friend Overrides ReadOnly Property GenerateDebugInfoImpl As Boolean + Get + Return False + End Get + End Property + + Friend Overrides Function CalculateLocalSyntaxOffset(localPosition As Integer, localTree As SyntaxTree) As Integer + Throw ExceptionUtilities.Unreachable + End Function + + Friend Overrides Function GetBoundMethodBody(compilationState As TypeCompilationState, diagnostics As BindingDiagnosticBag, ByRef Optional methodBodyBinder As Binder = Nothing) As BoundBlock + Dim containingExceptionType = DirectCast(ContainingType, SynthesizedHotReloadExceptionSymbol) + + Dim factory = New SyntheticBoundNodeFactory(Me, Me, Syntax, compilationState, diagnostics) + + Dim exceptionConstructor = factory.WellKnownMember(Of MethodSymbol)(WellKnownMember.System_Exception__ctorString, isOptional:=True) + If exceptionConstructor Is Nothing Then + diagnostics.Add(ERRID.ERR_EncUpdateFailedMissingSymbol, + Location.None, + CodeAnalysisResources.Constructor, + "System.Exception..ctor(string)") + + Return factory.Block() + End If + + Dim block = factory.Block( + ImmutableArray.Create(Of BoundStatement)( + factory.ExpressionStatement(factory.Call( + factory.Me(), + exceptionConstructor, + factory.Parameter(MessageParameter, isLValue:=False))), + factory.Assignment(factory.Field(factory.Me(), containingExceptionType.CodeField, isLValue:=True), factory.Parameter(CodeParameter, isLValue:=False)), + factory.Return() + )) + + Return block + End Function + End Class +End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedHotReloadExceptionSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedHotReloadExceptionSymbol.vb new file mode 100644 index 0000000000000..faa75fb2e647e --- /dev/null +++ b/src/Compilers/VisualBasic/Portable/Symbols/SynthesizedSymbols/SynthesizedHotReloadExceptionSymbol.vb @@ -0,0 +1,317 @@ +' 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.Runtime.InteropServices +Imports System.Threading + +Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols + Friend NotInheritable Class SynthesizedHotReloadExceptionSymbol + Inherits InstanceTypeSymbol + + Public Const NamespaceName As String = "System.Runtime.CompilerServices" + Public Const TypeName As String = "HotReloadException" + Public Const CodeFieldName As String = "Code" + + Private ReadOnly _baseType As NamedTypeSymbol + Private ReadOnly _namespace As NamespaceSymbol + Private ReadOnly _members As ImmutableArray(Of Symbol) + + Friend Sub New( + containingNamespace As NamespaceSymbol, + baseType As NamedTypeSymbol, + stringType As TypeSymbol, + intType As TypeSymbol) + + _baseType = baseType + _namespace = containingNamespace + _members = ImmutableArray.Create(Of Symbol)( + New SynthesizedHotReloadExceptionConstructorSymbol(Me, stringType, intType), + New SynthesizedFieldSymbol(Me, implicitlyDefinedBy:=Me, intType, CodeFieldName, Accessibility.Public, isReadOnly:=True, isShared:=False)) + End Sub + + Public ReadOnly Property Constructor As MethodSymbol + Get + Return DirectCast(_members(0), MethodSymbol) + End Get + End Property + + Public ReadOnly Property CodeField As FieldSymbol + Get + Return DirectCast(_members(1), FieldSymbol) + End Get + End Property + + Public Overloads Overrides Function GetMembers() As ImmutableArray(Of Symbol) + Return _members + End Function + + Public Overloads Overrides Function GetMembers(name As String) As ImmutableArray(Of Symbol) + Return (From m In GetMembers() Where IdentifierComparison.Equals(m.Name, name)).AsImmutable + End Function + + Public Overloads Overrides Function GetTypeMembers() As ImmutableArray(Of NamedTypeSymbol) + Return ImmutableArray(Of NamedTypeSymbol).Empty + End Function + + Public Overloads Overrides Function GetTypeMembers(name As String) As ImmutableArray(Of NamedTypeSymbol) + Return ImmutableArray(Of NamedTypeSymbol).Empty + End Function + + Public Overloads Overrides Function GetTypeMembers(name As String, arity As Integer) As ImmutableArray(Of NamedTypeSymbol) + Return ImmutableArray(Of NamedTypeSymbol).Empty + End Function + + Public Overrides ReadOnly Property MemberNames As IEnumerable(Of String) + Get + Return New HashSet(Of String)(From member In GetMembers() Select member.Name) + End Get + End Property + + Friend Overrides Function GetFieldsToEmit() As IEnumerable(Of FieldSymbol) + Return SpecializedCollections.SingletonEnumerable(CodeField) + End Function + + Public Overrides ReadOnly Property AssociatedSymbol As Symbol + Get + Return Nothing + End Get + End Property + + Public Overrides ReadOnly Property Arity As Integer + Get + Return 0 + End Get + End Property + + Public Overrides ReadOnly Property ContainingSymbol As Symbol + Get + Return _namespace + End Get + End Property + + Public Overrides ReadOnly Property ContainingType As NamedTypeSymbol + Get + Return Nothing + End Get + End Property + + Public Overrides ReadOnly Property DeclaredAccessibility As Accessibility + Get + Return Accessibility.Friend + End Get + End Property + + Friend Overrides ReadOnly Property DefaultPropertyName As String + Get + Return Nothing + End Get + End Property + + Public Overrides ReadOnly Property IsMustInherit As Boolean + Get + Return False + End Get + End Property + + Public Overrides ReadOnly Property IsNotInheritable As Boolean + Get + Return True + End Get + End Property + + Friend Overrides ReadOnly Property ShadowsExplicitly As Boolean + Get + Return False + End Get + End Property + + Public Overrides ReadOnly Property Locations As ImmutableArray(Of Location) + Get + Return ImmutableArray(Of Location).Empty + End Get + End Property + + Public Overrides ReadOnly Property DeclaringSyntaxReferences As ImmutableArray(Of SyntaxReference) + Get + Return ImmutableArray(Of SyntaxReference).Empty + End Get + End Property + + Friend Overrides Function MakeAcyclicBaseType(diagnostics As BindingDiagnosticBag) As NamedTypeSymbol + Return MakeDeclaredBase(Nothing, diagnostics) + End Function + + Friend Overrides Function MakeAcyclicInterfaces(diagnostics As BindingDiagnosticBag) As ImmutableArray(Of NamedTypeSymbol) + Return ImmutableArray(Of NamedTypeSymbol).Empty + End Function + + Friend Overrides Function MakeDeclaredBase(basesBeingResolved As BasesBeingResolved, diagnostics As BindingDiagnosticBag) As NamedTypeSymbol + Return _baseType + End Function + + Friend Overrides Function MakeDeclaredInterfaces(basesBeingResolved As BasesBeingResolved, diagnostics As BindingDiagnosticBag) As ImmutableArray(Of NamedTypeSymbol) + Return ImmutableArray(Of NamedTypeSymbol).Empty + End Function + + Friend Overrides ReadOnly Property MangleName As Boolean + Get + Return False + End Get + End Property + + Public Overrides ReadOnly Property MightContainExtensionMethods As Boolean + Get + Return False + End Get + End Property + + Friend Overrides ReadOnly Property HasCodeAnalysisEmbeddedAttribute As Boolean + Get + Return False + End Get + End Property + + Friend Overrides ReadOnly Property HasVisualBasicEmbeddedAttribute As Boolean + Get + Return False + End Get + End Property + + Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean + Get + Return False + End Get + End Property + + Friend Overrides ReadOnly Property IsWindowsRuntimeImport As Boolean + Get + Return False + End Get + End Property + + Friend Overrides ReadOnly Property ShouldAddWinRTMembers As Boolean + Get + Return False + End Get + End Property + + Friend Overrides ReadOnly Property IsComImport As Boolean + Get + Return False + End Get + End Property + + Friend Overrides ReadOnly Property CoClassType As TypeSymbol + Get + Return Nothing + End Get + End Property + + Friend Overrides Function GetAppliedConditionalSymbols() As ImmutableArray(Of String) + Return ImmutableArray(Of String).Empty + End Function + + Friend Overrides Function GetAttributeUsageInfo() As AttributeUsageInfo + Throw ExceptionUtilities.Unreachable + End Function + + Friend Overrides ReadOnly Property HasDeclarativeSecurity As Boolean + Get + Return False + End Get + End Property + + Friend Overrides Function GetGuidString(ByRef guidString As String) As Boolean + guidString = Nothing + Return False + End Function + + Friend Overrides Function GetSecurityInformation() As IEnumerable(Of Microsoft.Cci.SecurityAttribute) + Throw ExceptionUtilities.Unreachable + End Function + + Public Overrides ReadOnly Property Name As String + Get + Return TypeName + End Get + End Property + + Friend Overrides ReadOnly Property HasSpecialName As Boolean + Get + Return False + End Get + End Property + + Public Overrides ReadOnly Property IsSerializable As Boolean + Get + Return False + End Get + End Property + + Friend Overrides ReadOnly Property Layout As TypeLayout + Get + Return Nothing + End Get + End Property + + Friend Overrides ReadOnly Property MarshallingCharSet As CharSet + Get + Return DefaultMarshallingCharSet + End Get + End Property + + Public Overrides ReadOnly Property TypeKind As TypeKind + Get + Return TypeKind.Class + End Get + End Property + + Friend Overrides ReadOnly Property IsInterface As Boolean + Get + Return False + End Get + End Property + + Public Overrides ReadOnly Property TypeParameters As ImmutableArray(Of TypeParameterSymbol) + Get + Return ImmutableArray(Of TypeParameterSymbol).Empty + End Get + End Property + + ''' + ''' Force all declaration errors to be generated. + ''' + Friend Overrides Sub GenerateDeclarationErrors(cancellationToken As CancellationToken) + End Sub + + Public Overrides ReadOnly Property IsImplicitlyDeclared As Boolean + Get + Return True + End Get + End Property + + Friend Overrides ReadOnly Property EmbeddedSymbolKind As EmbeddedSymbolKind + Get + Return EmbeddedSymbolKind.None + End Get + End Property + + Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData + Get + Return Nothing + End Get + End Property + + Friend Overrides Function GetSynthesizedWithEventsOverrides() As IEnumerable(Of PropertySymbol) + Return SpecializedCollections.EmptyEnumerable(Of PropertySymbol)() + End Function + + Friend Overrides ReadOnly Property HasAnyDeclaredRequiredMembers As Boolean + Get + Return False + End Get + End Property + End Class +End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxEquivalence.vb b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxEquivalence.vb index 9f55a27e336d8..dfb7c13a73052 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxEquivalence.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxEquivalence.vb @@ -52,7 +52,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax SyntaxKind.FloatingLiteralToken, SyntaxKind.IntegerLiteralToken, SyntaxKind.InterpolatedStringTextToken, - SyntaxKind.StringLiteralToken + SyntaxKind.StringLiteralToken, + SyntaxKind.XmlTextLiteralToken, + SyntaxKind.XmlNameToken Return String.Equals(DirectCast(before, Green.SyntaxToken).Text, DirectCast(after, Green.SyntaxToken).Text, StringComparison.Ordinal) diff --git a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFactory.vb b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFactory.vb index d2a50e41bf262..f96da951b8305 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFactory.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxFactory.vb @@ -508,7 +508,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return element.WithStartTag(element.StartTag.AddAttributes( XmlAttribute( - XmlName(Nothing, XmlTextLiteralToken(DocumentationCommentXmlNames.CrefAttributeName, DocumentationCommentXmlNames.CrefAttributeName)), + XmlName(Nothing, XmlNameToken(DocumentationCommentXmlNames.HrefAttributeName, SyntaxKind.XmlName)).WithLeadingTrivia(ElasticSpace), XmlString( Token(SyntaxKind.DoubleQuoteToken), SyntaxTokenList.Create( diff --git a/src/Compilers/VisualBasic/Portable/VBResources.resx b/src/Compilers/VisualBasic/Portable/VBResources.resx index 4dd5ec5747fa2..6e3a339790dbb 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.resx +++ b/src/Compilers/VisualBasic/Portable/VBResources.resx @@ -818,7 +818,7 @@ Failed to emit module '{0}': {1} - + Cannot update '{0}'; attribute '{1}' is missing. @@ -5541,7 +5541,7 @@ Type is for evaluation purposes only and is subject to change or removal in future updates. - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} {0} is not a valid Visual Basic conversion expression @@ -5707,4 +5707,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + + The type name '{0}' is reserved to be used by the compiler. + \ No newline at end of file diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf index cc4300138ba74..58a67c5e5dee6 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf @@ -42,6 +42,11 @@ Atribut System.Runtime.CompilerServices.RequiredMemberAttribute je vyhrazen pouze pro použití kompilátoru. + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier Argument diagnosticId atributu Experimental musí být platný identifikátor @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + Zadaný řetězec verze obsahuje zástupné znaky, které nejsou kompatibilní s determinismem. Odeberte zástupné znaky z řetězce verze nebo pro tuto kompilaci zakažte determinismus. @@ -112,6 +117,11 @@ {0} je definováno v sestavení {1}. + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} {1} nemůže implementovat rozhraní {3}, protože obsahuje sdílené abstraktní nebo virtuální {2}. @@ -1762,11 +1772,6 @@ Nepovedlo se vygenerovat modul {0}: {1} - - Cannot update '{0}'; attribute '{1}' is missing. - Nelze aktualizovat {0}; chybí atribut {1}. - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. Pro {0} – {1} nejde použít deklaraci Overrides, protože nepřepisuje typ {0} v základní třídě. @@ -7698,7 +7703,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - Zadaný řetězec verze není v souladu s doporučeným formátem – hlavní_verze.dílčí_verze.build.revize. + Zadaný řetězec verze neodpovídá doporučenému formátu – major.minor.build.revision (bez zástupných znaků). @@ -9317,8 +9322,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - Informace o ladění metody {0} (token 0x{1}) ze sestavení {2} nelze přečíst. + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf index 65d45f00829f6..9e9ed4cc30aa5 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf @@ -42,6 +42,11 @@ "System.Runtime.CompilerServices.RequiredMemberAttribute" ist nur für die Compilerverwendung reserviert. + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier Das diagnosticId-Argument für das Experimental-Attribut muss ein gültiger Bezeichner sein. @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + Die angegebene Versionszeichenfolge enthält Platzhalter, die mit Determinismus nicht kompatibel sind. Entfernen Sie die Platzhalter aus der Versionszeichenfolge, oder deaktivieren Sie Determinismus für diese Kompilierung. @@ -112,6 +117,11 @@ "{0}" ist in Assembly "{1}" definiert. + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} "{1}" kann die Schnittstelle "{3}" nicht implementieren, da sie freigegebene abstrakte oder virtuelle "{2}" enthält. @@ -1762,11 +1772,6 @@ Fehler beim Ausgeben von Modul "{0}": {1} - - Cannot update '{0}'; attribute '{1}' is missing. - "{0}" kann nicht aktualisiert werden. Das Attribut "{1}" fehlt. - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. {0} "{1}" kann nicht als "Overrides" deklariert werden, da es kein {0} in einer Basisklasse überschreibt. @@ -7698,7 +7703,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - Die angegebene Versionszeichenfolge entspricht nicht dem empfohlenen Format: Hauptversion.Nebenversion.Build.Revision + Die angegebene Versionszeichenfolge entspricht nicht dem empfohlenen Format: Hauptversion.Nebenversion.Build.Revision (ohne Platzhalter). @@ -9317,8 +9322,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - Die Debuginformationen der Methode "{0}" (Token 0x{1}) können nicht aus der Assembly "{2}" gelesen werden. + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf index 8e8b75a247b70..edd7d212905a9 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf @@ -42,6 +42,11 @@ 'System.Runtime.CompilerServices.RequiredMemberAttribute' está reservado solo para uso del compilador. + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier El argumento diagnosticId del atributo "Experimental" debe ser un identificador válido. @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + La versión especificada contiene comodines, que no son compatibles con la determinación. Quite los comodines de la cadena de versión o deshabilite la determinación para esta compilación. @@ -112,6 +117,11 @@ '{0}' se define en el ensamblado '{1}'. + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} '{1}' no puede implementar la interfaz '{3}' porque contiene abstracto compartido o '{2}' virtual. @@ -1762,11 +1772,6 @@ No se pudo emitir el módulo "{0}": {1} - - Cannot update '{0}'; attribute '{1}' is missing. - No se puede actualizar '{0}'; falta el atributo '{1}'. - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. {0} '{1}' no se puede declarar 'Overrides' porque no invalida {0} en una clase base. @@ -7698,7 +7703,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - La cadena de versión especificada no se ajusta al formato recomendado: principal,secundaria,compilación,revisión + La cadena de versión especificada no es compatible con el formato recomendado - major.minor.build.revision (sin caracteres comodín) @@ -9317,8 +9322,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - No se puede leer la información de depuración del método "{0}" (token 0x{1}) desde el ensamblado "{2}" + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf index a47c640155e10..e9940a1be752b 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf @@ -42,6 +42,11 @@ 'System.Runtime.CompilerServices.RequiredMemberAttribute' est réservé à l'usage du compilateur uniquement. + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier L’argument diagnosticId de l’attribut « Experimental » doit être un identificateur valide @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + La chaîne de version spécifiée contient des caractères génériques qui ne sont pas compatibles avec le déterminisme. Supprimez les caractères génériques de la chaîne de version ou désactivez le déterminisme pour cette compilation @@ -112,6 +117,11 @@ '{0}' est défini dans l'assemblage '{1}'. + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} '{1}' ne peut pas mettre en œuvre l'interface '{3}' car elle contient des données abstraites ou virtuelles partagées '{2}'. @@ -1762,11 +1772,6 @@ Échec de l'émission du module '{0}' : {1} - - Cannot update '{0}'; attribute '{1}' is missing. - Impossible de mettre à jour '{0}' ; l'attribut '{1}' est manquant. - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. {0} '{1}' ne peut pas être déclaré 'Overrides', car il ne se substitue pas à un {0} dans une classe de base. @@ -7698,7 +7703,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - Le format de la chaîne de version spécifiée n'est pas conforme au format requis - major.minor.build.revision + La chaîne de version spécifiée n'est pas conforme au format recommandé - major.minor.build.revision (sans caractères génériques) @@ -9317,8 +9322,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - Impossible de lire les informations de débogage de la méthode '{0}' (jeton 0x{1}) dans l'assembly '{2}' + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf index 2ff6029bf7de6..1115589772d4f 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf @@ -42,6 +42,11 @@ 'System.Runtime.CompilerServices.RequiredMemberAttribute' è riservato solo all’uso del compilatore. + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier L'argomento diagnosticId dell'attributo 'Experimental' deve essere un identificatore valido @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + La stringa di versione specificata contiene caratteri jolly e questo non è compatibile con il determinismo. Rimuovere i caratteri jolly dalla stringa di versione o disabilitare il determinismo per questa compilazione @@ -112,6 +117,11 @@ '{0}' è definito nell'assembly '{1}'. + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} '{1}' non può implementare l'interfaccia '{3}' perché contiene '{2}' condiviso astratto o virtuale. @@ -1763,11 +1773,6 @@ Non è stato possibile creare il modulo '{0}': {1} - - Cannot update '{0}'; attribute '{1}' is missing. - Non è possibile aggiornare '{0}'. Manca l'attributo '{1}'. - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. {0} '{1}' non può essere dichiarato come 'Overrides' perché non esegue l'override di un elemento {0} in una classe di base. @@ -7699,7 +7704,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - La stringa di versione specificata non è conforme al formato consigliato: principale.secondaria.build.revisione + La stringa di versione specificata non è conforme al formato consigliato: principale.secondaria.build.revisione (senza caratteri jolly) @@ -9318,8 +9323,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - Non è possibile leggere le informazione di debug del metodo '{0}' (token 0x{1}) dall'assembly '{2}' + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf index 1b8c6cfef3458..dd1aeb31ff170 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf @@ -42,6 +42,11 @@ 'System.Runtime.CompilerServices.RequiredMemberAttribute' は、コンパイラでのみ使用するために予約されています。 + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier 'Experimental' 属性への diagnosticId 引数は有効な識別子である必要があります @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + 指定されたバージョン文字列には、決定性と互換性のないワイルドカードが含まれています。バージョン文字列からワイルドカードを削除するか、このコンパイルの決定性を無効にしてください。 @@ -112,6 +117,11 @@ '{0}' はアセンブリ '{1}' で定義されています。 + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} '{1}' には、共有された抽象または仮想 '{2}' が含まれているため、インターフェイス '{3}' を実装できません。 @@ -1764,11 +1774,6 @@ モジュール '{0}' の生成に失敗しました: {1} - - Cannot update '{0}'; attribute '{1}' is missing. - '{0}' を更新できません。属性 '{1}' がありません。 - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. 基底クラスで {0} をオーバーライドしないため、{0} '{1}' を 'Overrides' として宣言することはできません。 @@ -7700,7 +7705,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - 指定したバージョン文字列は、推奨される形式 (major.minor.build.revision) に従っていません + 指定したバージョン文字列は、推奨される形式 (major.minor.build.revision、ワイルドカードなし) に従っていません。 @@ -9319,8 +9324,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - メソッド '{0}' (トークン 0x{1}) のデバッグ情報をアセンブリ '{2}' から読み取ることができません + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf index 11d6152dab173..7810d8be04987 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf @@ -42,6 +42,11 @@ 'System.Runtime.CompilerServices.RequiredMemberAttribute'는 컴파일러 용도로만 예약되어 있습니다. + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier 'Experimental' 특성에 대한 diagnosticId 인수는 유효한 식별자여야 합니다. @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + 지정한 버전 문자열에는 결정성과 호환되지 않는 와일드카드가 포함되어 있습니다. 버전 문자열에서 와일드카드를 제거하거나 이 컴파일에 대해 결정성을 사용하지 않도록 설정하세요. @@ -112,6 +117,11 @@ '{0}'은(는) '{1}' 어셈블리에 정의되어 있습니다. + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} '{1}'은(는) 공유 추상 또는 가상 '{2}'이(가) 포함되어 있으므로 '{3}' 인터페이스를 구현할 수 없습니다. @@ -1762,11 +1772,6 @@ 모듈 '{0}'을(를) 내보내지 못했습니다. {1} - - Cannot update '{0}'; attribute '{1}' is missing. - '{0}'을(를) 업데이트할 수 없습니다. 특성 '{1}'이(가) 없습니다. - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. {0} '{1}'은(는) 기본 클래스의 {0}을(를) 재정의하지 않으므로 'Overrides'로 선언할 수 없습니다. @@ -7698,7 +7703,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - 지정한 버전 문자열이 권장 형식 major.minor.build.revision을 따르지 않습니다. + 지정된 버전 문자열이 권장 형식인 major.minor.build.revision(와일드카드 없음)을 따르지 않습니다. @@ -9317,8 +9322,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - '{2}' 어셈블리에서 '{0}' 메서드(토큰 0x{1})의 디버그 정보를 읽을 수 없습니다. + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf index f92306e04a691..07f875f3c3812 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf @@ -42,6 +42,11 @@ Element „System.Runtime.CompilerServices.RequiredMemberAttribute” jest zarezerwowany tylko do użycia przez kompilator. + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier Argument diagnosticId atrybutu „Experimental” musi być prawidłowym identyfikatorem @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + Określony ciąg wersji zawiera znaki wieloznaczne, które nie są zgodne z determinizmem. Usuń znaki wieloznaczne z ciągu wersji lub wyłącz determinizm dla tej kompilacji @@ -112,6 +117,11 @@ „{0}” jest zdefiniowany w zestawie „{1}”. + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0}„{1}” nie może zaimplementować interfejsu „{3}”, ponieważ zawiera udostępnioną abstrakcyjną lub wirtualną „{2}”. @@ -1762,11 +1772,6 @@ Wyemitowanie modułu „{0}” nie powiodło się: {1} - - Cannot update '{0}'; attribute '{1}' is missing. - Nie można zaktualizować elementu „{0}”. Brak atrybutu „{1}”. - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. Nie można zadeklarować elementu {0} „{1}” jako „Overrides”, ponieważ nie przesłania on elementu {0} w klasie bazowej. @@ -7698,7 +7703,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - Określony ciąg wersji nie jest zgodny z zalecanym formatem — wersja_główna.wersja_pomocnicza.kompilacja.poprawka + Określony ciąg wersji nie jest zgodny z zalecanym formatem — major.minor.build.revision (bez symboli wieloznacznych) @@ -9317,8 +9322,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - Nie można odczytać informacji debugowania metody „{0}” (token 0x{1}) z zestawu „{2}” + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf index 4fd7cb780476a..80f5bd687e3e0 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf @@ -42,6 +42,11 @@ 'System.Runtime.CompilerServices.RequiredMemberAttribute' está reservado somente para uso do compilador. + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier O argumento diagnosticId para o atributo 'Experimental' deve ser um identificador válido @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + A cadeia de caracteres da versão especificada contém curingas, que não são compatíveis com o determinismo. Remova os curingas da cadeia de caracteres da versão ou desabilite o determinismo da compilação @@ -112,6 +117,11 @@ '{0}' é definido no assembly '{1}'. + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} '{1}' não é possível implementar a interface '{3}' porque ela contém um abstrato compartilhado ou virtual '{2}'. @@ -1762,11 +1772,6 @@ Falha ao emitir o módulo '{0}': {1} - - Cannot update '{0}'; attribute '{1}' is missing. - Não é possível atualizar '{0}'; o atributo '{1}' está ausente. - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. {0} "{1}" não pode ser declarado como "Overrides" porque não substitui um {0} em uma classe base. @@ -7698,7 +7703,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - A cadeia de caracteres de versão especificada não está de acordo com o formato recomendado - major.minor.build.revision + A cadeia de versão especificada não está em conformidade com o formato recomendado - major.minor.build.revision (sem caracteres curinga) @@ -9317,8 +9322,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - Não é possível ler as informações de depuração do método '{0}' (token 0x{1}) do assembly '{2}' + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf index f42d3d642e59a..09bf20a178096 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf @@ -42,6 +42,11 @@ "System.Runtime.CompilerServices.RequiredMemberAttribute" зарезервирован только для использования компилятором. + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier Аргумент diagnosticId атрибута "Experimental" должен быть допустимым идентификатором @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + Указанная строка версии содержит подстановочные знаки, которые несовместимы с детерминизмом. Удалите подстановочные знаки из строки версии или отключите детерминизм для этой компиляции @@ -112,6 +117,11 @@ '{0}' определен в сборке '{1}'. + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} "{1}" не может реализовать интерфейс "{3}", поскольку он содержит общий абстрактный или виртуальный элемент "{2}". @@ -1762,11 +1772,6 @@ optionstrict[+|-] Принудительное применени Не удалось выдать модуль "{0}": {1} - - Cannot update '{0}'; attribute '{1}' is missing. - Невозможно обновить "{0}"; нет атрибута "{1}". - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. {0} "{1}" не может быть объявлен как "Overrides", так как он не переопределяет {0} в базовом классе. @@ -7698,7 +7703,7 @@ optionstrict[+|-] Принудительное применени The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - Указанная строка версии не соответствует рекомендованному формату — основной номер.дополнительный номер.сборка.редакция + Указанная строка версии не соответствует рекомендуемому формату: основной номер.дополнительный номер.сборка.редакция (без подстановочных знаков) @@ -9317,8 +9322,8 @@ optionstrict[+|-] Принудительное применени - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - Не удается считать сведения об отладке метода "{0}" (маркер 0x{1}) из сборки "{2}". + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf index badc24e04fecb..68462011b0d12 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf @@ -42,6 +42,11 @@ 'System.Runtime.CompilerServices.RequiredMemberAttribute' yalnızca derleyici kullanımı için ayrılmıştır. + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier 'Experimental' özniteliğinin diagnosticId bağımsız değişkeni geçerli bir tanımlayıcı olmalıdır @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + Belirtilen sürüm dizesi gerekircilikle uyumlu olmayan joker karakterler içeriyor. Joker karakterleri sürüm dizesinden kaldırın veya bu derleme için gerekirciliği devre dışı bırakın @@ -112,6 +117,11 @@ '{0}', '{1}' derlemesinde tanımlı. + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} '{1}', paylaşılan soyut veya sanal '{2}' içerdiğinden '{3}' arabirimini uygulayamıyor. @@ -1763,11 +1773,6 @@ '{0}' modülü gösterilemedi: {1} - - Cannot update '{0}'; attribute '{1}' is missing. - '{0}' güncelleştirilemiyor; '{1}' özniteliği eksik. - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. {0} '{1}', bir temel sınıfta {0} öğesini geçersiz kılmadığından, 'Overrides' olarak bildirilemez. @@ -7699,7 +7704,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - Belirtilen sürüm dizesi önerilen biçime uymuyor - major.minor.build.revision + Belirtilen sürüm dizesi önerilen biçime uymuyor - major.minor.build.revision (joker karakterler olmadan) @@ -9318,8 +9323,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - '{2}' bütünleştirilmiş kodundan '{0}' (simge 0 x{1}) metodunun hata ayıklama bilgileri okunamıyor + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf index 152ab5f8d9354..76bc9c7093c0c 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf @@ -42,6 +42,11 @@ "System.Runtime.CompilerServices.RequiredMemberAttribute" 仅供编译器使用。 + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier “Experimental” 属性的 diagnosticId 参数必须是有效的标识符 @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + 指定的版本字符串包含通配符,这与确定性不兼容。请删除版本字符串中的通配符,或禁用此编译的确定性。 @@ -112,6 +117,11 @@ “{0}”在程序集“{1}”中定义。 + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} '{1}'无法实现接口 '{3}' ,因为它包含共享抽象或虚拟'{2}'。 @@ -1762,11 +1772,6 @@ 未能发出模块“{0}”: {1} - - Cannot update '{0}'; attribute '{1}' is missing. - 无法更新“{0}”;特性“{1}”缺失。 - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. {0}“{1}”不能声明为“Overrides”,因为它不重写基类中的 {0}。 @@ -7698,7 +7703,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - 指定版本字符串不符合建议格式 - major.minor.build.revision + 指定的版本字符串不符合建议的格式 - major.minor.build.revision (不带通配符) @@ -9317,8 +9322,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - 无法从程序集“{2}”读取方法“{0}”(令牌 0x{1})的调试信息 + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf index f7e46e4e6e90d..de5cea83ecad1 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf @@ -42,6 +42,11 @@ 'System.Runtime.CompilerServices.RequiredMemberAttribute' 僅保留給編譯器使用。 + + Cannot update '{0}'; attribute '{1}' is missing. + Cannot update '{0}'; attribute '{1}' is missing. + + The diagnosticId argument to the 'Experimental' attribute must be a valid identifier 'Experimental' 屬性的 diagnosticId 引數必須是有效的識別碼 @@ -49,7 +54,7 @@ The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation - The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation + 指定的版本字串包含萬用字元,但這與確定性不相容。請移除版本字串中的萬用字元,或停用此編譯的確定性。 @@ -112,6 +117,11 @@ '{0}' 於組件 '{1}' 中定義。 + + The type name '{0}' is reserved to be used by the compiler. + The type name '{0}' is reserved to be used by the compiler. + + {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. {0} '{1}' 無法實作介面 '{3}' 因為其包含共用摘要或虛擬效果 '{2}'。 @@ -1763,11 +1773,6 @@ 無法發出模組 '{0}': {1} - - Cannot update '{0}'; attribute '{1}' is missing. - 無法更新 '{0}'; 缺少屬性 '{1}'。 - - {0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class. {0} '{1}' 不可宣告為 'Overrides',因為其在基底類別中不會覆寫 {0}。 @@ -7699,7 +7704,7 @@ The specified version string does not conform to the recommended format - major.minor.build.revision (without wildcards) - 指定的版本字串不符合建議的格式 - major.minor.build.revision + 指定的版本字串不符合建議的格式: major.minor.build.revision (不含萬用字元) @@ -9318,8 +9323,8 @@ - Unable to read debug information of method '{0}' (token 0x{1}) from assembly '{2}' - 無法從組件 '{2}' 讀取方法 '{0}' 的偵錯資訊 (權杖 0x{1}) + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} + Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}': {3} diff --git a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb index 6a03a96a948a7..11eebfbc837bd 100644 --- a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb +++ b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb @@ -29,6 +29,7 @@ Imports Roslyn.Test.Utilities.SharedResourceHelpers Imports Roslyn.Test.Utilities.TestGenerators Imports Roslyn.Utilities Imports TestResources.Analyzers +Imports Basic.Reference.Assemblies Imports Xunit Namespace Microsoft.CodeAnalysis.VisualBasic.CommandLine.UnitTests @@ -4937,7 +4938,7 @@ End Class Public Sub BinaryFile() - Dim binaryPath = Temp.CreateFile().WriteAllBytes(TestMetadata.ResourcesNet451.mscorlib).Path + Dim binaryPath = Temp.CreateFile().WriteAllBytes(Net461.Resources.mscorlib).Path Dim outWriter As New StringWriter() Dim exitCode As Integer = New MockVisualBasicCompiler(Nothing, _baseDirectory, {"/nologo", "/preferreduilang:en", binaryPath}).Run(outWriter, Nothing) Assert.Equal(1, exitCode) @@ -10657,6 +10658,33 @@ End Class") Assert.Equal(absPath, parsedArgs.GeneratedFilesOutputDirectory) End Sub + + Public Sub Compiler_DoesNot_RunHostOutputs() + Dim dir = Temp.CreateDirectory() + Dim src = dir.CreateFile("temp.vb").WriteAllText(" +Class C +End Class") + Dim hostOutputRan As Boolean = False + Dim sourceOutputRan As Boolean = False + Dim generator = New PipelineCallbackGenerator(Sub(ctx) +#Disable Warning RSEXPERIMENTAL004 + ctx.RegisterHostOutput(ctx.CompilationProvider, Sub(hostCtx, value) + hostOutputRan = True + hostCtx.AddOutput("output", "value") + End Sub) +#Enable Warning RSEXPERIMENTAL004 + ctx.RegisterSourceOutput(ctx.CompilationProvider, Sub(spc, po) + sourceOutputRan = True + spc.AddSource("output.vb", "'value") + End Sub) + End Sub) + VerifyOutput(dir, src, includeCurrentAssemblyAsAnalyzerReference:=False, generators:={generator.AsSourceGenerator()}) + Assert.[False](hostOutputRan) + Assert.[True](sourceOutputRan) + CleanupAllGeneratedFiles(src.Path) + Directory.Delete(dir.Path, True) + End Sub + Public Sub ExperimentalWithWhitespaceDiagnosticID_WarnForInvalidDiagID() Dim dir = Temp.CreateDirectory() diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb index 1dbe752231e70..e1ad88031f7e5 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AssemblyAttributes.vb @@ -792,11 +792,11 @@ end class Assert.Equal(AssemblyHashAlgorithm.Sha1, assembly.HashAlgorithm) Dim file1 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(1)) - Assert.Equal(New Byte() {&H6C, &H9C, &H3E, &HDA, &H60, &HF, &H81, &H93, &H4A, &HC1, &HD, &H41, &HB3, &HE9, &HB2, &HB7, &H2D, &HEE, &H59, &HA8}, + AssertEx.Equal(New Byte() {&H6C, &H9C, &H3E, &HDA, &H60, &HF, &H81, &H93, &H4A, &HC1, &HD, &H41, &HB3, &HE9, &HB2, &HB7, &H2D, &HEE, &H59, &HA8}, reader.GetBlobBytes(file1.HashValue)) Dim file2 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(2)) - Assert.Equal(New Byte() {&H7F, &H28, &HEA, &HD1, &HF4, &HA1, &H7C, &HB8, &HC, &H14, &HC0, &H2E, &H8C, &HFF, &H10, &HEC, &HB3, &HC2, &HA5, &H1D}, + AssertEx.Equal(New Byte() {&H7F, &H28, &HEA, &HD1, &HF4, &HA1, &H7C, &HB8, &HC, &H14, &HC0, &H2E, &H8C, &HFF, &H10, &HEC, &HB3, &HC2, &HA5, &H1D}, reader.GetBlobBytes(file2.HashValue)) Assert.Null(peAssembly.ManifestModule.FindTargetAttributes(peAssembly.Handle, AttributeDescription.AssemblyAlgorithmIdAttribute)) @@ -823,11 +823,11 @@ end class Assert.Equal(AssemblyHashAlgorithm.None, assembly.HashAlgorithm) Dim file1 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(1)) - Assert.Equal(New Byte() {&H6C, &H9C, &H3E, &HDA, &H60, &HF, &H81, &H93, &H4A, &HC1, &HD, &H41, &HB3, &HE9, &HB2, &HB7, &H2D, &HEE, &H59, &HA8}, + AssertEx.Equal(New Byte() {&H6C, &H9C, &H3E, &HDA, &H60, &HF, &H81, &H93, &H4A, &HC1, &HD, &H41, &HB3, &HE9, &HB2, &HB7, &H2D, &HEE, &H59, &HA8}, reader.GetBlobBytes(file1.HashValue)) Dim file2 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(2)) - Assert.Equal(New Byte() {&H7F, &H28, &HEA, &HD1, &HF4, &HA1, &H7C, &HB8, &HC, &H14, &HC0, &H2E, &H8C, &HFF, &H10, &HEC, &HB3, &HC2, &HA5, &H1D}, + AssertEx.Equal(New Byte() {&H7F, &H28, &HEA, &HD1, &HF4, &HA1, &H7C, &HB8, &HC, &H14, &HC0, &H2E, &H8C, &HFF, &H10, &HEC, &HB3, &HC2, &HA5, &H1D}, reader.GetBlobBytes(file2.HashValue)) Assert.Null(peAssembly.ManifestModule.FindTargetAttributes(peAssembly.Handle, AttributeDescription.AssemblyAlgorithmIdAttribute)) @@ -854,11 +854,11 @@ end class Assert.Equal(AssemblyHashAlgorithm.MD5, assembly.HashAlgorithm) Dim file1 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(1)) - Assert.Equal(New Byte() {&H24, &H22, &H3, &HC3, &H94, &HD5, &HC2, &HD9, &H99, &HB3, &H6D, &H59, &HB2, &HCA, &H23, &HBC}, + AssertEx.Equal(New Byte() {&H24, &H22, &H3, &HC3, &H94, &HD5, &HC2, &HD9, &H99, &HB3, &H6D, &H59, &HB2, &HCA, &H23, &HBC}, reader.GetBlobBytes(file1.HashValue)) Dim file2 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(2)) - Assert.Equal(New Byte() {&H8D, &HFE, &HBF, &H49, &H8D, &H62, &H2A, &H88, &H89, &HD1, &HE, &H0, &H9E, &H29, &H72, &HF1}, + AssertEx.Equal(New Byte() {&H8D, &HFE, &HBF, &H49, &H8D, &H62, &H2A, &H88, &H89, &HD1, &HE, &H0, &H9E, &H29, &H72, &HF1}, reader.GetBlobBytes(file2.HashValue)) Assert.Null(peAssembly.ManifestModule.FindTargetAttributes(peAssembly.Handle, AttributeDescription.AssemblyAlgorithmIdAttribute)) @@ -885,11 +885,11 @@ end class Assert.Equal(AssemblyHashAlgorithm.Sha1, assembly.HashAlgorithm) Dim file1 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(1)) - Assert.Equal(New Byte() {&H6C, &H9C, &H3E, &HDA, &H60, &HF, &H81, &H93, &H4A, &HC1, &HD, &H41, &HB3, &HE9, &HB2, &HB7, &H2D, &HEE, &H59, &HA8}, + AssertEx.Equal(New Byte() {&H6C, &H9C, &H3E, &HDA, &H60, &HF, &H81, &H93, &H4A, &HC1, &HD, &H41, &HB3, &HE9, &HB2, &HB7, &H2D, &HEE, &H59, &HA8}, reader.GetBlobBytes(file1.HashValue)) Dim file2 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(2)) - Assert.Equal(New Byte() {&H7F, &H28, &HEA, &HD1, &HF4, &HA1, &H7C, &HB8, &HC, &H14, &HC0, &H2E, &H8C, &HFF, &H10, &HEC, &HB3, &HC2, &HA5, &H1D}, + AssertEx.Equal(New Byte() {&H7F, &H28, &HEA, &HD1, &HF4, &HA1, &H7C, &HB8, &HC, &H14, &HC0, &H2E, &H8C, &HFF, &H10, &HEC, &HB3, &HC2, &HA5, &H1D}, reader.GetBlobBytes(file2.HashValue)) Assert.Null(peAssembly.ManifestModule.FindTargetAttributes(peAssembly.Handle, AttributeDescription.AssemblyAlgorithmIdAttribute)) @@ -915,11 +915,11 @@ end class Assert.Equal(System.Configuration.Assemblies.AssemblyHashAlgorithm.SHA256, CType(assembly.HashAlgorithm, System.Configuration.Assemblies.AssemblyHashAlgorithm)) Dim file1 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(1)) - Assert.Equal(New Byte() {&HA2, &H32, &H3F, &HD, &HF4, &HB8, &HED, &H5A, &H1B, &H7B, &HBE, &H14, &H4F, &HEC, &HBF, &H88, &H23, &H61, &HEB, &H40, &HF7, &HF9, &H46, &HEF, &H68, &H3B, &H70, &H29, &HCF, &H12, &H5, &H35}, + AssertEx.Equal(New Byte() {&HA2, &H32, &H3F, &HD, &HF4, &HB8, &HED, &H5A, &H1B, &H7B, &HBE, &H14, &H4F, &HEC, &HBF, &H88, &H23, &H61, &HEB, &H40, &HF7, &HF9, &H46, &HEF, &H68, &H3B, &H70, &H29, &HCF, &H12, &H5, &H35}, reader.GetBlobBytes(file1.HashValue)) Dim file2 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(2)) - Assert.Equal(New Byte() {&HCC, &HAE, &HA0, &HB4, &H9E, &HAE, &H28, &HE0, &HA3, &H46, &HE9, &HCF, &HF3, &HEF, &HEA, &HF7, + AssertEx.Equal(New Byte() {&HCC, &HAE, &HA0, &HB4, &H9E, &HAE, &H28, &HE0, &HA3, &H46, &HE9, &HCF, &HF3, &HEF, &HEA, &HF7, &H1D, &HDE, &H62, &H8F, &HD6, &HF4, &H87, &H76, &H1A, &HC3, &H6F, &HAD, &H10, &H1C, &H10, &HAC}, reader.GetBlobBytes(file2.HashValue)) @@ -946,13 +946,13 @@ end class Assert.Equal(System.Configuration.Assemblies.AssemblyHashAlgorithm.SHA384, CType(assembly.HashAlgorithm, System.Configuration.Assemblies.AssemblyHashAlgorithm)) Dim file1 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(1)) - Assert.Equal(New Byte() {&HB6, &H35, &H9B, &HBE, &H82, &H89, &HFF, &H1, &H22, &H8B, &H56, &H5E, &H9B, &H15, &H5D, &H10, + AssertEx.Equal(New Byte() {&HB6, &H35, &H9B, &HBE, &H82, &H89, &HFF, &H1, &H22, &H8B, &H56, &H5E, &H9B, &H15, &H5D, &H10, &H68, &H83, &HF7, &H75, &H4E, &HA6, &H30, &HF7, &H8D, &H39, &H9A, &HB7, &HE8, &HB6, &H47, &H1F, &HF6, &HFD, &H1E, &H64, &H63, &H6B, &HE7, &HF4, &HBE, &HA7, &H21, &HED, &HFC, &H82, &H38, &H95}, reader.GetBlobBytes(file1.HashValue)) Dim file2 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(2)) - Assert.Equal(New Byte() {&H45, &H5, &H2E, &H90, &H9B, &H61, &HA3, &HF8, &H60, &HD2, &H86, &HCB, &H10, &H33, &HC9, &H86, + AssertEx.Equal(New Byte() {&H45, &H5, &H2E, &H90, &H9B, &H61, &HA3, &HF8, &H60, &HD2, &H86, &HCB, &H10, &H33, &HC9, &H86, &H68, &HA5, &HEE, &H4A, &HCF, &H21, &H10, &HA9, &H8F, &H14, &H62, &H8D, &H3E, &H7D, &HFD, &H7E, &HE6, &H23, &H6F, &H2D, &HBA, &H4, &HE7, &H13, &HE4, &H5E, &H8C, &HEB, &H80, &H68, &HA3, &H17}, reader.GetBlobBytes(file2.HashValue)) @@ -980,14 +980,14 @@ end class Assert.Equal(System.Configuration.Assemblies.AssemblyHashAlgorithm.SHA512, CType(assembly.HashAlgorithm, System.Configuration.Assemblies.AssemblyHashAlgorithm)) Dim file1 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(1)) - Assert.Equal(New Byte() {&H5F, &H4D, &H7E, &H63, &HC9, &H87, &HD9, &HEB, &H4F, &H5C, &HFD, &H96, &H3F, &H25, &H58, &H74, + AssertEx.Equal(New Byte() {&H5F, &H4D, &H7E, &H63, &HC9, &H87, &HD9, &HEB, &H4F, &H5C, &HFD, &H96, &H3F, &H25, &H58, &H74, &H86, &HDF, &H97, &H75, &H93, &HEE, &HC2, &H5F, &HFD, &H8A, &H40, &H5C, &H92, &H5E, &HB5, &H7, &HD6, &H12, &HE9, &H21, &H55, &HCE, &HD7, &HE5, &H15, &HF5, &HBA, &HBC, &H1B, &H31, &HAD, &H3C, &H5E, &HE0, &H91, &H98, &HC2, &HE0, &H96, &HBB, &HAD, &HD, &H4E, &HF4, &H91, &H53, &H3D, &H84}, reader.GetBlobBytes(file1.HashValue)) Dim file2 = reader.GetAssemblyFile(MetadataTokens.AssemblyFileHandle(2)) - Assert.Equal(New Byte() {&H79, &HFE, &H97, &HAB, &H8, &H8E, &HDF, &H74, &HC2, &HEF, &H84, &HBB, &HFC, &H74, &HAC, &H60, + AssertEx.Equal(New Byte() {&H79, &HFE, &H97, &HAB, &H8, &H8E, &HDF, &H74, &HC2, &HEF, &H84, &HBB, &HFC, &H74, &HAC, &H60, &H18, &H6E, &H1A, &HD2, &HC5, &H94, &HE0, &HDA, &HE0, &H45, &H33, &H43, &H99, &HF0, &HF3, &HF1, &H72, &H5, &H4B, &HF, &H37, &H50, &HC5, &HD9, &HCE, &H29, &H82, &H4C, &HF7, &HE6, &H94, &H5F, &HE5, &H7, &H2B, &H4A, &H18, &H9, &H56, &HC9, &H52, &H69, &H7D, &HC4, &H48, &H63, &H70, &HF2}, diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb index b71cb2f002ede..3c64b76dadf01 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests.vb @@ -4393,7 +4393,7 @@ End Class Dim nullArray As Integer() = Nothing Dim emptyArray As Integer() = {} - Assert.NotEqual(nullArray, emptyArray) + AssertEx.NotEqual(nullArray, emptyArray) attrs(0).VerifyValue(0, TypedConstantKind.Array, nullArray) @@ -5111,7 +5111,7 @@ Namespace a End Class End Namespace " - CreateCompilationWithMscorlib45(code).VerifyDiagnostics( + CreateCompilationWithMscorlib461(code).VerifyDiagnostics( Diagnostic(ERRID.ERR_BadAttributeConstructor1, "Command").WithArguments("a.Class1.CommandAttribute.FxCommand").WithLocation(20, 10), Diagnostic(ERRID.ERR_RequiredConstExpr, "AddressOf UserInfo").WithLocation(20, 18)) End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_CallerArgumentExpression.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_CallerArgumentExpression.vb index 14eccf6a78093..b96759f1ff04f 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_CallerArgumentExpression.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_CallerArgumentExpression.vb @@ -5,7 +5,6 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_ObsoleteAttribute.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_ObsoleteAttribute.vb index 7cd3698198c11..08b0e544245c3 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_ObsoleteAttribute.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_ObsoleteAttribute.vb @@ -5,6 +5,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities Imports Xunit +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -272,7 +273,7 @@ End Module ]]> - CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {TestMetadata.Net40.SystemCore}).AssertTheseDiagnostics( + CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}).AssertTheseDiagnostics( args As ValueTuple(Of T)) ~~~~~~~~~~~~~~~~~~~~~~~~ -BC30662: Attribute 'TupleElementNamesAttribute' cannot be applied to 'Event1' because the attribute is not valid on this declaration type. +BC37269: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. - ~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~ BC37269: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -BC37269: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. +BC30455: Argument not specified for parameter 'transformNames' of 'Public Overloads Sub New(transformNames As String())'. Default Public ReadOnly Property Item1( t As (a As Integer, b As Integer)) As (a As Integer, b As Integer) ~~~~~~~~~~~~~~~~~ BC37269: Cannot reference 'System.Runtime.CompilerServices.TupleElementNamesAttribute' explicitly. Use the tuple syntax to define tuple names. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ]]> +]]> ) End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb index bf2e9de2b2f2a..aef030c9b44ca 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb @@ -14,6 +14,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies #Disable Warning SYSLIB0050 ' 'TypeAttributes.Serializable' is obsolete @@ -2220,7 +2221,7 @@ End Class - CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {TestMetadata.Net40.SystemCore}).VerifyDiagnostics() + CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}).VerifyDiagnostics() End Sub @@ -5733,7 +5734,7 @@ End Class ' Dev10 Runtime Exception: ' Unhandled Exception: System.TypeLoadException: Windows Runtime types can only be declared in Windows Runtime assemblies. - Dim validator = CompileAndVerifyEx(source, sourceSymbolValidator:=sourceValidator, symbolValidator:=metadataValidator, verify:=Verification.Fails, targetFramework:=TargetFramework.Mscorlib45) + Dim validator = CompileAndVerifyEx(source, sourceSymbolValidator:=sourceValidator, symbolValidator:=metadataValidator, verify:=Verification.Fails, targetFramework:=TargetFramework.Mscorlib461) validator.EmitAndVerify("Type load failed.") End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/InternalsVisibleToAndStrongNameTests.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/InternalsVisibleToAndStrongNameTests.vb index fea12702c8e2c..4d90278dfd7f4 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/InternalsVisibleToAndStrongNameTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/InternalsVisibleToAndStrongNameTests.vb @@ -1140,7 +1140,7 @@ End Class Assert.True(comp.IsRealSigned) VerifySigned(comp) Assert.Equal(TestResources.General.snMaxSizePublicKey, comp.Assembly.Identity.PublicKey) - Assert.Equal(Of Byte)(pubKeyTokenBytes, comp.Assembly.Identity.PublicKeyToken) + AssertEx.Equal(Of Byte)(pubKeyTokenBytes, comp.Assembly.Identity.PublicKeyToken) Dim src = @@ -1158,14 +1158,14 @@ End Class CompileAndVerify(comp2, expectedOutput:="Called M") Assert.Equal(TestResources.General.snMaxSizePublicKey, comp2.Assembly.Identity.PublicKey) - Assert.Equal(Of Byte)(pubKeyTokenBytes, comp2.Assembly.Identity.PublicKeyToken) + AssertEx.Equal(Of Byte)(pubKeyTokenBytes, comp2.Assembly.Identity.PublicKeyToken) Dim comp3 = CreateCompilation(src, references:={comp.EmitToImageReference()}, options:=TestOptions.SigningReleaseExe.WithCryptoKeyFile(SigningTestHelpers.MaxSizeKeyFile), parseOptions:=parseOptions) CompileAndVerify(comp3, expectedOutput:="Called M") Assert.Equal(TestResources.General.snMaxSizePublicKey, comp3.Assembly.Identity.PublicKey) - Assert.Equal(Of Byte)(pubKeyTokenBytes, comp3.Assembly.Identity.PublicKeyToken) + AssertEx.Equal(Of Byte)(pubKeyTokenBytes, comp3.Assembly.Identity.PublicKeyToken) End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb index 91ab1cf5f0e32..96f40fcfc1e6e 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -9361,7 +9361,7 @@ Public Class TestCase End Class - Dim comp = CreateEmptyCompilationWithReferences(source, {Net40.mscorlib}, TestOptions.ReleaseDll) ' NOTE: 4.0, Not 4.5, so it's missing the async helpers. + Dim comp = CreateEmptyCompilationWithReferences(source, {Net40.References.mscorlib}, TestOptions.ReleaseDll) ' NOTE: 4.0, Not 4.5, so it's missing the async helpers. comp.AssertTheseEmitDiagnostics( BC31091: Import of type 'AsyncVoidMethodBuilder' from assembly or module 'AsyncVoid.dll' failed. @@ -9397,7 +9397,7 @@ Public Class TestCase End Class - Dim comp = CreateEmptyCompilationWithReferences(source, {Net40.mscorlib}, TestOptions.ReleaseDll) ' NOTE: 4.0, Not 4.5, so it's missing the async helpers. + Dim comp = CreateEmptyCompilationWithReferences(source, {Net40.References.mscorlib}, TestOptions.ReleaseDll) ' NOTE: 4.0, Not 4.5, so it's missing the async helpers. comp.AssertTheseEmitDiagnostics( BC31091: Import of type 'AsyncTaskMethodBuilder' from assembly or module 'AsyncTask.dll' failed. @@ -9434,7 +9434,7 @@ Public Class TestCase End Class - Dim comp = CreateEmptyCompilationWithReferences(source, {Net40.mscorlib}, TestOptions.ReleaseDll) ' NOTE: 4.0, Not 4.5, so it's missing the async helpers. + Dim comp = CreateEmptyCompilationWithReferences(source, {Net40.References.mscorlib}, TestOptions.ReleaseDll) ' NOTE: 4.0, Not 4.5, so it's missing the async helpers. comp.AssertTheseEmitDiagnostics( BC31091: Import of type 'AsyncTaskMethodBuilder(Of )' from assembly or module 'AsyncTask_T.dll' failed. diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenExpression.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenExpression.vb index 2af2f1d27603e..7f26da2be191d 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenExpression.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenExpression.vb @@ -75,8 +75,8 @@ Class C1 CheckSingle(1.99F, 1) CheckSingle(Integer.MaxValue - 65F, 2147483520) ' https://github.com/dotnet/roslyn/issues/74026 - ' CheckSingle(Integer.MaxValue - 64F, Integer.MinValue) ' overflow - ' CheckSingle(Integer.MaxValue - 0F, Integer.MinValue) ' overflow + CheckSingle(Integer.MaxValue - 64F, ]]><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %><%= If(ExecutionConditionUtil.IsMonoOrCoreClr, "Integer.MaxValue", "Integer.MinValue") %>.Value Dim tree = VisualBasicSyntaxTree.ParseText(source, options:=TestOptions.Script) - Dim c = CreateCompilationWithMscorlib45({tree}) + Dim c = CreateCompilationWithMscorlib461({tree}) c.VerifyDiagnostics() End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenSyncLock.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenSyncLock.vb index 74183fa099e4b..9661abc6ff75b 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenSyncLock.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenSyncLock.vb @@ -7,6 +7,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class CodeGenSyncLock @@ -87,7 +88,7 @@ End Class Dim allReferences As MetadataReference() = { - TestMetadata.Net20.mscorlib, + Net20.References.mscorlib, SystemRef, MsvbRef} diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb index c61678721a842..5283e27fcd974 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb @@ -5,12 +5,11 @@ Imports System.Collections.Immutable Imports System.Reflection Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Test.Resources.Proprietary Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -10481,7 +10480,7 @@ Public Class C1(Of T) End Function End Class - , references:={MetadataReference.CreateFromImage(ResourcesNet40.mscorlib.AsImmutableOrNull())})) + , references:={MetadataReference.CreateFromImage(Net40.Resources.mscorlib.AsImmutableOrNull())})) Dim comp = CompilationUtils.CreateEmptyCompilationWithReferences( @@ -10498,7 +10497,7 @@ Public Class C2(Of U) End Function End Class - , references:={MetadataReference.CreateFromImage(ResourcesNet40.mscorlib.AsImmutableOrNull()), ref1}) + , references:={MetadataReference.CreateFromImage(Net40.Resources.mscorlib.AsImmutableOrNull()), ref1}) CompileAndVerify(comp) @@ -10539,7 +10538,7 @@ Public Class C1 End Sub End Class - , references:={MetadataReference.CreateFromImage(ResourcesNet40.mscorlib.AsImmutableOrNull())})) + , references:={MetadataReference.CreateFromImage(Net40.Resources.mscorlib.AsImmutableOrNull())})) Dim comp = CompilationUtils.CreateEmptyCompilationWithReferences( @@ -10566,7 +10565,7 @@ Public Class C2 End Sub End Class - , references:={MetadataReference.CreateFromImage(ResourcesNet40.mscorlib.AsImmutableOrNull()), ref1}) + , references:={MetadataReference.CreateFromImage(Net40.Resources.mscorlib.AsImmutableOrNull()), ref1}) Dim compilationVerifier = CompileAndVerify(comp) @@ -13655,7 +13654,7 @@ End Module - Dim testReference = AssemblyMetadata.CreateFromImage(ProprietaryTestResources.Repros.BadDefaultParameterValue).GetReference() + Dim testReference = AssemblyMetadata.CreateFromImage(TestResources.SymbolsTests.Metadata.BadDefaultParameterValue).GetReference() Dim compilation = CompileAndVerify(source, references:=New MetadataReference() {testReference}) compilation.VerifyIL("C.Main", @@ -6331,7 +6330,7 @@ Module Extensions End Module , - references:={ValueTupleRef, Net451.SystemRuntime, Net451.SystemCore}, + references:={ValueTupleRef, NetFramework.SystemRuntime, NetFramework.SystemCore}, parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15)) comp.AssertTheseDiagnostics( @@ -6449,7 +6448,7 @@ End Module ' When VB 15 shipped, no tuple element would be found/inferred, so the extension method was called. ' The VB 15.3 compiler disallows that, even when LanguageVersion is 15. Dim comp15 = CreateCompilationWithMscorlib45AndVBRuntime(source, - references:={ValueTupleRef, Net451.SystemRuntime, Net451.SystemCore}, + references:={ValueTupleRef, NetFramework.SystemRuntime, NetFramework.SystemCore}, parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15)) comp15.AssertTheseDiagnostics( BC37289: Tuple element name 'M' is inferred. Please use language version 15.3 or greater to access an element by its inferred name. @@ -6458,7 +6457,7 @@ BC37289: Tuple element name 'M' is inferred. Please use language version 15.3 or ) Dim verifier15_3 = CompileAndVerify(source, - allReferences:={ValueTupleRef, Net451.mscorlib, Net451.SystemCore, Net451.SystemRuntime, Net451.MicrosoftVisualBasic}, + allReferences:={ValueTupleRef, NetFramework.mscorlib, NetFramework.SystemCore, NetFramework.SystemRuntime, NetFramework.MicrosoftVisualBasic}, parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_3), expectedOutput:="lambda") verifier15_3.VerifyDiagnostics() @@ -9091,7 +9090,7 @@ End Class comp.AssertTheseDiagnostics( -BC30652: Reference required to assembly 'System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' containing the type 'ValueTuple(Of ,)'. Add one to your project. +BC30652: Reference required to assembly 'System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' containing the type 'ValueTuple(Of ,)'. Add one to your project. A.M() ~~~~~ ) @@ -14925,7 +14924,7 @@ options:=TestOptions.DebugExe, additionalRefs:=s_valueTupleRefs) "ReadOnly Property (System.Int32, System.Int32).System.ITupleInternal.Size As System.Int32" ) - Assert.Equal({ + AssertEx.Equal({ ".ctor", ".ctor", "CompareTo", @@ -14968,7 +14967,7 @@ options:=TestOptions.DebugExe, additionalRefs:=s_valueTupleRefs) "ReadOnly Property (a2 As System.Int32, b2 As System.Int32).System.ITupleInternal.Size As System.Int32" ) - Assert.Equal({ + AssertEx.Equal({ ".ctor", ".ctor", "CompareTo", @@ -15009,7 +15008,7 @@ options:=TestOptions.DebugExe, additionalRefs:=s_valueTupleRefs) "ReadOnly Property (Item1 As System.Int32, Item2 As System.Int32).System.ITupleInternal.Size As System.Int32" ) - Assert.Equal({ + AssertEx.Equal({ ".ctor", ".ctor", "CompareTo", @@ -15042,7 +15041,7 @@ options:=TestOptions.DebugExe, additionalRefs:=s_valueTupleRefs) Assert.Same(m1Tuple.TupleUnderlyingType.ContainingSymbol, m1Tuple.ContainingSymbol) Assert.Null(m1Tuple.EnumUnderlyingType) - Assert.Equal({ + AssertEx.Equal({ "Item1", "Item2", ".ctor", @@ -15060,7 +15059,7 @@ options:=TestOptions.DebugExe, additionalRefs:=s_valueTupleRefs) "System.ITupleInternal.Size"}, m1Tuple.MemberNames.ToArray()) - Assert.Equal({ + AssertEx.Equal({ "Item1", "a2", "Item2", @@ -16300,9 +16299,9 @@ options:=TestOptions.DebugExe) Assert.Same(m1Tuple.TupleUnderlyingType.ContainingSymbol, m1Tuple.ContainingSymbol) Assert.Null(m1Tuple.GetUseSiteErrorInfo()) Assert.Null(m1Tuple.EnumUnderlyingType) - Assert.Equal({".ctor", "Item1", "Item2", "ToString"}, + AssertEx.Equal({".ctor", "Item1", "Item2", "ToString"}, m1Tuple.MemberNames.ToArray()) - Assert.Equal({".ctor", "Item1", "a2", "Item2", "b2", "ToString"}, + AssertEx.Equal({".ctor", "Item1", "a2", "Item2", "b2", "ToString"}, m2Tuple.MemberNames.ToArray()) Assert.Equal(0, m1Tuple.Arity) Assert.True(m1Tuple.TypeParameters.IsEmpty) @@ -19360,7 +19359,7 @@ Interface I End Interface , - references:={ValueTupleRef}) + references:={ValueTupleLegacyRef}) comp.AssertTheseEmitDiagnostics( BC30652: Reference required to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' containing the type 'ValueType'. Add one to your project. @@ -20067,7 +20066,7 @@ Module C End Module ]]> -, additionalRefs:={ValueTupleRef}) +, additionalRefs:={ValueTupleLegacyRef}) Assert.Equal(TypeKind.Class, comp.GetWellKnownType(WellKnownType.System_ValueTuple_T2).TypeKind) @@ -20114,7 +20113,6 @@ options:=TestOptions.ReleaseExe, additionalRefs:=s_valueTupleRefs) Dim comp = CreateCompilationWithMscorlib40AndVBRuntime( -Imports System Imports System.Collections.Generic Public Class C @@ -20123,7 +20121,7 @@ Public Class C End Function End Class -, additionalRefs:={ValueTupleRef}) +, additionalRefs:={ValueTupleLegacyRef}) comp.AssertTheseEmitDiagnostics( diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenWinMdEvents.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenWinMdEvents.vb index 2c6bbfc76fd04..d9ae7cda4db98 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenWinMdEvents.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenWinMdEvents.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class CodeGenWinMdEvents @@ -535,7 +536,7 @@ End Namespace Dim comp1 = CreateEmptyCompilationWithReferences(source1, WinRtRefs, options:=TestOptions.ReleaseWinMD) comp1.VerifyDiagnostics() - Dim serializationRef = TestMetadata.Net451.SystemRuntimeSerialization + Dim serializationRef = Net461.References.SystemRuntimeSerialization Dim comp2 = CreateEmptyCompilationWithReferences(source2, WinRtRefs.Concat({New VisualBasicCompilationReference(comp1), serializationRef, MsvbRef, SystemXmlRef}), options:=TestOptions.ReleaseExe) CompileAndVerify(comp2, expectedOutput:= - Dim compilation = CreateEmptyCompilationWithReferences(source, {TestMetadata.Net20.mscorlib}, Nothing) + Dim compilation = CreateEmptyCompilationWithReferences(source, {Net20.References.mscorlib}, Nothing) Dim metadata = ModuleMetadata.CreateFromImage(compilation.EmitToArray()) ' this is built with a 2.0 mscorlib. The runtimeMetadataVersion should be the same as the runtimeMetadataVersion stored in the assembly @@ -2459,7 +2460,7 @@ Imports System Dim actualGlobalMembers = DirectCast(m, SourceModuleSymbol).GlobalNamespace.GetMembers().ToArray() Assert.NotNull(m.GlobalNamespace.ContainingModule) - Assert.Equal(Of String)("C.dll", m.GlobalNamespace.ContainingModule.ToString) + AssertEx.Equal(Of String)("C.dll", m.GlobalNamespace.ContainingModule.ToString) For i As Integer = 0 To Math.Max(expectedGlobalMembers.Length, actualGlobalMembers.Length) - 1 Assert.Equal(expectedGlobalMembers(i), actualGlobalMembers(i).Name) diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb index e4072e17c1d39..5d0139f6947fb 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb @@ -430,6 +430,7 @@ End Module ' no new synthesized members generated (with #1 in names) diff1.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {VB$StateMachine_1_F}", "C.VB$StateMachine_1_F: {$State, $Builder, $VB$Local_x, $A0, MoveNext, System.Runtime.CompilerServices.IAsyncStateMachine.SetStateMachine}") @@ -440,8 +441,13 @@ End Module CheckEncLogDefinitions(reader1, Row(6, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(7, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(7, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(7, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(11, TableIndex.Field, EditAndContinueOperation.Default), Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(7, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(16, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(6, TableIndex.Param, EditAndContinueOperation.Default), Row(9, TableIndex.CustomAttribute, EditAndContinueOperation.Default), Row(10, TableIndex.CustomAttribute, EditAndContinueOperation.Default), @@ -2242,7 +2248,7 @@ End Class "C: {_Closure$__}", "C._Closure$__: {$I1-0, $I1-1, _Lambda$__1-0, _Lambda$__1-1}") End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System Class C @@ -2259,70 +2265,83 @@ End Class ' Static lambda is reused. ' A new display class and method is generated for lambda that captures x. g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__, _Closure$__1-0#1}", "C._Closure$__: {$I1-1, _Lambda$__1-1}", "C._Closure$__1-0#1: {_Lambda$__0#1}") - g.VerifyMethodDefNames("F", "_Lambda$__1-0", "_Lambda$__1-1", ".ctor", "_Lambda$__0#1") + g.VerifyMethodDefNames("F", "_Lambda$__1-0", "_Lambda$__1-1", ".ctor", ".ctor", "_Lambda$__0#1") g.VerifyIL(" { - // Code size 67 (0x43) - .maxstack 2 - IL_0000: nop - IL_0001: newobj 0x06000007 - IL_0006: stloc.3 - IL_0007: ldloc.3 - IL_0008: ldc.i4.1 - IL_0009: stfld 0x04000004 - IL_000e: ldloc.3 - IL_000f: ldftn 0x06000008 - IL_0015: newobj 0x0A000009 - IL_001a: stloc.s V_4 - IL_001c: ldsfld 0x04000003 - IL_0021: brfalse.s IL_002a - IL_0023: ldsfld 0x04000003 - IL_0028: br.s IL_0040 - IL_002a: ldsfld 0x04000001 - IL_002f: ldftn 0x06000006 - IL_0035: newobj 0x0A000009 - IL_003a: dup - IL_003b: stsfld 0x04000003 - IL_0040: stloc.s V_5 - IL_0042: ret -} -{ - // Code size 11 (0xb) - .maxstack 8 - IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw -} -{ - // Code size 9 (0x9) - .maxstack 8 - IL_0000: nop - IL_0001: ldc.i4.1 - IL_0002: call 0x0A00000B - IL_0007: nop - IL_0008: ret -} -{ - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call 0x0A00000C - IL_0006: ret -} -{ - // Code size 14 (0xe) - .maxstack 8 - IL_0000: nop - IL_0001: ldarg.0 - IL_0002: ldfld 0x04000004 - IL_0007: call 0x0A00000B - IL_000c: nop - IL_000d: ret + // Code size 67 (0x43) + .maxstack 2 + IL_0000: nop + IL_0001: newobj 0x06000008 + IL_0006: stloc.3 + IL_0007: ldloc.3 + IL_0008: ldc.i4.1 + IL_0009: stfld 0x04000005 + IL_000e: ldloc.3 + IL_000f: ldftn 0x06000009 + IL_0015: newobj 0x0A000009 + IL_001a: stloc.s V_4 + IL_001c: ldsfld 0x04000003 + IL_0021: brfalse.s IL_002a + IL_0023: ldsfld 0x04000003 + IL_0028: br.s IL_0040 + IL_002a: ldsfld 0x04000001 + IL_002f: ldftn 0x06000006 + IL_0035: newobj 0x0A000009 + IL_003a: dup + IL_003b: stsfld 0x04000003 + IL_0040: stloc.s V_5 + IL_0042: ret +} +{ + // Code size 12 (0xc) + .maxstack 8 + IL_0000: ldstr 0x70000005 + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000007 + IL_000b: throw +} +{ + // Code size 9 (0x9) + .maxstack 8 + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call 0x0A00000A + IL_0007: nop + IL_0008: ret +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000004 + IL_000e: ret +} +{ + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call 0x0A00000C + IL_0006: ret +} +{ + // Code size 14 (0xe) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldfld 0x04000005 + IL_0007: call 0x0A00000A + IL_000c: nop + IL_000d: ret } ") End Sub). @@ -2363,22 +2382,23 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__, _Closure$__1-0#1}", "C._Closure$__: {$I1-0, _Lambda$__1-0}", "C._Closure$__1-0#1: {_Lambda$__1#1}") - g.VerifyMethodDefNames("F", "_Lambda$__1-0", "_Lambda$__1-1", ".ctor", "_Lambda$__1#1") + g.VerifyMethodDefNames("F", "_Lambda$__1-0", "_Lambda$__1-1", ".ctor", ".ctor", "_Lambda$__1#1") g.VerifyIL(" { // Code size 66 (0x42) .maxstack 2 IL_0000: nop - IL_0001: newobj 0x06000007 + IL_0001: newobj 0x06000008 IL_0006: stloc.2 IL_0007: ldloc.2 IL_0008: ldarg.1 - IL_0009: stfld 0x04000004 + IL_0009: stfld 0x04000005 IL_000e: ldsfld 0x04000002 IL_0013: brfalse.s IL_001c IL_0015: ldsfld 0x04000002 @@ -2390,7 +2410,7 @@ End Class IL_002d: stsfld 0x04000002 IL_0032: stloc.3 IL_0033: ldloc.2 - IL_0034: ldftn 0x06000008 + IL_0034: ldftn 0x06000009 IL_003a: newobj 0x0A000009 IL_003f: stloc.s V_4 IL_0041: ret @@ -2405,11 +2425,23 @@ End Class IL_0008: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000B - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000007 + IL_000b: throw +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000004 + IL_000e: ret } { // Code size 7 (0x7) @@ -2423,7 +2455,7 @@ End Class .maxstack 8 IL_0000: nop IL_0001: ldarg.0 - IL_0002: ldfld 0x04000004 + IL_0002: ldfld 0x04000005 IL_0007: call 0x0A00000A IL_000c: nop IL_000d: ret @@ -2455,7 +2487,7 @@ End Class "C: {_Closure$__}", "C._Closure$__: {$I2-0, $I2-1, _Lambda$__2-0, _Lambda$__2-1}") End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System Class C @@ -2471,10 +2503,11 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Lambda$__2-1#1, _Closure$__}", "C._Closure$__: {$I2-0, _Lambda$__2-0}") - g.VerifyMethodDefNames("F", "_Lambda$__2-0", "_Lambda$__2-1", "_Lambda$__2-1#1") + g.VerifyMethodDefNames("F", "_Lambda$__2-0", "_Lambda$__2-1", "_Lambda$__2-1#1", ".ctor") g.VerifyIL(" { @@ -2507,11 +2540,12 @@ End Class IL_0008: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000B - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000008 + IL_000b: throw } { // Code size 14 (0xe) @@ -2523,6 +2557,17 @@ End Class IL_000c: nop IL_000d: ret } +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000005 + IL_000e: ret +} ") End Sub). Verify() @@ -2623,7 +2668,7 @@ End Class "C._Closure$__1-0: {_Lambda$__0}", "C: {_Closure$__1-0}") End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System Class C @@ -2637,10 +2682,11 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__}", "C._Closure$__: {$I1-0#1, _Lambda$__1-0#1}") - g.VerifyMethodDefNames("F", "_Lambda$__0", ".ctor", ".cctor", "_Lambda$__1-0#1") + g.VerifyMethodDefNames("F", "_Lambda$__0", ".ctor", ".ctor", ".cctor", "_Lambda$__1-0#1") g.VerifyIL(" { @@ -2649,24 +2695,36 @@ End Class IL_0000: nop IL_0001: ldc.i4.1 IL_0002: stloc.2 - IL_0003: ldsfld 0x04000003 + IL_0003: ldsfld 0x04000004 IL_0008: brfalse.s IL_0011 - IL_000a: ldsfld 0x04000003 + IL_000a: ldsfld 0x04000004 IL_000f: br.s IL_0027 - IL_0011: ldsfld 0x04000002 - IL_0016: ldftn 0x0600000B + IL_0011: ldsfld 0x04000003 + IL_0016: ldftn 0x0600000C IL_001c: newobj 0x0A000009 IL_0021: dup - IL_0022: stsfld 0x04000003 + IL_0022: stsfld 0x04000004 IL_0027: stloc.3 IL_0028: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000009 + IL_000b: throw +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000A + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000002 + IL_000e: ret } { // Code size 7 (0x7) @@ -2678,8 +2736,8 @@ End Class { // Code size 11 (0xb) .maxstack 8 - IL_0000: newobj 0x06000009 - IL_0005: stsfld 0x04000002 + IL_0000: newobj 0x0600000A + IL_0005: stsfld 0x04000003 IL_000a: ret } { @@ -2694,7 +2752,7 @@ End Class } ") End Sub). - AddGeneration(' resume capture + AddGeneration(' 2: resume capture source:=" Imports System Class C @@ -2708,6 +2766,7 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__1-0#2, _Closure$__}", "C._Closure$__: {$I1-0#1, _Lambda$__1-0#1}", "C._Closure$__1-0#2: {_Lambda$__0#2}") @@ -2719,29 +2778,30 @@ End Class // Code size 32 (0x20) .maxstack 2 IL_0000: nop - IL_0001: newobj 0x0600000C + IL_0001: newobj 0x0600000D IL_0006: stloc.s V_4 IL_0008: ldloc.s V_4 IL_000a: ldc.i4.1 - IL_000b: stfld 0x04000004 + IL_000b: stfld 0x04000005 IL_0010: ldloc.s V_4 - IL_0012: ldftn 0x0600000D + IL_0012: ldftn 0x0600000E IL_0018: newobj 0x0A00000D IL_001d: stloc.s V_5 IL_001f: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x7000014D - IL_0005: newobj 0x0A00000E - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000009 + IL_000b: throw } { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 - IL_0001: call 0x0A00000F + IL_0001: call 0x0A00000E IL_0006: ret } { @@ -2749,7 +2809,7 @@ End Class .maxstack 2 IL_0000: nop IL_0001: ldarg.0 - IL_0002: ldfld 0x04000004 + IL_0002: ldfld 0x04000005 IL_0007: ldc.i4.1 IL_0008: add.ovf IL_0009: stloc.0 @@ -2784,7 +2844,7 @@ End Class "C: {_Lambda$__2-0, _Closure$__}", "C._Closure$__: {$I2-1, _Lambda$__2-1}") End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System Class C @@ -2800,25 +2860,26 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__}", "C._Closure$__: {$I2-0#1, $I2-1, _Lambda$__2-0#1, _Lambda$__2-1}") - g.VerifyMethodDefNames("F", "_Lambda$__2-0", "_Lambda$__2-1", "_Lambda$__2-0#1") + g.VerifyMethodDefNames("F", "_Lambda$__2-0", "_Lambda$__2-1", ".ctor", "_Lambda$__2-0#1") g.VerifyIL(" { // Code size 76 (0x4c) .maxstack 2 IL_0000: nop - IL_0001: ldsfld 0x04000004 + IL_0001: ldsfld 0x04000005 IL_0006: brfalse.s IL_000f - IL_0008: ldsfld 0x04000004 + IL_0008: ldsfld 0x04000005 IL_000d: br.s IL_0025 IL_000f: ldsfld 0x04000002 - IL_0014: ldftn 0x0600000B + IL_0014: ldftn 0x0600000C IL_001a: newobj 0x0A000009 IL_001f: dup - IL_0020: stsfld 0x04000004 + IL_0020: stsfld 0x04000005 IL_0025: stloc.2 IL_0026: ldsfld 0x04000003 IL_002b: brfalse.s IL_0034 @@ -2833,11 +2894,12 @@ End Class IL_004b: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x0600000B + IL_000b: throw } { // Code size 7 (0x7) @@ -2849,6 +2911,17 @@ End Class IL_0005: ldloc.0 IL_0006: ret } +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000A + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000004 + IL_000e: ret +} { // Code size 7 (0x7) .maxstack 1 @@ -2881,7 +2954,7 @@ End Class Sub(g) g.VerifySynthesizedMembers() End Sub). - AddGeneration('add closure + AddGeneration('1: add closure source:=" Imports System Class C @@ -2937,7 +3010,7 @@ End Class } ") End Sub). - AddGeneration('remove closure + AddGeneration('2: remove closure source:=" Imports System Class C @@ -2950,10 +3023,11 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__1#1-0#1}", "C._Closure$__1#1-0#1: {_Lambda$__0#1}") - g.VerifyMethodDefNames("F", "_Lambda$__0#1") + g.VerifyMethodDefNames("F", "_Lambda$__0#1", ".ctor") g.VerifyIL(" { @@ -2965,11 +3039,23 @@ End Class IL_0003: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000009 - IL_0005: newobj 0x0A000008 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000005 + IL_000b: throw +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000002 + IL_000e: ret } ") End Sub). @@ -3005,7 +3091,7 @@ End Class "C._Closure$__2-0: {$I0, _Lambda$__0}", "C: {_Closure$__2-0, _Closure$__2-1}") End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System Class C @@ -3027,11 +3113,12 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__2-0, _Closure$__2-1#1}", "C._Closure$__2-1#1: {$VB$NonLocal_$VB$Closure_2, _Lambda$__1#1}", "C._Closure$__2-0: {$I0, _Lambda$__0}") - g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__1", ".ctor", "_Lambda$__1#1") + g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__1", ".ctor", ".ctor", "_Lambda$__1#1") g.VerifyIL(" { @@ -3046,26 +3133,26 @@ End Class IL_000a: stfld 0x04000002 IL_000f: br.s IL_007b IL_0011: ldloc.s V_6 - IL_0013: newobj 0x06000007 + IL_0013: newobj 0x06000008 IL_0018: stloc.s V_6 IL_001a: ldloc.s V_6 IL_001c: ldloc.0 - IL_001d: stfld 0x04000006 + IL_001d: stfld 0x04000007 IL_0022: ldloc.s V_6 IL_0024: ldc.i4.1 - IL_0025: stfld 0x04000005 + IL_0025: stfld 0x04000006 IL_002a: ldloc.s V_6 - IL_002c: ldfld 0x04000006 + IL_002c: ldfld 0x04000007 IL_0031: ldfld 0x04000003 IL_0036: brfalse.s IL_0046 IL_0038: ldloc.s V_6 - IL_003a: ldfld 0x04000006 + IL_003a: ldfld 0x04000007 IL_003f: ldfld 0x04000003 IL_0044: br.s IL_0069 IL_0046: ldloc.s V_6 - IL_0048: ldfld 0x04000006 + IL_0048: ldfld 0x04000007 IL_004d: ldloc.s V_6 - IL_004f: ldfld 0x04000006 + IL_004f: ldfld 0x04000007 IL_0054: ldftn 0x06000004 IL_005a: newobj 0x0A000008 IL_005f: dup @@ -3074,7 +3161,7 @@ End Class IL_0067: ldloc.s V_9 IL_0069: stloc.s V_7 IL_006b: ldloc.s V_6 - IL_006d: ldftn 0x06000008 + IL_006d: ldftn 0x06000009 IL_0073: newobj 0x0A000008 IL_0078: stloc.s V_8 IL_007a: nop @@ -3094,11 +3181,23 @@ End Class IL_000b: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000007 + IL_000b: throw +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000005 + IL_000e: ret } { // Code size 22 (0x16) @@ -3109,8 +3208,8 @@ End Class IL_0007: brfalse.s IL_0015 IL_0009: ldarg.0 IL_000a: ldarg.1 - IL_000b: ldfld 0x04000005 - IL_0010: stfld 0x04000005 + IL_000b: ldfld 0x04000006 + IL_0010: stfld 0x04000006 IL_0015: ret } { @@ -3118,10 +3217,10 @@ End Class .maxstack 2 IL_0000: nop IL_0001: ldarg.0 - IL_0002: ldfld 0x04000006 + IL_0002: ldfld 0x04000007 IL_0007: ldfld 0x04000002 IL_000c: ldarg.0 - IL_000d: ldfld 0x04000005 + IL_000d: ldfld 0x04000006 IL_0012: add.ovf IL_0013: stloc.0 IL_0014: br.s IL_0016 @@ -3160,7 +3259,7 @@ End Class "C._Closure$__1-0: {$I0, _Lambda$__0}", "C._Closure$__1-1: {$VB$NonLocal_$VB$Closure_2, _Lambda$__1}") End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System Class C @@ -3180,11 +3279,12 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__1-0, _Closure$__1-1#1}", "C._Closure$__1-0: {$I0, _Lambda$__0}", "C._Closure$__1-1#1: {_Lambda$__1#1}") - g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__1", ".ctor", "_Lambda$__1#1") + g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__1", ".ctor", ".ctor", "_Lambda$__1#1") g.VerifyIL(" { @@ -3199,11 +3299,11 @@ End Class IL_000a: stfld 0x04000001 IL_000f: br.s IL_005b IL_0011: ldloc.s V_6 - IL_0013: newobj 0x0600000B + IL_0013: newobj 0x0600000C IL_0018: stloc.s V_6 IL_001a: ldloc.s V_6 IL_001c: ldc.i4.1 - IL_001d: stfld 0x04000005 + IL_001d: stfld 0x04000006 IL_0022: ldloc.0 IL_0023: ldfld 0x04000002 IL_0028: brfalse.s IL_0032 @@ -3220,7 +3320,7 @@ End Class IL_0047: ldloc.s V_9 IL_0049: stloc.s V_7 IL_004b: ldloc.s V_6 - IL_004d: ldftn 0x0600000C + IL_004d: ldftn 0x0600000D IL_0053: newobj 0x0A000009 IL_0058: stloc.s V_8 IL_005a: nop @@ -3240,11 +3340,23 @@ End Class IL_000b: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x0600000B + IL_000b: throw +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000A + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000005 + IL_000e: ret } { // Code size 22 (0x16) @@ -3255,8 +3367,8 @@ End Class IL_0007: brfalse.s IL_0015 IL_0009: ldarg.0 IL_000a: ldarg.1 - IL_000b: ldfld 0x04000005 - IL_0010: stfld 0x04000005 + IL_000b: ldfld 0x04000006 + IL_0010: stfld 0x04000006 IL_0015: ret } { @@ -3264,7 +3376,7 @@ End Class .maxstack 1 IL_0000: nop IL_0001: ldarg.0 - IL_0002: ldfld 0x04000005 + IL_0002: ldfld 0x04000006 IL_0007: stloc.0 IL_0008: br.s IL_000a IL_000a: ldloc.0 @@ -3308,7 +3420,7 @@ End Class "C._Closure$__2-0: {$I0, _Lambda$__0}", "C._Closure$__2-1: {$VB$NonLocal_$VB$Closure_2, _Lambda$__1}") End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System Class C @@ -3336,15 +3448,16 @@ End Class Sub(g) ' closure #0 is preserved, new closures #1 and #2 are created: g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__2-0, _Closure$__2-1#1, _Closure$__2-2#1}", "C._Closure$__2-0: {$I0, _Lambda$__0}", "C._Closure$__2-1#1: {$VB$NonLocal_$VB$Closure_3, _Lambda$__1#1, _Lambda$__2#1}", "C._Closure$__2-2#1: {$VB$NonLocal_$VB$Closure_2}") - g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__1", ".ctor", "_Lambda$__1#1", "_Lambda$__2#1", ".ctor") + g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__1", ".ctor", ".ctor", "_Lambda$__1#1", "_Lambda$__2#1", ".ctor") g.VerifyIL(" -{ + { // Code size 208 (0xd0) .maxstack 3 IL_0000: nop @@ -3356,40 +3469,40 @@ End Class IL_000a: stfld 0x04000002 IL_000f: br IL_00c8 IL_0014: ldloc.s V_8 - IL_0016: newobj 0x0600000E + IL_0016: newobj 0x0600000F IL_001b: stloc.s V_8 IL_001d: ldloc.s V_8 IL_001f: ldloc.0 - IL_0020: stfld 0x04000009 + IL_0020: stfld 0x0400000A IL_0025: ldloc.s V_8 IL_0027: ldc.i4.2 - IL_0028: stfld 0x04000008 + IL_0028: stfld 0x04000009 IL_002d: br IL_00c0 IL_0032: ldloc.s V_9 - IL_0034: newobj 0x0600000B + IL_0034: newobj 0x0600000C IL_0039: stloc.s V_9 IL_003b: ldloc.s V_9 IL_003d: ldloc.s V_8 - IL_003f: stfld 0x04000007 + IL_003f: stfld 0x04000008 IL_0044: ldloc.s V_9 IL_0046: ldc.i4.3 - IL_0047: stfld 0x04000006 + IL_0047: stfld 0x04000007 IL_004c: ldloc.s V_9 - IL_004e: ldfld 0x04000007 - IL_0053: ldfld 0x04000009 + IL_004e: ldfld 0x04000008 + IL_0053: ldfld 0x0400000A IL_0058: ldfld 0x04000003 IL_005d: brfalse.s IL_0072 IL_005f: ldloc.s V_9 - IL_0061: ldfld 0x04000007 - IL_0066: ldfld 0x04000009 + IL_0061: ldfld 0x04000008 + IL_0066: ldfld 0x0400000A IL_006b: ldfld 0x04000003 IL_0070: br.s IL_009f IL_0072: ldloc.s V_9 - IL_0074: ldfld 0x04000007 - IL_0079: ldfld 0x04000009 + IL_0074: ldfld 0x04000008 + IL_0079: ldfld 0x0400000A IL_007e: ldloc.s V_9 - IL_0080: ldfld 0x04000007 - IL_0085: ldfld 0x04000009 + IL_0080: ldfld 0x04000008 + IL_0085: ldfld 0x0400000A IL_008a: ldftn 0x06000008 IL_0090: newobj 0x0A000009 IL_0095: dup @@ -3398,11 +3511,11 @@ End Class IL_009d: ldloc.s V_13 IL_009f: stloc.s V_10 IL_00a1: ldloc.s V_9 - IL_00a3: ldftn 0x0600000C + IL_00a3: ldftn 0x0600000D IL_00a9: newobj 0x0A000009 IL_00ae: stloc.s V_11 IL_00b0: ldloc.s V_9 - IL_00b2: ldftn 0x0600000D + IL_00b2: ldftn 0x0600000E IL_00b8: newobj 0x0A000009 IL_00bd: stloc.s V_12 IL_00bf: nop @@ -3425,11 +3538,23 @@ End Class IL_000b: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x0600000B + IL_000b: throw +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000A + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000006 + IL_000e: ret } { // Code size 22 (0x16) @@ -3440,8 +3565,8 @@ End Class IL_0007: brfalse.s IL_0015 IL_0009: ldarg.0 IL_000a: ldarg.1 - IL_000b: ldfld 0x04000006 - IL_0010: stfld 0x04000006 + IL_000b: ldfld 0x04000007 + IL_0010: stfld 0x04000007 IL_0015: ret } { @@ -3449,10 +3574,10 @@ End Class .maxstack 2 IL_0000: nop IL_0001: ldarg.0 - IL_0002: ldfld 0x04000006 + IL_0002: ldfld 0x04000007 IL_0007: ldarg.0 - IL_0008: ldfld 0x04000007 - IL_000d: ldfld 0x04000009 + IL_0008: ldfld 0x04000008 + IL_000d: ldfld 0x0400000A IL_0012: ldfld 0x04000002 IL_0017: add.ovf IL_0018: stloc.0 @@ -3465,15 +3590,15 @@ End Class .maxstack 2 IL_0000: nop IL_0001: ldarg.0 - IL_0002: ldfld 0x04000006 + IL_0002: ldfld 0x04000007 IL_0007: ldarg.0 - IL_0008: ldfld 0x04000007 - IL_000d: ldfld 0x04000009 + IL_0008: ldfld 0x04000008 + IL_000d: ldfld 0x0400000A IL_0012: ldfld 0x04000002 IL_0017: add.ovf IL_0018: ldarg.0 - IL_0019: ldfld 0x04000007 - IL_001e: ldfld 0x04000008 + IL_0019: ldfld 0x04000008 + IL_001e: ldfld 0x04000009 IL_0023: add.ovf IL_0024: stloc.0 IL_0025: br.s IL_0027 @@ -3489,8 +3614,8 @@ End Class IL_0007: brfalse.s IL_0015 IL_0009: ldarg.0 IL_000a: ldarg.1 - IL_000b: ldfld 0x04000008 - IL_0010: stfld 0x04000008 + IL_000b: ldfld 0x04000009 + IL_0010: stfld 0x04000009 IL_0015: ret } ") @@ -3526,7 +3651,7 @@ End Class "C._Closure$__1-0: {$I0, $I2, _Lambda$__0, _Lambda$__2}", "C._Closure$__1-1: {_Lambda$__1}") End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System Class C @@ -3547,14 +3672,15 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__1-0, _Closure$__1-1}", "C._Closure$__1-0: {$I0, _Lambda$__0}", "C._Closure$__1-1: {_Lambda$__1, _Lambda$__2#1}") - g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__2", "_Lambda$__1", "_Lambda$__2#1") + g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__2", "_Lambda$__1", ".ctor", "_Lambda$__2#1") g.VerifyIL(" - { +{ // Code size 106 (0x6a) .maxstack 3 IL_0000: nop @@ -3591,7 +3717,7 @@ End Class IL_004f: newobj 0x0A000008 IL_0054: stloc.s V_8 IL_0056: ldloc.1 - IL_0057: ldftn 0x06000008 + IL_0057: ldftn 0x06000009 IL_005d: newobj 0x0A000008 IL_0062: stloc.s V_9 IL_0064: nop @@ -3611,11 +3737,12 @@ End Class IL_000b: ret } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000008 + IL_000b: throw } { // Code size 12 (0xc) @@ -3628,6 +3755,17 @@ End Class IL_000a: ldloc.0 IL_000b: ret } +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000005 + IL_000e: ret +} { // Code size 14 (0xe) .maxstack 2 diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinuePdbTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinuePdbTests.vb index 1ff1a442e99b8..30bc296bea330 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinuePdbTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinuePdbTests.vb @@ -257,6 +257,7 @@ End Class", fileName:="C:\Enc1.vb") New SemanticEdit(SemanticEditKind.Insert, Nothing, b2))) diff2.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__}", "C._Closure$__: {$I4-3#1, $I4-1, _Lambda$__4-1, _Lambda$__4-3#1, $I4-0, $I4-2, _Lambda$__4-0, _Lambda$__4-2}") @@ -266,6 +267,9 @@ End Class", fileName:="C:\Enc1.vb") Row(8, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(9, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(10, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(6, TableIndex.Field, EditAndContinueOperation.Default), Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(11, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(13, TableIndex.MethodDef, EditAndContinueOperation.Default), @@ -274,7 +278,9 @@ End Class", fileName:="C:\Enc1.vb") Row(18, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(19, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(20, TableIndex.MethodDef, EditAndContinueOperation.Default)) + Row(20, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(21, TableIndex.MethodDef, EditAndContinueOperation.Default)) If format = DebugInformationFormat.PortablePdb Then Using pdbProvider = MetadataReaderProvider.FromPortablePdbImage(diff2.PdbDelta) @@ -286,7 +292,8 @@ End Class", fileName:="C:\Enc1.vb") Handle(17, TableIndex.MethodDebugInformation), Handle(18, TableIndex.MethodDebugInformation), Handle(19, TableIndex.MethodDebugInformation), - Handle(20, TableIndex.MethodDebugInformation)) + Handle(20, TableIndex.MethodDebugInformation), + Handle(21, TableIndex.MethodDebugInformation)) End Using End If diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb index 121c12b2f7dd1..5a32eb6ade51f 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb @@ -9,12 +9,19 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Roslyn.Test.Utilities +Imports Xunit.Abstractions Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class EditAndContinueStateMachineTests Inherits EditAndContinueTestBase + ReadOnly _logger As ITestOutputHelper + + Sub New(logger As ITestOutputHelper) + _logger = logger + End Sub + Public Sub AddIteratorMethod() Dim source0 = @@ -977,7 +984,7 @@ End Class Public Sub AsyncMethodOverloads() - Using New EditAndContinueTest(). + Using New EditAndContinueTest(_logger). AddBaseline( source:=" Imports System.Threading.Tasks @@ -995,20 +1002,53 @@ End Class ", validator:= Sub(g) + g.VerifyPdb("C.F", " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +") End Sub). AddGeneration( source:=" Imports System.Threading.Tasks Class C - Async Function F(a As Long) As Task(Of Integer) - Return Await Task.FromResult(2) - End Function Async Function F(a As Integer) As Task(Of Integer) Return Await Task.FromResult(3) End Function Async Function F(a As Short) As Task(Of Integer) Return Await Task.FromResult(4) End Function + Async Function F(a As Long) As Task(Of Integer) + Return Await Task.FromResult(2) + End Function End Class ", edits:= @@ -1019,7 +1059,9 @@ End Class }, validator:= Sub(g) - ' notice no TypeDefs, FieldDefs + g.VerifyTypeDefNames("HotReloadException") + g.VerifyFieldDefNames("Code") + g.VerifyEncLogDefinitions( { Row(7, TableIndex.StandAloneSig, EditAndContinueOperation.Default), @@ -1028,12 +1070,17 @@ End Class Row(10, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(11, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(12, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(16, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(14, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(1, TableIndex.Param, EditAndContinueOperation.Default), Row(2, TableIndex.Param, EditAndContinueOperation.Default), Row(3, TableIndex.Param, EditAndContinueOperation.Default), @@ -2164,7 +2211,7 @@ End Class") }") diff1.VerifyIL("C.VB$StateMachine_5_F.MoveNext", " { - // Code size 316 (0x13c) + // Code size 318 (0x13e) .maxstack 3 .locals init (Integer V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -2183,130 +2230,126 @@ End Class") IL_000d: ldc.i4.2 IL_000e: beq.s IL_0014 IL_0010: br.s IL_0019 - IL_0012: br.s IL_0064 - IL_0014: br IL_00ca + IL_0012: br.s IL_0066 + IL_0014: br IL_00cc IL_0019: ldloc.0 IL_001a: ldc.i4.0 - IL_001b: blt.s IL_0028 + IL_001b: blt.s IL_002a IL_001d: ldstr """ & CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod & """ - IL_0022: newobj ""Sub System.InvalidOperationException..ctor(String)"" - IL_0027: throw - - IL_0028: nop - IL_0029: call ""Function C.M1() As System.Threading.Tasks.Task"" - IL_002e: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0033: stloc.1 - IL_0034: ldloca.s V_1 - IL_0036: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" - IL_003b: brtrue.s IL_0082 - IL_003d: ldarg.0 - IL_003e: ldc.i4.0 - IL_003f: dup - IL_0040: stloc.0 - IL_0041: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_0046: ldarg.0 - IL_0047: ldloc.1 - IL_0048: stfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_004d: ldarg.0 - IL_004e: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_0053: ldloca.s V_1 - IL_0055: ldarg.0 - IL_0056: stloc.2 - IL_0057: ldloca.s V_2 - IL_0059: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C.VB$StateMachine_5_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C.VB$StateMachine_5_F)"" - IL_005e: nop - IL_005f: leave IL_013b - - IL_0064: ldarg.0 - IL_0065: ldc.i4.m1 - IL_0066: dup - IL_0067: stloc.0 - IL_0068: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_006d: ldarg.0 - IL_006e: ldfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0073: stloc.1 - IL_0074: ldarg.0 - IL_0075: ldflda ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_007a: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0080: br.s IL_0082 - IL_0082: ldloca.s V_1 - IL_0084: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_0089: nop - IL_008a: ldloca.s V_1 - IL_008c: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0092: call ""Function C.M2() As System.Threading.Tasks.Task"" - IL_0097: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" - IL_009c: stloc.3 - IL_009d: ldloca.s V_3 - IL_009f: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" - IL_00a4: brtrue.s IL_00e8 - - IL_00a6: ldarg.0 - IL_00a7: ldc.i4.2 - IL_00a8: dup - IL_00a9: stloc.0 - IL_00aa: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_00af: ldarg.0 - IL_00b0: ldloc.3 - IL_00b1: stfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_00b6: ldarg.0 - IL_00b7: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_00bc: ldloca.s V_3 - IL_00be: ldarg.0 - IL_00bf: stloc.2 - IL_00c0: ldloca.s V_2 - IL_00c2: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C.VB$StateMachine_5_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C.VB$StateMachine_5_F)"" - IL_00c7: nop - IL_00c8: leave.s IL_013b - - IL_00ca: ldarg.0 - IL_00cb: ldc.i4.m1 - IL_00cc: dup - IL_00cd: stloc.0 - IL_00ce: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_00d3: ldarg.0 - IL_00d4: ldfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_00d9: stloc.3 - IL_00da: ldarg.0 - IL_00db: ldflda ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_00e0: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00e6: br.s IL_00e8 - - IL_00e8: ldloca.s V_3 - IL_00ea: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00ef: nop - IL_00f0: ldloca.s V_3 - IL_00f2: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00f8: call ""Sub C.End()"" - IL_00fd: nop - IL_00fe: leave.s IL_0125 + IL_0022: ldc.i4.s -4 + IL_0024: newobj ""Sub System.Runtime.CompilerServices.HotReloadException..ctor(String, Integer)"" + IL_0029: throw + IL_002a: nop + IL_002b: call ""Function C.M1() As System.Threading.Tasks.Task"" + IL_0030: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" + IL_0035: stloc.1 + IL_0036: ldloca.s V_1 + IL_0038: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" + IL_003d: brtrue.s IL_0084 + IL_003f: ldarg.0 + IL_0040: ldc.i4.0 + IL_0041: dup + IL_0042: stloc.0 + IL_0043: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_0048: ldarg.0 + IL_0049: ldloc.1 + IL_004a: stfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_004f: ldarg.0 + IL_0050: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_0055: ldloca.s V_1 + IL_0057: ldarg.0 + IL_0058: stloc.2 + IL_0059: ldloca.s V_2 + IL_005b: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C.VB$StateMachine_5_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C.VB$StateMachine_5_F)"" + IL_0060: nop + IL_0061: leave IL_013d + IL_0066: ldarg.0 + IL_0067: ldc.i4.m1 + IL_0068: dup + IL_0069: stloc.0 + IL_006a: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_006f: ldarg.0 + IL_0070: ldfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_0075: stloc.1 + IL_0076: ldarg.0 + IL_0077: ldflda ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_007c: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0082: br.s IL_0084 + IL_0084: ldloca.s V_1 + IL_0086: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_008b: nop + IL_008c: ldloca.s V_1 + IL_008e: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0094: call ""Function C.M2() As System.Threading.Tasks.Task"" + IL_0099: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" + IL_009e: stloc.3 + IL_009f: ldloca.s V_3 + IL_00a1: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" + IL_00a6: brtrue.s IL_00ea + IL_00a8: ldarg.0 + IL_00a9: ldc.i4.2 + IL_00aa: dup + IL_00ab: stloc.0 + IL_00ac: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_00b1: ldarg.0 + IL_00b2: ldloc.3 + IL_00b3: stfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_00b8: ldarg.0 + IL_00b9: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_00be: ldloca.s V_3 + IL_00c0: ldarg.0 + IL_00c1: stloc.2 + IL_00c2: ldloca.s V_2 + IL_00c4: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C.VB$StateMachine_5_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C.VB$StateMachine_5_F)"" + IL_00c9: nop + IL_00ca: leave.s IL_013d + IL_00cc: ldarg.0 + IL_00cd: ldc.i4.m1 + IL_00ce: dup + IL_00cf: stloc.0 + IL_00d0: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_00d5: ldarg.0 + IL_00d6: ldfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_00db: stloc.3 + IL_00dc: ldarg.0 + IL_00dd: ldflda ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_00e2: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00e8: br.s IL_00ea + IL_00ea: ldloca.s V_3 + IL_00ec: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00f1: nop + IL_00f2: ldloca.s V_3 + IL_00f4: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00fa: call ""Sub C.End()"" + IL_00ff: nop + IL_0100: leave.s IL_0127 } catch System.Exception { - IL_0100: dup - IL_0101: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" - IL_0106: stloc.s V_4 - IL_0108: ldarg.0 - IL_0109: ldc.i4.s -2 - IL_010b: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_0110: ldarg.0 - IL_0111: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_0116: ldloc.s V_4 - IL_0118: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_011d: nop - IL_011e: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" - IL_0123: leave.s IL_013b + IL_0102: dup + IL_0103: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" + IL_0108: stloc.s V_4 + IL_010a: ldarg.0 + IL_010b: ldc.i4.s -2 + IL_010d: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_0112: ldarg.0 + IL_0113: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_0118: ldloc.s V_4 + IL_011a: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_011f: nop + IL_0120: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" + IL_0125: leave.s IL_013d } - IL_0125: ldarg.0 - IL_0126: ldc.i4.s -2 - IL_0128: dup - IL_0129: stloc.0 - IL_012a: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_012f: ldarg.0 - IL_0130: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_0135: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_013a: nop - IL_013b: ret + IL_0127: ldarg.0 + IL_0128: ldc.i4.s -2 + IL_012a: dup + IL_012b: stloc.0 + IL_012c: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_0131: ldarg.0 + IL_0132: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_0137: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_013c: nop + IL_013d: ret }") diff1.VerifyPdb(Enumerable.Range(1, 20).Select(AddressOf MetadataTokens.MethodDefinitionHandle), " @@ -2318,22 +2361,22 @@ End Class") - - + + @@ -2343,7 +2386,7 @@ End Class") ") diff2.VerifyIL("C.VB$StateMachine_5_F.MoveNext", " { - // Code size 198 (0xc6) + // Code size 200 (0xc8) .maxstack 3 .locals init (Integer V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -2357,87 +2400,85 @@ End Class") IL_0007: ldloc.0 IL_0008: brfalse.s IL_000c IL_000a: br.s IL_000e - IL_000c: br.s IL_0056 + IL_000c: br.s IL_0058 IL_000e: ldloc.0 IL_000f: ldc.i4.0 - IL_0010: blt.s IL_001d + IL_0010: blt.s IL_001f IL_0012: ldstr """ & CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod & """ - IL_0017: newobj ""Sub System.InvalidOperationException..ctor(String)"" - IL_001c: throw - IL_001d: nop - IL_001e: call ""Function C.M1() As System.Threading.Tasks.Task"" - IL_0023: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0028: stloc.1 - IL_0029: ldloca.s V_1 - IL_002b: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" - IL_0030: brtrue.s IL_0074 - - IL_0032: ldarg.0 - IL_0033: ldc.i4.0 - IL_0034: dup - IL_0035: stloc.0 - IL_0036: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_003b: ldarg.0 - IL_003c: ldloc.1 - IL_003d: stfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0042: ldarg.0 - IL_0043: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_0048: ldloca.s V_1 - IL_004a: ldarg.0 - IL_004b: stloc.2 - IL_004c: ldloca.s V_2 - IL_004e: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C.VB$StateMachine_5_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C.VB$StateMachine_5_F)"" - IL_0053: nop - IL_0054: leave.s IL_00c5 - - IL_0056: ldarg.0 - IL_0057: ldc.i4.m1 - IL_0058: dup - IL_0059: stloc.0 - IL_005a: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_005f: ldarg.0 - IL_0060: ldfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0065: stloc.1 - IL_0066: ldarg.0 - IL_0067: ldflda ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_006c: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0072: br.s IL_0074 - - IL_0074: ldloca.s V_1 - IL_0076: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_007b: nop - IL_007c: ldloca.s V_1 - IL_007e: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0084: call ""Sub C.End()"" - IL_0089: nop - IL_008a: leave.s IL_00af + IL_0017: ldc.i4.s -4 + IL_0019: newobj ""Sub System.Runtime.CompilerServices.HotReloadException..ctor(String, Integer)"" + IL_001e: throw + IL_001f: nop + IL_0020: call ""Function C.M1() As System.Threading.Tasks.Task"" + IL_0025: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" + IL_002a: stloc.1 + IL_002b: ldloca.s V_1 + IL_002d: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" + IL_0032: brtrue.s IL_0076 + IL_0034: ldarg.0 + IL_0035: ldc.i4.0 + IL_0036: dup + IL_0037: stloc.0 + IL_0038: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_003d: ldarg.0 + IL_003e: ldloc.1 + IL_003f: stfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_0044: ldarg.0 + IL_0045: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_004a: ldloca.s V_1 + IL_004c: ldarg.0 + IL_004d: stloc.2 + IL_004e: ldloca.s V_2 + IL_0050: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C.VB$StateMachine_5_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C.VB$StateMachine_5_F)"" + IL_0055: nop + IL_0056: leave.s IL_00c7 + IL_0058: ldarg.0 + IL_0059: ldc.i4.m1 + IL_005a: dup + IL_005b: stloc.0 + IL_005c: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_0061: ldarg.0 + IL_0062: ldfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_0067: stloc.1 + IL_0068: ldarg.0 + IL_0069: ldflda ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_006e: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0074: br.s IL_0076 + IL_0076: ldloca.s V_1 + IL_0078: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_007d: nop + IL_007e: ldloca.s V_1 + IL_0080: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0086: call ""Sub C.End()"" + IL_008b: nop + IL_008c: leave.s IL_00b1 } catch System.Exception { - IL_008c: dup - IL_008d: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" - IL_0092: stloc.3 - IL_0093: ldarg.0 - IL_0094: ldc.i4.s -2 - IL_0096: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_009b: ldarg.0 - IL_009c: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_00a1: ldloc.3 - IL_00a2: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_00a7: nop - IL_00a8: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" - IL_00ad: leave.s IL_00c5 + IL_008e: dup + IL_008f: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" + IL_0094: stloc.3 + IL_0095: ldarg.0 + IL_0096: ldc.i4.s -2 + IL_0098: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_009d: ldarg.0 + IL_009e: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_00a3: ldloc.3 + IL_00a4: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_00a9: nop + IL_00aa: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" + IL_00af: leave.s IL_00c7 } - IL_00af: ldarg.0 - IL_00b0: ldc.i4.s -2 - IL_00b2: dup - IL_00b3: stloc.0 - IL_00b4: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_00b9: ldarg.0 - IL_00ba: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_00bf: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_00c4: nop - IL_00c5: ret + IL_00b1: ldarg.0 + IL_00b2: ldc.i4.s -2 + IL_00b4: dup + IL_00b5: stloc.0 + IL_00b6: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_00bb: ldarg.0 + IL_00bc: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_00c1: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_00c6: nop + IL_00c7: ret }") End Using End Sub @@ -2831,7 +2872,7 @@ End Class") }") diff1.VerifyIL("C._Closure$__.VB$StateMachine___Lambda$__0-1.MoveNext", " { - // Code size 201 (0xc9) + // Code size 203 (0xcb) .maxstack 3 .locals init (Integer V_0, System.Threading.Tasks.Task V_1, @@ -2847,84 +2888,85 @@ End Class") IL_0008: ldc.i4.1 IL_0009: beq.s IL_000d IL_000b: br.s IL_000f - IL_000d: br.s IL_0057 + IL_000d: br.s IL_0059 IL_000f: ldloc.0 IL_0010: ldc.i4.0 - IL_0011: blt.s IL_001e + IL_0011: blt.s IL_0020 IL_0013: ldstr """ & CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod & """ - IL_0018: newobj ""Sub System.InvalidOperationException..ctor(String)"" - IL_001d: throw - IL_001e: nop - IL_001f: call ""Function C.M2() As System.Threading.Tasks.Task"" - IL_0024: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0029: stloc.2 - IL_002a: ldloca.s V_2 - IL_002c: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" - IL_0031: brtrue.s IL_0075 - IL_0033: ldarg.0 - IL_0034: ldc.i4.1 - IL_0035: dup - IL_0036: stloc.0 - IL_0037: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" - IL_003c: ldarg.0 - IL_003d: ldloc.2 - IL_003e: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0043: ldarg.0 - IL_0044: ldflda ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_0049: ldloca.s V_2 - IL_004b: ldarg.0 - IL_004c: stloc.3 - IL_004d: ldloca.s V_3 - IL_004f: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C._Closure$__.VB$StateMachine___Lambda$__0-1)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C._Closure$__.VB$StateMachine___Lambda$__0-1)"" - IL_0054: nop - IL_0055: leave.s IL_00c8 - IL_0057: ldarg.0 - IL_0058: ldc.i4.m1 - IL_0059: dup - IL_005a: stloc.0 - IL_005b: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" - IL_0060: ldarg.0 - IL_0061: ldfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0066: stloc.2 - IL_0067: ldarg.0 - IL_0068: ldflda ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_006d: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0073: br.s IL_0075 - IL_0075: ldloca.s V_2 - IL_0077: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_007c: nop - IL_007d: ldloca.s V_2 - IL_007f: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0085: call ""Sub C.End()"" - IL_008a: nop - IL_008b: leave.s IL_00b2 + IL_0018: ldc.i4.s -4 + IL_001a: newobj ""Sub System.Runtime.CompilerServices.HotReloadException..ctor(String, Integer)"" + IL_001f: throw + IL_0020: nop + IL_0021: call ""Function C.M2() As System.Threading.Tasks.Task"" + IL_0026: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" + IL_002b: stloc.2 + IL_002c: ldloca.s V_2 + IL_002e: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" + IL_0033: brtrue.s IL_0077 + IL_0035: ldarg.0 + IL_0036: ldc.i4.1 + IL_0037: dup + IL_0038: stloc.0 + IL_0039: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" + IL_003e: ldarg.0 + IL_003f: ldloc.2 + IL_0040: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_0045: ldarg.0 + IL_0046: ldflda ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_004b: ldloca.s V_2 + IL_004d: ldarg.0 + IL_004e: stloc.3 + IL_004f: ldloca.s V_3 + IL_0051: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C._Closure$__.VB$StateMachine___Lambda$__0-1)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C._Closure$__.VB$StateMachine___Lambda$__0-1)"" + IL_0056: nop + IL_0057: leave.s IL_00ca + IL_0059: ldarg.0 + IL_005a: ldc.i4.m1 + IL_005b: dup + IL_005c: stloc.0 + IL_005d: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" + IL_0062: ldarg.0 + IL_0063: ldfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_0068: stloc.2 + IL_0069: ldarg.0 + IL_006a: ldflda ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_006f: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0075: br.s IL_0077 + IL_0077: ldloca.s V_2 + IL_0079: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_007e: nop + IL_007f: ldloca.s V_2 + IL_0081: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0087: call ""Sub C.End()"" + IL_008c: nop + IL_008d: leave.s IL_00b4 } catch System.Exception { - IL_008d: dup - IL_008e: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" - IL_0093: stloc.s V_4 - IL_0095: ldarg.0 - IL_0096: ldc.i4.s -2 - IL_0098: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" - IL_009d: ldarg.0 - IL_009e: ldflda ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_00a3: ldloc.s V_4 - IL_00a5: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_00aa: nop - IL_00ab: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" - IL_00b0: leave.s IL_00c8 + IL_008f: dup + IL_0090: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" + IL_0095: stloc.s V_4 + IL_0097: ldarg.0 + IL_0098: ldc.i4.s -2 + IL_009a: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" + IL_009f: ldarg.0 + IL_00a0: ldflda ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_00a5: ldloc.s V_4 + IL_00a7: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_00ac: nop + IL_00ad: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" + IL_00b2: leave.s IL_00ca } - IL_00b2: ldarg.0 - IL_00b3: ldc.i4.s -2 - IL_00b5: dup - IL_00b6: stloc.0 - IL_00b7: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" - IL_00bc: ldarg.0 - IL_00bd: ldflda ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_00c2: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_00c7: nop - IL_00c8: ret + IL_00b4: ldarg.0 + IL_00b5: ldc.i4.s -2 + IL_00b7: dup + IL_00b8: stloc.0 + IL_00b9: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" + IL_00be: ldarg.0 + IL_00bf: ldflda ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_00c4: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_00c9: nop + IL_00ca: ret }") End Sub @@ -2995,7 +3037,7 @@ End Class") diff1.VerifyIL("C.VB$StateMachine_5_F.MoveNext", " { - // Code size 199 (0xc7) + // Code size 201 (0xc9) .maxstack 3 .locals init (Integer V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -3010,84 +3052,85 @@ End Class") IL_0008: ldc.i4.1 IL_0009: beq.s IL_000d IL_000b: br.s IL_000f - IL_000d: br.s IL_0057 + IL_000d: br.s IL_0059 IL_000f: ldloc.0 IL_0010: ldc.i4.0 - IL_0011: blt.s IL_001e + IL_0011: blt.s IL_0020 IL_0013: ldstr """ & CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod & """ - IL_0018: newobj ""Sub System.InvalidOperationException..ctor(String)"" - IL_001d: throw - IL_001e: nop - IL_001f: call ""Function C.M2() As System.Threading.Tasks.Task"" - IL_0024: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0029: stloc.1 - IL_002a: ldloca.s V_1 - IL_002c: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" - IL_0031: brtrue.s IL_0075 - IL_0033: ldarg.0 - IL_0034: ldc.i4.1 - IL_0035: dup - IL_0036: stloc.0 - IL_0037: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_003c: ldarg.0 - IL_003d: ldloc.1 - IL_003e: stfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0043: ldarg.0 - IL_0044: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_0049: ldloca.s V_1 - IL_004b: ldarg.0 - IL_004c: stloc.2 - IL_004d: ldloca.s V_2 - IL_004f: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C.VB$StateMachine_5_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C.VB$StateMachine_5_F)"" - IL_0054: nop - IL_0055: leave.s IL_00c6 - IL_0057: ldarg.0 - IL_0058: ldc.i4.m1 - IL_0059: dup - IL_005a: stloc.0 - IL_005b: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_0060: ldarg.0 - IL_0061: ldfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0066: stloc.1 - IL_0067: ldarg.0 - IL_0068: ldflda ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_006d: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0073: br.s IL_0075 - IL_0075: ldloca.s V_1 - IL_0077: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_007c: nop - IL_007d: ldloca.s V_1 - IL_007f: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_0085: call ""Sub C.End()"" - IL_008a: nop - IL_008b: leave.s IL_00b0 + IL_0018: ldc.i4.s -4 + IL_001a: newobj ""Sub System.Runtime.CompilerServices.HotReloadException..ctor(String, Integer)"" + IL_001f: throw + IL_0020: nop + IL_0021: call ""Function C.M2() As System.Threading.Tasks.Task"" + IL_0026: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" + IL_002b: stloc.1 + IL_002c: ldloca.s V_1 + IL_002e: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" + IL_0033: brtrue.s IL_0077 + IL_0035: ldarg.0 + IL_0036: ldc.i4.1 + IL_0037: dup + IL_0038: stloc.0 + IL_0039: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_003e: ldarg.0 + IL_003f: ldloc.1 + IL_0040: stfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_0045: ldarg.0 + IL_0046: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_004b: ldloca.s V_1 + IL_004d: ldarg.0 + IL_004e: stloc.2 + IL_004f: ldloca.s V_2 + IL_0051: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C.VB$StateMachine_5_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C.VB$StateMachine_5_F)"" + IL_0056: nop + IL_0057: leave.s IL_00c8 + IL_0059: ldarg.0 + IL_005a: ldc.i4.m1 + IL_005b: dup + IL_005c: stloc.0 + IL_005d: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_0062: ldarg.0 + IL_0063: ldfld ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_0068: stloc.1 + IL_0069: ldarg.0 + IL_006a: ldflda ""C.VB$StateMachine_5_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_006f: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0075: br.s IL_0077 + IL_0077: ldloca.s V_1 + IL_0079: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_007e: nop + IL_007f: ldloca.s V_1 + IL_0081: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0087: call ""Sub C.End()"" + IL_008c: nop + IL_008d: leave.s IL_00b2 } catch System.Exception { - IL_008d: dup - IL_008e: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" - IL_0093: stloc.3 - IL_0094: ldarg.0 - IL_0095: ldc.i4.s -2 - IL_0097: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_009c: ldarg.0 - IL_009d: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_00a2: ldloc.3 - IL_00a3: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_00a8: nop - IL_00a9: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" - IL_00ae: leave.s IL_00c6 + IL_008f: dup + IL_0090: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" + IL_0095: stloc.3 + IL_0096: ldarg.0 + IL_0097: ldc.i4.s -2 + IL_0099: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_009e: ldarg.0 + IL_009f: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_00a4: ldloc.3 + IL_00a5: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_00aa: nop + IL_00ab: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" + IL_00b0: leave.s IL_00c8 } - IL_00b0: ldarg.0 - IL_00b1: ldc.i4.s -2 - IL_00b3: dup - IL_00b4: stloc.0 - IL_00b5: stfld ""C.VB$StateMachine_5_F.$State As Integer"" - IL_00ba: ldarg.0 - IL_00bb: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_00c0: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_00c5: nop - IL_00c6: ret + IL_00b2: ldarg.0 + IL_00b3: ldc.i4.s -2 + IL_00b5: dup + IL_00b6: stloc.0 + IL_00b7: stfld ""C.VB$StateMachine_5_F.$State As Integer"" + IL_00bc: ldarg.0 + IL_00bd: ldflda ""C.VB$StateMachine_5_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_00c2: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_00c7: nop + IL_00c8: ret } ") End Using @@ -3382,7 +3425,7 @@ End Try }") diff1.VerifyIL("C.VB$StateMachine_8_F.MoveNext", " { - // Code size 263 (0x107) + // Code size 265 (0x109) .maxstack 3 .locals init (Integer V_0, System.Runtime.CompilerServices.TaskAwaiter V_1, @@ -3401,117 +3444,118 @@ End Try IL_000f: ldc.i4.1 IL_0010: beq.s IL_0014 IL_0012: br.s IL_0016 - IL_0014: br.s IL_002c + IL_0014: br.s IL_002e IL_0016: ldloc.0 IL_0017: ldc.i4.0 - IL_0018: blt.s IL_0025 + IL_0018: blt.s IL_0027 IL_001a: ldstr """ & CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod & """ - IL_001f: newobj ""Sub System.InvalidOperationException..ctor(String)"" - IL_0024: throw - IL_0025: nop - IL_0026: call ""Sub C.Start()"" - IL_002b: nop - IL_002c: nop + IL_001f: ldc.i4.s -4 + IL_0021: newobj ""Sub System.Runtime.CompilerServices.HotReloadException..ctor(String, Integer)"" + IL_0026: throw + IL_0027: nop + IL_0028: call ""Sub C.Start()"" + IL_002d: nop + IL_002e: nop .try { - IL_002d: ldloc.0 - IL_002e: ldc.i4.s -3 - IL_0030: beq.s IL_003a - IL_0032: br.s IL_0034 - IL_0034: ldloc.0 - IL_0035: ldc.i4.1 - IL_0036: beq.s IL_003c - IL_0038: br.s IL_003e + IL_002f: ldloc.0 + IL_0030: ldc.i4.s -3 + IL_0032: beq.s IL_003c + IL_0034: br.s IL_0036 + IL_0036: ldloc.0 + IL_0037: ldc.i4.1 + IL_0038: beq.s IL_003e IL_003a: br.s IL_0040 - IL_003c: br.s IL_0087 - IL_003e: br.s IL_004e - IL_0040: ldarg.0 - IL_0041: ldc.i4.m1 - IL_0042: dup - IL_0043: stloc.0 - IL_0044: stfld ""C.VB$StateMachine_8_F.$State As Integer"" - IL_0049: leave IL_0106 - IL_004e: nop - IL_004f: call ""Function C.M2() As System.Threading.Tasks.Task"" - IL_0054: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0059: stloc.1 - IL_005a: ldloca.s V_1 - IL_005c: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" - IL_0061: brtrue.s IL_00a5 - IL_0063: ldarg.0 - IL_0064: ldc.i4.1 - IL_0065: dup - IL_0066: stloc.0 - IL_0067: stfld ""C.VB$StateMachine_8_F.$State As Integer"" - IL_006c: ldarg.0 - IL_006d: ldloc.1 - IL_006e: stfld ""C.VB$StateMachine_8_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0073: ldarg.0 - IL_0074: ldflda ""C.VB$StateMachine_8_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_0079: ldloca.s V_1 - IL_007b: ldarg.0 - IL_007c: stloc.2 - IL_007d: ldloca.s V_2 - IL_007f: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C.VB$StateMachine_8_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C.VB$StateMachine_8_F)"" - IL_0084: nop - IL_0085: leave.s IL_0106 - IL_0087: ldarg.0 - IL_0088: ldc.i4.m1 - IL_0089: dup - IL_008a: stloc.0 - IL_008b: stfld ""C.VB$StateMachine_8_F.$State As Integer"" - IL_0090: ldarg.0 - IL_0091: ldfld ""C.VB$StateMachine_8_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_0096: stloc.1 - IL_0097: ldarg.0 - IL_0098: ldflda ""C.VB$StateMachine_8_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" - IL_009d: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00a3: br.s IL_00a5 - IL_00a5: ldloca.s V_1 - IL_00a7: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" - IL_00ac: nop - IL_00ad: ldloca.s V_1 - IL_00af: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" - IL_00b5: leave.s IL_00c4 + IL_003c: br.s IL_0042 + IL_003e: br.s IL_0089 + IL_0040: br.s IL_0050 + IL_0042: ldarg.0 + IL_0043: ldc.i4.m1 + IL_0044: dup + IL_0045: stloc.0 + IL_0046: stfld ""C.VB$StateMachine_8_F.$State As Integer"" + IL_004b: leave IL_0108 + IL_0050: nop + IL_0051: call ""Function C.M2() As System.Threading.Tasks.Task"" + IL_0056: callvirt ""Function System.Threading.Tasks.Task.GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter"" + IL_005b: stloc.1 + IL_005c: ldloca.s V_1 + IL_005e: call ""Function System.Runtime.CompilerServices.TaskAwaiter.get_IsCompleted() As Boolean"" + IL_0063: brtrue.s IL_00a7 + IL_0065: ldarg.0 + IL_0066: ldc.i4.1 + IL_0067: dup + IL_0068: stloc.0 + IL_0069: stfld ""C.VB$StateMachine_8_F.$State As Integer"" + IL_006e: ldarg.0 + IL_006f: ldloc.1 + IL_0070: stfld ""C.VB$StateMachine_8_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_0075: ldarg.0 + IL_0076: ldflda ""C.VB$StateMachine_8_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_007b: ldloca.s V_1 + IL_007d: ldarg.0 + IL_007e: stloc.2 + IL_007f: ldloca.s V_2 + IL_0081: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter, C.VB$StateMachine_8_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter, ByRef C.VB$StateMachine_8_F)"" + IL_0086: nop + IL_0087: leave.s IL_0108 + IL_0089: ldarg.0 + IL_008a: ldc.i4.m1 + IL_008b: dup + IL_008c: stloc.0 + IL_008d: stfld ""C.VB$StateMachine_8_F.$State As Integer"" + IL_0092: ldarg.0 + IL_0093: ldfld ""C.VB$StateMachine_8_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_0098: stloc.1 + IL_0099: ldarg.0 + IL_009a: ldflda ""C.VB$StateMachine_8_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter"" + IL_009f: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00a5: br.s IL_00a7 + IL_00a7: ldloca.s V_1 + IL_00a9: call ""Sub System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00ae: nop + IL_00af: ldloca.s V_1 + IL_00b1: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00b7: leave.s IL_00c6 } catch System.Exception { - IL_00b7: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" - IL_00bc: nop - IL_00bd: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" - IL_00c2: leave.s IL_00c4 + IL_00b9: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" + IL_00be: nop + IL_00bf: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" + IL_00c4: leave.s IL_00c6 } - IL_00c4: nop - IL_00c5: call ""Sub C.End()"" - IL_00ca: nop - IL_00cb: leave.s IL_00f0 + IL_00c6: nop + IL_00c7: call ""Sub C.End()"" + IL_00cc: nop + IL_00cd: leave.s IL_00f2 } catch System.Exception { - IL_00cd: dup - IL_00ce: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" - IL_00d3: stloc.3 - IL_00d4: ldarg.0 - IL_00d5: ldc.i4.s -2 - IL_00d7: stfld ""C.VB$StateMachine_8_F.$State As Integer"" - IL_00dc: ldarg.0 - IL_00dd: ldflda ""C.VB$StateMachine_8_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_00e2: ldloc.3 - IL_00e3: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" - IL_00e8: nop - IL_00e9: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" - IL_00ee: leave.s IL_0106 + IL_00cf: dup + IL_00d0: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)"" + IL_00d5: stloc.3 + IL_00d6: ldarg.0 + IL_00d7: ldc.i4.s -2 + IL_00d9: stfld ""C.VB$StateMachine_8_F.$State As Integer"" + IL_00de: ldarg.0 + IL_00df: ldflda ""C.VB$StateMachine_8_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_00e4: ldloc.3 + IL_00e5: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_00ea: nop + IL_00eb: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()"" + IL_00f0: leave.s IL_0108 } - IL_00f0: ldarg.0 - IL_00f1: ldc.i4.s -2 - IL_00f3: dup - IL_00f4: stloc.0 - IL_00f5: stfld ""C.VB$StateMachine_8_F.$State As Integer"" - IL_00fa: ldarg.0 - IL_00fb: ldflda ""C.VB$StateMachine_8_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" - IL_0100: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" - IL_0105: nop - IL_0106: ret + IL_00f2: ldarg.0 + IL_00f3: ldc.i4.s -2 + IL_00f5: dup + IL_00f6: stloc.0 + IL_00f7: stfld ""C.VB$StateMachine_8_F.$State As Integer"" + IL_00fc: ldarg.0 + IL_00fd: ldflda ""C.VB$StateMachine_8_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder"" + IL_0102: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_0107: nop + IL_0108: ret }") End Using End Sub @@ -3968,7 +4012,7 @@ End Class") Dim compilation1 = compilation0.WithSource(source1.Tree) Dim v0 = CompileAndVerify(compilation:=compilation0, symbolValidator:=Sub([module] As ModuleSymbol) - Assert.Equal( + AssertEx.Equal( { "$State: System.Int32", "$Current: System.Int32", @@ -3981,7 +4025,7 @@ End Class") End Sub) Dim v1 = CompileAndVerify(compilation:=compilation1, symbolValidator:=Sub([module] As ModuleSymbol) - Assert.Equal( + AssertEx.Equal( { "$State: System.Int32", "$Current: System.Int32", @@ -4434,7 +4478,7 @@ End Class" diff1.VerifyIL("C.VB$StateMachine_6_F.MoveNext", " { - // Code size 134 (0x86) + // Code size 136 (0x88) .maxstack 3 .locals init (Boolean V_0, Integer V_1) @@ -4448,61 +4492,58 @@ End Class" IL_0021, IL_0023) IL_001d: br.s IL_0025 - IL_001f: br.s IL_0036 - IL_0021: br.s IL_0056 - IL_0023: br.s IL_0075 + IL_001f: br.s IL_0038 + IL_0021: br.s IL_0058 + IL_0023: br.s IL_0077 IL_0025: ldloc.1 IL_0026: ldc.i4.1 - IL_0027: blt.s IL_0034 + IL_0027: blt.s IL_0036 IL_0029: ldstr """ & CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod & """ - IL_002e: newobj ""Sub System.InvalidOperationException..ctor(String)"" - IL_0033: throw - - IL_0034: ldc.i4.0 - IL_0035: ret - - IL_0036: ldarg.0 - IL_0037: ldc.i4.m1 - IL_0038: dup - IL_0039: stloc.1 - IL_003a: stfld ""C.VB$StateMachine_6_F.$State As Integer"" - IL_003f: nop - IL_0040: ldarg.0 - IL_0041: call ""Function C.M2() As Integer"" - IL_0046: stfld ""C.VB$StateMachine_6_F.$Current As Integer"" - IL_004b: ldarg.0 - IL_004c: ldc.i4.2 - IL_004d: dup - IL_004e: stloc.1 - IL_004f: stfld ""C.VB$StateMachine_6_F.$State As Integer"" - IL_0054: ldc.i4.1 - IL_0055: ret - - IL_0056: ldarg.0 - IL_0057: ldc.i4.m1 - IL_0058: dup - IL_0059: stloc.1 - IL_005a: stfld ""C.VB$StateMachine_6_F.$State As Integer"" - IL_005f: ldarg.0 - IL_0060: call ""Function C.M3() As Integer"" - IL_0065: stfld ""C.VB$StateMachine_6_F.$Current As Integer"" - IL_006a: ldarg.0 - IL_006b: ldc.i4.3 - IL_006c: dup - IL_006d: stloc.1 - IL_006e: stfld ""C.VB$StateMachine_6_F.$State As Integer"" - IL_0073: ldc.i4.1 - IL_0074: ret - - IL_0075: ldarg.0 - IL_0076: ldc.i4.m1 - IL_0077: dup - IL_0078: stloc.1 - IL_0079: stfld ""C.VB$StateMachine_6_F.$State As Integer"" - IL_007e: call ""Sub C.End()"" - IL_0083: nop - IL_0084: ldc.i4.0 - IL_0085: ret + IL_002e: ldc.i4.s -3 + IL_0030: newobj ""Sub System.Runtime.CompilerServices.HotReloadException..ctor(String, Integer)"" + IL_0035: throw + IL_0036: ldc.i4.0 + IL_0037: ret + IL_0038: ldarg.0 + IL_0039: ldc.i4.m1 + IL_003a: dup + IL_003b: stloc.1 + IL_003c: stfld ""C.VB$StateMachine_6_F.$State As Integer"" + IL_0041: nop + IL_0042: ldarg.0 + IL_0043: call ""Function C.M2() As Integer"" + IL_0048: stfld ""C.VB$StateMachine_6_F.$Current As Integer"" + IL_004d: ldarg.0 + IL_004e: ldc.i4.2 + IL_004f: dup + IL_0050: stloc.1 + IL_0051: stfld ""C.VB$StateMachine_6_F.$State As Integer"" + IL_0056: ldc.i4.1 + IL_0057: ret + IL_0058: ldarg.0 + IL_0059: ldc.i4.m1 + IL_005a: dup + IL_005b: stloc.1 + IL_005c: stfld ""C.VB$StateMachine_6_F.$State As Integer"" + IL_0061: ldarg.0 + IL_0062: call ""Function C.M3() As Integer"" + IL_0067: stfld ""C.VB$StateMachine_6_F.$Current As Integer"" + IL_006c: ldarg.0 + IL_006d: ldc.i4.3 + IL_006e: dup + IL_006f: stloc.1 + IL_0070: stfld ""C.VB$StateMachine_6_F.$State As Integer"" + IL_0075: ldc.i4.1 + IL_0076: ret + IL_0077: ldarg.0 + IL_0078: ldc.i4.m1 + IL_0079: dup + IL_007a: stloc.1 + IL_007b: stfld ""C.VB$StateMachine_6_F.$State As Integer"" + IL_0080: call ""Sub C.End()"" + IL_0085: nop + IL_0086: ldc.i4.0 + IL_0087: ret }") End Using End Sub @@ -4784,7 +4825,7 @@ End Class") }") diff1.VerifyIL("C._Closure$__.VB$StateMachine___Lambda$__0-1.MoveNext", " { - // Code size 88 (0x58) + // Code size 90 (0x5a) .maxstack 3 .locals init (Boolean V_0, Integer V_1, @@ -4799,42 +4840,44 @@ End Class") IL_000d: ldc.i4.2 IL_000e: beq.s IL_0014 IL_0010: br.s IL_0016 - IL_0012: br.s IL_0027 - IL_0014: br.s IL_0047 + IL_0012: br.s IL_0029 + IL_0014: br.s IL_0049 IL_0016: ldloc.1 IL_0017: ldc.i4.1 - IL_0018: blt.s IL_0025 + IL_0018: blt.s IL_0027 IL_001a: ldstr """ & CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod & """ - IL_001f: newobj ""Sub System.InvalidOperationException..ctor(String)"" - IL_0024: throw - IL_0025: ldc.i4.0 - IL_0026: ret - IL_0027: ldarg.0 - IL_0028: ldc.i4.m1 - IL_0029: dup - IL_002a: stloc.1 - IL_002b: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" - IL_0030: nop - IL_0031: ldarg.0 - IL_0032: call ""Function C.M2() As Integer"" - IL_0037: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$Current As Integer"" - IL_003c: ldarg.0 - IL_003d: ldc.i4.2 - IL_003e: dup - IL_003f: stloc.1 - IL_0040: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" - IL_0045: ldc.i4.1 - IL_0046: ret - IL_0047: ldarg.0 - IL_0048: ldc.i4.m1 - IL_0049: dup - IL_004a: stloc.1 - IL_004b: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" - IL_0050: call ""Sub C.End()"" - IL_0055: nop - IL_0056: ldc.i4.0 - IL_0057: ret -}") + IL_001f: ldc.i4.s -3 + IL_0021: newobj ""Sub System.Runtime.CompilerServices.HotReloadException..ctor(String, Integer)"" + IL_0026: throw + IL_0027: ldc.i4.0 + IL_0028: ret + IL_0029: ldarg.0 + IL_002a: ldc.i4.m1 + IL_002b: dup + IL_002c: stloc.1 + IL_002d: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" + IL_0032: nop + IL_0033: ldarg.0 + IL_0034: call ""Function C.M2() As Integer"" + IL_0039: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$Current As Integer"" + IL_003e: ldarg.0 + IL_003f: ldc.i4.2 + IL_0040: dup + IL_0041: stloc.1 + IL_0042: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" + IL_0047: ldc.i4.1 + IL_0048: ret + IL_0049: ldarg.0 + IL_004a: ldc.i4.m1 + IL_004b: dup + IL_004c: stloc.1 + IL_004d: stfld ""C._Closure$__.VB$StateMachine___Lambda$__0-1.$State As Integer"" + IL_0052: call ""Sub C.End()"" + IL_0057: nop + IL_0058: ldc.i4.0 + IL_0059: ret +} +") End Sub @@ -7027,7 +7070,7 @@ End Class") Dim h3 = compilation3.GetMember(Of MethodSymbol)("C.H") Dim v0 = CompileAndVerify(compilation:=compilation0, symbolValidator:=Sub([module] As ModuleSymbol) - Assert.Equal( + AssertEx.Equal( { "$State: System.Int32", "$Builder: System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of System.Int32)", @@ -7374,7 +7417,7 @@ End Class Dim compilation0 = CreateEmptyCompilationWithReferences(source0, references:=LatestVbReferences, options:=ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) CompileAndVerify(compilation:=compilation0, symbolValidator:=Sub([module] As ModuleSymbol) - Assert.Equal( + AssertEx.Equal( { "$State: System.Int32", "$Builder: System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of System.Int32)", @@ -7383,7 +7426,7 @@ End Class "$A1: System.Runtime.CompilerServices.TaskAwaiter(Of System.Int32)" }, [module].GetFieldNamesAndTypes("C.VB$StateMachine_4_F")) - Assert.Equal( + AssertEx.Equal( { "$State: System.Int32", "$Builder: System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of System.Int32)", @@ -7528,7 +7571,7 @@ End Class") Dim v0 = CompileAndVerify(compilation:=compilation0, symbolValidator:= Sub([module] As ModuleSymbol) - Assert.Equal( + AssertEx.Equal( { "$State: System.Int32", "$Builder: System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of System.Int32)", @@ -8126,13 +8169,13 @@ Class C End Function End Class") - Dim compilation0 = CreateCompilationWithMscorlib45AndVBRuntime({source0.Tree}, options:=ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) + Dim compilation0 = CreateCompilationWithMscorlib461AndVBRuntime({source0.Tree}, options:=ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)) Dim compilation1 = compilation0.WithSource(source1.Tree) Dim compilation2 = compilation1.WithSource(source2.Tree) Dim v0 = CompileAndVerify(compilation0, symbolValidator:= Sub([module]) - Assert.Equal( + AssertEx.Equal( { "$State: System.Int32", "$Builder: System.Runtime.CompilerServices.AsyncTaskMethodBuilder", @@ -8210,7 +8253,7 @@ Class C Shared Sub G(f As Func(Of Integer)) End Sub End Class") - Dim compilation0 = CreateCompilationWithMscorlib45AndVBRuntime({source0.Tree}, options:=ComSafeDebugDll) + Dim compilation0 = CreateCompilationWithMscorlib461AndVBRuntime({source0.Tree}, options:=ComSafeDebugDll) Dim compilation1 = compilation0.WithSource(source1.Tree) Dim m0 = compilation0.GetMember(Of MethodSymbol)("C.M") @@ -8328,7 +8371,7 @@ Class C Return Task.FromResult(1) End Function End Class") - Dim compilation0 = CreateCompilationWithMscorlib45AndVBRuntime({source0.Tree}, options:=ComSafeDebugDll) + Dim compilation0 = CreateCompilationWithMscorlib461AndVBRuntime({source0.Tree}, options:=ComSafeDebugDll) Dim compilation1 = compilation0.WithSource(source1.Tree) Dim m0 = compilation0.GetMember(Of MethodSymbol)("C.M") @@ -8436,7 +8479,7 @@ Class C End Function End Class ") - Dim compilation0 = CreateCompilationWithMscorlib45({source0.Tree}, options:=ComSafeDebugDll) + Dim compilation0 = CreateCompilationWithMscorlib461({source0.Tree}, options:=ComSafeDebugDll) Dim compilation1 = compilation0.WithSource(source1.Tree) Dim compilation2 = compilation1.WithSource(source2.Tree) @@ -8568,7 +8611,7 @@ Class C End Function End Class ") - Dim compilation0 = CreateCompilationWithMscorlib45({source0.Tree}, options:=ComSafeDebugDll) + Dim compilation0 = CreateCompilationWithMscorlib461({source0.Tree}, options:=ComSafeDebugDll) Dim compilation1 = compilation0.WithSource(source1.Tree) Dim compilation2 = compilation1.WithSource(source2.Tree) @@ -8701,7 +8744,7 @@ End Class Dim source4 = source0 Dim source5 = source1 - Dim compilation0 = CreateCompilationWithMscorlib45AndVBRuntime({source0.Tree}, {SystemCoreRef}, options:=ComSafeDebugDll) + Dim compilation0 = CreateCompilationWithMscorlib461AndVBRuntime({source0.Tree}, {SystemCoreRef}, options:=ComSafeDebugDll) Dim compilation1 = compilation0.WithSource(source1.Tree) Dim compilation2 = compilation0.WithSource(source2.Tree) Dim compilation3 = compilation0.WithSource(source3.Tree) @@ -8822,7 +8865,7 @@ End Class ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))) diff1.EmitResult.Diagnostics.Verify( - Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("Public Function F() As IEnumerable(Of Integer)", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(6, 30)) + Diagnostic(ERRID.ERR_EncUpdateFailedMissingSymbol, "F").WithArguments(CodeAnalysisResources.Attribute, "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(6, 30)) End Sub @@ -8880,7 +8923,7 @@ End Class ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))) diff1.EmitResult.Diagnostics.Verify( - Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("Public Function F() As IEnumerable(Of Integer)", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(12, 30)) + Diagnostic(ERRID.ERR_EncUpdateFailedMissingSymbol, "F").WithArguments(CodeAnalysisResources.Attribute, "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(12, 30)) End Sub @@ -9051,7 +9094,8 @@ End Class ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))) diff1.EmitResult.Diagnostics.Verify( - Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("Public Function F() As Task(Of Integer)", "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(15, 27)) + Diagnostic(ERRID.ERR_EncUpdateFailedMissingSymbol).WithArguments(CodeAnalysisResources.Constructor, "System.Exception..ctor(string)").WithLocation(1, 1), + Diagnostic(ERRID.ERR_EncUpdateFailedMissingSymbol, "F").WithArguments(CodeAnalysisResources.Attribute, "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(15, 27)) End Sub @@ -9072,7 +9116,7 @@ Class C End Function End Class ") - Dim compilation0 = CompilationUtils.CreateEmptyCompilation({source0.Tree}, {TestMetadata.Net451.mscorlib}, options:=ComSafeDebugDll) + Dim compilation0 = CompilationUtils.CreateEmptyCompilation({source0.Tree}, {NetFramework.mscorlib}, options:=ComSafeDebugDll) Dim compilation1 = compilation0.WithSource(source1.Tree) Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)) @@ -9128,7 +9172,8 @@ End Class ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))) diff1.EmitResult.Diagnostics.Verify( - Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("Public Function F() As Task(Of Integer)", "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(15, 27)) + Diagnostic(ERRID.ERR_EncUpdateFailedMissingSymbol).WithArguments(CodeAnalysisResources.Constructor, "System.Exception..ctor(string)").WithLocation(1, 1), + Diagnostic(ERRID.ERR_EncUpdateFailedMissingSymbol, "F").WithArguments(CodeAnalysisResources.Attribute, "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(15, 27)) End Sub @@ -9167,7 +9212,7 @@ End Class ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1)))) diff1.EmitResult.Diagnostics.Verify( - Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("Public Function F() As IEnumerable(Of Integer)", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(5, 30)) + Diagnostic(ERRID.ERR_EncUpdateFailedMissingSymbol, "F").WithArguments(CodeAnalysisResources.Attribute, "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(5, 30)) End Sub End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.vb index c6baeca616c75..1539a9fec8dd4 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTest.vb @@ -7,6 +7,7 @@ Imports Microsoft.CodeAnalysis.EditAndContinue.UnitTests Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests +Imports Xunit.Abstractions Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests @@ -17,23 +18,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests Private ReadOnly _parseOptions As VisualBasicParseOptions Private ReadOnly _targetFramework As TargetFramework Private ReadOnly _references As IEnumerable(Of MetadataReference) + Private ReadOnly _assemblyName As String - Sub New(Optional options As VisualBasicCompilationOptions = Nothing, + Sub New(Optional output As ITestOutputHelper = Nothing, + Optional options As VisualBasicCompilationOptions = Nothing, Optional parseOptions As VisualBasicParseOptions = Nothing, Optional targetFramework As TargetFramework = TargetFramework.StandardAndVBRuntime, Optional references As IEnumerable(Of MetadataReference) = Nothing, + Optional assemblyName As String = "", Optional verification As Verification? = Nothing) - MyBase.New(verification) + MyBase.New(output, verification) _options = If(options, TestOptions.DebugDll).WithConcurrentBuild(False) _parseOptions = If(parseOptions, TestOptions.Regular) _targetFramework = targetFramework _references = references + _assemblyName = assemblyName End Sub Protected Overrides Function CreateCompilation(tree As SyntaxTree) As Compilation - Return CompilationUtils.CreateCompilation(tree, _references, options:=_options, targetFramework:=_targetFramework) + Return CompilationUtils.CreateCompilation(tree, _references, options:=_options, assemblyName:=_assemblyName, targetFramework:=_targetFramework) End Function Protected Overrides Function CreateSourceWithMarkedNodes(source As String) As SourceWithMarkedNodes diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb index d538ab6ee456d..7fa811e5b6e87 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports System.IO +Imports System.Reflection Imports System.Reflection.Metadata Imports System.Reflection.Metadata.Ecma335 Imports Microsoft.CodeAnalysis @@ -19,6 +20,43 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class EditAndContinueTests Inherits EditAndContinueTestBase + + + + + Public Sub SymReaderErrors(exceptionType As Type) + Using New EditAndContinueTest(assemblyName:="test"). + AddBaseline( + source:=" + Class C + Sub F() + Dim x = 1 + End Sub + End Class + ", + debugInformationProvider:=Function(method) + Throw DirectCast(Activator.CreateInstance(exceptionType, {"bug!"}), Exception) + End Function). + AddGeneration(' 1 + source:=" + Class C + Sub F() + Dim x = 2 + End Sub + End Class + ", + edits:= + { + Edit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"), preserveLocalVariables:=True) + }, + expectedErrors:= + { + Diagnostic(ERRID.ERR_InvalidDebugInfo, "F").WithArguments("Public Sub F()", &H6000002, "test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "bug!").WithLocation(3, 29) + }). + Verify() + End Using + End Sub + Public Sub SemanticErrors_MethodBody() Dim source0 = MarkedSource(" @@ -320,7 +358,7 @@ End Class ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, method0, method1))) Dim methods = diff1.TestData.GetMethodsByName() - Assert.Equal(methods.Count, 1) + Assert.Equal(methods.Count, 2) Assert.True(methods.ContainsKey("C.M2()")) Using md1 = diff1.GetMetadata() @@ -786,7 +824,7 @@ Class C End Class ") - Dim compilation0 = CreateCompilationWithMscorlib45AndVBRuntime({source0.Tree}, options:=ComSafeDebugDll) + Dim compilation0 = CreateCompilationWithMscorlib461AndVBRuntime({source0.Tree}, options:=ComSafeDebugDll) Dim compilation1 = compilation0.WithSource(source1.Tree) Dim v0 = CompileAndVerify(compilation0) @@ -1403,7 +1441,7 @@ End Class validator:= Sub(g) End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Class C End Class @@ -1417,31 +1455,48 @@ End Class }, validator:= Sub(g) - g.VerifyTypeDefNames() - g.VerifyFieldDefNames() - g.VerifyMethodDefNames("add_E", "remove_E", "raise_E") + g.VerifyTypeDefNames("HotReloadException") + g.VerifyFieldDefNames("Code") + g.VerifyMethodDefNames("add_E", "remove_E", "raise_E", ".ctor") g.VerifyDeletedMembers("C: {raise_E, add_E, remove_E, E}") ' We should update the Event table entry to indicate that the event has been deleted: ' TODO: https://github.com/dotnet/roslyn/issues/69834 g.VerifyEncLogDefinitions( { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default) }) g.VerifyIL(" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000006 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000005 + IL_000c: throw +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000006 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000001 + IL_000e: ret } ") End Sub). - AddGeneration( + AddGeneration(' 2 source:=" Class C Custom Event E As System.Action(Of Integer) @@ -1536,7 +1591,7 @@ End Class validator:= Sub(g) End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Class C Custom Event E As System.Action(Of Boolean) @@ -1561,24 +1616,29 @@ End Class }, validator:= Sub(g) - g.VerifyTypeDefNames() - g.VerifyFieldDefNames() + g.VerifyTypeDefNames("HotReloadException") + g.VerifyFieldDefNames("Code") ' We do not update raise_E since its signature has not changed. - g.VerifyMethodDefNames("add_E", "remove_E", "add_E", "remove_E") + g.VerifyMethodDefNames("add_E", "remove_E", "add_E", "remove_E", ".ctor") g.VerifyDeletedMembers("C: {add_E, remove_E}") ' New event is added to the Event table associated with the new accessors. ' Events can't be overloaded on type so we will update the existing Event table entry. g.VerifyEncLogDefinitions( { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), Row(1, TableIndex.Event, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), Row(3, TableIndex.Param, EditAndContinueOperation.Default), Row(6, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), @@ -1590,18 +1650,19 @@ End Class g.VerifyIL(" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000006 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000007 + IL_000c: throw } { // Code size 10 (0xa) .maxstack 8 IL_0000: nop IL_0001: ldc.i4.s 10 - IL_0003: call 0x0A000007 + IL_0003: call 0x0A000006 IL_0008: nop IL_0009: ret } @@ -1610,13 +1671,24 @@ End Class .maxstack 8 IL_0000: nop IL_0001: ldc.i4.s 20 - IL_0003: call 0x0A000007 + IL_0003: call 0x0A000006 IL_0008: nop IL_0009: ret } +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000007 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000001 + IL_000e: ret +} ") End Sub). - AddGeneration( + AddGeneration(' 2 source:=" Class C Custom Event E As System.Action(Of Integer) @@ -1683,11 +1755,12 @@ End Class IL_000c: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000151 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000007 + IL_000c: throw } ") End Sub). @@ -2201,7 +2274,7 @@ End Class g.VerifyFieldDefNames() g.VerifyMethodDefNames(".ctor", "get_P", "set_P") End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System @@ -2228,11 +2301,11 @@ End Class }, validator:= Sub(g) - g.VerifyTypeDefNames() - g.VerifyFieldDefNames() + g.VerifyTypeDefNames("HotReloadException") + g.VerifyFieldDefNames("Code") ' old accessors are updated to throw, new accessors are added: - g.VerifyMethodDefNames("get_P", "set_P", "get_P", "set_P") + g.VerifyMethodDefNames("get_P", "set_P", "get_P", "set_P", ".ctor") g.VerifyDeletedMembers("C: {P, get_P, set_P}") ' New property is added to the Property table associated with the new accessors. @@ -2244,34 +2317,40 @@ End Class g.VerifyEncLogDefinitions( { Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), ' Action get_P - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), ' set_P(Action) - Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), ' Action get_P + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), ' HotReloadException + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), ' HotReloadException.Code + Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), ' Action get_P + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), ' set_P(Action) + Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), ' Action get_P Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), ' set_P(Action) + Row(2, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), ' set_P(Action) Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.PropertyMap, EditAndContinueOperation.AddProperty), ' Action P + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), ' HotReloadException..ctor + Row(1, TableIndex.PropertyMap, EditAndContinueOperation.AddProperty), ' Action P Row(2, TableIndex.Property, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), Row(2, TableIndex.Param, EditAndContinueOperation.Default), - Row(3, TableIndex.MethodSemantics, EditAndContinueOperation.Default), ' Action P <-> Action get_P - Row(4, TableIndex.MethodSemantics, EditAndContinueOperation.Default) ' Action P <-> set_P(Action) + Row(3, TableIndex.MethodSemantics, EditAndContinueOperation.Default), ' Action P <-> Action get_P + Row(4, TableIndex.MethodSemantics, EditAndContinueOperation.Default) ' Action P <-> set_P(Action) }) g.VerifyIL(" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000006 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } { // Code size 15 (0xf) .maxstack 1 IL_0000: nop IL_0001: ldc.i4.s 10 - IL_0003: call 0x0A000007 + IL_0003: call 0x0A000006 IL_0008: nop IL_0009: ldnull IL_000a: stloc.0 @@ -2284,12 +2363,23 @@ End Class .maxstack 8 IL_0000: nop IL_0001: ldc.i4.s 20 - IL_0003: call 0x0A000007 + IL_0003: call 0x0A000006 IL_0008: nop IL_0009: ret +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000007 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000001 + IL_000e: ret }") End Sub). - AddGeneration( + AddGeneration(' 2 source:=" Imports System @@ -2362,11 +2452,12 @@ End Class IL_000c: ret } { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000151 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } ") End Sub). @@ -2397,7 +2488,7 @@ End Class g.VerifyFieldDefNames() g.VerifyMethodDefNames(".ctor", "get_P", "set_P") End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System @@ -2412,30 +2503,47 @@ End Class }, validator:= Sub(g) - g.VerifyTypeDefNames() - g.VerifyFieldDefNames() + g.VerifyTypeDefNames("HotReloadException") + g.VerifyFieldDefNames("Code") ' deleted getter is updated to throw: - g.VerifyMethodDefNames("get_P", "set_P") + g.VerifyMethodDefNames("get_P", "set_P", ".ctor") g.VerifyDeletedMembers("C: {P, get_P, set_P}") g.VerifyEncLogDefinitions( { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default) }) g.VerifyIL(" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000005 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000001 + IL_000e: ret } ") End Sub). - AddGeneration( + AddGeneration(' 2 source:=" Imports System @@ -2506,7 +2614,7 @@ End Class g.VerifyFieldDefNames() g.VerifyMethodDefNames(".ctor", "get_P", "set_P") End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System @@ -2523,29 +2631,46 @@ End Class }, validator:= Sub(g) - g.VerifyTypeDefNames() - g.VerifyFieldDefNames() + g.VerifyTypeDefNames("HotReloadException") + g.VerifyFieldDefNames("Code") g.VerifyDeletedMembers("C: {get_P}") ' deleted getter is updated to throw: - g.VerifyMethodDefNames("get_P") + g.VerifyMethodDefNames("get_P", ".ctor") g.VerifyEncLogDefinitions( { - Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default) }) g.VerifyIL(" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000005 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000005 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000001 + IL_000e: ret } ") End Sub). - AddGeneration( + AddGeneration(' 2 source:=" Imports System @@ -5382,7 +5507,7 @@ End Class Dim source1 = MarkedSource(template.Replace("<>", "1")) Dim source2 = MarkedSource(template.Replace("<>", "2")) - Dim compilation0 = CreateCompilationWithMscorlib45({source0.Tree}, {SystemCoreRef}, options:=ComSafeDebugDll) + Dim compilation0 = CreateCompilationWithMscorlib461({source0.Tree}, {SystemCoreRef}, options:=ComSafeDebugDll) Dim compilation1 = compilation0.WithSource(source1.Tree) Dim compilation2 = compilation0.WithSource(source2.Tree) @@ -5805,7 +5930,7 @@ End Class End Sub ). - AddGeneration( + AddGeneration(' 1 source:=" Imports System @@ -5822,61 +5947,82 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__}", "C._Closure$__: {$I1-1, _Lambda$__1-1}") - g.VerifyTypeDefNames() - g.VerifyMethodDefNames("F", "_Lambda$__1-0", "_Lambda$__1-1") - g.VerifyTypeRefNames("Object", "Action", "CompilerGeneratedAttribute", "MissingMethodException", "Console") - g.VerifyMemberRefNames(".ctor", ".ctor", ".ctor", "WriteLine") + g.VerifyTypeDefNames("HotReloadException") + g.VerifyMethodDefNames("F", "_Lambda$__1-0", "_Lambda$__1-1", ".ctor") + g.VerifyTypeRefNames("Object", "Action", "CompilerGeneratedAttribute", "Exception", "Console") + g.VerifyMemberRefNames(".ctor", ".ctor", "WriteLine", ".ctor") g.VerifyEncLogDefinitions( { Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(4, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default) }) g.VerifyEncMapDefinitions( { + Handle(4, TableIndex.TypeDef), + Handle(4, TableIndex.Field), Handle(2, TableIndex.MethodDef), Handle(5, TableIndex.MethodDef), Handle(6, TableIndex.MethodDef), + Handle(7, TableIndex.MethodDef), Handle(2, TableIndex.StandAloneSig) }) g.VerifyIL(" { - // Code size 39 (0x27) - .maxstack 2 - IL_0000: nop - IL_0001: ldsfld 0x04000003 - IL_0006: brfalse.s IL_000f - IL_0008: ldsfld 0x04000003 - IL_000d: br.s IL_0025 - IL_000f: ldsfld 0x04000001 - IL_0014: ldftn 0x06000006 - IL_001a: newobj 0x0A000009 - IL_001f: dup - IL_0020: stsfld 0x04000003 - IL_0025: stloc.2 - IL_0026: ret + // Code size 39 (0x27) + .maxstack 2 + IL_0000: nop + IL_0001: ldsfld 0x04000003 + IL_0006: brfalse.s IL_000f + IL_0008: ldsfld 0x04000003 + IL_000d: br.s IL_0025 + IL_000f: ldsfld 0x04000001 + IL_0014: ldftn 0x06000006 + IL_001a: newobj 0x0A000009 + IL_001f: dup + IL_0020: stsfld 0x04000003 + IL_0025: stloc.2 + IL_0026: ret } { - // Code size 11 (0xb) - .maxstack 8 - IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A00000A - IL_000a: throw + // Code size 12 (0xc) + .maxstack 8 + IL_0000: ldstr 0x70000005 + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000007 + IL_000b: throw } { - // Code size 9 (0x9) - .maxstack 8 - IL_0000: nop - IL_0001: ldc.i4.2 - IL_0002: call 0x0A00000B - IL_0007: nop - IL_0008: ret + // Code size 9 (0x9) + .maxstack 8 + IL_0000: nop + IL_0001: ldc.i4.2 + IL_0002: call 0x0A00000A + IL_0007: nop + IL_0008: ret +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A00000B + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000004 + IL_000e: ret } ") End Sub). @@ -5900,7 +6046,7 @@ End Class validator:= Sub(g) End Sub). - AddGeneration( + AddGeneration(' 1 source:=" Imports System @@ -5913,42 +6059,63 @@ End Class }, validator:= Sub(g) - g.VerifySynthesizedMembers() - g.VerifyTypeDefNames() - g.VerifyMethodDefNames("F", "_Lambda$__1-0") - g.VerifyTypeRefNames("Object", "MissingMethodException") + g.VerifySynthesizedMembers("System.Runtime.CompilerServices.HotReloadException") + g.VerifyTypeDefNames("HotReloadException") + g.VerifyMethodDefNames("F", "_Lambda$__1-0", ".ctor") + g.VerifyTypeRefNames("Object", "Exception") g.VerifyMemberRefNames(".ctor") g.VerifyEncLogDefinitions( { + Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default) }) g.VerifyEncMapDefinitions( { + Handle(4, TableIndex.TypeDef), + Handle(3, TableIndex.Field), Handle(2, TableIndex.MethodDef), - Handle(5, TableIndex.MethodDef) + Handle(5, TableIndex.MethodDef), + Handle(6, TableIndex.MethodDef) }) g.VerifyIL(" { - // Code size 11 (0xb) - .maxstack 8 - IL_0000: ldstr 0x70000005 - IL_0005: newobj 0x0A000008 - IL_000a: throw -} -{ - // Code size 11 (0xb) - .maxstack 8 - IL_0000: ldstr 0x7000014E - IL_0005: newobj 0x0A000008 - IL_000a: throw -} + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldstr 0x70000005 + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw + } + { + // Code size 12 (0xc) + .maxstack 8 + IL_0000: ldstr 0x7000014E + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000006 + IL_000b: throw + } + { + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000003 + IL_000e: ret + } ") End Sub). - AddGeneration( + AddGeneration(' 2 source:=" Imports System @@ -5965,6 +6132,7 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__}", "C._Closure$__: {$I1#2-0#2, _Lambda$__1#2-0#2}") g.VerifyTypeDefNames() @@ -5975,19 +6143,19 @@ End Class { Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(3, TableIndex.Field, EditAndContinueOperation.Default), + Row(4, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default) }) g.VerifyEncMapDefinitions( { - Handle(3, TableIndex.Field), + Handle(4, TableIndex.Field), Handle(2, TableIndex.MethodDef), Handle(3, TableIndex.MethodDef), - Handle(6, TableIndex.MethodDef), + Handle(7, TableIndex.MethodDef), Handle(2, TableIndex.StandAloneSig) }) @@ -5996,15 +6164,15 @@ End Class // Code size 39 (0x27) .maxstack 2 IL_0000: nop - IL_0001: ldsfld 0x04000003 + IL_0001: ldsfld 0x04000004 IL_0006: brfalse.s IL_000f - IL_0008: ldsfld 0x04000003 + IL_0008: ldsfld 0x04000004 IL_000d: br.s IL_0025 IL_000f: ldsfld 0x04000001 - IL_0014: ldftn 0x06000006 + IL_0014: ldftn 0x06000007 IL_001a: newobj 0x0A00000A IL_001f: dup - IL_0020: stsfld 0x04000003 + IL_0020: stsfld 0x04000004 IL_0025: stloc.0 IL_0026: ret } @@ -6026,7 +6194,7 @@ End Class } ") End Sub). - AddGeneration( + AddGeneration(' 3 source:=" Imports System @@ -6043,40 +6211,43 @@ End Class Sub(g) ' unchanged from previous generation: g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__}", "C._Closure$__: {$I1#2-0#2, _Lambda$__1#2-0#2}") g.VerifyTypeDefNames() g.VerifyMethodDefNames("F", "_Lambda$__1#2-0#2") - g.VerifyTypeRefNames("Object", "MissingMethodException") - g.VerifyMemberRefNames(".ctor") + g.VerifyTypeRefNames("Object") + g.VerifyMemberRefNames() g.VerifyEncLogDefinitions( { Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default) }) g.VerifyEncMapDefinitions( { Handle(2, TableIndex.MethodDef), - Handle(6, TableIndex.MethodDef) + Handle(7, TableIndex.MethodDef) }) g.VerifyIL(" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000299 - IL_0005: newobj 0x0A00000D - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x700003E2 - IL_0005: newobj 0x0A00000D - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000006 + IL_000b: throw } ") End Sub). @@ -6099,7 +6270,7 @@ End Class validator:= Sub(g) End Sub). - AddGeneration(' Add method with a lambda + AddGeneration('1: Add method with a lambda source:=" Imports System @@ -6122,7 +6293,7 @@ End Class g.VerifyTypeDefNames("_Closure$__") g.VerifyMethodDefNames("F", ".ctor", ".cctor", "_Lambda$__1#1-0#1") End Sub). - AddGeneration(' Delete the method + AddGeneration('2: Delete the method source:=" Imports System @@ -6136,39 +6307,61 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C: {_Closure$__}", "C._Closure$__: {$I1#1-0#1, _Lambda$__1#1-0#1}") - g.VerifyTypeDefNames() - g.VerifyMethodDefNames("F", "_Lambda$__1#1-0#1") - g.VerifyTypeRefNames("Object", "MissingMethodException") + g.VerifyTypeDefNames("HotReloadException") + g.VerifyMethodDefNames("F", "_Lambda$__1#1-0#1", ".ctor") + g.VerifyTypeRefNames("Object", "Exception") g.VerifyMemberRefNames(".ctor") g.VerifyEncLogDefinitions( { + Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default) }) g.VerifyEncMapDefinitions( { + Handle(4, TableIndex.TypeDef), + Handle(3, TableIndex.Field), Handle(2, TableIndex.MethodDef), - Handle(5, TableIndex.MethodDef) + Handle(5, TableIndex.MethodDef), + Handle(6, TableIndex.MethodDef) }) g.VerifyIL(" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000009 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000152 - IL_0005: newobj 0x0A000009 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000006 + IL_000b: throw +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000009 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000003 + IL_000e: ret } ") End Sub). @@ -6197,7 +6390,7 @@ End Class validator:= Sub(g) End Sub). - AddGeneration( + AddGeneration(' 1 source:=common & " Class C(Of T) Function F(Of S As Structure)(a As T, b As S) As S @@ -6217,7 +6410,7 @@ End Class "C(Of T): {_Closure$__1}", "C(Of T)._Closure$__1(Of $CLS0 As Structure): {$I1-0, $I1-1#1, _Lambda$__1-0, _Lambda$__1-1#1}") End Sub). - AddGeneration( + AddGeneration(' 2 source:=common & " Class C(Of T) Function F(Of S As Structure)(a As T, b As S) As S @@ -6238,7 +6431,7 @@ End Class "C(Of T): {_Closure$__1}", "C(Of T)._Closure$__1(Of $CLS0 As Structure): {$I1-0, $I1-1#1, $I1-2#2, _Lambda$__1-0, _Lambda$__1-1#1, _Lambda$__1-2#2}") End Sub). - AddGeneration( + AddGeneration(' 3 source:=common & " Class C(Of T) End Class @@ -6250,49 +6443,71 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C(Of T): {_Closure$__1}", "C(Of T)._Closure$__1(Of $CLS0 As Structure): {$I1-0, $I1-1#1, $I1-2#2, _Lambda$__1-0, _Lambda$__1-1#1, _Lambda$__1-2#2}") - g.VerifyTypeDefNames() - g.VerifyMethodDefNames("F", "_Lambda$__1-0", "_Lambda$__1-1#1", "_Lambda$__1-2#2") - g.VerifyTypeRefNames("Object", "MissingMethodException") + g.VerifyTypeDefNames("HotReloadException") + g.VerifyMethodDefNames("F", "_Lambda$__1-0", "_Lambda$__1-1#1", "_Lambda$__1-2#2", ".ctor") + g.VerifyTypeRefNames("Object", "Exception") g.VerifyMemberRefNames(".ctor") g.VerifyEncLogDefinitions( { + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(5, TableIndex.Field, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default) }) g.VerifyEncMapDefinitions( { + Handle(5, TableIndex.TypeDef), + Handle(5, TableIndex.Field), Handle(3, TableIndex.MethodDef), Handle(6, TableIndex.MethodDef), Handle(7, TableIndex.MethodDef), - Handle(8, TableIndex.MethodDef) + Handle(8, TableIndex.MethodDef), + Handle(9, TableIndex.MethodDef) }) g.VerifyIL(" - { - // Code size 11 (0xb) +{ + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x7000000D - IL_0005: newobj 0x0A000023 - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000009 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x70000156 - IL_0005: newobj 0x0A000023 - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000009 + IL_000b: throw +} +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000023 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000005 + IL_000e: ret } ") End Sub). - AddGeneration(' Add deleted method back with another lambda + AddGeneration('4: Add deleted method back with another lambda source:=common & " Class C(Of T) Function F(Of S As Structure)(a As T, b As S) As S @@ -6308,6 +6523,7 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C(Of T): {_Closure$__1#4, _Closure$__1}", "C(Of T)._Closure$__1#4(Of $CLS0 As Structure): {$I1#4-0#4, _Lambda$__1#4-0#4}", "C(Of T)._Closure$__1(Of $CLS0 As Structure): {$I1-0, $I1-1#1, $I1-2#2, _Lambda$__1-0, _Lambda$__1-1#1, _Lambda$__1-2#2}") @@ -6363,7 +6579,7 @@ End Class } ") End Sub). - AddGeneration(' Delete the method again. + AddGeneration('5: Delete the method again. source:=common & " Class C(Of T) End Class @@ -6375,6 +6591,7 @@ End Class validator:= Sub(g) g.VerifySynthesizedMembers( + "System.Runtime.CompilerServices.HotReloadException", "C(Of T): {_Closure$__1#4, _Closure$__1}", "C(Of T)._Closure$__1#4(Of $CLS0 As Structure): {$I1#4-0#4, _Lambda$__1#4-0#4}", "C(Of T)._Closure$__1(Of $CLS0 As Structure): {$I1-0, $I1-1#1, $I1-2#2, _Lambda$__1-0, _Lambda$__1-1#1, _Lambda$__1-2#2}") @@ -6384,35 +6601,37 @@ End Class ' Only lambdas that were not deleted before are updated: g.VerifyMethodDefNames("F", "_Lambda$__1#4-0#4") - g.VerifyTypeRefNames("Object", "MissingMethodException") - g.VerifyMemberRefNames(".ctor") + g.VerifyTypeRefNames("Object") + g.VerifyMemberRefNames() g.VerifyEncLogDefinitions( { Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(11, TableIndex.MethodDef, EditAndContinueOperation.Default) + Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default) }) g.VerifyEncMapDefinitions( { Handle(3, TableIndex.MethodDef), - Handle(11, TableIndex.MethodDef) + Handle(12, TableIndex.MethodDef) }) g.VerifyIL(" { - // Code size 11 (0xb) + // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x700002A1 - IL_0005: newobj 0x0A00002D - IL_000a: throw + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000009 + IL_000c: throw } { - // Code size 11 (0xb) + // Code size 12 (0xc) .maxstack 8 IL_0000: ldstr 0x700003EA - IL_0005: newobj 0x0A00002D - IL_000a: throw + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000009 + IL_000b: throw } ") End Sub). @@ -7020,8 +7239,9 @@ End Class Public Sub Method_Delete() - - Dim source0 = MarkedSource(" + Using New EditAndContinueTest(). + AddBaseline( + source:=" Imports System.ComponentModel Class C @@ -7030,44 +7250,187 @@ Class C Return Nothing End Function End Class -") - Dim source1 = MarkedSource(" +"). + AddGeneration( + source:=" Imports System.ComponentModel Class C +End Class", + edits:={Edit(SemanticEditKind.Delete, Function(c) c.GetMember("C.M"), newSymbolProvider:=Function(c) c.GetMember("C"))}, + validator:= + Sub(v) + v.VerifyTypeDefNames("HotReloadException") + v.VerifyMethodDefNames("M", ".ctor") + + v.VerifyEncLogDefinitions( + { + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default) + }) + + v.VerifyEncMapDefinitions( + { + Handle(3, TableIndex.TypeDef), + Handle(1, TableIndex.Field), + Handle(2, TableIndex.MethodDef), + Handle(3, TableIndex.MethodDef) + }) + End Sub). + Verify() + End Using + End Sub + + + Public Sub Method_Delete_PredefinedHotReloadException() + Dim exceptionSource = " +Namespace System.Runtime.CompilerServices + Public Class HotReloadException + Inherits Exception + + Public Sub New(message As String, code As Integer) + MyBase.New(message) + End Sub + End Class +End Namespace +" + + Using New EditAndContinueTest(). + AddBaseline( + source:=exceptionSource & " +Class C + Sub M() + End Sub End Class -") - Dim compilation0 = CreateCompilation(source0.Tree, targetFramework:=TargetFramework.NetStandard20, options:=ComSafeDebugDll) - Dim compilation1 = compilation0.WithSource(source1.Tree) +"). + AddGeneration( + source:=exceptionSource & " +Class C +End Class", + edits:={Edit(SemanticEditKind.Delete, Function(c) c.GetMember("C.M"), newSymbolProvider:=Function(c) c.GetMember("C"))}, + validator:= + Sub(v) + v.VerifySynthesizedMembers() + v.VerifyTypeDefNames() + v.VerifyTypeRefNames("Object") - Dim m0 = compilation0.GetMember(Of MethodSymbol)("C.M") - Dim c0 = compilation1.GetMember(Of NamedTypeSymbol)("C") + v.VerifyIL(" +{ + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldstr 0x70000005 + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000001 + IL_000c: throw +} + ") + End Sub). + Verify() + End Using + End Sub - Dim v0 = CompileAndVerify(compilation0) - Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) - Dim generation0 = CreateInitialBaseline(compilation0, md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo) + + Public Sub Method_Delete_PredefinedHotReloadException_Inserted() + Dim exceptionSource = " +Namespace System.Runtime.CompilerServices + Public Class HotReloadException + Inherits Exception - ' Pretend there was an update to C.E to ensure we haven't invalidated the test + Public Sub New(message As String, code As Integer) + MyBase.New(message) + End Sub + End Class +End Namespace +" - Dim diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Delete, m0, c0))) + Using New EditAndContinueTest(). + AddBaseline( + source:=" +Class C + Sub M() + End Sub +End Class +"). + AddGeneration( + source:=exceptionSource & " +Class C +End Class", + edits:= + { + Edit(SemanticEditKind.Insert, Function(c) c.GetMember("System.Runtime.CompilerServices.HotReloadException")), + Edit(SemanticEditKind.Delete, Function(c) c.GetMember("C.M"), newSymbolProvider:=Function(c) c.GetMember("C")) + }, + validator:= + Sub(v) + v.VerifySynthesizedMembers() + v.VerifyTypeDefNames("HotReloadException") + v.VerifyTypeRefNames("Exception", "Object") - Dim reader0 = md0.MetadataReader + v.VerifyIL(" +{ + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldstr 0x70000005 + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000003 + IL_000c: throw +} +{ + // Code size 10 (0xa) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldarg.1 + IL_0003: call 0x0A000005 + IL_0008: nop + IL_0009: ret +} +") + End Sub). + Verify() + End Using + End Sub - ' Verify delta metadata contains expected rows. - Using md1 = diff1.GetMetadata() - Dim reader1 = md1.Reader - Dim readers = {reader0, reader1} - EncValidation.VerifyModuleMvid(1, reader0, reader1) - CheckNames(readers, reader1.GetTypeDefNames()) - CheckNames(readers, reader1.GetMethodDefNames(), "M") - - CheckEncLogDefinitions(reader1, - Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default)) - - CheckEncMapDefinitions(reader1, - Handle(2, TableIndex.MethodDef)) + + Public Sub Method_Delete_PredefinedHotReloadException_BadConstructor() + Dim exceptionSource = " +Namespace System.Runtime.CompilerServices + Public Class HotReloadException + Inherits Exception + + Public Sub New(message As String) + MyBase.New(message) + End Sub + End Class +End Namespace +" + + Using New EditAndContinueTest(assemblyName:="TestAssembly"). + AddBaseline( + source:=exceptionSource & " +Class C + Sub M() + End Sub +End Class +"). + AddGeneration( + source:=exceptionSource & " +Class C +End Class", + edits:= + { + Edit(SemanticEditKind.Delete, Function(c) c.GetMember("C.M"), newSymbolProvider:=Function(c) c.GetMember("C")) + }, + expectedErrors:= + { + Diagnostic(ERRID.ERR_ModuleEmitFailure). + WithArguments("TestAssembly", String.Format(CodeAnalysisResources.Type0DoesNotHaveExpectedConstructor, "System.Runtime.CompilerServices.HotReloadException")) + }). + Verify() End Using End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EmitCustomModifiers.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EmitCustomModifiers.vb index 2bfe960e6417f..fdf70732dae90 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EmitCustomModifiers.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EmitCustomModifiers.vb @@ -12,6 +12,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities Imports Xunit +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit @@ -20,7 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit Public Sub Test1() - Dim mscorlibRef = TestMetadata.Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim source As String = Public Class A diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EmitMetadata.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EmitMetadata.vb index 8a73cbdda10ba..0cad9d7c20a7e 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EmitMetadata.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EmitMetadata.vb @@ -11,7 +11,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit @@ -26,7 +26,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit Public Sub InstantiatedGenerics() - Dim mscorlibRef = Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim source As String = Class A(Of T) @@ -218,7 +218,7 @@ Public Class D Shared arrayField As String() End Class -, {Net40.mscorlib}, TestOptions.ReleaseExe) +, {Net40.References.mscorlib}, TestOptions.ReleaseExe) CompileAndVerify(comp, expectedOutput:= @@ -229,7 +229,7 @@ End Class Public Sub AssemblyRefs() - Dim mscorlibRef = Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim metadataTestLib1 = TestReferences.SymbolsTests.MDTestLib1 Dim metadataTestLib2 = TestReferences.SymbolsTests.MDTestLib2 @@ -289,7 +289,7 @@ End Class Public Sub AddModule() - Dim mscorlibRef = Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim netModule1 = ModuleMetadata.CreateFromImage(TestResources.SymbolsTests.netModule.netModule1) Dim netModule2 = ModuleMetadata.CreateFromImage(TestResources.SymbolsTests.netModule.netModule2) @@ -346,7 +346,7 @@ End Class Public Sub ImplementingAnInterface() - Dim mscorlibRef = Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim source As String = Public Interface I1 @@ -403,7 +403,7 @@ End Class Public Sub Types() - Dim mscorlibRef = Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim source As String = Public MustInherit Class A @@ -551,7 +551,7 @@ End Class Public Sub Fields() - Dim mscorlibRef = Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim source As String = Public Class A public F1 As Integer diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EntryPointTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EntryPointTests.vb index 28cc55adc6ea0..bb7a31777277b 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EntryPointTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EntryPointTests.vb @@ -5,7 +5,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit @@ -990,7 +990,7 @@ End Class End Module - CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.SystemCore}, options:=TestOptions.ReleaseExe).VerifyDiagnostics( + CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, options:=TestOptions.ReleaseExe).VerifyDiagnostics( Diagnostic(ERRID.ERR_InValidSubMainsFound1).WithArguments("a")) End Sub @@ -1009,7 +1009,7 @@ End Class End Module - CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.SystemCore}, options:=TestOptions.ReleaseExe).VerifyDiagnostics( + CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, options:=TestOptions.ReleaseExe).VerifyDiagnostics( Diagnostic(ERRID.ERR_InValidSubMainsFound1).WithArguments("a")) End Sub @@ -1028,7 +1028,7 @@ End Class End Module - CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.SystemCore}, options:=TestOptions.ReleaseExe).VerifyDiagnostics( + CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, options:=TestOptions.ReleaseExe).VerifyDiagnostics( Diagnostic(ERRID.ERR_InValidSubMainsFound1).WithArguments("a")) End Sub @@ -1281,10 +1281,10 @@ End Class End Module - CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.SystemCore}, options:=TestOptions.ReleaseExe.WithMainTypeName("B")).VerifyDiagnostics( + CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithMainTypeName("B")).VerifyDiagnostics( Diagnostic(ERRID.ERR_StartupCodeNotFound1).WithArguments("B")) - CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.SystemCore}, options:=TestOptions.ReleaseExe.WithMainTypeName("Extension")).VerifyDiagnostics( + CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithMainTypeName("Extension")).VerifyDiagnostics( Diagnostic(ERRID.ERR_InValidSubMainsFound1).WithArguments("Extension")) End Sub @@ -1302,13 +1302,13 @@ End Class Delegate Sub mydelegate(args As String()) - CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.SystemCore}, options:=TestOptions.ReleaseExe.WithMainTypeName("I1")).VerifyDiagnostics( + CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithMainTypeName("I1")).VerifyDiagnostics( Diagnostic(ERRID.ERR_StartupCodeNotFound1).WithArguments("i1")) - CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.SystemCore}, options:=TestOptions.ReleaseExe.WithMainTypeName("COLOR")).VerifyDiagnostics( + CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithMainTypeName("COLOR")).VerifyDiagnostics( Diagnostic(ERRID.ERR_StartupCodeNotFound1).WithArguments("color")) - CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.SystemCore}, options:=TestOptions.ReleaseExe.WithMainTypeName("mydelegate")).VerifyDiagnostics( + CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithMainTypeName("mydelegate")).VerifyDiagnostics( Diagnostic(ERRID.ERR_StartupCodeNotFound1).WithArguments("mydelegate")) End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb index 54bfd2b2c17e7..615ddc687332a 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/NoPiaEmbedTypes.vb @@ -15,7 +15,7 @@ Imports Xunit Imports System.Reflection.Metadata Imports Microsoft.CodeAnalysis.Emit Imports System.Collections.Immutable -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -1743,7 +1743,7 @@ End Structure End Sub Dim compilation1 = CreateEmptyCompilationWithReferences( sources1, - references:={Net40.mscorlib, Net40.System, compilation0.EmitToImageReference(embedInteropTypes:=True)}) + references:={Net40.References.mscorlib, Net40.References.System, compilation0.EmitToImageReference(embedInteropTypes:=True)}) verifier = CompileAndVerify(compilation1, symbolValidator:=validator) AssertTheseDiagnostics(verifier, ()) verifier.VerifyIL("S.F", ) compilation1 = CreateEmptyCompilationWithReferences( sources1, - references:={Net451.mscorlib, Net451.System, compilation0.EmitToImageReference(embedInteropTypes:=True)}) + references:={NetFramework.mscorlib, NetFramework.System, compilation0.EmitToImageReference(embedInteropTypes:=True)}) verifier = CompileAndVerify(compilation1, symbolValidator:=validator) AssertTheseDiagnostics(verifier, ()) verifier.VerifyIL("S.F", - Dim dispIdDefinition = CreateCSharpCompilation(dispId, assemblyName:="DispId", referencedAssemblies:=TargetFrameworkUtil.GetReferences(TargetFramework.DesktopLatestExtended, Nothing)).EmitToImageReference(aliases:=ImmutableArray.Create("dispId")) + Dim dispIdDefinition = CreateCSharpCompilation(dispId, assemblyName:="DispId", referencedAssemblies:=TargetFrameworkUtil.GetReferences(TargetFramework.Mscorlib461Extended, Nothing)).EmitToImageReference(aliases:=ImmutableArray.Create("dispId")) Dim pia = - Dim piaCompilation = CreateCSharpCompilation(pia, assemblyName:="Pia", referencedAssemblies:=TargetFrameworkUtil.GetReferences(TargetFramework.DesktopLatestExtended, {dispIdDefinition})). + Dim piaCompilation = CreateCSharpCompilation(pia, assemblyName:="Pia", referencedAssemblies:=TargetFrameworkUtil.GetReferences(TargetFramework.Mscorlib461Extended, {dispIdDefinition})). EmitToImageReference(embedInteropTypes:=True) Dim sources1 = @@ -2715,7 +2715,7 @@ End Structure Assert.Equal("System.Runtime.InteropServices.DispIdAttribute(124)", attr.ToString()) End Sub - Dim compilation1 = CreateCompilation(sources1, references:={piaCompilation}, targetFramework:=TargetFramework.DesktopLatestExtended) + Dim compilation1 = CreateCompilation(sources1, references:={piaCompilation}, targetFramework:=TargetFramework.Mscorlib461Extended) Dim verifier = CompileAndVerify(compilation1.AddReferences(dispIdDefinition), symbolValidator:=validator) AssertTheseDiagnostics(verifier, ()) @@ -2731,7 +2731,7 @@ BC30652: Reference required to assembly 'DispId, Version=0.0.0.0, Culture=neutra Public Sub DispIdAttribute_03() - Dim empty = CreateCompilation("", targetFramework:=TargetFramework.DesktopLatestExtended).EmitToImageReference() + Dim empty = CreateCompilation("", targetFramework:=TargetFramework.Mscorlib461Extended).EmitToImageReference() Dim pia = - Dim piaCompilation = CreateCompilation(pia, references:={empty}, targetFramework:=TargetFramework.DesktopLatestExtended) + Dim piaCompilation = CreateCompilation(pia, references:={empty}, targetFramework:=TargetFramework.Mscorlib461Extended) piaCompilation.AssertTheseDiagnostics( - Dim piaCompilation = CreateCompilation(pia, targetFramework:=TargetFramework.DesktopLatestExtended) + Dim piaCompilation = CreateCompilation(pia, targetFramework:=TargetFramework.Mscorlib461Extended) piaCompilation.AssertTheseDiagnostics( @@ -38,7 +38,7 @@ End Module]]> CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithOverflowChecks(True), expectedOutput:= CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithOverflowChecks(True), expectedOutput:=expected ) CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithOverflowChecks(False), expectedOutput:=expected ) @@ -1201,7 +1201,7 @@ Lambda( CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithOverflowChecks(checked), expectedOutput:=result.Trim ).VerifyDiagnostics() @@ -1223,7 +1223,7 @@ Lambda( CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithOverflowChecks(checked), expectedOutput:=result.Trim ).VerifyDiagnostics() @@ -1448,7 +1448,7 @@ Lambda( CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithOverflowChecks(checked), expectedOutput:=result.Trim ).VerifyDiagnostics(Diagnostic(ERRID.WRN_ObsoleteIdentityDirectCastForValueType, "x"), @@ -1918,7 +1918,7 @@ End Module Dim src = source....Value CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe.WithOverflowChecks(checked), expectedOutput:=result.Trim ).VerifyDiagnostics(If(diagnostics, {})) @@ -2012,7 +2012,7 @@ End Module ]]> - CompileAndVerify(source, references:={Net40.SystemCore}).VerifyDiagnostics() + CompileAndVerify(source, references:={Net40.References.SystemCore}).VerifyDiagnostics() End Sub @@ -6628,7 +6628,7 @@ End Module CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:= CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:= CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:= CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:=).VerifyDiagnostics() End Sub @@ -6884,7 +6884,7 @@ End Module CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:="GroupBy 1;Select;GroupBy 2;Select;").VerifyDiagnostics() End Sub @@ -6927,7 +6927,7 @@ End Module]]> CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:="GroupJoin;").VerifyDiagnostics() End Sub @@ -7010,7 +7010,7 @@ End Module CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:=) End Sub @@ -7051,7 +7051,7 @@ End Module]]> CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:=) End Sub @@ -7078,7 +7078,7 @@ End Module CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:="() => (value(Form1+_Closure$__0-0).$VB$Local_s1_a ?? Convert(value(Form1+_Closure$__0-0).$VB$Local_s1_b))").VerifyDiagnostics() End Sub @@ -7196,7 +7196,7 @@ End Module CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:="10").VerifyDiagnostics() End Sub @@ -7275,7 +7275,7 @@ end class CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:="m => m").VerifyDiagnostics() End Sub @@ -7314,7 +7314,7 @@ End Class CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, expectedOutput:="").VerifyDiagnostics() End Sub @@ -8310,7 +8310,7 @@ End Module CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe, expectedOutput:= (value(M+_Closure$__2-0`1[M+X]).$VB$Local_x == null) @@ -8370,7 +8370,7 @@ End Module CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe, expectedOutput:= (value(M+_Closure$__2-0`1[M+X]).$VB$Local_x == null) @@ -8412,7 +8412,7 @@ End Module CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe, expectedOutput:= Concat(value(M+_Closure$__0-0).$VB$Local_str, null) @@ -8466,7 +8466,7 @@ End Namespace CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe, expectedOutput:= CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe, expectedOutput:= x.set_City(ItIs(s => IsNullOrEmpty(s))) @@ -8607,7 +8607,7 @@ End Module CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe, expectedOutput:= x.set_City(1, ItIs(s => IsNullOrEmpty(s))) @@ -8672,7 +8672,7 @@ End Module Dim compilation = CreateCompilationWithMscorlib45AndVBRuntime(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe) compilation.VerifyDiagnostics( @@ -8722,7 +8722,7 @@ End Class CompileAndVerify(source, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe, expectedOutput:= Library - $(NetRoslyn);net472 + $(NetRoslynNext);net472 diff --git a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb index 0cbd68f6cca18..057a7f2316d38 100644 --- a/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/PDB/PDBTests.vb @@ -4540,7 +4540,7 @@ Class C c.Select(Function(i) i) End Function End Class" - Dim c = CreateCompilationWithMscorlib45AndVBRuntime({Parse(source)}, options:=TestOptions.DebugDll, references:={SystemCoreRef}) + Dim c = CreateCompilationWithMscorlib461AndVBRuntime({Parse(source)}, options:=TestOptions.DebugDll, references:={SystemCoreRef}) ' Note: since the method is first, it is recording the imports (rather than using an importsforward) c.VerifyPdb("C+VB$StateMachine_1_F.MoveNext", @@ -4597,7 +4597,7 @@ Class C End Sub End Sub End Class" - Dim c = CreateCompilationWithMscorlib45AndVBRuntime({Parse(source)}, options:=TestOptions.DebugDll, references:={SystemCoreRef}) + Dim c = CreateCompilationWithMscorlib461AndVBRuntime({Parse(source)}, options:=TestOptions.DebugDll, references:={SystemCoreRef}) c.VerifyPdb("C+_Closure$__+VB$StateMachine___Lambda$__1-0.MoveNext", diff --git a/src/Compilers/VisualBasic/Test/Emit/Perf.vb b/src/Compilers/VisualBasic/Test/Emit/Perf.vb index 97d47421f4281..6448b2df8e81b 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Perf.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Perf.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit Public Class Perf : Inherits BasicTestBase @@ -29,7 +30,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit <%= TestResources.PerfTests.VBPerfTest %> - , references:={TestMetadata.Net40.SystemCore}).VerifyDiagnostics() + , references:={Net40.References.SystemCore}).VerifyDiagnostics() End Sub End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Emit/PrivateProtected.vb b/src/Compilers/VisualBasic/Test/Emit/PrivateProtected.vb index ea1ec59408133..25b0bc9987e7b 100644 --- a/src/Compilers/VisualBasic/Test/Emit/PrivateProtected.vb +++ b/src/Compilers/VisualBasic/Test/Emit/PrivateProtected.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class PrivateProtected @@ -931,7 +932,7 @@ End Class ]]> - Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {TestMetadata.Net40.SystemCore}, + Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, parseOptions:=TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15_5)) CompilationUtils.AssertTheseDiagnostics(compilation, diff --git a/src/Compilers/VisualBasic/Test/Emit/XmlLiteralTests.vb b/src/Compilers/VisualBasic/Test/Emit/XmlLiteralTests.vb index d123b6c0b47db..d1ed11a266a7c 100644 --- a/src/Compilers/VisualBasic/Test/Emit/XmlLiteralTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/XmlLiteralTests.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -4962,9 +4963,9 @@ End Class Dim tree = VisualBasicSyntaxTree.ParseText(source) Dim refBuilder = ArrayBuilder(Of MetadataReference).GetInstance() - refBuilder.Add(TestMetadata.Net40.mscorlib) - refBuilder.Add(TestMetadata.Net40.System) - refBuilder.Add(TestMetadata.Net40.MicrosoftVisualBasic) + refBuilder.Add(Net40.References.mscorlib) + refBuilder.Add(Net40.References.System) + refBuilder.Add(Net40.References.MicrosoftVisualBasic) refBuilder.AddRange(Net40XmlReferences) Dim refs = refBuilder.ToImmutableAndFree() diff --git a/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.vb b/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.vb index 8d61b7b62d964..3d68e2ea1eae5 100644 --- a/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.vb +++ b/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_ICompoundAssignmentOperation.vb @@ -34,7 +34,7 @@ End Module]]>.Value Dim fileName = "a.vb" Dim syntaxTree = Parse(source, fileName) - Dim compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}) + Dim compilation = CreateCompilationWithMscorlib461AndVBRuntime({syntaxTree}) Dim result = GetOperationTreeForTest(Of AssignmentStatementSyntax)(compilation, fileName) Dim compoundAssignment = DirectCast(DirectCast(result.operation, IExpressionStatementOperation).Operation, ICompoundAssignmentOperation) @@ -57,7 +57,7 @@ End Module]]>.Value Dim fileName = "a.vb" Dim syntaxTree = Parse(source, fileName) - Dim compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}) + Dim compilation = CreateCompilationWithMscorlib461AndVBRuntime({syntaxTree}) Dim result = GetOperationTreeForTest(Of AssignmentStatementSyntax)(compilation, fileName) Dim compoundAssignment = DirectCast(DirectCast(result.operation, IExpressionStatementOperation).Operation, ICompoundAssignmentOperation) @@ -92,7 +92,7 @@ End Module]]>.Value Dim fileName = "a.vb" Dim syntaxTree = Parse(source, fileName) - Dim compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}) + Dim compilation = CreateCompilationWithMscorlib461AndVBRuntime({syntaxTree}) Dim result = GetOperationTreeForTest(Of AssignmentStatementSyntax)(compilation, fileName) Dim compoundAssignment = DirectCast(DirectCast(result.operation, IExpressionStatementOperation).Operation, ICompoundAssignmentOperation) diff --git a/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_IConditionalAccessExpression.vb b/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_IConditionalAccessExpression.vb index d5ff14f6cb93d..987ff4f2e4e07 100644 --- a/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_IConditionalAccessExpression.vb +++ b/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_IConditionalAccessExpression.vb @@ -716,7 +716,7 @@ Block[B8] - Exit Statements (0) ]]>.Value - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(source, Net451XmlReferences) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(source, Net461XmlReferences) VerifyFlowGraphAndDiagnosticsForTest(Of MethodBlockSyntax)(comp, expectedFlowGraph, expectedDiagnostics) End Sub @@ -821,7 +821,7 @@ Block[B6] - Exit Statements (0) ]]>.Value - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(source, Net451XmlReferences) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(source, Net461XmlReferences) VerifyFlowGraphAndDiagnosticsForTest(Of MethodBlockSyntax)(comp, expectedFlowGraph, expectedDiagnostics) End Sub @@ -928,7 +928,7 @@ Block[B6] - Exit Statements (0) ]]>.Value - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(source, Net451XmlReferences) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(source, Net461XmlReferences) VerifyFlowGraphAndDiagnosticsForTest(Of MethodBlockSyntax)(comp, expectedFlowGraph, expectedDiagnostics) End Sub @@ -1093,7 +1093,7 @@ Block[B10] - Exit Statements (0) ]]>.Value - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(source, Net451XmlReferences) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(source, Net461XmlReferences) VerifyFlowGraphAndDiagnosticsForTest(Of MethodBlockSyntax)(comp, expectedFlowGraph, expectedDiagnostics) End Sub End Class diff --git a/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_IForLoopStatement.vb b/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_IForLoopStatement.vb index fe95fd4c9bda7..c24ad47e5cfec 100644 --- a/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_IForLoopStatement.vb +++ b/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_IForLoopStatement.vb @@ -8852,7 +8852,7 @@ Public Class C End Class ]]>.Value - Dim compilation = CreateCompilationWithMscorlib45(source, options:=TestOptions.ReleaseDebugDll) + Dim compilation = CreateCompilationWithMscorlib461(source, options:=TestOptions.ReleaseDebugDll) Dim expectedDiagnostics = String.Empty @@ -8926,7 +8926,7 @@ Public Class C End Class ]]>.Value - Dim compilation = CreateCompilationWithMscorlib45(source, options:=TestOptions.ReleaseDebugDll) + Dim compilation = CreateCompilationWithMscorlib461(source, options:=TestOptions.ReleaseDebugDll) compilation.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault) Dim expectedDiagnostics = String.Empty diff --git a/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_INoPiaObjectCreationOperation.vb b/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_INoPiaObjectCreationOperation.vb index 8d580954e5591..f15b297334dd8 100644 --- a/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_INoPiaObjectCreationOperation.vb +++ b/src/Compilers/VisualBasic/Test/IOperation/IOperation/IOperationTests_INoPiaObjectCreationOperation.vb @@ -36,7 +36,7 @@ public mustinherit class ClassITest33 End class " - Dim piaCompilation = CreateCompilationWithMscorlib45(pia, options:=TestOptions.ReleaseDll) + Dim piaCompilation = CreateCompilationWithMscorlib461(pia, options:=TestOptions.ReleaseDll) CompileAndVerify(piaCompilation) @@ -93,7 +93,7 @@ public mustinherit class ClassITest33 End class " - Dim piaCompilation = CreateCompilationWithMscorlib45(pia, options:=TestOptions.ReleaseDll) + Dim piaCompilation = CreateCompilationWithMscorlib461(pia, options:=TestOptions.ReleaseDll) CompileAndVerify(piaCompilation) @@ -147,7 +147,7 @@ public mustinherit class ClassITest33 End class " - Dim piaCompilation = CreateCompilationWithMscorlib45(pia, options:=TestOptions.ReleaseDll) + Dim piaCompilation = CreateCompilationWithMscorlib461(pia, options:=TestOptions.ReleaseDll) CompileAndVerify(piaCompilation) @@ -196,7 +196,7 @@ public mustinherit class ClassITest33 End class " - Dim piaCompilation = CreateCompilationWithMscorlib45(pia, options:=TestOptions.ReleaseDll) + Dim piaCompilation = CreateCompilationWithMscorlib461(pia, options:=TestOptions.ReleaseDll) CompileAndVerify(piaCompilation) @@ -286,7 +286,7 @@ public mustinherit class ClassITest33 End class " - Dim piaCompilation = CreateCompilationWithMscorlib45(pia, options:=TestOptions.ReleaseDll) + Dim piaCompilation = CreateCompilationWithMscorlib461(pia, options:=TestOptions.ReleaseDll) CompileAndVerify(piaCompilation) @@ -373,7 +373,7 @@ public mustinherit class ClassITest33 End class " - Dim piaCompilation = CreateCompilationWithMscorlib45(pia, options:=TestOptions.ReleaseDll) + Dim piaCompilation = CreateCompilationWithMscorlib461(pia, options:=TestOptions.ReleaseDll) CompileAndVerify(piaCompilation) @@ -441,7 +441,7 @@ public mustinherit class ClassITest33 End class " - Dim piaCompilation = CreateCompilationWithMscorlib45(pia, options:=TestOptions.ReleaseDll) + Dim piaCompilation = CreateCompilationWithMscorlib461(pia, options:=TestOptions.ReleaseDll) CompileAndVerify(piaCompilation) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingCollectionInitializerTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingCollectionInitializerTests.vb index 077fb5968150b..51fac213420f2 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingCollectionInitializerTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingCollectionInitializerTests.vb @@ -1847,7 +1847,7 @@ End Class Assert.Null(symbolInfo.Symbol) Assert.Equal(CandidateReason.OverloadResolutionFailure, symbolInfo.CandidateReason) Assert.Equal(2, symbolInfo.CandidateSymbols.Length) - Assert.Equal({"Sub X.Add(x As System.Collections.Generic.List(Of System.Byte))", + AssertEx.Equal({"Sub X.Add(x As System.Collections.Generic.List(Of System.Byte))", "Sub X.Add(x As X)"}, (symbolInfo.CandidateSymbols.Select(Function(s) s.ToTestDisplayString()).Order()).ToArray()) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingErrorTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingErrorTests.vb index 712f2eb4d7ab4..6007a4597119e 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingErrorTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingErrorTests.vb @@ -7,7 +7,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -1988,7 +1988,7 @@ Class MyAttribute End Sub End Class ]]> - , references:={Net40.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_RequiredConstExpr, "(From x In q Select x).Count()")) + , references:={Net40.References.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_RequiredConstExpr, "(From x In q Select x).Count()")) End Sub @@ -2015,7 +2015,7 @@ Class MyAttribute End Sub End Class ]]> - , references:={Net40.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_BadInstanceMemberAccess, "F1")) + , references:={Net40.References.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_BadInstanceMemberAccess, "F1")) End Sub @@ -2043,7 +2043,7 @@ Class MyAttribute End Sub End Class ]]> - , references:={Net40.SystemCore}).VerifyDiagnostics({Diagnostic(ERRID.ERR_RequiredConstExpr, "(From x In ""s"" Select x).Count()"), + , references:={Net40.References.SystemCore}).VerifyDiagnostics({Diagnostic(ERRID.ERR_RequiredConstExpr, "(From x In ""s"" Select x).Count()"), Diagnostic(ERRID.ERR_ObjectReferenceNotSupplied, "Program.F1")}) End Sub @@ -5909,7 +5909,7 @@ Class DerivedClass End Sub End Class -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC30393: 'Exit Try' can only appear inside a 'Try' statement. @@ -8176,7 +8176,7 @@ Class DerivedClass End Sub End Class -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC30101: Branching out of a 'Finally' is not valid. @@ -11512,7 +11512,7 @@ Module M End Function End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) Dim expectedErrors1 = BC30978: Range variable 'foo' hides a variable in an enclosing block or a range variable previously defined in the query expression. @@ -11540,7 +11540,7 @@ BC30978: Range variable 'foo' hides a variable in an enclosing block or a range End Sub End Module - , {Net40.SystemCore}, options:=TestOptions.ReleaseExe) + , {Net40.References.SystemCore}, options:=TestOptions.ReleaseExe) Dim expectedErrors1 = BC30978: Range variable 'x' hides a variable in an enclosing block or a range variable previously defined in the query expression. @@ -14485,7 +14485,7 @@ BC32006: 'Char' values cannot be converted to 'Short'. Use 'Microsoft.VisualBasi Public Structure S End Structure - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC32006: 'Char' values cannot be converted to 'Integer'. Use 'Microsoft.VisualBasic.AscW' to interpret a character as a Unicode value or 'Microsoft.VisualBasic.Val' to interpret it as a digit. @@ -16347,7 +16347,7 @@ BC36532: Nested function does not have the same signature as delegate 'Func(Of E End Sub End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -16375,7 +16375,7 @@ BC36533: 'ByRef' parameter 'filterValue' cannot be used in a query expression. End Sub End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, ) End Sub @@ -16394,7 +16394,7 @@ BC36533: 'ByRef' parameter 'filterValue' cannot be used in a query expression. End Sub End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36534: Expression cannot be converted into an expression tree. @@ -16418,7 +16418,7 @@ BC36534: Expression cannot be converted into an expression tree. End Sub End Structure - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36535: Instance members and 'Me' cannot be used within query expressions in structures. @@ -16442,7 +16442,7 @@ BC36535: Instance members and 'Me' cannot be used within query expressions in st End Sub End Structure - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36535: Instance members and 'Me' cannot be used within query expressions in structures. @@ -16494,7 +16494,7 @@ BC30311: Value of type 'Integer' cannot be converted to 'Object()'. End Sub End Module - , references:={Net40.SystemCore}) + , references:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36538: References to 'ByRef' parameters cannot be converted to an expression tree. @@ -16540,7 +16540,7 @@ BC36547: Anonymous type member or property 'GetHashCode' is already declared. End Sub End Module - , {Net40.System, Net40.SystemCore, Net40.MicrosoftVisualBasic}) + , {Net40.References.System, Net40.References.SystemCore, Net40.References.MicrosoftVisualBasic}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36548: Cannot convert anonymous type to an expression tree because a property of the type is used to initialize another property. @@ -16559,7 +16559,7 @@ BC36548: Cannot convert anonymous type to an expression tree because a property Dim x = New With {.y = 1, .z = From y In "" Select .y} End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseEmitDiagnostics(compilation, @@ -16672,7 +16672,7 @@ BC36558: The custom-designed version of 'System.Runtime.CompilerServices.Extensi End Function End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36559: Anonymous type member property 'X' cannot be used to infer the type of another member property because the type of 'X' is not yet established. @@ -16758,7 +16758,7 @@ Imports System End Sub End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -16785,7 +16785,7 @@ BC36582: Too many arguments to extension method 'Public Sub FooGeneric01()' defi End Sub End Module - , {Net40.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_NamedArgAlsoOmitted3, "Y").WithArguments("Y", "Public Sub ABC([Y As Byte = 0], [Z As Byte = 0])", "M")) + , {Net40.References.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_NamedArgAlsoOmitted3, "Y").WithArguments("Y", "Public Sub ABC([Y As Byte = 0], [Z As Byte = 0])", "M")) End Sub @@ -16805,7 +16805,7 @@ BC36582: Too many arguments to extension method 'Public Sub FooGeneric01()' defi End Sub End Module - , {Net40.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_NamedArgUsedTwice3, "Y").WithArguments("Y", "Public Sub ABC(Y As Byte, [Z As Byte = 0])", "M"), + , {Net40.References.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_NamedArgUsedTwice3, "Y").WithArguments("Y", "Public Sub ABC(Y As Byte, [Z As Byte = 0])", "M"), Diagnostic(ERRID.ERR_NamedArgUsedTwice3, "Y").WithArguments("Y", "Public Sub ABC(Y As Byte, [Z As Byte = 0])", "M")) End Sub @@ -16835,7 +16835,7 @@ BC36582: Too many arguments to extension method 'Public Sub FooGeneric01()' defi End Sub End Module - , {Net40.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_QueryOperatorNotFound, "Group Join").WithArguments("GroupJoin")) + , {Net40.References.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_QueryOperatorNotFound, "Group Join").WithArguments("GroupJoin")) End Sub @@ -16861,7 +16861,7 @@ BC36582: Too many arguments to extension method 'Public Sub FooGeneric01()' defi Implements Ifoo(Of T) End Class - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC42104: Variable 'x' is used before it has been assigned a value. A null reference exception could result at runtime. @@ -16895,7 +16895,7 @@ BC36590: Too few type arguments to extension method 'Public Sub foo(Of t2, t3)(p Implements Ifoo(Of T) End Class - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -16942,7 +16942,7 @@ BC36593: Expression of type 'S1' is not queryable. Make sure you are not missing End Sub End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36594: Definition of method 'y' is not accessible in this context. @@ -16992,7 +16992,7 @@ BC36597: 'Goto Label1' is not valid because 'Label1' is inside a scope that defi End Sub End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) compilation.VerifyDiagnostics( Diagnostic(ERRID.ERR_QueryAnonymousTypeFieldNameInference, "Nothing"), @@ -17024,7 +17024,7 @@ BC36597: 'Goto Label1' is not valid because 'Label1' is inside a scope that defi End Function End Module - , {Net40.SystemCore}).VerifyDiagnostics( + , {Net40.References.SystemCore}).VerifyDiagnostics( Diagnostic(ERRID.ERR_QueryDuplicateAnonTypeMemberName1, "Bar").WithArguments("Bar")) End Sub @@ -17041,7 +17041,7 @@ BC36597: 'Goto Label1' is not valid because 'Label1' is inside a scope that defi Dim q = From x% In New Integer() {1} End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -17112,7 +17112,7 @@ BC36602: 'ReadOnly' variable cannot be the target of an assignment in a lambda e End Sub End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36603: Multi-dimensional array cannot be converted to an expression tree. @@ -17134,7 +17134,7 @@ BC36603: Multi-dimensional array cannot be converted to an expression tree. End Sub End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36604: Late binding operations cannot be converted to an expression tree. @@ -17155,7 +17155,7 @@ BC36604: Late binding operations cannot be converted to an expression tree. Dim x = From y In "" Select ToString() End Class - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36606: Range variable name cannot match the name of a member of the 'Object' class. @@ -17166,7 +17166,7 @@ BC36606: Range variable name cannot match the name of a member of the 'Object' c Public Sub BC36610ERR_QueryNameNotDeclared() - Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(references:={Net40.SystemCore}, source:= + Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(references:={Net40.References.SystemCore}, source:= Imports System @@ -17234,7 +17234,7 @@ BC36614: Range variable name cannot be inferred from an XML identifier that is n End Function End Module - , {Net40.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_TypeCharOnAggregation, "Bar$"), + , {Net40.References.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_TypeCharOnAggregation, "Bar$"), Diagnostic(ERRID.ERR_QueryAnonymousTypeDisallowsTypeChar, "Bar$")) End Sub @@ -17355,7 +17355,7 @@ Module M1 End Sub End Module - , {Net40.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_IterationVariableShadowLocal2, "implicit").WithArguments("implicit"), + , {Net40.References.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_IterationVariableShadowLocal2, "implicit").WithArguments("implicit"), Diagnostic(ERRID.ERR_IterationVariableShadowLocal2, "implicit").WithArguments("implicit"), Diagnostic(ERRID.ERR_IterationVariableShadowLocal2, "implicit").WithArguments("implicit"), Diagnostic(ERRID.ERR_IterationVariableShadowLocal2, "implicit").WithArguments("implicit"), @@ -17440,7 +17440,7 @@ BC36635: Lambda expressions are not valid in the first expression of a 'Select C End Sub End Structure - , references:={Net40.SystemCore}) + , references:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36638: Instance members and 'Me' cannot be used within a lambda expression in structures. @@ -17775,7 +17775,7 @@ BC42104: Variable 'y' is used before it has been assigned a value. A null refere End Sub End Module - , {Net40.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_LambdaBindingMismatch2, + , {Net40.References.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_LambdaBindingMismatch2, .Value.Replace(vbLf, Environment.NewLine)).WithArguments("System.Action") @@ -17799,7 +17799,7 @@ BC42104: Variable 'y' is used before it has been assigned a value. A null refere End Sub End Module - , {Net40.SystemCore}).VerifyDiagnostics( + , {Net40.References.SystemCore}).VerifyDiagnostics( Diagnostic(ERRID.ERR_StatementLambdaInExpressionTree, .Value.Replace(vbLf, Environment.NewLine))) @@ -17832,7 +17832,7 @@ BC42104: Variable 'y' is used before it has been assigned a value. A null refere End Function End Module - , {Net40.SystemCore}).VerifyDiagnostics( + , {Net40.References.SystemCore}).VerifyDiagnostics( Diagnostic(ERRID.ERR_DelegateBindingMismatchStrictOff3, "o.moo(Of Integer)").WithArguments("Public Function moo(Of Integer)(y As Integer) As String", "Delegate Function M.del1g(Of String)(x As String) As String", "m1")) End Sub @@ -17859,7 +17859,7 @@ Module M End Function End Module ]]> -, targetFramework:=TargetFramework.Mscorlib45AndVBRuntime, references:=Net451XmlReferences) +, targetFramework:=TargetFramework.Mscorlib461AndVBRuntime, references:=Net461XmlReferences) compilation.AssertTheseDiagnostics(.E2) @@ -18394,7 +18394,7 @@ Module Extension01 End Sub End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, BC36907: Extension method 'Public Sub FooGeneric01()' defined in 'Extension01' is not generic (or has no free type parameters) and so cannot have type arguments. @@ -19162,7 +19162,7 @@ Class E End Property End Class - , {Net40.SystemCore}).VerifyDiagnostics( + , {Net40.References.SystemCore}).VerifyDiagnostics( Diagnostic(ERRID.WRN_SharedMemberThroughInstance, "1")) End Sub @@ -21303,7 +21303,7 @@ Class DerivedClass End Sub End Class - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) VerifyDiagnostics(compilation, Diagnostic(ERRID.WRN_DefAsgNoRetValFuncVal1, "End Function").WithArguments("")) End Sub @@ -21331,7 +21331,7 @@ Class DerivedClass End Sub End Class - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) AssertTheseDiagnostics(compilation, - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -23648,7 +23648,7 @@ Return item.ToString() = "" End Function).ToList() End Sub - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) VerifyDiagnostics(compilation, Diagnostic(ERRID.ERR_Syntax, """"""), Diagnostic(ERRID.ERR_ExecutableAsDeclaration, "Return lab1"), Diagnostic(ERRID.ERR_InvalidEndFunction, "End Function"), @@ -24290,7 +24290,7 @@ Class Test End Sub End Class ]]> - , {Net40.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom)) + , {Net40.References.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom)) AssertTheseDiagnostics(compilation, @@ -24328,7 +24328,7 @@ Class Test End Sub End Class ]]> - , {Net40.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom)) + , {Net40.References.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom)) AssertTheseDiagnostics(compilation, @@ -24363,7 +24363,7 @@ Class Test End Sub End Class ]]> - , {Net40.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom)) + , {Net40.References.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom)) AssertTheseDiagnostics(compilation, @@ -24411,7 +24411,7 @@ Class C1 End Sub End Class ]]> - , {Net40.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom)) + , {Net40.References.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom)) AssertTheseDiagnostics(compilation, @@ -24454,7 +24454,7 @@ Class C1 End Sub End Class ]]> - , {Net40.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom)) + , {Net40.References.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom)) AssertTheseDiagnostics(compilation, @@ -26134,7 +26134,7 @@ End Module ]]> - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.SystemCore}) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, diff --git a/src/Compilers/VisualBasic/Test/Semantic/Binding/ForEachTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Binding/ForEachTests.vb index 5a11f981df825..f28793c052ada 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Binding/ForEachTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Binding/ForEachTests.vb @@ -11,9 +11,9 @@ Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class ForLoopTests @@ -2325,7 +2325,7 @@ Module Program End Module - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, references:={TestMetadata.Net40.SystemCore}) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, references:={Net40.References.SystemCore}) compilation.AssertNoDiagnostics() ' NOTE: this did not succeed in Dev10, but it does in Roslyn because we do a full overload resolution and can decide whether this ' is ambiguous or not. @@ -2375,7 +2375,7 @@ Module Program End Module - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, references:={TestMetadata.Net40.SystemCore}) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, references:={Net40.References.SystemCore}) AssertTheseDiagnostics(compilation, BC42025: Access of shared member, constant member, enum member or nested type through an instance; qualifying expression will not be evaluated. @@ -2428,7 +2428,7 @@ Module Program End Module - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, references:={TestMetadata.Net40.SystemCore}) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, references:={Net40.References.SystemCore}) AssertTheseDiagnostics(compilation, BC42025: Access of shared member, constant member, enum member or nested type through an instance; qualifying expression will not be evaluated. @@ -3240,7 +3240,7 @@ BC30105: Number of indices is less than the number of dimensions of the indexed 1 2 3 -]]>, references:={TestMetadata.Net40.SystemCore}) +]]>, references:={Net40.References.SystemCore}) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Binding/LookupTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Binding/LookupTests.vb index 044ae1609d6b6..839c36a9d8df2 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Binding/LookupTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Binding/LookupTests.vb @@ -12,7 +12,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class LookupTests @@ -941,7 +941,7 @@ P.Q.R.S ' We need to be careful about metadata references we use here. ' The test checks that fields of namespace symbols are initialized in certain order. ' If we used a shared Mscorlib reference then other tests might have already initialized it's shared AssemblySymbol. - Dim nonSharedMscorlibReference = AssemblyMetadata.CreateFromImage(ResourcesNet451.mscorlib).GetReference(display:="mscorlib.v4_0_30319.dll") + Dim nonSharedMscorlibReference = AssemblyMetadata.CreateFromImage(Net461.Resources.mscorlib).GetReference(display:="mscorlib.v4_0_30319.dll") Dim c = VisualBasicCompilation.Create("DoNotLoadTypesForAccessibilityOfMostAccessibleTypeWithinANamespace", syntaxTrees:={Parse( @@ -1606,7 +1606,7 @@ Module Module1 End Sub End Module -, references:={Net451.mscorlib, Net451.System, Net451.MicrosoftVisualBasic, Net451.SystemWindowsForms}) +, references:={Net461.References.mscorlib, Net461.References.System, Net461.References.MicrosoftVisualBasic, Net461.References.SystemWindowsForms}) CompilationUtils.AssertNoDiagnostics(compilation) @@ -1622,11 +1622,11 @@ End Module Assert.Equal(NamespaceKind.Module, ns.NamespaceKind) Assert.Equal("System.ComponentModel", ns.ToTestDisplayString()) - Assert.Equal({"System.ComponentModel", "System.Windows.Forms.ComponentModel"}, + AssertEx.Equal({"System.ComponentModel", "System.Windows.Forms.ComponentModel"}, semanticModel.LookupNamespacesAndTypes(node.Position, name:="ComponentModel").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"System.ComponentModel", "System.Windows.Forms.ComponentModel"}, + AssertEx.Equal({"System.ComponentModel", "System.Windows.Forms.ComponentModel"}, semanticModel.LookupSymbols(node.Position, name:="ComponentModel").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) End Sub @@ -1672,11 +1672,11 @@ BC30112: 'Diagnostics' is a namespace and cannot be used as an expression. Assert.Equal(NamespaceKind.Compilation, ns.NamespaceKind) Assert.Equal("System.Diagnostics", ns.ToTestDisplayString()) - Assert.Equal({"System.Diagnostics", "Windows.Foundation.Diagnostics"}, + AssertEx.Equal({"System.Diagnostics", "Windows.Foundation.Diagnostics"}, semanticModel.LookupNamespacesAndTypes(node.Position, name:="Diagnostics").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"System.Diagnostics", "Windows.Foundation.Diagnostics"}, + AssertEx.Equal({"System.Diagnostics", "Windows.Foundation.Diagnostics"}, semanticModel.LookupSymbols(node.Position, name:="Diagnostics").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) End Sub @@ -1741,11 +1741,11 @@ End Namespace Assert.Equal(NamespaceKind.Module, ns1.NamespaceKind) Assert.Equal("NS1.NS3", ns1.ToTestDisplayString()) - Assert.Equal({"NS1.NS3", "NS2.NS3"}, + AssertEx.Equal({"NS1.NS3", "NS2.NS3"}, semanticModel.LookupNamespacesAndTypes(node1.Position, name:="NS3").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"NS1.NS3", "NS2.NS3"}, + AssertEx.Equal({"NS1.NS3", "NS2.NS3"}, semanticModel.LookupSymbols(node1.Position, name:="NS3").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) End Sub @@ -1928,7 +1928,7 @@ BC37229: 'T1' is ambiguous between declarations in namespaces 'NS1.NS6.NS7, NS2. Assert.Null(info3.Symbol) Assert.Equal(CandidateReason.Ambiguous, info3.CandidateReason) ' Content of this list should determine content of lists below !!! - Assert.Equal({"NS1.NS6.NS7.T1", "NS2.NS6.NS7.T1", "NS4.NS6.NS7.T1", "NS5.NS6.NS7.T1"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"NS1.NS6.NS7.T1", "NS2.NS6.NS7.T1", "NS4.NS6.NS7.T1", "NS5.NS6.NS7.T1"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next For Each i In {2, 5, 8, 23} @@ -1936,7 +1936,7 @@ BC37229: 'T1' is ambiguous between declarations in namespaces 'NS1.NS6.NS7, NS2. Assert.Null(info2.Symbol) Assert.Equal(CandidateReason.Ambiguous, info2.CandidateReason) - Assert.Equal({"NS1.NS6.NS7", "NS2.NS6.NS7", "NS4.NS6.NS7", "NS5.NS6.NS7"}, info2.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"NS1.NS6.NS7", "NS2.NS6.NS7", "NS4.NS6.NS7", "NS5.NS6.NS7"}, info2.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next For Each i In {1, 4, 7, 22} @@ -1944,13 +1944,13 @@ BC37229: 'T1' is ambiguous between declarations in namespaces 'NS1.NS6.NS7, NS2. Assert.Null(info1.Symbol) Assert.Equal(CandidateReason.Ambiguous, info1.CandidateReason) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS4.NS6", "NS5.NS6"}, info1.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS4.NS6", "NS5.NS6"}, info1.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupNamespacesAndTypes(nodes(i).Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupSymbols(nodes(i).Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next @@ -1960,7 +1960,7 @@ BC37229: 'T1' is ambiguous between declarations in namespaces 'NS1.NS6.NS7, NS2. Assert.Null(info2.Symbol) Assert.Equal(If(i = 16, CandidateReason.Ambiguous, If(i = 19, CandidateReason.NotAnAttributeType, CandidateReason.NotATypeOrNamespace)), info2.CandidateReason) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, info2.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, info2.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next For Each i In {12, 15, 18, 21} @@ -1969,7 +1969,7 @@ BC37229: 'T1' is ambiguous between declarations in namespaces 'NS1.NS6.NS7, NS2. Assert.Null(info3.Symbol) Assert.Equal(If(i = 18, CandidateReason.Ambiguous, If(i = 21, CandidateReason.NotAnAttributeType, CandidateReason.NotATypeOrNamespace)), info3.CandidateReason) ' Content of this list should determine content of lists below !!! - Assert.Equal({"NS1.NS6.NS7", "NS2.NS6.NS7", "NS4.NS6.NS7", "NS5.NS6.NS7", "NS9.NS6.NS7"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"NS1.NS6.NS7", "NS2.NS6.NS7", "NS4.NS6.NS7", "NS5.NS6.NS7", "NS9.NS6.NS7"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next For Each i In {11, 14, 17, 20} @@ -1977,7 +1977,7 @@ BC37229: 'T1' is ambiguous between declarations in namespaces 'NS1.NS6.NS7, NS2. Assert.Null(info3.Symbol) Assert.Equal(CandidateReason.Ambiguous, info3.CandidateReason) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next End Sub @@ -2112,11 +2112,11 @@ End Namespace Assert.Equal("NS1.NS6", info1.Symbol.ToTestDisplayString()) Assert.Equal(NamespaceKind.Module, DirectCast(info1.Symbol, NamespaceSymbol).NamespaceKind) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupNamespacesAndTypes(nodes(i).Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS4.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupSymbols(nodes(i).Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next @@ -2240,27 +2240,27 @@ BC30002: Type 'NS6.NS7.M1' is not defined. Assert.Null(info3.Symbol) Assert.Equal(If(i = 3, CandidateReason.Ambiguous, CandidateReason.NotATypeOrNamespace), info3.CandidateReason) ' Content of this list should determine content of lists below !!! - Assert.Equal({"Sub NS1.NS6.NS7.T1.M1()", "Sub NS2.NS6.NS7.T1.M1()", "Sub NS5.NS6.NS7.T1.M1()"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"Sub NS1.NS6.NS7.T1.M1()", "Sub NS2.NS6.NS7.T1.M1()", "Sub NS5.NS6.NS7.T1.M1()"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next For Each i In {2, 5, 8, 11} Dim info2 = semanticModel.GetSymbolInfo(nodes(i)) Assert.Null(info2.Symbol) Assert.Equal(CandidateReason.Ambiguous, info2.CandidateReason) - Assert.Equal({"NS1.NS6.NS7", "NS2.NS6.NS7", "NS5.NS6.NS7"}, info2.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"NS1.NS6.NS7", "NS2.NS6.NS7", "NS5.NS6.NS7"}, info2.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next For Each i In {1, 4, 7, 10} Dim info1 = semanticModel.GetSymbolInfo(nodes(i)) Assert.Null(info1.Symbol) Assert.Equal(CandidateReason.Ambiguous, info1.CandidateReason) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS5.NS6"}, info1.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS5.NS6"}, info1.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupNamespacesAndTypes(nodes(i).Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupSymbols(nodes(i).Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next @@ -2353,7 +2353,7 @@ BC30516: Overload resolution failed because no accessible 'M1' accepts this numb Assert.Null(info3.Symbol) Assert.Equal(CandidateReason.OverloadResolutionFailure, info3.CandidateReason) - Assert.Equal({"Sub NS1.NS6.NS7.T1.M1(x As System.Int32)", "Sub NS1.NS6.NS7.T1.M1(x As System.Int64)"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"Sub NS1.NS6.NS7.T1.M1(x As System.Int32)", "Sub NS1.NS6.NS7.T1.M1(x As System.Int64)"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Dim node2 As IdentifierNameSyntax = CompilationUtils.FindBindingText(Of IdentifierNameSyntax)(compilation, "a.vb", 2) @@ -2367,11 +2367,11 @@ BC30516: Overload resolution failed because no accessible 'M1' accepts this numb Assert.Equal("NS1.NS6", info1.Symbol.ToTestDisplayString()) Assert.Equal(NamespaceKind.Module, DirectCast(info1.Symbol, NamespaceSymbol).NamespaceKind) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupNamespacesAndTypes(node1.Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupSymbols(node1.Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) End Sub @@ -2468,11 +2468,11 @@ End Namespace Assert.Equal("NS1.NS6", info1.Symbol.ToTestDisplayString()) Assert.Equal(NamespaceKind.Module, DirectCast(info1.Symbol, NamespaceSymbol).NamespaceKind) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupNamespacesAndTypes(node1.Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupSymbols(node1.Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) End Sub @@ -2598,27 +2598,27 @@ BC30562: 'T1' is ambiguous between declarations in Modules 'NS1.NS6.NS7.Module1, Assert.Null(info3.Symbol) Assert.Equal(CandidateReason.Ambiguous, info3.CandidateReason) ' Content of this list should determine content of lists below !!! - Assert.Equal({"NS1.NS6.NS7.Module1.T1", "NS2.NS6.NS7.Module1.T1", "NS5.NS6.NS7.Module1.T1"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"NS1.NS6.NS7.Module1.T1", "NS2.NS6.NS7.Module1.T1", "NS5.NS6.NS7.Module1.T1"}, info3.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next For Each i In {2, 5, 8, 11} Dim info2 = semanticModel.GetSymbolInfo(nodes(i)) Assert.Null(info2.Symbol) Assert.Equal(CandidateReason.Ambiguous, info2.CandidateReason) - Assert.Equal({"NS1.NS6.NS7", "NS2.NS6.NS7", "NS5.NS6.NS7"}, info2.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"NS1.NS6.NS7", "NS2.NS6.NS7", "NS5.NS6.NS7"}, info2.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next For Each i In {1, 4, 7, 10} Dim info1 = semanticModel.GetSymbolInfo(nodes(i)) Assert.Null(info1.Symbol) Assert.Equal(CandidateReason.Ambiguous, info1.CandidateReason) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS5.NS6"}, info1.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS5.NS6"}, info1.CandidateSymbols.AsEnumerable().Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupNamespacesAndTypes(nodes(i).Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupSymbols(nodes(i).Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next @@ -2745,11 +2745,11 @@ BC30109: 'Module1.T1' is a class type and cannot be used as an expression. Assert.Equal("NS1.NS6", info1.Symbol.ToTestDisplayString()) Assert.Equal(NamespaceKind.Module, DirectCast(info1.Symbol, NamespaceSymbol).NamespaceKind) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupNamespacesAndTypes(nodes(i).Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) - Assert.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, + AssertEx.Equal({"NS1.NS6", "NS2.NS6", "NS3.NS6", "NS5.NS6", "NS9.NS6"}, semanticModel.LookupSymbols(nodes(i).Position, name:="NS6").AsEnumerable(). Select(Function(s) s.ToTestDisplayString()).OrderBy(Function(s) s).ToArray()) Next diff --git a/src/Compilers/VisualBasic/Test/Semantic/Binding/SyncLockTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Binding/SyncLockTests.vb index 4577b389bf2ad..3a349595a3cac 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Binding/SyncLockTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Binding/SyncLockTests.vb @@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class SyncLockTests @@ -88,7 +89,7 @@ Class Program End Sub End Class -, {TestMetadata.Net40.SystemCore}).VerifyDiagnostics() +, {Net40.References.SystemCore}).VerifyDiagnostics() End Sub @@ -180,7 +181,7 @@ Module StringExtensions End Sub End Module -, {TestMetadata.Net40.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_SyncLockRequiresReferenceType1, "syncroot.PrintInt()").WithArguments("Integer"), +, {Net40.References.SystemCore}).VerifyDiagnostics(Diagnostic(ERRID.ERR_SyncLockRequiresReferenceType1, "syncroot.PrintInt()").WithArguments("Integer"), Diagnostic(ERRID.ERR_VoidValue, "syncroot.PrintVoid"), Diagnostic(ERRID.WRN_DefAsgUseNullRef, "syncroot").WithArguments("syncroot")) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb b/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb index 1670665c25413..fa7e860d7c8c4 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Compilation/CompilationAPITests.vb @@ -18,7 +18,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests Imports Roslyn.Test.Utilities Imports Roslyn.Test.Utilities.TestHelpers -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Imports CS = Microsoft.CodeAnalysis.CSharp Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -43,12 +43,12 @@ Class C End Class") Dim options = New VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary). WithGeneralDiagnosticOption(ReportDiagnostic.Suppress) - Dim comp = CreateCompilationWithMscorlib45({tree}, options:=options) + Dim comp = CreateCompilationWithMscorlib461({tree}, options:=options) comp.AssertNoDiagnostics() options = options.WithSyntaxTreeOptionsProvider( New TestSyntaxTreeOptionsProvider(tree, ("BC42024", ReportDiagnostic.Warn))) - comp = CreateCompilationWithMscorlib45({tree}, options:=options) + comp = CreateCompilationWithMscorlib461({tree}, options:=options) ' Global options override syntax tree options. This is the opposite of C# behavior comp.AssertNoDiagnostics() End Sub @@ -106,12 +106,12 @@ End Class") Dim options = TestOptions.DebugDll.WithSpecificDiagnosticOptions( CreateImmutableDictionary(("BC42024", ReportDiagnostic.Suppress))) - Dim comp = CreateCompilationWithMscorlib45({tree}, options:=options) + Dim comp = CreateCompilationWithMscorlib461({tree}, options:=options) comp.AssertNoDiagnostics() options = options.WithSyntaxTreeOptionsProvider( New TestSyntaxTreeOptionsProvider(tree, ("BC42024", ReportDiagnostic.Error))) - Dim comp2 = CreateCompilationWithMscorlib45({tree}, options:=options) + Dim comp2 = CreateCompilationWithMscorlib461({tree}, options:=options) ' Specific diagnostic options should have precedence over tree options comp2.AssertNoDiagnostics() End Sub @@ -135,7 +135,7 @@ End Class") New TestSyntaxTreeOptionsProvider( (tree, {("BC42024", ReportDiagnostic.Suppress)}), (newTree, {("BC4024", ReportDiagnostic.Error)}))) - Dim comp = CreateCompilationWithMscorlib45({tree, newTree}, options:=options) + Dim comp = CreateCompilationWithMscorlib461({tree, newTree}, options:=options) comp.AssertTheseDiagnostics( BC42024: Unused local variable: 'y'. @@ -285,7 +285,7 @@ BC37283: Invalid assembly name: Name contains invalid characters. listSyntaxTree.Add(t1) ' System.dll - listRef.Add(Net451.System) + listRef.Add(NetFramework.System) Dim ops = TestOptions.ReleaseExe ' Create Compilation with Option is not Nothing @@ -381,7 +381,7 @@ End Namespace comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef) 'IsCaseSensitive - Assert.Equal(Of Boolean)(False, comp.IsCaseSensitive) + AssertEx.Equal(Of Boolean)(False, comp.IsCaseSensitive) Assert.Equal("D", comp.GetTypeByMetadataName("C+D").Name) Assert.Equal("E", comp.GetTypeByMetadataName("C+D+E").Name) @@ -530,8 +530,8 @@ End Namespace Public Sub ReferenceAPITest() ' Create Compilation takes two args Dim comp = VisualBasicCompilation.Create("Compilation") - Dim ref1 = Net451.mscorlib - Dim ref2 = Net451.System + Dim ref1 = NetFramework.mscorlib + Dim ref2 = NetFramework.System Dim ref3 = New TestMetadataReference(fullPath:="c:\xml.bms") Dim ref4 = New TestMetadataReference(fullPath:="c:\aaa.dll") @@ -561,19 +561,19 @@ End Namespace 'WithReferences Dim hs1 As New HashSet(Of MetadataReference) From {ref1, ref2, ref3} Dim compCollection1 = VisualBasicCompilation.Create("Compilation") - Assert.Equal(Of Integer)(0, Enumerable.Count(Of MetadataReference)(compCollection1.References)) + AssertEx.Equal(Of Integer)(0, Enumerable.Count(Of MetadataReference)(compCollection1.References)) Dim c2 As Compilation = compCollection1.WithReferences(hs1) - Assert.Equal(Of Integer)(3, Enumerable.Count(Of MetadataReference)(c2.References)) + AssertEx.Equal(Of Integer)(3, Enumerable.Count(Of MetadataReference)(c2.References)) 'WithReferences Dim compCollection2 = VisualBasicCompilation.Create("Compilation") - Assert.Equal(Of Integer)(0, Enumerable.Count(Of MetadataReference)(compCollection2.References)) + AssertEx.Equal(Of Integer)(0, Enumerable.Count(Of MetadataReference)(compCollection2.References)) Dim c3 As Compilation = compCollection1.WithReferences(ref1, ref2, ref3) - Assert.Equal(Of Integer)(3, Enumerable.Count(Of MetadataReference)(c3.References)) + AssertEx.Equal(Of Integer)(3, Enumerable.Count(Of MetadataReference)(c3.References)) 'ReferencedAssemblyNames Dim RefAsm_Names As IEnumerable(Of AssemblyIdentity) = c2.ReferencedAssemblyNames - Assert.Equal(Of Integer)(2, Enumerable.Count(Of AssemblyIdentity)(RefAsm_Names)) + AssertEx.Equal(Of Integer)(2, Enumerable.Count(Of AssemblyIdentity)(RefAsm_Names)) Dim ListNames As New List(Of String) Dim I As AssemblyIdentity For Each I In RefAsm_Names @@ -584,7 +584,7 @@ End Namespace 'RemoveAllReferences c2 = c2.RemoveAllReferences - Assert.Equal(Of Integer)(0, Enumerable.Count(Of MetadataReference)(c2.References)) + AssertEx.Equal(Of Integer)(0, Enumerable.Count(Of MetadataReference)(c2.References)) ' Overload with Hashset Dim hs = New HashSet(Of MetadataReference)() From {ref1, ref2, ref3} @@ -796,13 +796,13 @@ End Namespace 'ContainsSyntaxTree Dim b1 As Boolean = comp.ContainsSyntaxTree(t2) - Assert.Equal(Of Boolean)(False, b1) + AssertEx.Equal(Of Boolean)(False, b1) comp = comp.AddSyntaxTrees({t2}) b1 = comp.ContainsSyntaxTree(t2) - Assert.Equal(Of Boolean)(True, b1) + AssertEx.Equal(Of Boolean)(True, b1) Dim xt As SyntaxTree = Nothing - Assert.Equal(Of Boolean)(False, comp.ContainsSyntaxTree(xt)) + AssertEx.Equal(Of Boolean)(False, comp.ContainsSyntaxTree(xt)) comp = comp.RemoveSyntaxTrees({t2}) Assert.Equal(1, comp.SyntaxTrees.Length) @@ -813,8 +813,8 @@ End Namespace comp = comp.RemoveAllSyntaxTrees Assert.Equal(0, comp.SyntaxTrees.Length) comp = VisualBasicCompilation.Create("Compilation").AddSyntaxTrees(listSyntaxTree).RemoveSyntaxTrees({t2}) - Assert.Equal(Of Integer)(1, comp.SyntaxTrees.Length) - Assert.Equal(Of String)("Object", comp.ObjectType.Name) + AssertEx.Equal(Of Integer)(1, comp.SyntaxTrees.Length) + AssertEx.Equal(Of String)("Object", comp.ObjectType.Name) ' Remove mid SyntaxTree listSyntaxTree.Add(t3) @@ -837,7 +837,7 @@ End Namespace ' Create compilation with args is disordered Dim comp1 = VisualBasicCompilation.Create("Compilation") Dim Err = "c:\file_that_does_not_exist" - Dim ref1 = Net451.mscorlib + Dim ref1 = NetFramework.mscorlib Dim listRef = New List(Of MetadataReference) ' this is NOT testing Roslyn listRef.Add(ref1) @@ -1053,8 +1053,8 @@ BC37224: Module 'a1.netmodule' is already defined in this assembly. Each module Dim csCompRef = csComp.ToMetadataReference(embedInteropTypes:=True) - Dim ref1 = Net451.mscorlib - Dim ref2 = Net451.System + Dim ref1 = NetFramework.mscorlib + Dim ref2 = NetFramework.System ' Add VisualBasicCompilationReference comp = VisualBasicCompilation.Create("Test1", @@ -1169,7 +1169,7 @@ BC37224: Module 'a1.netmodule' is already defined in this assembly. Each module Public Sub AssemblySuppliedAsModule() - Dim comp = VisualBasicCompilation.Create("Compilation", references:={ModuleMetadata.CreateFromImage(ResourcesNet451.System).GetReference()}) + Dim comp = VisualBasicCompilation.Create("Compilation", references:={ModuleMetadata.CreateFromImage(Net461.Resources.System).GetReference()}) Assert.Equal(comp.GetDiagnostics().First().Code, ERRID.ERR_MetaDataIsNotModule) End Sub @@ -1179,7 +1179,7 @@ BC37224: Module 'a1.netmodule' is already defined in this assembly. Each module Public Sub NegReference1() Dim comp = VisualBasicCompilation.Create("Compilation") - Assert.Null(comp.GetReferencedAssemblySymbol(Net451.System)) + Assert.Null(comp.GetReferencedAssemblySymbol(NetFramework.System)) Dim modRef1 = ModuleMetadata.CreateFromImage(TestResources.MetadataTests.NetModule01.ModuleVB01).GetReference() Assert.Null(comp.GetReferencedModuleSymbol(modRef1)) @@ -1190,7 +1190,7 @@ BC37224: Module 'a1.netmodule' is already defined in this assembly. Each module Public Sub NegReference2() Dim comp = VisualBasicCompilation.Create("Compilation") - Dim ref1 = Net451.System + Dim ref1 = NetFramework.System Dim ref2 = New TestMetadataReference(fullPath:="c:\a\xml.bms") Dim ref3 = ref2 Dim ref4 = New TestMetadataReference(fullPath:="c:\aaa.dll") @@ -1218,7 +1218,7 @@ BC37224: Module 'a1.netmodule' is already defined in this assembly. Each module Public Sub NegReference3() Dim comp = VisualBasicCompilation.Create("Compilation") Dim ref1 = New TestMetadataReference(fullPath:="c:\xml.bms") - Dim ref2 = Net451.System + Dim ref2 = NetFramework.System comp = comp.AddReferences(ref1) Assert.Equal(1, comp.References.Count) @@ -1256,8 +1256,8 @@ BC37224: Module 'a1.netmodule' is already defined in this assembly. Each module Public Sub NegReference5() Dim comp = VisualBasicCompilation.Create("Compilation") - Dim ref1 = Net451.mscorlib - Dim ref2 = Net451.System + Dim ref1 = NetFramework.mscorlib + Dim ref2 = NetFramework.System Assert.Throws(Of ArgumentException)( Sub() comp = comp.ReplaceReference(ref1, ref2) @@ -2134,7 +2134,7 @@ End Class Public Sub GetEntryPoint_Script() Dim source = - Dim compilation = CreateCompilationWithMscorlib45({VisualBasicSyntaxTree.ParseText(source.Value, options:=TestOptions.Script)}, options:=TestOptions.ReleaseDll) + Dim compilation = CreateCompilationWithMscorlib461({VisualBasicSyntaxTree.ParseText(source.Value, options:=TestOptions.Script)}, options:=TestOptions.ReleaseDll) compilation.VerifyDiagnostics() Dim scriptMethod = compilation.GetMember("Script.
") @@ -2154,7 +2154,7 @@ End Class End Sub End Class ]]> - Dim compilation = CreateCompilationWithMscorlib45({VisualBasicSyntaxTree.ParseText(source.Value, options:=TestOptions.Script)}, options:=TestOptions.ReleaseDll) + Dim compilation = CreateCompilationWithMscorlib461({VisualBasicSyntaxTree.ParseText(source.Value, options:=TestOptions.Script)}, options:=TestOptions.ReleaseDll) compilation.VerifyDiagnostics(Diagnostic(ERRID.WRN_MainIgnored, "Main").WithArguments("Public Shared Sub Main()").WithLocation(3, 20)) Dim scriptMethod = compilation.GetMember("Script.
") @@ -2485,7 +2485,7 @@ End Class Public Sub GetMetadataReferenceAPITest() Dim comp = VisualBasicCompilation.Create("Compilation") - Dim metadata = Net451.mscorlib + Dim metadata = NetFramework.mscorlib comp = comp.AddReferences(metadata) Dim assemblySmb = comp.GetReferencedAssemblySymbol(metadata) Dim reference = comp.GetMetadataReference(assemblySmb) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Compilation/ReferenceManagerTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Compilation/ReferenceManagerTests.vb index 753998b9b279b..6772b41a13223 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Compilation/ReferenceManagerTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Compilation/ReferenceManagerTests.vb @@ -6,7 +6,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -656,11 +656,11 @@ BC31539: Cannot find the interop type that matches the embedded type 'IB'. Are y Dim comp = VisualBasicCompilation.Create( "DupSignedRefs", {VisualBasicSyntaxTree.ParseText(text)}, - {Net451.System, Net20.System}, + {NetFramework.System, Net20.References.System}, TestOptions.ReleaseDll.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default)) comp.VerifyDiagnostics( - Diagnostic(ERRID.ERR_DuplicateReferenceStrong).WithArguments(Net451.System.Display, Net20.System.Display)) + Diagnostic(ERRID.ERR_DuplicateReferenceStrong).WithArguments(NetFramework.System.Display, Net20.References.System.Display)) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelAPITests.vb b/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelAPITests.vb index ee55f0694bd8a..62a79f5dd481c 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelAPITests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelAPITests.vb @@ -7,8 +7,8 @@ Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -4549,7 +4549,7 @@ Namespace Global.Microsoft.CodeAnalysis.VisualBasic End Class End Namespace ]]> -, {TestMetadata.Net40.SystemCore}, options:=TestOptions.DebugDll.WithRootNamespace("Microsoft.CodeAnalysis.VisualBasic.UnitTests")) +, {Net40.References.SystemCore}, options:=TestOptions.DebugDll.WithRootNamespace("Microsoft.CodeAnalysis.VisualBasic.UnitTests")) Dim semanticModel = CompilationUtils.GetSemanticModel(compilation, "a.vb") diff --git a/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelGetDeclaredSymbolAPITests.vb b/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelGetDeclaredSymbolAPITests.vb index c3cbe9b56c90a..82518b12199b3 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelGetDeclaredSymbolAPITests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelGetDeclaredSymbolAPITests.vb @@ -1939,7 +1939,7 @@ End Module Assert.False(symLabel.IsOverrides) Assert.False(symLabel.IsOverridable) Assert.False(symLabel.IsShared) - Assert.Equal(Of Accessibility)(Accessibility.NotApplicable, symLabel.DeclaredAccessibility) + AssertEx.Equal(Of Accessibility)(Accessibility.NotApplicable, symLabel.DeclaredAccessibility) Assert.Equal(1, symLabel.Locations.Length) Assert.Equal("Public Sub Main()", symLabel.ContainingSymbol.ToString) Assert.Equal("Public Sub Main()", symLabel.ContainingMethod.ToString) @@ -2625,7 +2625,7 @@ End Namespace Dim memSymbol = compilation.GlobalNamespace.GetMembers("System").Single() Assert.Equal(nsSymbolA.Locations.Length, memSymbol.Locations.Length) - Assert.Equal(Of ISymbol)(nsSymbolA, memSymbol) + AssertEx.Equal(Of ISymbol)(nsSymbolA, memSymbol) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelLookupSymbolsAPITests.vb b/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelLookupSymbolsAPITests.vb index a4f4f27e9c39e..99c206f0edc56 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelLookupSymbolsAPITests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Compilation/SemanticModelLookupSymbolsAPITests.vb @@ -7,7 +7,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - +Imports Basic.Reference.Assemblies Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -308,7 +308,7 @@ Module E End Sub End Module ]]> -, {TestMetadata.Net40.SystemCore}) +, {Net40.References.SystemCore}) Dim tree = compilation.SyntaxTrees.Single() Dim semanticModel = compilation.GetSemanticModel(tree) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.vb index d405f22faf4f2..b072d3e1fe5c5 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.vb @@ -880,7 +880,7 @@ End Class ' Verify no compiler diagnostics. Dim trees = builder.ToImmutable() - Dim compilation = CreateCompilationWithMscorlib45(trees.ToArray(), {SystemRef}, TestOptions.ReleaseDll) + Dim compilation = CreateCompilationWithMscorlib461(trees.ToArray(), {SystemRef}, TestOptions.ReleaseDll) compilation.VerifyDiagnostics() Dim isGeneratedFile As Func(Of String, Boolean) = Function(fileName) fileName.Contains("SourceFileWithAutoGeneratedComment") OrElse generatedFileNames.Contains(fileName) @@ -912,7 +912,7 @@ Partial Class PartialType End Class ]]>.Value Dim tree = VisualBasicSyntaxTree.ParseText(source, path:="SourceFileRegular.vb") - Dim compilation = CreateCompilationWithMscorlib45({tree}, {SystemRef}, TestOptions.ReleaseDll) + Dim compilation = CreateCompilationWithMscorlib461({tree}, {SystemRef}, TestOptions.ReleaseDll) compilation.VerifyDiagnostics() Dim builder = ArrayBuilder(Of DiagnosticDescription).GetInstance() @@ -1649,7 +1649,7 @@ End Namespace Public Async Function TestAdditionalFileAnalyzer(registerFromInitialize As Boolean) As Task Dim tree = VisualBasicSyntaxTree.ParseText(String.Empty) - Dim compilation = CreateCompilationWithMscorlib45({tree}) + Dim compilation = CreateCompilationWithMscorlib461({tree}) compilation.VerifyDiagnostics() Dim additionalFile As AdditionalText = New TestAdditionalText("Additional File Text") diff --git a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/GetDiagnosticsTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/GetDiagnosticsTests.vb index 94e1a95057e8b..9727459ed33e3 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/GetDiagnosticsTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/GetDiagnosticsTests.vb @@ -149,7 +149,7 @@ End Namespace Dim tree1 = VisualBasicSyntaxTree.ParseText(source1, path:="file1") Dim tree2 = VisualBasicSyntaxTree.ParseText(source2, path:="file2") Dim eventQueue = New AsyncQueue(Of CompilationEvent)() - Dim compilation = CreateCompilationWithMscorlib45({tree1, tree2}).WithEventQueue(eventQueue) + Dim compilation = CreateCompilationWithMscorlib461({tree1, tree2}).WithEventQueue(eventQueue) ' Invoke SemanticModel.GetDiagnostics to force populate the event queue for symbols in the first source file. Dim tree = compilation.SyntaxTrees.[Single](Function(t) t Is tree1) @@ -204,7 +204,7 @@ End Namespace Dim tree1 = VisualBasicSyntaxTree.ParseText(source1, path:="file1") Dim tree2 = VisualBasicSyntaxTree.ParseText(source2, path:="file2") Dim eventQueue = New AsyncQueue(Of CompilationEvent)() - Dim compilation = CreateCompilationWithMscorlib45({tree1, tree2}).WithEventQueue(eventQueue) + Dim compilation = CreateCompilationWithMscorlib461({tree1, tree2}).WithEventQueue(eventQueue) ' Invoke SemanticModel.GetDiagnostics to force populate the event queue for symbols in the first source file. Dim tree = compilation.SyntaxTrees.[Single](Function(t) t Is tree1) @@ -244,7 +244,7 @@ BC31030: Conditional compilation constant '1' is not valid: Identifier expected. Public Sub CompilingCodeWithInvalidSourceCodeKindShouldProvideDiagnostics() #Disable Warning BC40000 ' Type or member is obsolete - Dim compilation = CreateCompilationWithMscorlib45(String.Empty, parseOptions:=New VisualBasicParseOptions().WithKind(SourceCodeKind.Interactive)) + Dim compilation = CreateCompilationWithMscorlib461(String.Empty, parseOptions:=New VisualBasicParseOptions().WithKind(SourceCodeKind.Interactive)) #Enable Warning BC40000 ' Type or member is obsolete CompilationUtils.AssertTheseDiagnostics(compilation, @@ -451,7 +451,7 @@ BC31030: Conditional compilation constant '2' is not valid: Identifier expected. Public Sub TestEventQueueCompletionForEmptyCompilation() - Dim compilation = CreateCompilationWithMscorlib45(source:=Nothing).WithEventQueue(New AsyncQueue(Of CompilationEvent)()) + Dim compilation = CreateCompilationWithMscorlib461(source:=Nothing).WithEventQueue(New AsyncQueue(Of CompilationEvent)()) ' Force complete compilation event queue Dim unused = compilation.GetDiagnostics() diff --git a/src/Compilers/VisualBasic/Test/Semantic/ExtensionMethods/SemanticModelTests.vb b/src/Compilers/VisualBasic/Test/Semantic/ExtensionMethods/SemanticModelTests.vb index ee4ca4eb7984c..6bc3a935d1b16 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/ExtensionMethods/SemanticModelTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/ExtensionMethods/SemanticModelTests.vb @@ -5,8 +5,8 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.ExtensionMethods @@ -1420,7 +1420,7 @@ Module E End Sub End Module ]]> -, {TestMetadata.Net40.SystemCore}) +, {Net40.References.SystemCore}) compilation.AssertTheseDiagnostics( - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.SystemCore}) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(comp, BC42104: Variable 'x' is used before it has been assigned a value. A null reference exception could result at runtime. @@ -278,7 +278,7 @@ Friend Module TestNone End Module - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.SystemCore}) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(comp, ) End Sub @@ -311,7 +311,7 @@ Friend Module TestStruct End Module - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.SystemCore}) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(comp, ) End Sub @@ -344,7 +344,7 @@ Friend Module TestClass End Module - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.SystemCore}) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(comp, BC42109: Variable 's1' is used before it has been assigned a value. A null reference exception could result at runtime. Make sure the structure or all the reference members are initialized before use @@ -384,7 +384,7 @@ Friend Module TestNewAndDisposable End Module - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.SystemCore}) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(comp, ) End Sub @@ -473,7 +473,7 @@ Friend Class TestNewAndDisposable(Of T As {IDisposable, New}) End Class - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.SystemCore}) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(comp, BC42109: Variable 's1' is used before it has been assigned a value. A null reference exception could result at runtime. Make sure the structure or all the reference members are initialized before use @@ -507,7 +507,7 @@ Structure MEMORY_BASIC_INFORMATION End Structure - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.SystemCore}) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, references:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(comp, ) End Sub @@ -1474,7 +1474,7 @@ End Module ]]> - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, {Net40.SystemCore}) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(program, {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(comp, diff --git a/src/Compilers/VisualBasic/Test/Semantic/FlowAnalysis/FlowTestBase.vb b/src/Compilers/VisualBasic/Test/Semantic/FlowAnalysis/FlowTestBase.vb index c22508b3c9745..1717b4f1aa6c3 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/FlowAnalysis/FlowTestBase.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/FlowAnalysis/FlowTestBase.vb @@ -225,19 +225,19 @@ tryAgain: Dim analysis = CompileAndAnalyzeDataFlow(code) Assert.True(analysis.Succeeded) - Assert.Equal(If(alwaysAssigned, {}), analysis.AlwaysAssigned.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(captured, {}), analysis.Captured.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(dataFlowsIn, {}), analysis.DataFlowsIn.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(dataFlowsOut, {}), analysis.DataFlowsOut.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(definitelyAssignedOnEntry, {}), analysis.DefinitelyAssignedOnEntry.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(definitelyAssignedOnExit, {}), analysis.DefinitelyAssignedOnExit.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(readInside, {}), analysis.ReadInside.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(readOutside, {}), analysis.ReadOutside.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(variablesDeclared, {}), analysis.VariablesDeclared.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(writtenInside, {}), analysis.WrittenInside.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(writtenOutside, {}), analysis.WrittenOutside.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(capturedInside, {}), analysis.CapturedInside.Select(Function(s) s.Name).ToArray()) - Assert.Equal(If(capturedOutside, {}), analysis.CapturedOutside.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(alwaysAssigned, {}), analysis.AlwaysAssigned.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(captured, {}), analysis.Captured.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(dataFlowsIn, {}), analysis.DataFlowsIn.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(dataFlowsOut, {}), analysis.DataFlowsOut.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(definitelyAssignedOnEntry, {}), analysis.DefinitelyAssignedOnEntry.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(definitelyAssignedOnExit, {}), analysis.DefinitelyAssignedOnExit.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(readInside, {}), analysis.ReadInside.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(readOutside, {}), analysis.ReadOutside.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(variablesDeclared, {}), analysis.VariablesDeclared.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(writtenInside, {}), analysis.WrittenInside.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(writtenOutside, {}), analysis.WrittenOutside.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(capturedInside, {}), analysis.CapturedInside.Select(Function(s) s.Name).ToArray()) + AssertEx.Equal(If(capturedOutside, {}), analysis.CapturedOutside.Select(Function(s) s.Name).ToArray()) End Sub End Class diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/AsyncAwait.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/AsyncAwait.vb index a029ef4744033..221261119f52d 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/AsyncAwait.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/AsyncAwait.vb @@ -6,9 +6,9 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - Imports Roslyn.Test.Utilities Imports System.Collections.ObjectModel +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -2004,7 +2004,7 @@ End Module - Dim compilation = CreateEmptyCompilationWithReferences(source, {TestMetadata.Net40.mscorlib, TestMetadata.Net40.MicrosoftVisualBasic}, TestOptions.ReleaseExe) + Dim compilation = CreateEmptyCompilationWithReferences(source, {Net40.References.mscorlib, Net40.References.MicrosoftVisualBasic}, TestOptions.ReleaseExe) AssertTheseDiagnostics(compilation, diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb index 02bee14431839..b9985e9a44067 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ConditionalAccessTests.vb @@ -6,7 +6,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -1470,7 +1470,7 @@ End Module - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, Net451XmlReferences, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, Net461XmlReferences, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) Dim verifier = CompileAndVerify(compilation, expectedOutput:= - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, Net451XmlReferences, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, Net461XmlReferences, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) AssertTheseDiagnostics(compilation, - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.SystemCore}, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.References.SystemCore}, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) AssertTheseDiagnostics(compilation, - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, Net451XmlReferences, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, Net461XmlReferences, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) AssertTheseDiagnostics(compilation, @@ -2656,7 +2656,7 @@ End Structure ]]> - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.SystemCore}, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.References.SystemCore}, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) Dim verifier = CompileAndVerify(compilation, expectedOutput:= - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.SystemCore}, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.References.SystemCore}, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) Dim verifier = CompileAndVerify(compilation, expectedOutput:= - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.SystemCore}, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.References.SystemCore}, TestOptions.ReleaseExe, TestOptions.ReleaseExe.ParseOptions) Dim verifier = CompileAndVerify(compilation, expectedOutput:= - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.SystemCore}, + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.References.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom), TestOptions.ReleaseExe.ParseOptions) @@ -3983,7 +3983,7 @@ End Class ]]> - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.SystemCore}, + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, {Net40.References.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom), TestOptions.ReleaseExe.ParseOptions) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/Conversions.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/Conversions.vb index 48524b27accda..fcf63a3f1fe0b 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/Conversions.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/Conversions.vb @@ -14,7 +14,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics.ConversionsTests.Parameters Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -41,7 +41,7 @@ End Class Dim vbConversionsRef = TestReferences.SymbolsTests.VBConversions Dim modifiersRef = TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll - Dim c1 = VisualBasicCompilation.Create("Test", syntaxTrees:={dummyTree}, references:={Net40.mscorlib, vbConversionsRef, modifiersRef}) + Dim c1 = VisualBasicCompilation.Create("Test", syntaxTrees:={dummyTree}, references:={Net40.References.mscorlib, vbConversionsRef, modifiersRef}) Dim sourceModule = DirectCast(c1.Assembly.Modules(0), SourceModuleSymbol) Dim methodDeclSymbol = DirectCast(sourceModule.GlobalNamespace.GetTypeMembers("C1").Single().GetMembers("MethodDecl").Single(), SourceMethodSymbol) @@ -220,7 +220,7 @@ End Class Dim dummyTree = VisualBasicSyntaxTree.ParseText(dummyCode.Value) - Dim c1 = VisualBasicCompilation.Create("Test", syntaxTrees:={dummyTree}, references:={Net40.mscorlib}) + Dim c1 = VisualBasicCompilation.Create("Test", syntaxTrees:={dummyTree}, references:={Net40.References.mscorlib}) Dim sourceModule = DirectCast(c1.Assembly.Modules(0), SourceModuleSymbol) Dim methodDeclSymbol = DirectCast(sourceModule.GlobalNamespace.GetTypeMembers("C1").Single().GetMembers("MethodDecl").Single(), SourceMethodSymbol) @@ -729,10 +729,7 @@ End Class Assert.True(gotException) - ' Conditioned due to https://github.com/dotnet/roslyn/issues/74026 - If numericType IsNot byteType AndAlso CType(mv.Value, Double) <> CDbl(&HF000000000000000UL) Then - Assert.Equal(UncheckedConvert(intermediate, numericType), resultValue.Value) - End If + Assert.Equal(UncheckedConvert(mv.Value, numericType), resultValue.Value) End If Else Assert.NotNull(resultValue) @@ -1074,7 +1071,7 @@ End Class Dim dummyTree = VisualBasicSyntaxTree.ParseText(dummyCode.Value) - Dim c1 = VisualBasicCompilation.Create("Test", syntaxTrees:={dummyTree}, references:={Net40.mscorlib}, + Dim c1 = VisualBasicCompilation.Create("Test", syntaxTrees:={dummyTree}, references:={Net40.References.mscorlib}, options:=TestOptions.ReleaseExe.WithOverflowChecks(False)) Dim sourceModule = DirectCast(c1.Assembly.Modules(0), SourceModuleSymbol) @@ -1293,10 +1290,7 @@ End Class Assert.True(gotException) - ' Conditioned due to https://github.com/dotnet/roslyn/issues/74026 - If numericType IsNot byteType AndAlso CType(mv.Value, Double) <> CDbl(&HF000000000000000UL) Then - Assert.Equal(UncheckedConvert(intermediate, numericType), resultValue.Value) - End If + Assert.Equal(UncheckedConvert(mv.Value, numericType), resultValue.Value) End If Else Assert.NotNull(resultValue) @@ -1405,6 +1399,22 @@ End Class Throw New NotSupportedException() End Select + Case TypeCode.Single, TypeCode.Double + Dim val As Double = Convert.ToDouble(value) + + Select Case type.SpecialType + Case System_Byte : Return UncheckedCByte(UncheckedCLng(val)) + Case System_SByte : Return UncheckedCSByte(UncheckedCLng(val)) + Case System_Int16 : Return UncheckedCShort(UncheckedCLng(val)) + Case System_UInt16 : Return UncheckedCUShort(UncheckedCLng(val)) + Case System_Int32 : Return UncheckedCInt(UncheckedCLng(val)) + Case System_UInt32 : Return UncheckedCUInt(UncheckedCLng(val)) + Case System_Int64 : Return UncheckedCLng(val) + Case System_UInt64 : Return UncheckedCULng(val) + Case Else + Throw New NotSupportedException() + End Select + Case Else Throw New NotSupportedException() End Select @@ -1445,7 +1455,7 @@ End Class Dim vbConversionsRef = TestReferences.SymbolsTests.VBConversions Dim modifiersRef = TestReferences.SymbolsTests.CustomModifiers.Modifiers.dll - Dim c1 = VisualBasicCompilation.Create("Test", references:={Net40.mscorlib, vbConversionsRef, modifiersRef}) + Dim c1 = VisualBasicCompilation.Create("Test", references:={Net40.References.mscorlib, vbConversionsRef, modifiersRef}) Dim asmVBConversions = c1.GetReferencedAssemblySymbol(vbConversionsRef) Dim asmModifiers = c1.GetReferencedAssemblySymbol(modifiersRef) @@ -2027,7 +2037,7 @@ End Class Public Sub BuiltIn() - Dim c1 = VisualBasicCompilation.Create("Test", references:={Net40.mscorlib}) + Dim c1 = VisualBasicCompilation.Create("Test", references:={Net40.References.mscorlib}) Dim nullable = c1.GetSpecialType(System_Nullable_T) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ForeachTest.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ForeachTest.vb index b4885ca05dd6f..29a41679c1bea 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ForeachTest.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ForeachTest.vb @@ -1148,7 +1148,7 @@ Public Class C End Sub End Class -, {MscorlibRefPortable}) +, {SystemRuntimePP7Ref}) comp.VerifyDiagnostics() @@ -1158,10 +1158,10 @@ End Class Dim loopSyntax = tree.GetRoot().DescendantNodes().OfType(Of ForEachStatementSyntax)().Single() Dim loopInfo = model.GetForEachStatementInfo(loopSyntax) - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator), loopInfo.GetEnumeratorMethod) - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__Current), loopInfo.CurrentProperty) - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext), loopInfo.MoveNextMethod) - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose), loopInfo.DisposeMethod) + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator), loopInfo.GetEnumeratorMethod) + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__Current), loopInfo.CurrentProperty) + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext), loopInfo.MoveNextMethod) + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose), loopInfo.DisposeMethod) ' The spec says that the element type is object. ' Therefore, we should infer object for "var". @@ -1188,7 +1188,7 @@ Public Class C End Sub End Class -, {MscorlibRefPortable}) +, {SystemRuntimePP7Ref}) comp.VerifyDiagnostics() @@ -1198,10 +1198,10 @@ End Class Dim loopSyntax = tree.GetRoot().DescendantNodes().OfType(Of ForEachStatementSyntax)().Single() Dim loopInfo = model.GetForEachStatementInfo(loopSyntax) - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator), loopInfo.GetEnumeratorMethod) - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__Current), loopInfo.CurrentProperty) - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext), loopInfo.MoveNextMethod) - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose), loopInfo.DisposeMethod) + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator), loopInfo.GetEnumeratorMethod) + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__Current), loopInfo.CurrentProperty) + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext), loopInfo.MoveNextMethod) + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose), loopInfo.DisposeMethod) ' The spec says that the element type is object. ' Therefore, we should infer object for "var". @@ -1254,15 +1254,15 @@ End Module Dim loopInfo0 = model.GetForEachStatementInfo(loopSyntaxes(0)) Assert.Equal(comp.GetSpecialType(SpecialType.System_Array), loopInfo0.GetEnumeratorMethod.ContainingType) ' Unlike C#, the spec doesn't say that arrays use IEnumerable - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__Current), loopInfo0.CurrentProperty) - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext), loopInfo0.MoveNextMethod) - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose), loopInfo0.DisposeMethod) + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__Current), loopInfo0.CurrentProperty) + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext), loopInfo0.MoveNextMethod) + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_IDisposable__Dispose), loopInfo0.DisposeMethod) Assert.Equal(SpecialType.System_String, loopInfo0.ElementType.SpecialType) Assert.Equal(udc, loopInfo0.ElementConversion.Method) Assert.Equal(ConversionKind.NarrowingReference, loopInfo0.CurrentConversion.Kind) Dim loopInfo1 = model.GetForEachStatementInfo(loopSyntaxes(1)) - Assert.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator), loopInfo1.GetEnumeratorMethod) ' No longer using System.Array method. + AssertEx.Equal(Of ISymbol)(comp.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerable__GetEnumerator), loopInfo1.GetEnumeratorMethod) ' No longer using System.Array method. Assert.Equal(loopInfo0.CurrentProperty, loopInfo1.CurrentProperty) Assert.Equal(loopInfo0.MoveNextMethod, loopInfo1.MoveNextMethod) Assert.Equal(loopInfo0.DisposeMethod, loopInfo1.DisposeMethod) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetExtendedSemanticInfoTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetExtendedSemanticInfoTests.vb index 06488930a536e..d00a160156b9b 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetExtendedSemanticInfoTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetExtendedSemanticInfoTests.vb @@ -12,7 +12,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.OverloadResolution Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - +Imports Basic.Reference.Assemblies Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -5764,7 +5764,7 @@ Module Program End Sub End Module ]]> -, {TestMetadata.Net40.SystemCore}) +, {Net40.References.SystemCore}) Dim semanticInfo = CompilationUtils.GetSemanticInfoSummary(Of IdentifierNameSyntax)(compilation, "a.vb") @@ -7395,7 +7395,7 @@ End Module ]]> -, {TestMetadata.Net40.SystemCore}, TestOptions.ReleaseExe) +, {Net40.References.SystemCore}, TestOptions.ReleaseExe) Dim semanticInfo = CompilationUtils.GetSemanticInfoSummary(Of IdentifierNameSyntax)(compilation, "a.vb") @@ -7620,7 +7620,7 @@ End Module ]]> -, {TestMetadata.Net40.SystemCore}, TestOptions.ReleaseExe) +, {Net40.References.SystemCore}, TestOptions.ReleaseExe) Dim semanticSummary = CompilationUtils.GetSemanticInfoSummary(Of GenericNameSyntax)(compilation, "a.vb") diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetSemanticInfoTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetSemanticInfoTests.vb index 08a325abca2ca..5f10e173e669a 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetSemanticInfoTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetSemanticInfoTests.vb @@ -14,9 +14,8 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.OverloadResolution Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Imports Roslyn.Test.Utilities.TestMetadata - Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics Partial Public Class SemanticModelTests @@ -4488,7 +4487,7 @@ Module Program End Function End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) comp.VerifyDiagnostics() Dim tree = comp.SyntaxTrees.Single() @@ -4550,7 +4549,7 @@ Module Program End Sub End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) comp.AssertNoDiagnostics() Dim tree = comp.SyntaxTrees.Single() @@ -5293,7 +5292,7 @@ End Namespace End Class apInitScenario("7. generic T_Method B ---------------------------- }]]> - , {Net40.SystemCore, Net40.System, Net40.SystemData}, TestOptions.ReleaseDll.WithOptionExplicit(False).WithOptionInfer(True)) + , {Net40.References.SystemCore, Net40.References.System, Net40.References.SystemData}, TestOptions.ReleaseDll.WithOptionExplicit(False).WithOptionInfer(True)) compilation.GetDiagnostics() diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetUnusedImportDirectivesTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetUnusedImportDirectivesTests.vb index b3b474af54249..d2208b6b56607 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetUnusedImportDirectivesTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/GetUnusedImportDirectivesTests.vb @@ -5,6 +5,7 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.VisualBasic Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -26,7 +27,7 @@ Class Program End Class -, {TestMetadata.Net40.SystemCore}) +, {Net40.References.SystemCore}) compilation.AssertTheseDiagnostics( BC50001: Unused import statement. @@ -89,7 +90,7 @@ Imports System.Reflection <%= snkPath %> ]]> -, references:={TestMetadata.Net40.SystemCore}, options:=TestOptions.ReleaseDll.WithStrongNameProvider(New DesktopStrongNameProvider())) +, references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseDll.WithStrongNameProvider(New DesktopStrongNameProvider())) Dim libCompilation = CreateCompilationWithMscorlib40AndReferences( @@ -305,7 +306,7 @@ End Class Public Sub UnusedImportScript() Dim tree = Parse("Imports System", options:=TestOptions.Script) - Dim compilation = CreateCompilationWithMscorlib45({tree}) + Dim compilation = CreateCompilationWithMscorlib461({tree}) compilation.AssertTheseDiagnostics( BC50001: Unused import statement. diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/GotoTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/GotoTests.vb index 1f7eb08ae6f06..446c2937ed103 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/GotoTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/GotoTests.vb @@ -207,7 +207,7 @@ End Module Assert.Equal("lab1", semanticSummary.Symbol.ToTestDisplayString()) Assert.Equal(SymbolKind.Label, semanticSummary.Symbol.Kind) - Assert.Equal(Of ISymbol)(declaredSymbol, semanticSummary.Symbol) + AssertEx.Equal(Of ISymbol)(declaredSymbol, semanticSummary.Symbol) End Sub @@ -238,7 +238,7 @@ End Module Assert.Equal(ConversionKind.Identity, semanticSummary0.ImplicitConversion.Kind) Assert.Equal("lab1", semanticSummary0.Symbol.ToTestDisplayString()) Assert.Equal(SymbolKind.Label, semanticSummary0.Symbol.Kind) - Assert.Equal(Of ISymbol)(declaredSymbol0, semanticSummary0.Symbol) + AssertEx.Equal(Of ISymbol)(declaredSymbol0, semanticSummary0.Symbol) Dim declaredSymbol1 = model.GetDeclaredSymbol(labelStatementSyntaxArray(1)) Dim semanticSummary1 = CompilationUtils.GetSemanticInfoSummary(Compilation, gotoSyntaxArray(1).Label) @@ -247,7 +247,7 @@ End Module Assert.Equal(ConversionKind.Identity, semanticSummary1.ImplicitConversion.Kind) Assert.Equal("lab1", semanticSummary1.Symbol.ToTestDisplayString()) Assert.Equal(SymbolKind.Label, semanticSummary1.Symbol.Kind) - Assert.Equal(Of ISymbol)(declaredSymbol0, semanticSummary1.Symbol) + AssertEx.Equal(Of ISymbol)(declaredSymbol0, semanticSummary1.Symbol) Assert.NotEqual(declaredSymbol0, declaredSymbol1) Assert.Equal(semanticSummary0.Symbol, semanticSummary1.Symbol) @@ -281,7 +281,7 @@ End Module Assert.Equal("0", semanticSummary.Symbol.ToTestDisplayString()) Assert.Equal(SymbolKind.Label, semanticSummary.Symbol.Kind) - Assert.Equal(Of ISymbol)(declaredSymbol, semanticSummary.Symbol) + AssertEx.Equal(Of ISymbol)(declaredSymbol, semanticSummary.Symbol) End Sub @@ -315,8 +315,8 @@ End Module Assert.Equal("0", semanticSummary.Symbol.ToTestDisplayString()) Assert.Equal(SymbolKind.Label, semanticSummary.Symbol.Kind) - Assert.NotEqual(Of ISymbol)(declaredSymbolOuter, semanticSummary.Symbol) - Assert.Equal(Of ISymbol)(declaredSymbolInner, semanticSummary.Symbol) + AssertEx.NotEqual(Of ISymbol)(declaredSymbolOuter, semanticSummary.Symbol) + AssertEx.Equal(Of ISymbol)(declaredSymbolInner, semanticSummary.Symbol) End Sub @@ -354,7 +354,7 @@ End Module Assert.Equal("1", semanticSummary.Symbol.ToTestDisplayString()) Assert.Equal(SymbolKind.Label, semanticSummary.Symbol.Kind) - Assert.Equal(Of ISymbol)(declaredSymbol, semanticSummary.Symbol) + AssertEx.Equal(Of ISymbol)(declaredSymbol, semanticSummary.Symbol) End Sub @@ -390,7 +390,7 @@ End Module Assert.Equal("1", semanticSummary.Symbol.ToTestDisplayString()) Assert.Equal(SymbolKind.Label, semanticSummary.Symbol.Kind) - Assert.Equal(Of ISymbol)(declaredSymbol, semanticSummary.Symbol) + AssertEx.Equal(Of ISymbol)(declaredSymbol, semanticSummary.Symbol) End Sub @@ -424,7 +424,7 @@ End Module Assert.Equal("lab1", semanticSummary.Symbol.ToTestDisplayString()) Assert.Equal(SymbolKind.Label, semanticSummary.Symbol.Kind) - Assert.Equal(Of ISymbol)(declaredSymbol, semanticSummary.Symbol) + AssertEx.Equal(Of ISymbol)(declaredSymbol, semanticSummary.Symbol) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/LambdaSemanticInfoTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/LambdaSemanticInfoTests.vb index a94d0dfa8c2f4..69fa3b36e8590 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/LambdaSemanticInfoTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/LambdaSemanticInfoTests.vb @@ -8,7 +8,7 @@ Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - +Imports Basic.Reference.Assemblies Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -1023,7 +1023,7 @@ Namespace ThenIncludeIntellisenseBug End Module End Namespace" ]]> -, references:={TestMetadata.Net40.SystemCore}) +, references:={Net40.References.SystemCore}) Dim tree = compilation.SyntaxTrees(0) Dim model = compilation.GetSemanticModel(tree) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/Lambda_Relaxation.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/Lambda_Relaxation.vb index dcabf94b466aa..0f29e798f54cb 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/Lambda_Relaxation.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/Lambda_Relaxation.vb @@ -5,7 +5,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - +Imports Basic.Reference.Assemblies Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -2976,7 +2976,7 @@ End Module ]]> - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {TestMetadata.Net40.SystemCore}, TestOptions.ReleaseDll) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {Net40.References.SystemCore}, TestOptions.ReleaseDll) CompilationUtils.AssertTheseDiagnostics(compilation, ) Dim verifier = CompileAndVerify(compilation) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/MeMyBaseMyClassTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/MeMyBaseMyClassTests.vb index 1dfbec1b78a3b..9f6ecbe14b73e 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/MeMyBaseMyClassTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/MeMyBaseMyClassTests.vb @@ -6,7 +6,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - +Imports Basic.Reference.Assemblies Imports Roslyn.Test.Utilities Imports VB = Microsoft.CodeAnalysis.VisualBasic @@ -515,7 +515,7 @@ Module MyExtensionModule End Function End Module -, {TestMetadata.Net40.SystemCore}) +, {Net40.References.SystemCore}) Dim symbol = LookUpSymbolTest(comp, "Sum", expectedCount:=1, expectedString:="Function C1.Sum() As System.Int32") GetSymbolInfoTest(comp, "MyClass.Sum", symbol) GetTypeInfoTest(comp, "MyClass.Sum", "Integer") diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/MethodCalls.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/MethodCalls.vb index 957a38b963639..e8fb53f6628ab 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/MethodCalls.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/MethodCalls.vb @@ -5,6 +5,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -4869,7 +4870,7 @@ End Module - Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {TestMetadata.Net40.SystemCore}, TestOptions.ReleaseExe) + Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, TestOptions.ReleaseExe) Dim compilationVerifier = CompileAndVerify(compilation, expectedOutput:= @@ -4909,7 +4910,7 @@ End Module - Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {TestMetadata.Net40.SystemCore}, TestOptions.ReleaseExe) + Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, TestOptions.ReleaseExe) Dim compilationVerifier = CompileAndVerify(compilation, expectedOutput:= @@ -5238,7 +5239,7 @@ End Module - Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {TestMetadata.Net40.SystemCore}, TestOptions.ReleaseExe) + Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source, {Net40.References.SystemCore}, TestOptions.ReleaseExe) Dim compilationVerifier = CompileAndVerify(compilation, expectedOutput:= diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/NameOfTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/NameOfTests.vb index 87526d70ac60b..be9f7f8d2ba72 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/NameOfTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/NameOfTests.vb @@ -12,6 +12,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -2339,7 +2340,7 @@ End Class ]]> - Dim comp = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {TestMetadata.Net40.SystemCore}, TestOptions.DebugExe) + Dim comp = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {Net40.References.SystemCore}, TestOptions.DebugExe) CompileAndVerify(comp, expectedOutput:= - Dim comp = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {TestMetadata.Net40.SystemCore}, TestOptions.DebugExe) + Dim comp = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {Net40.References.SystemCore}, TestOptions.DebugExe) AssertTheseDiagnostics(comp, @@ -3224,7 +3225,7 @@ End Class ]]> - Dim comp = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {TestMetadata.Net40.SystemCore}, TestOptions.DebugExe) + Dim comp = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {Net40.References.SystemCore}, TestOptions.DebugExe) CompileAndVerify(comp, expectedOutput:= - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {Net40.SystemCore}) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -5318,7 +5318,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -5419,7 +5419,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -6070,7 +6070,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -6735,7 +6735,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -7876,7 +7876,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -9530,7 +9530,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -10710,7 +10710,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -12534,7 +12534,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -12829,7 +12829,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, ) End Sub @@ -12874,7 +12874,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, ) End Sub @@ -12919,7 +12919,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, ) End Sub @@ -12955,7 +12955,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -13960,7 +13960,7 @@ End Class Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -14009,7 +14009,7 @@ Imports System.Linq End Sub End Module - , additionalRefs:={Net40.SystemCore}) + , additionalRefs:={Net40.References.SystemCore}) AssertTheseEmitDiagnostics(compilation, @@ -14071,7 +14071,7 @@ Class CI003 End Class , - expectedOutput:="CI003.Count", references:={Net451.SystemCore}) + expectedOutput:="CI003.Count", references:={NetFramework.SystemCore}) verifier.VerifyDiagnostics() End Sub @@ -14125,7 +14125,7 @@ End Class Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore, + additionalRefs:={Net40.References.SystemCore, SystemXmlRef, SystemXmlLinqRef}) @@ -14232,7 +14232,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -14323,7 +14323,7 @@ End Module Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime(compilationDef, - additionalRefs:={Net40.SystemCore}) + additionalRefs:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -14351,7 +14351,7 @@ Module M End Sub End Module - , references:={Net40.SystemCore}).AssertTheseDiagnostics( + , references:={Net40.References.SystemCore}).AssertTheseDiagnostics( BC31396: 'ArgIterator' cannot be made nullable, and cannot be used as the data type of an array element, field, anonymous type member, type argument, 'ByRef' parameter, or return statement. Dim c1 As System.ArgIterator()() = Nothing @@ -14438,7 +14438,7 @@ End Module - Dim verifier = CompileAndVerify(compilationDef, references:={Net40.SystemCore}, + Dim verifier = CompileAndVerify(compilationDef, references:={Net40.References.SystemCore}, expectedOutput:= - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.SystemCore}) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -14531,7 +14531,7 @@ End Module - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.SystemCore}, options:=TestOptions.ReleaseExe) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe) CompileAndVerify(compilation, expectedOutput:= @@ -14559,7 +14559,7 @@ End Module - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.SystemCore}, options:=TestOptions.ReleaseExe) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -14591,7 +14591,7 @@ End Module - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.SystemCore}) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -14895,7 +14895,7 @@ End Module - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.SystemCore}, options:=TestOptions.ReleaseExe) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe) CompilationUtils.AssertTheseDiagnostics(compilation, @@ -14961,7 +14961,7 @@ End Module ]]> - Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.SystemCore}, options:=TestOptions.ReleaseExe) + Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseExe) CompileAndVerify(compilation, expectedOutput:= @@ -14998,7 +14998,7 @@ End Module - CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.SystemCore}, options:=TestOptions.ReleaseDll).AssertNoDiagnostics() + CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseDll).AssertNoDiagnostics() End Sub @@ -15051,7 +15051,7 @@ Class C - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.SystemCore}, options:=TestOptions.ReleaseDll) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, references:={Net40.References.SystemCore}, options:=TestOptions.ReleaseDll) CompilationUtils.AssertTheseDiagnostics(compilation, BC30451: 'Whi' is not declared. It may be inaccessible due to its protection level. diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/QueryExpressions_SemanticModel.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/QueryExpressions_SemanticModel.vb index 8b6db416ee5fb..138261e789e0d 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/QueryExpressions_SemanticModel.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/QueryExpressions_SemanticModel.vb @@ -8,7 +8,7 @@ Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - +Imports Basic.Reference.Assemblies Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -3807,7 +3807,7 @@ Module AggrArgsInvalidmod End Sub End Module ]]> -, references:={TestMetadata.Net40.SystemCore}) +, references:={Net40.References.SystemCore}) compilation.VerifyDiagnostics(Diagnostic(ERRID.ERR_QueryOperatorNotFound, "aggr4").WithArguments("aggr4")) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ScriptSemanticsTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ScriptSemanticsTests.vb index 8d03045f1e117..12c757cc2435f 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/ScriptSemanticsTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/ScriptSemanticsTests.vb @@ -41,7 +41,7 @@ F(Function() Dim code = "System.Console.WriteLine(1)" Dim compilationUnit = VisualBasic.SyntaxFactory.ParseCompilationUnit(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script)) Dim syntaxTree = compilationUnit.SyntaxTree - Dim compilation = CreateCompilationWithMscorlib45({syntaxTree}, assemblyName:="Errors_01", options:=TestOptions.ReleaseExe) + Dim compilation = CreateCompilationWithMscorlib461({syntaxTree}, assemblyName:="Errors_01", options:=TestOptions.ReleaseExe) Dim semanticModel = compilation.GetSemanticModel(syntaxTree, True) Dim node5 As MemberAccessExpressionSyntax = ErrorTestsGetNode(syntaxTree) Assert.Equal("WriteLine", node5.Name.ToString()) @@ -56,7 +56,7 @@ System.Console.WriteLine(1) ) - compilation = CreateCompilationWithMscorlib45({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName("Script"), assemblyName:="Errors_01") + compilation = CreateCompilationWithMscorlib461({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName("Script"), assemblyName:="Errors_01") semanticModel = compilation.GetSemanticModel(syntaxTree, True) node5 = ErrorTestsGetNode(syntaxTree) Assert.Equal("WriteLine", node5.Name.ToString()) @@ -72,7 +72,7 @@ System.Console.WriteLine(1) ) syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script)) - compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe) + compilation = CreateCompilationWithMscorlib461AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe) semanticModel = compilation.GetSemanticModel(syntaxTree, True) node5 = ErrorTestsGetNode(syntaxTree) Assert.Equal("WriteLine", node5.Name.ToString()) @@ -81,7 +81,7 @@ System.Console.WriteLine(1) CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics() syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script)) - compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName("Script")) + compilation = CreateCompilationWithMscorlib461AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName("Script")) semanticModel = compilation.GetSemanticModel(syntaxTree, True) node5 = ErrorTestsGetNode(syntaxTree) Assert.Equal("WriteLine", node5.Name.ToString()) @@ -90,7 +90,7 @@ System.Console.WriteLine(1) CompileAndVerify(compilation, expectedOutput:="1").VerifyDiagnostics() syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script)) - compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName("")) + compilation = CreateCompilationWithMscorlib461AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName("")) semanticModel = compilation.GetSemanticModel(syntaxTree, True) node5 = ErrorTestsGetNode(syntaxTree) Assert.Equal("WriteLine", node5.Name.ToString()) @@ -103,7 +103,7 @@ BC2014: the value '' is invalid for option 'ScriptClassName' ) syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script)) - compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName(Nothing)) + compilation = CreateCompilationWithMscorlib461AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName(Nothing)) semanticModel = compilation.GetSemanticModel(syntaxTree, True) node5 = ErrorTestsGetNode(syntaxTree) Assert.Equal("WriteLine", node5.Name.ToString()) @@ -116,7 +116,7 @@ BC2014: the value 'Nothing' is invalid for option 'ScriptClassName' ) syntaxTree = SyntaxFactory.ParseSyntaxTree(code, options:=New VisualBasicParseOptions(kind:=SourceCodeKind.Script)) - compilation = CreateCompilationWithMscorlib45AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName("a" + ChrW(0) + "b")) + compilation = CreateCompilationWithMscorlib461AndVBRuntime({syntaxTree}, options:=TestOptions.ReleaseExe.WithScriptClassName("a" + ChrW(0) + "b")) semanticModel = compilation.GetSemanticModel(syntaxTree, True) node5 = ErrorTestsGetNode(syntaxTree) Assert.Equal("WriteLine", node5.Name.ToString()) @@ -138,7 +138,7 @@ BC2014: the value 'Nothing' is invalid for option 'ScriptClassName' Dim node2 As MemberAccessExpressionSyntax = ErrorTestsGetNode(syntaxTree2) Assert.Equal("WriteLine", node2.Name.ToString()) - Dim compilation = CreateCompilationWithMscorlib45({syntaxTree1, syntaxTree2}) + Dim compilation = CreateCompilationWithMscorlib461({syntaxTree1, syntaxTree2}) Dim semanticModel1 = compilation.GetSemanticModel(syntaxTree1, True) Dim semanticModel2 = compilation.GetSemanticModel(syntaxTree2, True) Assert.Null(semanticModel1.GetSymbolInfo(node1.Name).Symbol) @@ -152,7 +152,7 @@ System.Console.WriteLine(1) ) - compilation = CreateCompilationWithMscorlib45({syntaxTree2, syntaxTree1}) + compilation = CreateCompilationWithMscorlib461({syntaxTree2, syntaxTree1}) semanticModel1 = compilation.GetSemanticModel(syntaxTree1, True) semanticModel2 = compilation.GetSemanticModel(syntaxTree2, True) Assert.Null(semanticModel1.GetSymbolInfo(node1.Name).Symbol) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/VarianceConversions.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/VarianceConversions.vb index 9e224372deb6e..e09ea35cd5fa3 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/VarianceConversions.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/VarianceConversions.vb @@ -12,7 +12,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.OverloadResolution Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit - +Imports Basic.Reference.Assemblies Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Semantics @@ -888,7 +888,7 @@ End Module Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, - {TestMetadata.Net40.SystemCore}, + {Net40.References.SystemCore}, TestOptions.ReleaseExe.WithOptionStrict(OptionStrict.Custom)) CompilationUtils.AssertTheseDiagnostics(compilation, diff --git a/src/Compilers/VisualBasic/Test/Semantic/Semantics/WithBlockSemanticModelTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Semantics/WithBlockSemanticModelTests.vb index f9fc8a3fec61d..1c3b34604dd1a 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Semantics/WithBlockSemanticModelTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Semantics/WithBlockSemanticModelTests.vb @@ -5,7 +5,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -258,7 +258,7 @@ Module Program End Class End Module ]]> -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) compilation.AssertNoDiagnostics() @@ -399,7 +399,7 @@ Module Ext End Sub End Module ]]> -, additionalRefs:={Net40.SystemCore}) +, additionalRefs:={Net40.References.SystemCore}) compilation.AssertTheseDiagnostics() @@ -451,7 +451,7 @@ Module Ext End Sub End Module ]]> -, additionalRefs:={Net40.SystemCore}) +, additionalRefs:={Net40.References.SystemCore}) compilation.AssertTheseDiagnostics() @@ -508,7 +508,7 @@ Module Ext End Sub End Module ]]> -, additionalRefs:={Net40.SystemCore}) +, additionalRefs:={Net40.References.SystemCore}) compilation.AssertTheseDiagnostics() diff --git a/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests.vb b/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests.vb index dc64c86c0783c..fd75ab1e3c6d2 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/SourceGeneration/GeneratorDriverTests.vb @@ -721,7 +721,7 @@ End Class End Sub Shared Sub VerifyArgumentExceptionDiagnostic(diagnostic As Diagnostic, generatorName As String, message As String, parameterName As String, Optional initialization As Boolean = False) -#If NETCOREAPP Then +#If NET Then Dim expectedMessage = $"{message} (Parameter '{parameterName}')" #Else Dim expectedMessage = $"{message}{Environment.NewLine}Parameter name: {parameterName}" diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb index 758fdc0e43844..e67cb60331d87 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolDisplay/SymbolDisplayTests.vb @@ -13,6 +13,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -4976,7 +4977,7 @@ Class C Private f As (Integer, String) End Class - , references:={TestMetadata.Net40.SystemCore}) + , references:={Net40.References.SystemCore}) Dim format = New SymbolDisplayFormat(memberOptions:=SymbolDisplayMemberOptions.IncludeType, miscellaneousOptions:=SymbolDisplayMiscellaneousOptions.CollapseTupleTypes) @@ -5013,13 +5014,13 @@ End Class SymbolDisplayPartKind.Space, SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, - SymbolDisplayPartKind.ClassName, + SymbolDisplayPartKind.StructName, SymbolDisplayPartKind.Punctuation, SymbolDisplayPartKind.Keyword, SymbolDisplayPartKind.Space, SymbolDisplayPartKind.StructName, SymbolDisplayPartKind.Punctuation}, - references:={MetadataReference.CreateFromImage(TestResources.NetFX.ValueTuple.tuplelib)}) + references:={Net461.ExtraReferences.SystemValueTuple}) End Sub @@ -6053,7 +6054,7 @@ end class" expectedText As String, ParamArray kinds As SymbolDisplayPartKind()) - Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(text, references:={TestMetadata.Net40.SystemCore}) + Dim comp = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(text, references:={Net40.References.SystemCore}) ' symbol: Dim symbol = findSymbol(comp.GlobalNamespace) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AnonymousTypes/AnonymousTypesSemanticsTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AnonymousTypes/AnonymousTypesSemanticsTests.vb index 937f5abe2b958..e60294355455e 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AnonymousTypes/AnonymousTypesSemanticsTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AnonymousTypes/AnonymousTypesSemanticsTests.vb @@ -11,9 +11,9 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.ExtensionMethods @@ -144,7 +144,7 @@ End Module ' AnonymousObjectCreationExpression in the new { } declaration. Dim symbol = model.GetDeclaredSymbol(anonObjectCreation) Assert.NotNull(symbol) - Assert.Equal(Of ISymbol)(localType, symbol) + AssertEx.Equal(Of ISymbol)(localType, symbol) Assert.Same(anonObjectCreation, symbol.DeclaringSyntaxReferences(0).GetSyntax()) ' Locations: Return the Span of that particular @@ -176,7 +176,7 @@ End Module ' SemanticModel.GetDeclaredSymbol: Return this symbol when applied to its new { } ' declaration's AnonymousObjectMemberDeclarator. Dim propSymbol = model.GetDeclaredSymbol(propertyInitializer) - Assert.Equal(Of ISymbol)(member, propSymbol) + AssertEx.Equal(Of ISymbol)(member, propSymbol) Assert.Same(propertyInitializer, propSymbol.DeclaringSyntaxReferences(0).GetSyntax()) ' Locations: Return the Span of that particular @@ -1968,7 +1968,7 @@ End Module Dim spans As New List(Of TextSpan) ExtractTextIntervals(text, spans) - Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndReferences(text, {TestMetadata.Net40.System, TestMetadata.Net40.SystemCore, TestMetadata.Net40.MicrosoftVisualBasic}) + Dim compilation = CompilationUtils.CreateCompilationWithMscorlib40AndReferences(text, {Net40.References.System, Net40.References.SystemCore, Net40.References.MicrosoftVisualBasic}) If errors Is Nothing Then CompilationUtils.AssertNoErrors(compilation) Else diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AssemblyAndNamespaceTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AssemblyAndNamespaceTests.vb index 74bc5851f9131..8adfbeb969986 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AssemblyAndNamespaceTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AssemblyAndNamespaceTests.vb @@ -515,7 +515,7 @@ End Class - Dim aliasedCorlib = TestMetadata.Net451.mscorlib.WithAliases(ImmutableArray.Create("Goo")) + Dim aliasedCorlib = NetFramework.mscorlib.WithAliases(ImmutableArray.Create("Goo")) Dim comp = CreateEmptyCompilationWithReferences(source, {aliasedCorlib}) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AttributeTests_UnmanagedCallersOnly.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AttributeTests_UnmanagedCallersOnly.vb index d5c745de6986e..90d0325605594 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AttributeTests_UnmanagedCallersOnly.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/AttributeTests_UnmanagedCallersOnly.vb @@ -5,7 +5,6 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class AttributeTests_UnmanagedCallersOnly diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CompilationCreationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CompilationCreationTests.vb index 5bba005131b8d..6efa81702de30 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CompilationCreationTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CompilationCreationTests.vb @@ -11,7 +11,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace CompilationCreationTestHelpers Friend Module Helpers @@ -239,7 +239,7 @@ End Namespace Public Sub CyclicReference() - Dim mscorlibRef = Net451.mscorlib + Dim mscorlibRef = NetFramework.mscorlib Dim cyclic2Ref = TestReferences.SymbolsTests.Cyclic.Cyclic2.dll Dim tc1 = VisualBasicCompilation.Create("Cyclic1", references:={mscorlibRef, cyclic2Ref}) @@ -261,7 +261,7 @@ End Namespace Dim varV1MTTestLib2Path = TestReferences.SymbolsTests.V1.MTTestLib2.dll Dim asm1 = GetSymbolsForReferences( { - Net40.mscorlib, + Net40.References.mscorlib, varV1MTTestLib2Path }) @@ -274,9 +274,9 @@ End Namespace Dim asm2 = GetSymbolsForReferences( { - Net40.mscorlib, + Net40.References.mscorlib, varV1MTTestLib2Path, - TestReferences.SymbolsTests.V1.MTTestLib1.dll + TestReferences.SymbolsTests.V1.MTTestLib1.dll }) Assert.Same(asm2(0), asm1(0)) @@ -298,9 +298,9 @@ End Namespace Dim varV2MTTestLib3Path = TestReferences.SymbolsTests.V2.MTTestLib3.dll Dim asm3 = GetSymbolsForReferences( { - Net40.mscorlib, + Net40.References.mscorlib, varV1MTTestLib2Path, - TestReferences.SymbolsTests.V2.MTTestLib1.dll, + TestReferences.SymbolsTests.V2.MTTestLib1.dll, varV2MTTestLib3Path }) @@ -341,7 +341,7 @@ End Namespace Dim varV3MTTestLib4Path = TestReferences.SymbolsTests.V3.MTTestLib4.dll Dim asm4 = GetSymbolsForReferences( { - Net40.mscorlib, + Net40.References.mscorlib, varV1MTTestLib2Path, TestReferences.SymbolsTests.V3.MTTestLib1.dll, varV2MTTestLib3Path, @@ -409,7 +409,7 @@ End Namespace Assert.Same(retval14, asm4(3).GlobalNamespace.GetMembers("Class5").Single()) Dim asm5 = GetSymbolsForReferences( { - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.V2.MTTestLib3.dll }) @@ -417,7 +417,7 @@ End Namespace Assert.True(asm5(1).RepresentsTheSameAssemblyButHasUnresolvedReferencesByComparisonTo(asm3(3))) Dim asm6 = GetSymbolsForReferences( { - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.V1.MTTestLib2.dll }) @@ -425,7 +425,7 @@ End Namespace Assert.Same(asm6(1), asm1(1)) Dim asm7 = GetSymbolsForReferences( { - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.V1.MTTestLib2.dll, TestReferences.SymbolsTests.V2.MTTestLib3.dll, TestReferences.SymbolsTests.V3.MTTestLib4.dll @@ -472,7 +472,7 @@ End Namespace ' This test shows that simple reordering of references doesn't pick different set of assemblies Dim asm8 = GetSymbolsForReferences( { - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.V3.MTTestLib4.dll, TestReferences.SymbolsTests.V1.MTTestLib2.dll, TestReferences.SymbolsTests.V2.MTTestLib3.dll @@ -487,7 +487,7 @@ End Namespace Assert.Same(asm8(1), asm7(3)) Dim asm9 = GetSymbolsForReferences( { - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.V3.MTTestLib4.dll }) @@ -495,7 +495,7 @@ End Namespace Assert.True(asm9(1).RepresentsTheSameAssemblyButHasUnresolvedReferencesByComparisonTo(asm4(4))) Dim asm10 = GetSymbolsForReferences( { - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.V1.MTTestLib2.dll, TestReferences.SymbolsTests.V3.MTTestLib1.dll, TestReferences.SymbolsTests.V2.MTTestLib3.dll, @@ -667,7 +667,7 @@ End Namespace Public Class Class1 End Class - .Value}, {Net451.mscorlib}) + .Value}, {NetFramework.mscorlib}) Dim asm_MTTestLib1_V1 = varC_MTTestLib1_V1.SourceAssembly().BoundReferences() Dim varMTTestLib2_Name = New AssemblyIdentity("MTTestLib2") @@ -680,14 +680,14 @@ Public Class Class4 Public Bar As Class1 End Class - .Value}, {Net451.mscorlib, varC_MTTestLib1_V1.ToMetadataReference()}) + .Value}, {NetFramework.mscorlib, varC_MTTestLib1_V1.ToMetadataReference()}) Dim asm_MTTestLib2 = varC_MTTestLib2.SourceAssembly().BoundReferences() Assert.Same(asm_MTTestLib2(0), asm_MTTestLib1_V1(0)) Assert.Same(asm_MTTestLib2(1), varC_MTTestLib1_V1.SourceAssembly()) Dim c2 = CreateEmptyCompilation(New AssemblyIdentity("c2"), Nothing, - {Net451.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V1.ToMetadataReference()}) + {NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V1.ToMetadataReference()}) Dim asm2 = c2.SourceAssembly().BoundReferences() Assert.Same(asm2(0), asm_MTTestLib1_V1(0)) @@ -713,7 +713,7 @@ End Class Public Class Class2 End Class - .Value}, {Net451.mscorlib}) + .Value}, {NetFramework.mscorlib}) Dim asm_MTTestLib1_V2 = varC_MTTestLib1_V2.SourceAssembly().BoundReferences() Dim varMTTestLib3_Name = New AssemblyIdentity("MTTestLib3") Dim varC_MTTestLib3 = CreateEmptyCompilation(varMTTestLib3_Name, New String() { @@ -734,12 +734,12 @@ Public Class Class5 Public Bar2 As Class2 Public Bar3 As Class4 End Class - .Value}, {Net451.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V2.ToMetadataReference()}) + .Value}, {NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V2.ToMetadataReference()}) Dim asm_MTTestLib3 = varC_MTTestLib3.SourceAssembly().BoundReferences() Assert.Same(asm_MTTestLib3(0), asm_MTTestLib1_V1(0)) Assert.NotSame(asm_MTTestLib3(1), varC_MTTestLib2.SourceAssembly()) Assert.NotSame(asm_MTTestLib3(2), varC_MTTestLib1_V1.SourceAssembly()) - Dim c3 = CreateEmptyCompilation(New AssemblyIdentity("c3"), Nothing, {Net451.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V2.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference()}) + Dim c3 = CreateEmptyCompilation(New AssemblyIdentity("c3"), Nothing, {NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V2.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference()}) Dim asm3 = c3.SourceAssembly().BoundReferences() Assert.Same(asm3(0), asm_MTTestLib1_V1(0)) Assert.Same(asm3(1), asm_MTTestLib3(1)) @@ -787,7 +787,7 @@ End Class Public Class Class3 End Class - .Value}, {Net451.mscorlib}) + .Value}, {NetFramework.mscorlib}) Dim asm_MTTestLib1_V3 = varC_MTTestLib1_V3.SourceAssembly().BoundReferences() Dim varMTTestLib4_Name = New AssemblyIdentity("MTTestLib4") Dim varC_MTTestLib4 = CreateEmptyCompilation(varMTTestLib4_Name, New String() { @@ -819,7 +819,7 @@ Public Class Class6 Public Bar5 As Class5 End Class - .Value}, {Net451.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V3.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference()}) + .Value}, {NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V3.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference()}) Dim asm_MTTestLib4 = varC_MTTestLib4.SourceAssembly().BoundReferences() Assert.Same(asm_MTTestLib4(0), asm_MTTestLib1_V1(0)) @@ -829,7 +829,7 @@ End Class Dim c4 = CreateEmptyCompilation(New AssemblyIdentity("c4"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V3.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference(), @@ -899,15 +899,15 @@ End Class Dim retval14 = type3.GetMembers("Foo5").OfType(Of MethodSymbol)().Single().ReturnType Assert.NotEqual(SymbolKind.ErrorType, retval14.Kind) Assert.Same(retval14, asm4(3).GlobalNamespace.GetMembers("Class5").Single()) - Dim c5 = CreateEmptyCompilation(New AssemblyIdentity("c5"), Nothing, {Net451.mscorlib, varC_MTTestLib3.ToMetadataReference()}) + Dim c5 = CreateEmptyCompilation(New AssemblyIdentity("c5"), Nothing, {NetFramework.mscorlib, varC_MTTestLib3.ToMetadataReference()}) Dim asm5 = c5.SourceAssembly().BoundReferences() Assert.Same(asm5(0), asm2(0)) Assert.True(asm5(1).RepresentsTheSameAssemblyButHasUnresolvedReferencesByComparisonTo(asm3(3))) - Dim c6 = CreateEmptyCompilation(New AssemblyIdentity("c6"), Nothing, {Net451.mscorlib, varC_MTTestLib2.ToMetadataReference()}) + Dim c6 = CreateEmptyCompilation(New AssemblyIdentity("c6"), Nothing, {NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference()}) Dim asm6 = c6.SourceAssembly().BoundReferences() Assert.Same(asm6(0), asm2(0)) Assert.True(asm6(1).RepresentsTheSameAssemblyButHasUnresolvedReferencesByComparisonTo(varC_MTTestLib2.SourceAssembly())) - Dim c7 = CreateEmptyCompilation(New AssemblyIdentity("c6"), Nothing, {Net451.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference(), varC_MTTestLib4.ToMetadataReference()}) + Dim c7 = CreateEmptyCompilation(New AssemblyIdentity("c6"), Nothing, {NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference(), varC_MTTestLib4.ToMetadataReference()}) Dim asm7 = c7.SourceAssembly().BoundReferences() Assert.Same(asm7(0), asm2(0)) Assert.True(asm7(1).RepresentsTheSameAssemblyButHasUnresolvedReferencesByComparisonTo(varC_MTTestLib2.SourceAssembly())) @@ -950,7 +950,7 @@ End Class ' This test shows that simple reordering of references doesn't pick different set of assemblies Dim c8 = CreateEmptyCompilation(New AssemblyIdentity("c8"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, varC_MTTestLib4.ToMetadataReference(), varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference()}) @@ -963,13 +963,13 @@ End Class Assert.Same(asm8(3), asm7(2)) Assert.True(asm8(1).RepresentsTheSameAssemblyButHasUnresolvedReferencesByComparisonTo(asm4(4))) Assert.Same(asm8(1), asm7(3)) - Dim c9 = CreateEmptyCompilation(New AssemblyIdentity("c9"), Nothing, {Net451.mscorlib, varC_MTTestLib4.ToMetadataReference()}) + Dim c9 = CreateEmptyCompilation(New AssemblyIdentity("c9"), Nothing, {NetFramework.mscorlib, varC_MTTestLib4.ToMetadataReference()}) Dim asm9 = c9.SourceAssembly().BoundReferences() Assert.Same(asm9(0), asm2(0)) Assert.True(asm9(1).RepresentsTheSameAssemblyButHasUnresolvedReferencesByComparisonTo(asm4(4))) Dim c10 = CreateEmptyCompilation(New AssemblyIdentity("c10"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, varC_MTTestLib2.ToMetadataReference(), varC_MTTestLib1_V3.ToMetadataReference(), varC_MTTestLib3.ToMetadataReference(), @@ -1146,14 +1146,14 @@ End Class Dim varMTTestLib2_Name = New AssemblyIdentity("MTTestLib2") Dim varC_MTTestLib2 = CreateEmptyCompilation(varMTTestLib2_Name, Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.V1.MTTestLib1.dll, TestReferences.SymbolsTests.V1.MTTestModule2.netmodule}) Dim asm_MTTestLib2 = varC_MTTestLib2.SourceAssembly().BoundReferences() Dim c2 = CreateEmptyCompilation(New AssemblyIdentity("c2"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.V1.MTTestLib1.dll, New VisualBasicCompilationReference(varC_MTTestLib2)}) @@ -1178,7 +1178,7 @@ End Class Dim varC_MTTestLib3 = CreateEmptyCompilation(varMTTestLib3_Name, Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.V2.MTTestLib1.dll, New VisualBasicCompilationReference(varC_MTTestLib2), TestReferences.SymbolsTests.V2.MTTestModule3.netmodule}) @@ -1191,7 +1191,7 @@ End Class Dim c3 = CreateEmptyCompilation(New AssemblyIdentity("c3"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.V2.MTTestLib1.dll, New VisualBasicCompilationReference(varC_MTTestLib2), New VisualBasicCompilationReference(varC_MTTestLib3)}) @@ -1237,7 +1237,7 @@ End Class Dim varC_MTTestLib4 = CreateEmptyCompilation(varMTTestLib4_Name, Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.V3.MTTestLib1.dll, New VisualBasicCompilationReference(varC_MTTestLib2), New VisualBasicCompilationReference(varC_MTTestLib3), @@ -1253,7 +1253,7 @@ End Class Dim c4 = CreateEmptyCompilation(New AssemblyIdentity("c4"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.V3.MTTestLib1.dll, New VisualBasicCompilationReference(varC_MTTestLib2), New VisualBasicCompilationReference(varC_MTTestLib3), @@ -1327,7 +1327,7 @@ End Class Dim c5 = CreateEmptyCompilation(New AssemblyIdentity("c5"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, New VisualBasicCompilationReference(varC_MTTestLib3)}) Dim asm5 = c5.SourceAssembly().BoundReferences() @@ -1337,7 +1337,7 @@ End Class Dim c6 = CreateEmptyCompilation(New AssemblyIdentity("c6"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, New VisualBasicCompilationReference(varC_MTTestLib2)}) Dim asm6 = c6.SourceAssembly().BoundReferences() @@ -1347,7 +1347,7 @@ End Class Dim c7 = CreateEmptyCompilation(New AssemblyIdentity("c7"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, New VisualBasicCompilationReference(varC_MTTestLib2), New VisualBasicCompilationReference(varC_MTTestLib3), New VisualBasicCompilationReference(varC_MTTestLib4)}) @@ -1403,7 +1403,7 @@ End Class ' This test shows that simple reordering of references doesn't pick different set of assemblies Dim c8 = CreateEmptyCompilation(New AssemblyIdentity("c8"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, New VisualBasicCompilationReference(varC_MTTestLib4), New VisualBasicCompilationReference(varC_MTTestLib2), New VisualBasicCompilationReference(varC_MTTestLib3)}) @@ -1425,7 +1425,7 @@ End Class Dim c9 = CreateEmptyCompilation(New AssemblyIdentity("c9"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, New VisualBasicCompilationReference(varC_MTTestLib4)}) Dim asm9 = c9.SourceAssembly().BoundReferences() @@ -1435,7 +1435,7 @@ End Class Dim c10 = CreateEmptyCompilation(New AssemblyIdentity("c10"), Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.V3.MTTestLib1.dll, New VisualBasicCompilationReference(varC_MTTestLib2), New VisualBasicCompilationReference(varC_MTTestLib3), @@ -1643,7 +1643,7 @@ End Class Dim c1_V1 As VisualBasicCompilation = CreateEmptyCompilation(c1_V1_Name, {source1.Value}, - {Net451.mscorlib}) + {NetFramework.mscorlib}) Dim asm1_V1 = c1_V1.SourceAssembly @@ -1651,7 +1651,7 @@ End Class Dim c1_V2 As VisualBasicCompilation = CreateEmptyCompilation(c1_V2_Name, {source1.Value}, - {Net451.mscorlib}) + {NetFramework.mscorlib}) Dim asm1_V2 = c1_V2.SourceAssembly @@ -1665,7 +1665,7 @@ End Class Dim c4_V1 As VisualBasicCompilation = CreateEmptyCompilation(c4_V1_Name, {source4.Value}, - {Net451.mscorlib}) + {NetFramework.mscorlib}) Dim asm4_V1 = c4_V1.SourceAssembly @@ -1673,7 +1673,7 @@ End Class Dim c4_V2 As VisualBasicCompilation = CreateEmptyCompilation(c4_V2_Name, {source4.Value}, - {Net451.mscorlib}) + {NetFramework.mscorlib}) Dim asm4_V2 = c4_V2.SourceAssembly @@ -1688,7 +1688,7 @@ End Class Dim c7 As VisualBasicCompilation = CreateEmptyCompilation(New AssemblyIdentity("C7"), {source7.Value}, - {Net451.mscorlib}) + {NetFramework.mscorlib}) Dim asm7 = c7.SourceAssembly @@ -1762,7 +1762,7 @@ End Namespace Dim c3 As VisualBasicCompilation = CreateEmptyCompilation(New AssemblyIdentity("C3"), {source3.Value}, - {Net451.mscorlib, + {NetFramework.mscorlib, New VisualBasicCompilationReference(c1_V1), New VisualBasicCompilationReference(c4_V1), New VisualBasicCompilationReference(c7)}) @@ -1780,7 +1780,7 @@ End Class Dim c5 As VisualBasicCompilation = CreateEmptyCompilation(New AssemblyIdentity("C5"), {source5.Value}, - {Net451.mscorlib, + {NetFramework.mscorlib, New VisualBasicCompilationReference(c3), New VisualBasicCompilationReference(c1_V2), New VisualBasicCompilationReference(c4_V2), @@ -1997,7 +1997,7 @@ End Class Dim c2_Name = New AssemblyIdentity("MTTestLib2") Dim c2 = CreateEmptyCompilation(c2_Name, Nothing, - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.V2.MTTestLib1.dll, New VisualBasicCompilationReference(c1)}) @@ -2039,9 +2039,9 @@ End Class Public Sub AddRemoveReferences() - Dim mscorlibRef = Net451.mscorlib - Dim systemCoreRef = Net451.SystemCore - Dim systemRef = Net451.System + Dim mscorlibRef = NetFramework.mscorlib + Dim systemCoreRef = NetFramework.SystemCore + Dim systemRef = NetFramework.System Dim c = VisualBasicCompilation.Create("Test") Assert.False(HasSingleTypeOfKind(c, TypeKind.Structure, "System.Int32")) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/Choosing.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/Choosing.vb index 15755584b9802..0d1a7a1401345 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/Choosing.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/Choosing.vb @@ -12,6 +12,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Imports VBReferenceManager = Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilation.ReferenceManager Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.CorLibrary @@ -25,7 +26,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.CorLibrary Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { TestResources.SymbolsTests.CorLibrary.GuidTest2, - TestMetadata.ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) Assert.Same(assemblies(1), DirectCast(assemblies(0).Modules(0), PEModuleSymbol).CorLibrary) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/CorTypes.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/CorTypes.vb index cfdb9d5f2cbe3..e6a81031b282d 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/CorTypes.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CorLibrary/CorTypes.vb @@ -224,7 +224,7 @@ End Namespace Dim c1 = VisualBasicCompilation.Create("Test1", syntaxTrees:={VisualBasicSyntaxTree.ParseText(source1.Value)}, - references:={TestMetadata.Net40.mscorlib}) + references:={Net40.References.mscorlib}) Assert.Null(c1.GetTypeByMetadataName("DoesntExist")) Assert.Null(c1.GetTypeByMetadataName("DoesntExist`1")) @@ -239,14 +239,14 @@ End Namespace Dim c2 = VisualBasicCompilation.Create("Test2", syntaxTrees:={VisualBasicSyntaxTree.ParseText(source2.Value)}, references:={New VisualBasicCompilationReference(c1), - TestMetadata.Net40.mscorlib}) + Net40.References.mscorlib}) Dim c2TestClass As NamedTypeSymbol = c2.GetTypeByMetadataName("System.TestClass") Assert.Same(c2.Assembly, c2TestClass.ContainingAssembly) Dim c3 = VisualBasicCompilation.Create("Test3", references:={New VisualBasicCompilationReference(c2), - TestMetadata.Net40.mscorlib}) + Net40.References.mscorlib}) Dim c3TestClass As NamedTypeSymbol = c3.GetTypeByMetadataName("System.TestClass") Assert.NotSame(c2TestClass, c3TestClass) @@ -256,7 +256,7 @@ End Namespace Dim c4 = VisualBasicCompilation.Create("Test4", references:={New VisualBasicCompilationReference(c1), New VisualBasicCompilationReference(c2), - TestMetadata.Net40.mscorlib}) + Net40.References.mscorlib}) Dim c4TestClass As NamedTypeSymbol = c4.GetTypeByMetadataName("System.TestClass") Assert.Null(c4TestClass) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CustomModifiersTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CustomModifiersTests.vb index 70023459bc004..ee0606bec8104 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CustomModifiersTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/CustomModifiersTests.vb @@ -1337,7 +1337,7 @@ End Class Assert.Same(compilation1.SourceModule.CorLibrary(), test.Parameters.First.Type.OriginalDefinition.ContainingAssembly) Assert.Same(compilation1.SourceModule.CorLibrary(), DirectCast(test.Parameters.First.Type, NamedTypeSymbol).GetTypeArgumentCustomModifiers(0).First.Modifier.ContainingAssembly) - Dim compilation2 = CreateCompilationWithMscorlib45(source:=Nothing, references:={New VisualBasicCompilationReference(compilation1)}) + Dim compilation2 = CreateCompilationWithMscorlib461(source:=Nothing, references:={New VisualBasicCompilationReference(compilation1)}) test = compilation2.GetTypeByMetadataName("Module1").GetMember(Of MethodSymbol)("Test") Assert.Equal("Sub Module1.Test(x As System.Nullable(Of System.Int32 modopt(System.Runtime.CompilerServices.IsLong)))", test.ToTestDisplayString()) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/DefaultInterfaceImplementationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/DefaultInterfaceImplementationTests.vb index 287e4eab47567..9779ee9c1732d 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/DefaultInterfaceImplementationTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/DefaultInterfaceImplementationTests.vb @@ -1151,7 +1151,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -1196,7 +1196,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -1242,7 +1242,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) Assert.False(comp1.SupportsRuntimeCapability(RuntimeCapability.DefaultImplementationsOfInterfaces)) comp1.AssertTheseDiagnostics( @@ -1297,7 +1297,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -1351,7 +1351,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -1659,7 +1659,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -1693,7 +1693,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -2304,7 +2304,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -2529,7 +2529,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -6530,7 +6530,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -6568,7 +6568,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -6603,7 +6603,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -6638,7 +6638,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -6676,7 +6676,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -6711,7 +6711,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -6749,7 +6749,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37309: Target runtime doesn't support default interface implementation. @@ -6796,7 +6796,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -6843,7 +6843,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -6887,7 +6887,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -6931,7 +6931,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -6978,7 +6978,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -7022,7 +7022,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -8124,7 +8124,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -8158,7 +8158,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -8196,7 +8196,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37309: Target runtime doesn't support default interface implementation. @@ -8240,7 +8240,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -8284,7 +8284,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -9389,7 +9389,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -9423,7 +9423,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -9461,7 +9461,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37309: Target runtime doesn't support default interface implementation. @@ -9505,7 +9505,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -9549,7 +9549,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -10816,7 +10816,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -10854,7 +10854,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -10896,7 +10896,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37309: Target runtime doesn't support default interface implementation. @@ -10944,7 +10944,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. @@ -10992,7 +10992,7 @@ End Class ]]> - Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.DesktopLatestExtended, references:={csCompilation}) + Dim comp1 = CreateCompilation(source1, options:=TestOptions.DebugExe, targetFramework:=TargetFramework.Mscorlib461Extended, references:={csCompilation}) comp1.AssertTheseDiagnostics( BC37310: Target runtime doesn't support 'Protected', 'Protected Friend', or 'Private Protected' accessibility for a member of an interface. diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/ExtensionMethods/ExtensionMethodTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/ExtensionMethods/ExtensionMethodTests.vb index 8cc28a6121706..49e5e1a6ca83b 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/ExtensionMethods/ExtensionMethodTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/ExtensionMethods/ExtensionMethodTests.vb @@ -9,7 +9,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.ExtensionMethods @@ -27,7 +27,7 @@ Module Module1 End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) Dim enumerable As NamedTypeSymbol = compilation1.GetTypeByMetadataName("System.Linq.Enumerable") @@ -1115,7 +1115,7 @@ Module Module1 End Sub End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) Dim module1 As NamedTypeSymbol = compilation1.GetTypeByMetadataName("Module1") @@ -1205,7 +1205,7 @@ Class Module2 End Sub End Class - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) Dim module2 As NamedTypeSymbol = compilation2.GetTypeByMetadataName("Module2") @@ -1274,7 +1274,7 @@ End Module <System.Runtime.CompilerServices.Extension()> 'D Delegate Sub D() - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) For Each type As NamedTypeSymbol In compilation2.SourceModule.GlobalNamespace.GetTypeMembers() Assert.False(type.MightContainExtensionMethods) @@ -1353,7 +1353,7 @@ Module Module1 End Module End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) Dim module1 As NamedTypeSymbol = compilation1.GetTypeByMetadataName("Module2+Module1") @@ -1447,7 +1447,7 @@ Module Module2 End Module End Module - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) Dim module1 As NamedTypeSymbol = compilation1.GetTypeByMetadataName("Module1") @@ -1491,7 +1491,7 @@ End Module CompileAndVerify(compilationDef, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, symbolValidator:=Sub(m As ModuleSymbol) Assert.Equal(1, m.ContainingAssembly. GetAttributes("System.Runtime.CompilerServices", @@ -1522,7 +1522,7 @@ End Module CompileAndVerify(compilationDef, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, symbolValidator:=Sub(m As ModuleSymbol) Assert.Equal(1, m.ContainingAssembly. GetAttributes("System.Runtime.CompilerServices", @@ -1555,7 +1555,7 @@ End Module CompileAndVerify(compilationDef, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, symbolValidator:=Sub(m As ModuleSymbol) Assert.Equal(1, m.ContainingAssembly. GetAttributes("System.Runtime.CompilerServices", @@ -1587,7 +1587,7 @@ End Module CompileAndVerify(compilationDef, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, symbolValidator:=Sub(m As ModuleSymbol) Assert.Equal(1, m.ContainingAssembly. GetAttributes("System.Runtime.CompilerServices", @@ -1617,7 +1617,7 @@ End Module CompileAndVerify(compilationDef, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, symbolValidator:=Sub(m As ModuleSymbol) Assert.Equal(0, m.ContainingAssembly. GetAttributes("System.Runtime.CompilerServices", @@ -1646,7 +1646,7 @@ End Module CompileAndVerify(compilationDef, - references:={Net40.SystemCore}, + references:={Net40.References.SystemCore}, symbolValidator:=Sub(m As ModuleSymbol) Assert.Equal(0, m.ContainingAssembly. GetAttributes("System.Runtime.CompilerServices", @@ -1706,7 +1706,7 @@ End Module Dim compilation1 = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilation1Def, - {Net40.SystemCore, + {Net40.References.SystemCore, New VisualBasicCompilationReference(compilation2), New VisualBasicCompilationReference(compilation3)}, TestOptions.ReleaseExe) @@ -1725,7 +1725,7 @@ End Namespace ) Dim compilation1_1 = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilation1Def, - {Net40.SystemCore, + {Net40.References.SystemCore, New VisualBasicCompilationReference(compilation3_1)}, TestOptions.ReleaseExe) @@ -1762,7 +1762,7 @@ End Namespace ) Dim compilation1_2 = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilation1Def, - {Net40.SystemCore, + {Net40.References.SystemCore, New VisualBasicCompilationReference(compilation3_2)}, TestOptions.ReleaseExe) @@ -1786,7 +1786,7 @@ End Module Dim compilation1_3 = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilation1_3_Def, - {Net40.SystemCore, + {Net40.References.SystemCore, New VisualBasicCompilationReference(compilation3_1)}, TestOptions.ReleaseExe) @@ -1831,7 +1831,7 @@ End Namespace Dim compilation1_4 = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilation1_4_Def, - {Net40.SystemCore, + {Net40.References.SystemCore, New VisualBasicCompilationReference(compilation3_1)}, TestOptions.ReleaseExe) @@ -1883,7 +1883,7 @@ Module Module1 End Module - , {Net40.SystemCore, + , {Net40.References.SystemCore, New VisualBasicCompilationReference(compilation2), New VisualBasicCompilationReference(compilation3)}) @@ -1915,7 +1915,7 @@ Module Module1 End Module - , {Net40.SystemCore, + , {Net40.References.SystemCore, New VisualBasicCompilationReference(compilation2), New VisualBasicCompilationReference(compilation3)}) @@ -1945,7 +1945,7 @@ End Module - Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {Net40.SystemCore}) + Dim compilation = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(compilationDef, {Net40.References.SystemCore}) Dim assembly = compilation.SourceModule.ContainingAssembly Dim securityAttributes = assembly.GetAttributes() Debug.Assert(securityAttributes.Length = 1) @@ -2264,7 +2264,7 @@ End Module Class C End Class ]]> - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) CompilationUtils.AssertTheseDiagnostics(compilation2, - , references:={Net40.SystemCore}) + , references:={Net40.References.SystemCore}) Dim tree = comp.SyntaxTrees(0) Dim model = comp.GetSemanticModel(tree) @@ -2433,7 +2433,7 @@ Shared Function F(o As Object) As Object End Function Dim o As New Object() o.F()]]> - Dim comp = CreateCompilationWithMscorlib45( + Dim comp = CreateCompilationWithMscorlib461( {VisualBasicSyntaxTree.ParseText(source.Value, TestOptions.Script)}) comp.VerifyDiagnostics() Assert.True(comp.SourceAssembly.MightContainExtensionMethods) @@ -2441,7 +2441,7 @@ o.F()]]> Public Sub InteractiveExtensionMethods() - Dim references = {Net40.mscorlib, Net40.SystemCore} + Dim references = {Net40.References.mscorlib, Net40.References.SystemCore} Dim source0 = " Imports System.Runtime.CompilerServices @@ -2487,7 +2487,7 @@ public static class Extensions { System.Console.Write(p); } -}", referencedAssemblies:={Net40.mscorlib, Net40.SystemCore}, parseOptions:=options).EmitToImageReference() +}", referencedAssemblies:={Net40.References.mscorlib, Net40.References.SystemCore}, parseOptions:=options).EmitToImageReference() Dim vb = CreateCompilationWithMscorlib40AndVBRuntime( @@ -2516,7 +2516,7 @@ public static class Extensions { System.Console.Write(p); } -}", referencedAssemblies:={Net40.mscorlib, Net40.SystemCore}, parseOptions:=options).EmitToImageReference() +}", referencedAssemblies:={Net40.References.mscorlib, Net40.References.SystemCore}, parseOptions:=options).EmitToImageReference() Dim vb = CreateCompilationWithMscorlib40AndVBRuntime( @@ -2551,7 +2551,7 @@ Module E End Sub End Module ]]> -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) Dim extensionMethod = DirectCast(compilation.GetSymbolsWithName("ExtMethod", SymbolFilter.Member).Single(), IMethodSymbol) Assert.NotNull(extensionMethod) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/GenericConstraintTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/GenericConstraintTests.vb index bb6a60cb9b23b..0f6ea6c15d133 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/GenericConstraintTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/GenericConstraintTests.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -2033,7 +2033,7 @@ Module M End Sub End Module ]]> -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) ' Note: Dev10 reports several errors, although it seems those are incorrect. ' BC30456: 'M_Object' is not a member of 'U1'. ' x.M_Object() @@ -2135,7 +2135,7 @@ Module E End Sub End Module ]]> -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) compilation.AssertTheseDiagnostics( BC30456: 'M2' is not a member of 'T1'. _1.M2() @@ -2268,7 +2268,7 @@ Module E End Sub End Module ]]> -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) compilation.AssertNoErrors() End Sub @@ -2295,7 +2295,7 @@ Module E End Sub End Module ]]> -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) compilation.AssertTheseDiagnostics( BC30456: 'M2' is not a member of 'T'. x.M2(y) @@ -2330,7 +2330,7 @@ Module E End Sub End Module ]]> -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) compilation.AssertTheseDiagnostics( BC30456: 'M' is not a member of 'I(Of B, A)'. y.M(z) @@ -2433,7 +2433,7 @@ Module M End Module ]]> -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) compilation.AssertTheseDiagnostics( BC36593: Expression of type 'T2' is not queryable. Make sure you are not missing an assembly reference and/or namespace import for the LINQ provider. result = From o In _2 Where o IsNot Nothing @@ -2504,7 +2504,7 @@ Module E End Sub End Module ]]> -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) compilation.AssertTheseDiagnostics( BC32105: Type argument 'T' does not satisfy the 'Structure' constraint for type parameter 'T'. _1 = AddressOf arg.F1(Of T) @@ -5381,7 +5381,7 @@ Module M End Function End Module ]]> -, references:={Net40.SystemCore}) +, references:={Net40.References.SystemCore}) compilation.AssertNoErrors() End Sub @@ -5402,7 +5402,7 @@ Module M End Sub End Module ]]> -, references:={Net40.SystemCore}) +, references:={Net40.References.SystemCore}) compilation.AssertNoErrors() compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences( @@ -5416,7 +5416,7 @@ Module M End Sub End Module ]]> -, references:={Net40.SystemCore}) +, references:={Net40.References.SystemCore}) compilation.AssertNoErrors() End Sub @@ -5455,7 +5455,7 @@ Class C End Sub End Class ]]> -, references:={Net40.SystemCore}) +, references:={Net40.References.SystemCore}) compilation.AssertNoErrors() compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences( @@ -5493,7 +5493,7 @@ Class E End Sub End Class ]]> -, references:={Net40.SystemCore}) +, references:={Net40.References.SystemCore}) compilation.AssertNoErrors() compilation = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntimeAndReferences( @@ -5535,7 +5535,7 @@ Class D2 End Sub End Class ]]> -, references:={Net40.SystemCore}) +, references:={Net40.References.SystemCore}) compilation.AssertTheseDiagnostics( BC30456: 'E1' is not a member of 'X'. @@ -5878,7 +5878,7 @@ End Class]]> metadataComp.AssertTheseDiagnostics() - Dim finalComp = CreateCompilationWithMscorlib45( + Dim finalComp = CreateCompilationWithMscorlib461( Public Sub Test1() - Dim assembly = MetadataTestHelpers.LoadFromBytes(TestMetadata.ResourcesNet40.mscorlib) + Dim assembly = MetadataTestHelpers.LoadFromBytes(Net40.Resources.mscorlib) TestBaseTypeResolutionHelper1(assembly) Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( {TestResources.General.MDTestLib1, TestResources.General.MDTestLib2, - TestMetadata.ResourcesNet40.mscorlib}) + Net40.Resources.mscorlib}) TestBaseTypeResolutionHelper2(assemblies) @@ -288,7 +289,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub Test3() - Dim mscorlibRef = TestMetadata.Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim c1 = VisualBasicCompilation.Create("Test", references:={mscorlibRef}) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadCustomModifiers.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadCustomModifiers.vb index ec51f9e58a57b..b08336c56d925 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadCustomModifiers.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadCustomModifiers.vb @@ -12,6 +12,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities Imports Microsoft.CodeAnalysis.CSharp +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE @@ -23,7 +24,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { TestResources.SymbolsTests.CustomModifiers.Modifiers, - TestMetadata.ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) Dim modifiersModule = assemblies(0).Modules(0) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingAttributes.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingAttributes.vb index 34cbc9dfcf00d..9f66c5a2dd717 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingAttributes.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingAttributes.vb @@ -12,7 +12,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE @@ -66,7 +66,7 @@ End Class]]> { TestResources.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestResources.SymbolsTests.Metadata.MDTestAttributeDefLib, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) Dim assembly0 = assemblies(0) @@ -138,7 +138,7 @@ End Class]]> { TestResources.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestResources.SymbolsTests.Metadata.MDTestAttributeDefLib, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) Dim assembly1 = assemblies(1) @@ -211,7 +211,7 @@ End Class]]> { TestResources.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestResources.SymbolsTests.Metadata.MDTestAttributeDefLib, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) ' @@ -282,7 +282,7 @@ End Class]]> { TestResources.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestResources.SymbolsTests.Metadata.MDTestAttributeDefLib, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) Dim aBoolClass = TryCast(assemblies(1).Modules(0).GlobalNamespace.GetMember("ABooleanAttribute"), NamedTypeSymbol) @@ -368,7 +368,7 @@ End Class]]> { TestResources.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestResources.SymbolsTests.Metadata.MDTestAttributeDefLib, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) Dim aBoolClass = TryCast(assemblies(1).Modules(0).GlobalNamespace.GetMember("ABooleanAttribute"), NamedTypeSymbol) @@ -418,7 +418,7 @@ End Class]]> { TestResources.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestResources.SymbolsTests.Metadata.MDTestAttributeDefLib, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) ' @@ -469,7 +469,7 @@ End Class]]> { TestResources.SymbolsTests.Metadata.MDTestAttributeApplicationLib, TestResources.SymbolsTests.Metadata.MDTestAttributeDefLib, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) 'Public Class C2(Of T1) @@ -658,7 +658,7 @@ End Class]]> Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { TestResources.SymbolsTests.Metadata.AttributeInterop01, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) '[assembly: ImportedFromTypeLib("InteropAttributes")] @@ -750,7 +750,7 @@ End Class]]> Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { TestResources.SymbolsTests.Metadata.AttributeInterop01, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) '[ComImport, Guid("ABCDEF5D-2448-447A-B786-64682CBEF123")] @@ -817,7 +817,7 @@ End Class]]> Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { TestResources.SymbolsTests.Metadata.AttributeInterop01, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) ' [Serializable, ComVisible(false)] @@ -860,7 +860,7 @@ End Class]]> Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { TestResources.SymbolsTests.Metadata.AttributeInterop02, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) ' [Guid("31230DD5-2448-447A-B786-64682CBEFEEE"), Flags] @@ -900,7 +900,7 @@ End Class]]> Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { TestResources.SymbolsTests.Metadata.AttributeInterop01, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) '[ComImport, TypeLibType(TypeLibTypeFlags.FAggregatable)] @@ -1001,7 +1001,7 @@ End Class]]> { TestResources.SymbolsTests.Metadata.AttributeTestLib01, TestResources.SymbolsTests.Metadata.AttributeTestDef01, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) Dim caNS = DirectCast(assemblies(1).GlobalNamespace.GetMember("CustomAttribute"), NamespaceSymbol) @@ -1042,7 +1042,7 @@ End Class]]> { TestResources.SymbolsTests.Metadata.AttributeTestLib01, TestResources.SymbolsTests.Metadata.AttributeTestDef01, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) Dim caNS = DirectCast(assemblies(1).GlobalNamespace.GetMember("CustomAttribute"), NamespaceSymbol) @@ -1139,7 +1139,7 @@ End Class]]> { TestResources.SymbolsTests.Metadata.AttributeTestLib01, TestResources.SymbolsTests.Metadata.AttributeTestDef01, - ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) Dim caNS = DirectCast(assemblies(1).GlobalNamespace.GetMember("CustomAttribute"), NamespaceSymbol) @@ -1248,9 +1248,9 @@ End Class]]> Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { - ResourcesNet451.SystemCore, - ResourcesNet451.System, - ResourcesNet40.mscorlib + Net461.Resources.SystemCore, + Net461.Resources.System, + Net40.Resources.mscorlib }) Dim sysNS = DirectCast(assemblies(2).GlobalNamespace.GetMember("System"), NamespaceSymbol) @@ -1259,11 +1259,11 @@ End Class]]> Dim asmFileAttr = DirectCast(refNS.GetTypeMembers("AssemblyFileVersionAttribute").Single(), NamedTypeSymbol) Dim attr1 = assemblies(0).GetAttribute(asmFileAttr) - Assert.Equal("4.0.30319.18408", attr1.CommonConstructorArguments(0).Value) + Assert.Equal("4.6.1055.0", attr1.CommonConstructorArguments(0).Value) Dim asmInfoAttr = DirectCast(refNS.GetTypeMembers("AssemblyInformationalVersionAttribute").Single(), NamedTypeSymbol) attr1 = assemblies(0).GetAttribute(asmInfoAttr) - Assert.Equal("4.0.30319.18408", attr1.CommonConstructorArguments(0).Value) + Assert.Equal("4.6.1055.0", attr1.CommonConstructorArguments(0).Value) End Sub @@ -1272,9 +1272,9 @@ End Class]]> Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { - ResourcesNet451.SystemCore, - ResourcesNet451.System, - ResourcesNet40.mscorlib + Net461.Resources.SystemCore, + Net461.Resources.System, + Net40.Resources.mscorlib }) Dim corsysNS = TryCast(assemblies(2).GlobalNamespace.GetMembers("System").Single, NamespaceSymbol) @@ -1304,9 +1304,9 @@ End Class]]> Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { - ResourcesNet451.System, - ResourcesNet40.mscorlib, - ResourcesNet451.SystemConfiguration + Net461.Resources.System, + Net40.Resources.mscorlib, + Net461.Resources.SystemConfiguration }) Dim sysNS = DirectCast(assemblies(0).GlobalNamespace.GetMember("System"), NamespaceSymbol) @@ -1337,10 +1337,10 @@ End Class]]> Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { - ResourcesNet451.SystemData, - ResourcesNet451.SystemCore, - ResourcesNet451.System, - ResourcesNet451.mscorlib + Net461.Resources.SystemData, + Net461.Resources.SystemCore, + Net461.Resources.System, + Net461.Resources.mscorlib }) Dim sysNS = DirectCast(assemblies(0).GlobalNamespace.GetMember("System"), NamespaceSymbol) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingEvents.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingEvents.vb index 98759248fa2c4..196ea959d38fb 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingEvents.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingEvents.vb @@ -11,14 +11,13 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Class LoadingEvents : Inherits BasicTestBase Public Sub LoadNonGenericEvents() - Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({Net451.mscorlib, TestReferences.SymbolsTests.Events}) + Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetFramework.mscorlib, TestReferences.SymbolsTests.Events}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace Dim [class] = globalNamespace.GetMember(Of NamedTypeSymbol)("NonGeneric") @@ -27,7 +26,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub LoadGenericEvents() - Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({Net451.mscorlib, TestReferences.SymbolsTests.Events}) + Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetFramework.mscorlib, TestReferences.SymbolsTests.Events}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace Dim [class] = globalNamespace.GetMember(Of NamedTypeSymbol)("Generic") @@ -36,7 +35,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub LoadClosedGenericEvents() - Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({Net451.mscorlib, TestReferences.SymbolsTests.Events}) + Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetFramework.mscorlib, TestReferences.SymbolsTests.Events}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace Dim [class] = globalNamespace.GetMember(Of NamedTypeSymbol)("ClosedGeneric") @@ -126,7 +125,7 @@ BC30005: Reference required to assembly 'System.Drawing, Version=4.0.0.0, Cultur Public Sub LoadSignatureMismatchEvents() - Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({Net451.mscorlib, TestReferences.SymbolsTests.Events}) + Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetFramework.mscorlib, TestReferences.SymbolsTests.Events}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace Dim [class] = globalNamespace.GetMember(Of NamedTypeSymbol)("SignatureMismatch") Dim mismatchedAddEvent = [class].GetMember(Of EventSymbol)("AddMismatch") @@ -137,7 +136,7 @@ BC30005: Reference required to assembly 'System.Drawing, Version=4.0.0.0, Cultur Public Sub LoadMissingParameterEvents() - Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({Net451.mscorlib, TestReferences.SymbolsTests.Events}) + Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetFramework.mscorlib, TestReferences.SymbolsTests.Events}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace Dim [class] = globalNamespace.GetMember(Of NamedTypeSymbol)("AccessorMissingParameter") Dim noParamAddEvent = [class].GetMember(Of EventSymbol)("AddNoParam") @@ -148,7 +147,7 @@ BC30005: Reference required to assembly 'System.Drawing, Version=4.0.0.0, Cultur Public Sub LoadNonDelegateEvent() - Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({Net451.mscorlib, TestReferences.SymbolsTests.Events}) + Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetFramework.mscorlib, TestReferences.SymbolsTests.Events}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace Dim [class] = globalNamespace.GetMember(Of NamedTypeSymbol)("NonDelegateEvent") Dim nonDelegateEvent = [class].GetMember(Of EventSymbol)("NonDelegate") @@ -157,7 +156,7 @@ BC30005: Reference required to assembly 'System.Drawing, Version=4.0.0.0, Cultur Public Sub TestExplicitImplementationSimple() - Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({Net451.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp}) + Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace Dim [interface] = DirectCast(globalNamespace.GetTypeMembers("Interface").Single(), NamedTypeSymbol) Assert.Equal(TypeKind.[Interface], [interface].TypeKind) @@ -172,7 +171,7 @@ BC30005: Reference required to assembly 'System.Drawing, Version=4.0.0.0, Cultur Public Sub TestExplicitImplementationGeneric() - Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({Net451.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp}) + Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace Dim [interface] = DirectCast(globalNamespace.GetTypeMembers("IGeneric").Single(), NamedTypeSymbol) Assert.Equal(TypeKind.[Interface], [interface].TypeKind) @@ -190,7 +189,7 @@ BC30005: Reference required to assembly 'System.Drawing, Version=4.0.0.0, Cultur Public Sub TestExplicitImplementationConstructed() - Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({Net451.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp}) + Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace Dim [interface] = DirectCast(globalNamespace.GetTypeMembers("IGeneric").Single(), NamedTypeSymbol) Assert.Equal(TypeKind.[Interface], [interface].TypeKind) @@ -208,7 +207,7 @@ BC30005: Reference required to assembly 'System.Drawing, Version=4.0.0.0, Cultur Public Sub TestExplicitImplementationDefRefDef() - Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({Net451.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp}) + Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace Dim defInterface = DirectCast(globalNamespace.GetTypeMembers("Interface").Single(), NamedTypeSymbol) Assert.Equal(TypeKind.[Interface], defInterface.TypeKind) @@ -229,7 +228,7 @@ BC30005: Reference required to assembly 'System.Drawing, Version=4.0.0.0, Cultur Public Sub TestTypeParameterPositions() - Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({Net451.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp}) + Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences({NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Events.CSharp}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace Dim outerInterface = DirectCast(globalNamespace.GetTypeMembers("IGeneric2").Single(), NamedTypeSymbol) Assert.Equal(1, outerInterface.Arity) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingFields.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingFields.vb index 79116f6977e83..0f9f4763886ea 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingFields.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingFields.vb @@ -6,6 +6,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE @@ -17,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE { TestResources.SymbolsTests.Fields.CSFields, TestResources.SymbolsTests.Fields.VBFields, - TestMetadata.ResourcesNet40.mscorlib + Net40.Resources.mscorlib }, importInternals:=True) Dim module1 = assemblies(0).Modules(0) @@ -98,7 +99,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( { TestResources.SymbolsTests.Fields.ConstantFields, - TestMetadata.ResourcesNet40.mscorlib + Net40.Resources.mscorlib }) Dim module1 = assemblies(0).Modules(0) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingGenericTypeParameters.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingGenericTypeParameters.vb index 573a105749771..b11c05ee6cc3b 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingGenericTypeParameters.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingGenericTypeParameters.vb @@ -11,6 +11,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE @@ -18,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub Test1() - Dim assembly = MetadataTestHelpers.LoadFromBytes(TestMetadata.ResourcesNet40.mscorlib) + Dim assembly = MetadataTestHelpers.LoadFromBytes(Net40.Resources.mscorlib) Dim module0 = assembly.Modules(0) Dim objectType = module0.GlobalNamespace.GetMembers("System"). diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingMethods.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingMethods.vb index 7d94d33072767..c65f740f64d20 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingMethods.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingMethods.vb @@ -12,7 +12,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE @@ -28,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE TestResources.General.MDTestLib2, TestResources.SymbolsTests.Methods.CSMethods, TestResources.SymbolsTests.Methods.VBMethods, - ResourcesNet40.mscorlib, + Net40.Resources.mscorlib, TestResources.SymbolsTests.Methods.ByRefReturn }, importInternals:=True) @@ -430,7 +430,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub TestExplicitImplementationGeneric() Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Methods.CSharp}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace @@ -462,7 +462,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub TestExplicitImplementationConstructed() Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Methods.CSharp}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace @@ -525,7 +525,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub TestExplicitImplementationOfUnrelatedGenericInterfaceMethod() Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Methods.IL}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace @@ -554,7 +554,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub TestTypeParameterPositions() Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( - {Net451.mscorlib, + {NetFramework.mscorlib, TestReferences.SymbolsTests.ExplicitInterfaceImplementation.Methods.CSharp}) Dim globalNamespace = assemblies.ElementAt(1).GlobalNamespace diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingNamespacesAndTypes.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingNamespacesAndTypes.vb index 7211a586f63e1..96d76903989a7 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingNamespacesAndTypes.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/LoadingNamespacesAndTypes.vb @@ -8,7 +8,7 @@ Imports System.Xml.Linq Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE @@ -17,7 +17,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub Test1() - Dim assembly = LoadFromBytes(ResourcesNet40.mscorlib) + Dim assembly = LoadFromBytes(Net40.Resources.mscorlib) Dim dumpXML As XElement = LoadChildNamespace1(assembly.Modules(0).GlobalNamespace) Dim baseLine = XElement.Load(New MemoryStream(TestResources.SymbolsTests.Metadata.MscorlibNamespacesAndTypes)) @@ -30,7 +30,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub Test2() - Dim assembly = LoadFromBytes(ResourcesNet40.mscorlib) + Dim assembly = LoadFromBytes(Net40.Resources.mscorlib) Dim dumpXML As XElement = LoadChildNamespace2(assembly.Modules(0).GlobalNamespace) Dim baseLine = XElement.Load(New MemoryStream(TestResources.SymbolsTests.Metadata.MscorlibNamespacesAndTypes)) @@ -105,7 +105,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub Test3() - Dim assembly = LoadFromBytes(ResourcesNet40.mscorlib) + Dim assembly = LoadFromBytes(Net40.Resources.mscorlib) Dim module0 = assembly.Modules(0) Dim globalNS = module0.GlobalNamespace @@ -149,7 +149,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub Test4() - Dim assembly = LoadFromBytes(ResourcesNet40.mscorlib) + Dim assembly = LoadFromBytes(Net40.Resources.mscorlib) TestGetMembersOfName(assembly.Modules(0)) Dim assembly2 = LoadFromBytes(TestResources.SymbolsTests.DifferByCase.TypeAndNamespaceDifferByCase) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/MissingTypeReferences.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/MissingTypeReferences.vb index 6e5bd9555b935..b1f584f2ccabf 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/MissingTypeReferences.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/MissingTypeReferences.vb @@ -11,6 +11,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE @@ -26,7 +27,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences( {TestReferences.SymbolsTests.MissingTypes.MDMissingType, TestReferences.SymbolsTests.MissingTypes.MDMissingTypeLib, - TestMetadata.Net40.mscorlib}) + Net40.References.mscorlib}) TestMissingTypeReferencesHelper2(assemblies) End Sub diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/NoPia.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/NoPia.vb index c936f40df9f5d..6ca017493d472 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/NoPia.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/NoPia.vb @@ -7,7 +7,7 @@ Imports CompilationCreationTestHelpers Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Class NoPia @@ -33,7 +33,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1 }) Dim localTypes1_1 = assemblies1(0) @@ -64,7 +64,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib + Net40.References.mscorlib }) Dim localTypes1_2 = assemblies2(0) Dim localTypes2_2 = assemblies2(1) @@ -118,7 +118,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1 }) @@ -131,7 +131,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia2, - Net40.mscorlib + Net40.References.mscorlib }) Dim localTypes1_5 = assemblies5(0) Dim localTypes2_5 = assemblies5(1) @@ -159,7 +159,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia3, - Net40.mscorlib + Net40.References.mscorlib }) Dim localTypes1_6 = assemblies6(0) Dim localTypes2_6 = assemblies6(1) @@ -182,7 +182,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib + Net40.References.mscorlib }) Dim localTypes1_7 = assemblies7(0) Dim localTypes2_7 = assemblies7(1) @@ -206,7 +206,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE TestReferences.SymbolsTests.NoPia.LocalTypes2, TestReferences.SymbolsTests.NoPia.Pia4, TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib + Net40.References.mscorlib }) Dim localTypes1_8 = assemblies8(0) @@ -232,7 +232,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE TestReferences.SymbolsTests.NoPia.Library1, TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib + Net40.References.mscorlib }) Dim library1_9 = assemblies9(0) Dim localTypes1_9 = assemblies9(1) @@ -241,7 +241,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE TestReferences.SymbolsTests.NoPia.Library1, TestReferences.SymbolsTests.NoPia.LocalTypes1, TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1 }) Dim library1_10 = assemblies10(0) @@ -272,7 +272,7 @@ public class LocalTypes2 End Sub End Class .Value - Dim mscorlibRef = Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim pia1CopyLink = TestReferences.SymbolsTests.NoPia.Pia1Copy.WithEmbedInteropTypes(True) Dim pia1CopyRef = TestReferences.SymbolsTests.NoPia.Pia1Copy.WithEmbedInteropTypes(False) @@ -286,7 +286,7 @@ End Class Dim assemblies1 = MetadataTestHelpers.GetSymbolsForReferences( { TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1, TestReferences.SymbolsTests.MDTestLib2, localTypes1, @@ -330,7 +330,7 @@ End Class Dim assemblies2 = MetadataTestHelpers.GetSymbolsForReferences( { TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1, localTypes1, localTypes2 @@ -353,7 +353,7 @@ End Class Dim assemblies3 = MetadataTestHelpers.GetSymbolsForReferences( { TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, localTypes1, localTypes2 }) @@ -378,7 +378,7 @@ End Class Dim assemblies4 = MetadataTestHelpers.GetSymbolsForReferences( { TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1, TestReferences.SymbolsTests.MDTestLib2, localTypes1, @@ -392,7 +392,7 @@ End Class Dim assemblies5 = MetadataTestHelpers.GetSymbolsForReferences( { TestReferences.SymbolsTests.NoPia.Pia2, - Net40.mscorlib, + Net40.References.mscorlib, localTypes1, localTypes2 }) @@ -427,7 +427,7 @@ End Class Dim assemblies6 = MetadataTestHelpers.GetSymbolsForReferences( { TestReferences.SymbolsTests.NoPia.Pia3, - Net40.mscorlib, + Net40.References.mscorlib, localTypes1, localTypes2 }) @@ -452,7 +452,7 @@ End Class Dim assemblies7 = MetadataTestHelpers.GetSymbolsForReferences( { TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib, + Net40.References.mscorlib, localTypes1, localTypes2 }) @@ -481,7 +481,7 @@ End Class { TestReferences.SymbolsTests.NoPia.Pia4, TestReferences.SymbolsTests.NoPia.Pia1, - Net40.mscorlib, + Net40.References.mscorlib, localTypes1, localTypes2 }) @@ -507,7 +507,7 @@ End Class { TestReferences.SymbolsTests.NoPia.Library1, TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib, + Net40.References.mscorlib, localTypes1 }) @@ -518,7 +518,7 @@ End Class { TestReferences.SymbolsTests.NoPia.Library1, TestReferences.SymbolsTests.NoPia.Pia4, - Net40.mscorlib, + Net40.References.mscorlib, TestReferences.SymbolsTests.MDTestLib1, localTypes1 }) @@ -562,7 +562,7 @@ End Class Assert.Equal("C31(Of I1).I31(Of C33)", illegal.UnderlyingSymbol.ToTestDisplayString()) Assert.NotEqual(SymbolKind.ErrorType, localTypes3.GetMember(Of MethodSymbol)("Test4").ReturnType.Kind) Assert.IsType(Of NoPiaIllegalGenericInstantiationSymbol)(localTypes3.GetMember(Of MethodSymbol)("Test5").ReturnType) - assemblies = MetadataTestHelpers.GetSymbolsForReferences({TestReferences.SymbolsTests.NoPia.LocalTypes3, TestReferences.SymbolsTests.NoPia.Pia1, Net40.mscorlib}) + assemblies = MetadataTestHelpers.GetSymbolsForReferences({TestReferences.SymbolsTests.NoPia.LocalTypes3, TestReferences.SymbolsTests.NoPia.Pia1, Net40.References.mscorlib}) localTypes3 = assemblies(0).GlobalNamespace.GetTypeMembers("LocalTypes3").Single() Assert.NotEqual(SymbolKind.ErrorType, localTypes3.GetMember(Of MethodSymbol)("Test1").ReturnType.Kind) Assert.NotEqual(SymbolKind.ErrorType, localTypes3.GetMember(Of MethodSymbol)("Test2").ReturnType.Kind) @@ -574,7 +574,7 @@ End Class Public Sub GenericsClosedOverLocalTypes2() - Dim mscorlibRef = Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim pia5Link = TestReferences.SymbolsTests.NoPia.Pia5.WithEmbedInteropTypes(True) Dim pia5Ref = TestReferences.SymbolsTests.NoPia.Pia5.WithEmbedInteropTypes(False) Dim library2Ref = TestReferences.SymbolsTests.NoPia.Library2.WithEmbedInteropTypes(False) @@ -663,7 +663,7 @@ End Class Public Sub GenericsClosedOverLocalTypes3() - Dim varmscorlibRef = Net40.mscorlib + Dim varmscorlibRef = Net40.References.mscorlib Dim varALink = TestReferences.SymbolsTests.NoPia.A.WithEmbedInteropTypes(True) Dim varARef = TestReferences.SymbolsTests.NoPia.A.WithEmbedInteropTypes(False) Dim varBLink = TestReferences.SymbolsTests.NoPia.B.WithEmbedInteropTypes(True) @@ -764,7 +764,7 @@ End Interface public class C33 End Class .Value - Dim mscorlibRef = Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim pia1CopyLink = TestReferences.SymbolsTests.NoPia.Pia1Copy.WithEmbedInteropTypes(True) Dim pia1CopyRef = TestReferences.SymbolsTests.NoPia.Pia1Copy.WithEmbedInteropTypes(False) ' vbc /t:library /vbruntime- LocalTypes3.vb /l:Pia1.dll @@ -780,7 +780,7 @@ End Class Assert.Equal("C31(Of I1).I31(Of C33)", illegal.UnderlyingSymbol.ToTestDisplayString()) Assert.NotEqual(SymbolKind.ErrorType, localTypes3.GetMember(Of MethodSymbol)("Test4").ReturnType.Kind) Assert.IsType(Of NoPiaIllegalGenericInstantiationSymbol)(localTypes3.GetMember(Of MethodSymbol)("Test5").ReturnType) - assemblies = MetadataTestHelpers.GetSymbolsForReferences({TestReferences.SymbolsTests.NoPia.Pia1, Net40.mscorlib, varC_LocalTypes3}) + assemblies = MetadataTestHelpers.GetSymbolsForReferences({TestReferences.SymbolsTests.NoPia.Pia1, Net40.References.mscorlib, varC_LocalTypes3}) localTypes3 = assemblies(2).GlobalNamespace.GetTypeMembers("LocalTypes3").Single() Assert.NotEqual(SymbolKind.ErrorType, localTypes3.GetMember(Of MethodSymbol)("Test1").ReturnType.Kind) Assert.NotEqual(SymbolKind.ErrorType, localTypes3.GetMember(Of MethodSymbol)("Test2").ReturnType.Kind) @@ -841,7 +841,7 @@ public interface I7 Function Bar() As List(Of I1) End interface .Value - Dim mscorlibRef = Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib ' vbc /t:library /vbruntime- Pia5.vb Dim varC_Pia5 = VisualBasicCompilation.Create("Pia5", {Parse(pia5Source)}, {mscorlibRef}) Dim pia5Link = New VisualBasicCompilationReference(varC_Pia5, embedInteropTypes:=True) @@ -961,7 +961,7 @@ End interface Public Sub GenericsClosedOverLocalTypes6() - Dim mscorlibRef = Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim varC_A = VisualBasicCompilation.Create("A", references:={mscorlibRef}) Dim varALink = New VisualBasicCompilationReference(varC_A, embedInteropTypes:=True) Dim varARef = New VisualBasicCompilationReference(varC_A, embedInteropTypes:=False) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeAccessibility.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeAccessibility.vb index 54397dbba975e..67e1de062de9c 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeAccessibility.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeAccessibility.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE @@ -17,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub Test1() - Dim assembly = MetadataTestHelpers.LoadFromBytes(TestMetadata.ResourcesNet40.mscorlib) + Dim assembly = MetadataTestHelpers.LoadFromBytes(Net40.Resources.mscorlib) TestTypeAccessibilityHelper(assembly.Modules(0)) End Sub diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeForwarders.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeForwarders.vb index 4e1849a7465a8..027e1a2ddf2b0 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeForwarders.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeForwarders.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE @@ -20,7 +21,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE {TestResources.SymbolsTests.TypeForwarders.TypeForwarder, TestResources.SymbolsTests.TypeForwarders.TypeForwarderLib, TestResources.SymbolsTests.TypeForwarders.TypeForwarderBase, - TestMetadata.ResourcesNet40.mscorlib}) + Net40.Resources.mscorlib}) TestTypeForwarderHelper(assemblies) End Sub diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeKindTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeKindTests.vb index 76f38d30267f8..c6d00a5cc13f8 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeKindTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/TypeKindTests.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE @@ -17,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub Test1() - Dim assembly = MetadataTestHelpers.LoadFromBytes(TestMetadata.ResourcesNet40.mscorlib) + Dim assembly = MetadataTestHelpers.LoadFromBytes(Net40.Resources.mscorlib) TestTypeKindHelper(assembly) End Sub @@ -85,7 +86,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata.PE Public Sub Bug15562() - Dim assembly = MetadataTestHelpers.LoadFromBytes(TestMetadata.ResourcesNet40.mscorlib) + Dim assembly = MetadataTestHelpers.LoadFromBytes(Net40.Resources.mscorlib) Dim module0 = assembly.Modules(0) Dim system = (From n In module0.GlobalNamespace.GetMembers() Where n.Name.Equals("System")).Cast(Of NamespaceSymbol)().Single() diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/WinMdEventTest.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/WinMdEventTest.vb index 8400b18a63515..af6beadab7886 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/WinMdEventTest.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/WinMdEventTest.vb @@ -12,7 +12,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - +Imports Basic.Reference.Assemblies Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Metadata @@ -1308,7 +1308,7 @@ End Class - Dim comp = CreateEmptyCompilationWithReferences(source, {TestMetadata.Net40.mscorlib}, TestOptions.ReleaseWinMD) + Dim comp = CreateEmptyCompilationWithReferences(source, {Net40.References.mscorlib}, TestOptions.ReleaseWinMD) ' This diagnostic is from binding the return type of the AddHandler, not from checking the parameter type ' of the ReturnHandler. The key point is that a cascading ERR_RemoveParamWrongForWinRT is not reported. @@ -1388,7 +1388,7 @@ End Class - Dim comp = CreateEmptyCompilationWithReferences(source, {TestMetadata.Net40.mscorlib}, TestOptions.ReleaseWinMD) + Dim comp = CreateEmptyCompilationWithReferences(source, {Net40.References.mscorlib}, TestOptions.ReleaseWinMD) ' This diagnostic is from binding the return type of the AddHandler, not from checking the parameter type ' of the ReturnHandler. The key point is that a cascading ERR_RemoveParamWrongForWinRT is not reported. @@ -1421,7 +1421,7 @@ End Namespace - Dim comp = CreateEmptyCompilationWithReferences(source, {TestMetadata.Net40.mscorlib}, TestOptions.ReleaseWinMD) + Dim comp = CreateEmptyCompilationWithReferences(source, {Net40.References.mscorlib}, TestOptions.ReleaseWinMD) AssertTheseDeclarationDiagnostics(comp, Public Sub DuplicateReferences() - Dim mscorlibMetadata = AssemblyMetadata.CreateFromImage(TestMetadata.ResourcesNet451.mscorlib) + Dim mscorlibMetadata = AssemblyMetadata.CreateFromImage(Net461.Resources.mscorlib) Dim mscorlib1 = mscorlibMetadata.GetReference(filePath:="lib1.dll") Dim mscorlib2 = mscorlibMetadata.GetReference(filePath:="lib1.dll") diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/RefStructInterfacesTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/RefStructInterfacesTests.vb index 4d4b71b8779b6..0aa46af6e5626 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/RefStructInterfacesTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/RefStructInterfacesTests.vb @@ -20,7 +20,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Dim comp = CreateCompilation("", targetFramework:=s_targetFrameworkSupportingByRefLikeGenerics) Assert.True(comp.SupportsRuntimeCapability(RuntimeCapability.ByRefLikeGenerics)) - comp = CreateCompilation("", targetFramework:=TargetFramework.DesktopLatestExtended) + comp = CreateCompilation("", targetFramework:=TargetFramework.Mscorlib461Extended) Assert.False(comp.SupportsRuntimeCapability(RuntimeCapability.ByRefLikeGenerics)) comp = CreateCompilation("", targetFramework:=TargetFramework.Net80) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/NoPia.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/NoPia.vb index f434ef49a8b5c..83ac35b4e7814 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/NoPia.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/NoPia.vb @@ -8,6 +8,7 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities Imports System.Xml.Linq Imports Xunit +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Retargeting Public Class NoPia @@ -226,7 +227,7 @@ End Class Dim assemblies = MetadataTestHelpers.GetSymbolsForReferences(New Object() { compilation1, compilation2, - TestMetadata.Net40.mscorlib + Net40.References.mscorlib }) Dim localTypes1 = assemblies(0).Modules(0) Dim localTypes2 = assemblies(1).Modules(0) @@ -1660,7 +1661,7 @@ public delegate Sub Y(addin As List(Of string)) Dim comp1 = CreateCompilationWithMscorlib40(source1, options:=TestOptions.ReleaseDll, - references:={TestReferences.SymbolsTests.NoPia.StdOle.WithEmbedInteropTypes(True)}) + references:={TestReferences.SymbolsTests.NoPia.StdOleNet40.WithEmbedInteropTypes(True)}) Dim source2 = @@ -1675,14 +1676,14 @@ End Module Dim comp2 = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source2, {comp1.EmitToImageReference(), - TestReferences.SymbolsTests.NoPia.StdOle.WithEmbedInteropTypes(True)}, + TestReferences.SymbolsTests.NoPia.StdOleNet40.WithEmbedInteropTypes(True)}, TestOptions.ReleaseExe) CompileAndVerify(comp2, expectedOutput:="Y").Diagnostics.Verify() Dim comp3 = CreateCompilationWithMscorlib40AndVBRuntimeAndReferences(source2, {New VisualBasicCompilationReference(comp1), - TestReferences.SymbolsTests.NoPia.StdOle.WithEmbedInteropTypes(True)}, + TestReferences.SymbolsTests.NoPia.StdOleNet40.WithEmbedInteropTypes(True)}, TestOptions.ReleaseExe) CompileAndVerify(comp3, expectedOutput:="Y").Diagnostics.Verify() @@ -1701,7 +1702,7 @@ Imports System.Runtime.InteropServices Public Structure Test End Structure " - Dim piaCompilation = CreateCompilationWithMscorlib45(pia, options:=TestOptions.ReleaseDll, assemblyName:="Pia") + Dim piaCompilation = CreateCompilationWithMscorlib461(pia, options:=TestOptions.ReleaseDll, assemblyName:="Pia") Dim consumer1 = " Public Class UsePia1 @@ -1719,7 +1720,7 @@ Public Class Program End Class " For Each piaRef As MetadataReference In {piaCompilation.EmitToImageReference(), piaCompilation.ToMetadataReference()} - Dim compilation1 = CreateCompilationWithMscorlib45(consumer1, references:={piaRef.WithEmbedInteropTypes(True)}, options:=TestOptions.ReleaseDll) + Dim compilation1 = CreateCompilationWithMscorlib461(consumer1, references:={piaRef.WithEmbedInteropTypes(True)}, options:=TestOptions.ReleaseDll) For Each consumer1Ref As MetadataReference In {compilation1.EmitToImageReference(), compilation1.ToMetadataReference()} Dim compilation2 = CreateEmptyCompilation(consumer2, references:={MscorlibRef_v46, piaRef, consumer1Ref}) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetCustomModifiers.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetCustomModifiers.vb index b004cdcb3b46c..7f79ba5106022 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetCustomModifiers.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetCustomModifiers.vb @@ -16,7 +16,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols Imports Roslyn.Test.Utilities Imports Xunit -Imports Roslyn.Test.Utilities.TestMetadata +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Retargeting #If Not Retargeting Then @@ -25,11 +25,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Retargeting Public Sub Test1() - Dim oldMsCorLib = Net40.mscorlib + Dim oldMsCorLib = Net40.References.mscorlib Dim c1 = VisualBasicCompilation.Create("C1", references:={oldMsCorLib, TestReferences.SymbolsTests.CustomModifiers.Modifiers.netmodule}) Dim c1Assembly = c1.Assembly - Dim newMsCorLib = Net451.mscorlib + Dim newMsCorLib = NetFramework.mscorlib Dim c2 = VisualBasicCompilation.Create("C2", references:=New MetadataReference() {newMsCorLib, New VisualBasicCompilationReference(c1)}) Dim mscorlibAssembly = c2.GetReferencedAssemblySymbol(newMsCorLib) Assert.NotSame(mscorlibAssembly, c1.GetReferencedAssemblySymbol(oldMsCorLib)) @@ -90,7 +90,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Retargeting Public Sub Test2() - Dim oldMsCorLib = Net40.mscorlib + Dim oldMsCorLib = Net40.References.mscorlib Dim source = " public class Modifiers @@ -103,7 +103,7 @@ End Class" Dim c1 = VisualBasicCompilation.Create("C1", {Parse(source)}, {oldMsCorLib}) Dim c1Assembly = c1.Assembly - Dim newMsCorLib = Net451.mscorlib + Dim newMsCorLib = NetFramework.mscorlib Dim r1 = New VisualBasicCompilationReference(c1) Dim c2 As VisualBasicCompilation = VisualBasicCompilation.Create("C2", references:={newMsCorLib, r1}) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingCustomAttributes.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingCustomAttributes.vb index 48d35a4bd20f6..dbc2c52af669e 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingCustomAttributes.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingCustomAttributes.vb @@ -17,6 +17,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols Imports Roslyn.Test.Utilities Imports Xunit +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Retargeting #If Not Retargeting Then @@ -151,13 +152,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols.Retargeting Private Shared ReadOnly Property OldMsCorLib As MetadataReference Get - Return TestMetadata.Net40.mscorlib + Return Net40.References.mscorlib End Get End Property Private Shared ReadOnly Property NewMsCorLib As MetadataReference Get - Return TestMetadata.Net451.mscorlib + Return NetFramework.mscorlib End Get End Property diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb index 1e095a4e6c825..ff6a4f586de09 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb @@ -9,6 +9,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Retargeting Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols #If Not Retargeting Then @@ -3143,12 +3144,12 @@ End Namespace Else 'Retarget to use v2.0 assemblies If AssembliesToRetarget = 1 Then - NewCompilation = C.ReplaceReference(oldReference:=OldReference, newReference:=TestMetadata.Net20.mscorlib) + NewCompilation = C.ReplaceReference(oldReference:=OldReference, newReference:=Net20.References.mscorlib) ElseIf AssembliesToRetarget = 2 Then - NewCompilation = C.ReplaceReference(oldReference:=OldVBReference, newReference:=TestMetadata.Net20.MicrosoftVisualBasic) + NewCompilation = C.ReplaceReference(oldReference:=OldVBReference, newReference:=Net20.References.MicrosoftVisualBasic) ElseIf AssembliesToRetarget = 3 Then - NewCompilation = C.ReplaceReference(oldReference:=OldReference, newReference:=TestMetadata.Net20.mscorlib). - ReplaceReference(oldReference:=OldVBReference, newReference:=TestMetadata.Net20.MicrosoftVisualBasic) + NewCompilation = C.ReplaceReference(oldReference:=OldReference, newReference:=Net20.References.mscorlib). + ReplaceReference(oldReference:=OldVBReference, newReference:=Net20.References.MicrosoftVisualBasic) End If End If Else diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/BaseClassTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/BaseClassTests.vb index a8272822e83b7..f5b7afe4c488a 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/BaseClassTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/BaseClassTests.vb @@ -7,7 +7,6 @@ Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -725,7 +724,7 @@ Class C3 End Class , -{Net451.mscorlib, C1, C2}) +{NetFramework.mscorlib, C1, C2}) Dim expectedErrors = BC30916: Type 'C1' is not supported because it either directly or indirectly inherits from itself. @@ -750,7 +749,7 @@ BC30916: Type 'C1' is not supported because it either directly or indirectly inh End Class , -{Net451.mscorlib, C1, C2}) +{NetFramework.mscorlib, C1, C2}) Dim expectedErrors = BC30916: Type 'C1' is not supported because it either directly or indirectly inherits from itself. @@ -768,7 +767,7 @@ Class C4 End Class , -{Net451.mscorlib, C1, C2, C3}) +{NetFramework.mscorlib, C1, C2, C3}) expectedErrors = BC30916: Type 'C3' is not supported because it either directly or indirectly inherits from itself. @@ -793,7 +792,7 @@ Interface I4 End Interface , -{Net451.mscorlib, C1, C2}) +{NetFramework.mscorlib, C1, C2}) Dim expectedErrors = BC30916: Type 'I1' is not supported because it either directly or indirectly inherits from itself. @@ -823,7 +822,7 @@ Public Class ClassB End Class , -{Net451.mscorlib, ClassAv1}) +{NetFramework.mscorlib, ClassAv1}) Dim global1 = Comp.GlobalNamespace Dim B1 = global1.GetTypeMembers("ClassB", 0).Single() @@ -843,7 +842,7 @@ Public Class ClassC End Class , -New MetadataReference() {Net451.mscorlib, ClassAv2, New VisualBasicCompilationReference(Comp)}) +New MetadataReference() {NetFramework.mscorlib, ClassAv2, New VisualBasicCompilationReference(Comp)}) Dim [global] = Comp2.GlobalNamespace Dim B2 = [global].GetTypeMembers("ClassB", 0).Single() @@ -879,7 +878,7 @@ BC30916: Type 'ClassB' is not supported because it either directly or indirectly , { - Net451.mscorlib, + NetFramework.mscorlib, ClassAv1, ClassBv1 }) @@ -903,7 +902,7 @@ Public Class ClassC End Class , -New MetadataReference() {Net451.mscorlib, ClassAv2, New VisualBasicCompilationReference(Comp)}) +New MetadataReference() {NetFramework.mscorlib, ClassAv2, New VisualBasicCompilationReference(Comp)}) Dim [global] = Comp2.GlobalNamespace Dim B2 = [global].GetTypeMembers("ClassB", 0).Single() @@ -945,7 +944,7 @@ Public Class ClassB End Class , -{Net451.mscorlib, ClassAv2}) +{NetFramework.mscorlib, ClassAv2}) Dim global1 = Comp.GlobalNamespace Dim B1 = global1.GetTypeMembers("ClassB", 0).Single() @@ -977,7 +976,7 @@ Public Class ClassC End Class , -New MetadataReference() {Net451.mscorlib, ClassAv1, New VisualBasicCompilationReference(Comp)}) +New MetadataReference() {NetFramework.mscorlib, ClassAv1, New VisualBasicCompilationReference(Comp)}) Dim [global] = Comp2.GlobalNamespace Dim A2 = [global].GetTypeMembers("ClassA", 0).Single() @@ -1006,7 +1005,7 @@ New MetadataReference() {Net451.mscorlib, ClassAv1, New VisualBasicCompilationRe , { - Net451.mscorlib, + NetFramework.mscorlib, ClassAv2, ClassBv1 }) @@ -1038,7 +1037,7 @@ End Class , { - Net451.mscorlib, + NetFramework.mscorlib, ClassAv1, New VisualBasicCompilationReference(Comp) }) @@ -1074,7 +1073,7 @@ Public Class ClassB End Class , - {Net451.mscorlib, ClassAv2}) + {NetFramework.mscorlib, ClassAv2}) Dim global1 = Comp.GlobalNamespace Dim B1 = global1.GetTypeMembers("ClassB", 0).Single() @@ -1106,7 +1105,7 @@ Public Class ClassC End Class , - New MetadataReference() {Net451.mscorlib, ClassAv1, New VisualBasicCompilationReference(Comp)}) + New MetadataReference() {NetFramework.mscorlib, ClassAv1, New VisualBasicCompilationReference(Comp)}) Dim [global] = Comp2.GlobalNamespace Dim A2 = [global].GetTypeMembers("ClassA", 0).Single() diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/BindingsTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/BindingsTests.vb index d4b3713952fd1..8c83380829477 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/BindingsTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/BindingsTests.vb @@ -489,7 +489,7 @@ BC30179: interface 'Q' and class 'Q' conflict in namespace 'Goo.Bar.N1.N2'. symbol = importsYellowSymInfo.Symbol Assert.NotNull(symbol) Assert.Equal(SymbolKind.NamedType, symbol.Kind) - Assert.Equal(Of ISymbol)(importsYellowSymInfo.Type, symbol) + AssertEx.Equal(Of ISymbol)(importsYellowSymInfo.Type, symbol) Assert.Equal("Goo.Bar.N1.N2.Yellow(Of System.Int32)", symbol.ToDisplayString(SymbolDisplayFormat.TestFormat)) ' Bind "N2.IAmbig" in "arg1 as N2.IAmbig". It is ambiguous. diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/EventTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/EventTests.vb index b9e9c730c82c0..842d6e29869bc 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/EventTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/EventTests.vb @@ -144,7 +144,7 @@ Public Class E End Sub End Class ") - Dim vbCompilation = CompilationUtils.CreateCompilationWithMscorlib45AndVBRuntime( + Dim vbCompilation = CompilationUtils.CreateCompilationWithMscorlib461AndVBRuntime( source:={source}, references:={csharpCompilation.EmitToImageReference()}, options:=TestOptions.DebugDll.WithOptionStrict(OptionStrict.On)) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/MeMyBaseMyClassTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/MeMyBaseMyClassTests.vb index e7c3e35b3c9c6..63b82c5944b97 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/MeMyBaseMyClassTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/MeMyBaseMyClassTests.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class MeMyBaseMyClassTests @@ -1438,7 +1439,7 @@ Module MyExtensionModule End Function End Module -, references:={TestMetadata.Net40.SystemCore}).VerifyIL("C1.Goo", , references:={Net40.References.SystemCore}).VerifyIL("C1.Goo", -, references:={TestMetadata.Net40.SystemCore, TestMetadata.Net40.System}, options:=TestOptions.ReleaseDll.WithGlobalImports(GlobalImport.Parse("AnExt=System.Runtime.CompilerServices.ExtensionAttribute"))) +, references:={Net40.References.SystemCore, Net40.References.System}, options:=TestOptions.ReleaseDll.WithGlobalImports(GlobalImport.Parse("AnExt=System.Runtime.CompilerServices.ExtensionAttribute"))) Dim globalNS = compilation.SourceModule.GlobalNamespace Dim sourceMod = DirectCast(compilation.SourceModule, SourceModuleSymbol) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/SourceSymbolTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/SourceSymbolTests.vb index d2c3eafa1562f..d4b5daddb7953 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/SourceSymbolTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/SourceSymbolTests.vb @@ -678,8 +678,8 @@ End Namespace") ' NamespaceNames and TypeNames do not match SyntaxTrees order. ' This is expected. - Assert.Equal({"", "N3", "N0", "N", "", "N4", "N"}, comp2.Declarations.NamespaceNames.ToArray()) - Assert.Equal({"C3", "C0", "S", "C", "C4", "C"}, comp2.Declarations.TypeNames.ToArray()) + AssertEx.Equal({"", "N3", "N0", "N", "", "N4", "N"}, comp2.Declarations.NamespaceNames.ToArray()) + AssertEx.Equal({"C3", "C0", "S", "C", "C4", "C"}, comp2.Declarations.TypeNames.ToArray()) ' RemoveSyntaxTrees should preserve order of remaining trees. Dim comp3 = comp2.RemoveSyntaxTrees(source0) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/StaticLocals.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/StaticLocals.vb index b989b6125f2f9..5810924f4835d 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/StaticLocals.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/StaticLocals.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -583,7 +584,7 @@ End Class Dim compilation = CreateEmptyCompilationWithReferences( compilationDef, - {MsvbRef, TestMetadata.Net20.mscorlib}, + {MsvbRef, Net20.References.mscorlib}, TestOptions.DebugExe.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default)) Dim verifier = CompileAndVerify(compilation) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/TypeTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/TypeTests.vb index fa4e9431a7458..047f6779857aa 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/TypeTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Source/TypeTests.vb @@ -8,6 +8,7 @@ Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -673,7 +674,7 @@ End Namespace Public Sub UseTypeInNetModule() - Dim mscorlibRef = TestMetadata.Net40.mscorlib + Dim mscorlibRef = Net40.References.mscorlib Dim module1Ref = TestReferences.SymbolsTests.netModule.netModule1 Dim text = Class Test diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/SymbolErrorTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/SymbolErrorTests.vb index 45743700da313..131c09d199002 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/SymbolErrorTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/SymbolErrorTests.vb @@ -4,13 +4,13 @@ Imports System.Collections.Immutable Imports System.Xml.Linq +Imports Basic.Reference.Assemblies Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Test.Utilities -Imports Roslyn.Test.Utilities.TestMetadata Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests @@ -6666,7 +6666,7 @@ BC30639: Properties cannot be declared 'Partial'. Public Sub BC30645ERR_InvalidOptionalParameterUsage1() - Dim compilation1 = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime( + Dim compilation1 = CompilationUtils.CreateCompilation( - ) - compilation1 = compilation1.AddReferences(Net451.SystemWebServices) + , targetFramework:=TargetFramework.NetFramework) Dim expectedErrors1 = Public Sub BC30645ERR_InvalidOptionalParameterUsage1a() - Dim compilation1 = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime( + Dim compilation1 = CompilationUtils.CreateCompilation( - ) - compilation1 = compilation1.AddReferences(Net451.SystemWebServices) + , targetFramework:=TargetFramework.NetFramework) CompilationUtils.AssertTheseDeclarationDiagnostics(compilation1, ) End Sub - + Public Sub BC30645ERR_InvalidOptionalParameterUsage1b() - Dim compilation1 = CompilationUtils.CreateCompilationWithMscorlib40AndVBRuntime( + ' Dim references = {Net461.References.mscorlib, Net461.References.MicrosoftVisualBasic, Net461.References.SystemWebServices, Net461.References.SystemEnterpriseServices + Dim compilation1 = CompilationUtils.CreateCompilation( - ) - compilation1 = compilation1.AddReferences(Net451.SystemWebServices, - Net451.SystemEnterpriseServices) + , targetFramework:=TargetFramework.NetFramework) CompilationUtils.AssertTheseDiagnostics(compilation1, , -{Net451.mscorlib, C1, C2}) +{NetFramework.mscorlib, C1, C2}) Dim expectedErrors = , -{Net451.mscorlib, C1, C2}) +{NetFramework.mscorlib, C1, C2}) Dim expectedErrors = , -{Net451.mscorlib, C1, C2}) +{NetFramework.mscorlib, C1, C2}) Dim expectedErrors = - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) Dim expectedErrors1 = - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) Dim expectedErrors1 = - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) Dim expectedErrors1 = - , {Net40.SystemCore}) + , {Net40.References.SystemCore}) Dim expectedErrors1 = -, {Net40.SystemCore}) +, {Net40.References.SystemCore}) Dim expectedErrors1 = - Dim comp = CreateCompilationWithMscorlib45( + Dim comp = CreateCompilationWithMscorlib461( {VisualBasicSyntaxTree.ParseText(source.Value, TestOptions.Script)}, references:={SystemCoreRef}) comp.AssertTheseDiagnostics( diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/TypedConstantTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/TypedConstantTests.vb index 13ba0563a98bc..1d3617bfd1da1 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/TypedConstantTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/TypedConstantTests.vb @@ -7,6 +7,7 @@ Imports System.Linq Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports Roslyn.Test.Utilities Imports Xunit Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols @@ -37,7 +38,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols Assert.Equal(common.Value, lang.Value) Assert.Equal(common.Kind, lang.Kind) - Assert.Equal(Of Object)(common.Type, lang.Type) + AssertEx.Equal(Of Object)(common.Type, lang.Type) Assert.Equal(common.Value, common2.Value) Assert.Equal(common.Kind, common2.Kind) @@ -50,7 +51,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Symbols Assert.Equal(commonArray.Values.Single(), langArray.Values.Single()) Assert.Equal(commonArray.Kind, langArray.Kind) - Assert.Equal(Of Object)(commonArray.Type, langArray.Type) + AssertEx.Equal(Of Object)(commonArray.Type, langArray.Type) Assert.Equal(commonArray.Values, commonArray2.Values) Assert.Equal(commonArray.Kind, commonArray2.Kind) diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb index 798d74ecf6e0e..a3de0df7eec4b 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb @@ -2,6 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports Basic.Reference.Assemblies Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities @@ -466,7 +467,7 @@ End Namespace Public Sub AllSpecialTypeMembers() - Dim comp = CreateEmptyCompilationWithReferences((), {MscorlibRef_v4_0_30316_17626}) + Dim comp = CreateEmptyCompilationWithReferences((), {Net461.References.mscorlib}) For Each special As SpecialMember In [Enum].GetValues(GetType(SpecialMember)) Select Case special @@ -496,8 +497,7 @@ End Namespace special = SpecialMember.System_Runtime_CompilerServices_RuntimeFeature__ByRefLikeGenerics OrElse special = SpecialMember.System_Runtime_CompilerServices_PreserveBaseOverridesAttribute__ctor OrElse special = SpecialMember.System_Runtime_CompilerServices_InlineArrayAttribute__ctor OrElse - special = SpecialMember.System_ReadOnlySpan_T__ctor_Reference OrElse - special = SpecialMember.System_Array__Empty Then + special = SpecialMember.System_ReadOnlySpan_T__ctor_Reference Then Assert.Null(symbol) ' Not available Else Assert.NotNull(symbol) @@ -581,14 +581,15 @@ End Namespace WellKnownType.System_Runtime_CompilerServices_IsReadOnlyAttribute, WellKnownType.System_Runtime_CompilerServices_IsByRefLikeAttribute, WellKnownType.System_Runtime_CompilerServices_IsUnmanagedAttribute, - WellKnownType.System_Runtime_CompilerServices_ITuple + WellKnownType.System_Runtime_CompilerServices_ITuple, + WellKnownType.System_Runtime_CompilerServices_HotReloadException ' Not always available. Continue For End Select Dim symbol = comp.GetWellKnownType(wkt) Assert.NotNull(symbol) - Assert.NotEqual(SymbolKind.ErrorType, symbol.Kind) + Assert.True(SymbolKind.ErrorType <> symbol.Kind, $"{symbol} should not be an error type") Next comp = CreateEmptyCompilationWithReferences(, refs, TestOptions.ReleaseDll.WithEmbedVbCoreRuntime(True)) @@ -663,7 +664,8 @@ End Namespace WellKnownType.System_Runtime_CompilerServices_IsReadOnlyAttribute, WellKnownType.System_Runtime_CompilerServices_IsByRefLikeAttribute, WellKnownType.System_Runtime_CompilerServices_IsUnmanagedAttribute, - WellKnownType.System_Runtime_CompilerServices_ITuple + WellKnownType.System_Runtime_CompilerServices_ITuple, + WellKnownType.System_Runtime_CompilerServices_HotReloadException ' Not always available. Continue For End Select @@ -823,8 +825,10 @@ End Namespace WellKnownMember.System_Span_T__CopyTo_Span_T, WellKnownMember.System_ReadOnlySpan_T__CopyTo_Span_T, WellKnownMember.System_Collections_Immutable_ImmutableArray_T__AsSpan, + WellKnownMember.System_Collections_Immutable_ImmutableArray_T__Empty, WellKnownMember.System_Span_T__ctor_ref_T, - WellKnownMember.System_ReadOnlySpan_T__ctor_ref_readonly_T + WellKnownMember.System_ReadOnlySpan_T__ctor_ref_readonly_T, + WellKnownMember.System_Runtime_CompilerServices_HotReloadException__ctorStringInt32 ' Not always available. Continue For End Select @@ -1030,8 +1034,10 @@ End Namespace WellKnownMember.System_Span_T__CopyTo_Span_T, WellKnownMember.System_ReadOnlySpan_T__CopyTo_Span_T, WellKnownMember.System_Collections_Immutable_ImmutableArray_T__AsSpan, + WellKnownMember.System_Collections_Immutable_ImmutableArray_T__Empty, WellKnownMember.System_Span_T__ctor_ref_T, - WellKnownMember.System_ReadOnlySpan_T__ctor_ref_readonly_T + WellKnownMember.System_ReadOnlySpan_T__ctor_ref_readonly_T, + WellKnownMember.System_Runtime_CompilerServices_HotReloadException__ctorStringInt32 ' Not always available. Continue For End Select diff --git a/src/Compilers/VisualBasic/Test/Syntax/Parser/ParserRegressionTests.vb b/src/Compilers/VisualBasic/Test/Syntax/Parser/ParserRegressionTests.vb index e10774ec82a94..cb66eb6f17b9a 100644 --- a/src/Compilers/VisualBasic/Test/Syntax/Parser/ParserRegressionTests.vb +++ b/src/Compilers/VisualBasic/Test/Syntax/Parser/ParserRegressionTests.vb @@ -7,6 +7,7 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Text Imports Roslyn.Test.Utilities Imports Roslyn.Test.Utilities.Syntax +Imports Basic.Reference.Assemblies Public Class ParserRegressionTests : Inherits BasicTestBase @@ -753,7 +754,7 @@ End Select Public Sub ParseFileOnBinaryFile() ' This is doing the same thing as ParseFile, but using a MemoryStream ' instead of FileStream (because I don't want to write a file to disk). - Using data As New MemoryStream(TestMetadata.ResourcesNet451.mscorlib) + Using data As New MemoryStream(Net461.Resources.mscorlib) Const bug103047IsFixed = False If bug103047IsFixed Then diff --git a/src/Compilers/VisualBasic/Test/Syntax/Parser/XmlDocComments.vb b/src/Compilers/VisualBasic/Test/Syntax/Parser/XmlDocComments.vb index df324726b606a..71f2983de47ef 100644 --- a/src/Compilers/VisualBasic/Test/Syntax/Parser/XmlDocComments.vb +++ b/src/Compilers/VisualBasic/Test/Syntax/Parser/XmlDocComments.vb @@ -574,7 +574,7 @@ End Module Dim actual = documentationComment.ToFullString() - Assert.Equal(Of String)(expected, actual) + AssertEx.Equal(Of String)(expected, actual) End Sub @@ -594,7 +594,7 @@ End Module Dim actual = documentationComment.ToFullString() - Assert.Equal(Of String)(expected, actual) + AssertEx.Equal(Of String)(expected, actual) End Sub @@ -622,7 +622,19 @@ End Module Dim actual = documentationComment.ToFullString() - Assert.Equal(Of String)(expected, actual) + AssertEx.Equal(Of String)(expected, actual) + End Sub + + + + Public Sub TestXmlSeeAlsoElementWithLink() + Dim docComment = SyntaxFactory.DocumentationComment( + SyntaxFactory.XmlSeeAlsoElement(New Uri("https://dotnet.microsoft.com/"), + SyntaxFactory.List(New XmlNodeSyntax() {SyntaxFactory.XmlText(".NET")}))) + + Assert.Equal( + "''' .NET", + docComment.ToFullString()) End Sub @@ -653,7 +665,7 @@ End Module Dim actual = documentationComment.ToFullString() - Assert.Equal(Of String)(expected, actual) + AssertEx.Equal(Of String)(expected, actual) End Sub @@ -679,7 +691,7 @@ End Module Dim actual = documentationComment.ToFullString() - Assert.Equal(Of String)(expected, actual) + AssertEx.Equal(Of String)(expected, actual) End Sub @@ -706,7 +718,7 @@ End Module Dim actual = documentationComment.ToFullString() - Assert.Equal(Of String)(expected, actual) + AssertEx.Equal(Of String)(expected, actual) End Sub @@ -737,7 +749,7 @@ End Module Dim actual = documentationComment.ToFullString() - Assert.Equal(Of String)(expected, actual) + AssertEx.Equal(Of String)(expected, actual) End Sub @@ -762,7 +774,7 @@ End Module Dim actual = documentationComment.ToFullString() - Assert.Equal(Of String)(expected, actual) + AssertEx.Equal(Of String)(expected, actual) End Sub @@ -787,7 +799,7 @@ End Module Dim actual = documentationComment.ToFullString() - Assert.Equal(Of String)(expected, actual) + AssertEx.Equal(Of String)(expected, actual) End Sub End Class diff --git a/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxEquivalenceTests.vb b/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxEquivalenceTests.vb index af6167567223e..c21610dc21125 100644 --- a/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxEquivalenceTests.vb +++ b/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxEquivalenceTests.vb @@ -2,6 +2,8 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports Roslyn.Test.Utilities + Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class SyntaxEquivalenceTests @@ -274,6 +276,46 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests VerifyNotEquivalent(tree1, tree2, topLevel:=False) End Sub + + Public Sub TestXmlLiteral_Text() + Dim tree1 = VisualBasicSyntaxTree.ParseText(NewLines("namespace N \n class C \n sub Goo() \n Dim x = Text1 \n end sub \n end class \n end namespace")) + Dim tree2 = tree1.WithReplaceFirst("Text1", "Text2") + VerifyEquivalent(tree1, tree2, topLevel:=True) + VerifyNotEquivalent(tree1, tree2, topLevel:=False) + End Sub + + + Public Sub TestXmlLiteral_AttributeValue() + Dim tree1 = VisualBasicSyntaxTree.ParseText(NewLines("namespace N \n class C \n sub Goo() \n Dim x = Text \n end sub \n end class \n end namespace")) + Dim tree2 = tree1.WithReplaceFirst("attr1", "attr2") + VerifyEquivalent(tree1, tree2, topLevel:=True) + VerifyNotEquivalent(tree1, tree2, topLevel:=False) + End Sub + + + Public Sub TestXmlLiteral_AttributeName() + Dim tree1 = VisualBasicSyntaxTree.ParseText(NewLines("namespace N \n class C \n sub Goo() \n Dim x = Text \n end sub \n end class \n end namespace")) + Dim tree2 = tree1.WithReplaceFirst("attr1", "attr2") + VerifyEquivalent(tree1, tree2, topLevel:=True) + VerifyNotEquivalent(tree1, tree2, topLevel:=False) + End Sub + + + Public Sub TestXmlLiteral_CDATA() + Dim tree1 = VisualBasicSyntaxTree.ParseText(NewLines("namespace N \n class C \n sub Goo() \n Dim a = \n end sub \n end class \n end namespace")) + Dim tree2 = tree1.WithReplaceFirst("Text1", "Text2") + VerifyEquivalent(tree1, tree2, topLevel:=True) + VerifyNotEquivalent(tree1, tree2, topLevel:=False) + End Sub + + + Public Sub TestXmlLiteral_Comment() + Dim tree1 = VisualBasicSyntaxTree.ParseText(NewLines("namespace N \n class C \n sub Goo() \n Dim a = \n end sub \n end class \n end namespace")) + Dim tree2 = tree1.WithReplaceFirst("Text1", "Text2") + VerifyEquivalent(tree1, tree2, topLevel:=True) + VerifyNotEquivalent(tree1, tree2, topLevel:=False) + End Sub + #Region "Field" diff --git a/src/Compilers/VisualBasic/vbc/VbcCommandLine.projitems b/src/Compilers/VisualBasic/vbc/VbcCommandLine.projitems index a85e09f46fdde..1ff2a55ee9eba 100644 --- a/src/Compilers/VisualBasic/vbc/VbcCommandLine.projitems +++ b/src/Compilers/VisualBasic/vbc/VbcCommandLine.projitems @@ -36,7 +36,7 @@ - + diff --git a/src/Compilers/VisualBasic/vbc/arm64/vbc-arm64.csproj b/src/Compilers/VisualBasic/vbc/arm64/vbc-arm64.csproj index 3d83b4e2e48c3..5dce6cbbe8b24 100644 --- a/src/Compilers/VisualBasic/vbc/arm64/vbc-arm64.csproj +++ b/src/Compilers/VisualBasic/vbc/arm64/vbc-arm64.csproj @@ -10,7 +10,7 @@ vbc true true - true + true diff --git a/src/Dependencies/Collections/Internal/ArraySortHelper.cs b/src/Dependencies/Collections/Internal/ArraySortHelper.cs index 7c12f6f76a234..1817447d26878 100644 --- a/src/Dependencies/Collections/Internal/ArraySortHelper.cs +++ b/src/Dependencies/Collections/Internal/ArraySortHelper.cs @@ -13,7 +13,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; -#if NETCOREAPP +#if NET using System.Numerics; #else using System.Runtime.InteropServices; @@ -1263,7 +1263,7 @@ public static int MoveNansToFront(SegmentedArraySegment keys public static int Log2(uint value) { -#if NETCOREAPP +#if NET return BitOperations.Log2(value); #else // Fallback contract is 0->0 diff --git a/src/Dependencies/Collections/Internal/SegmentedArrayHelper.cs b/src/Dependencies/Collections/Internal/SegmentedArrayHelper.cs index ab4ffa67a1514..c9ca2d2d31f19 100644 --- a/src/Dependencies/Collections/Internal/SegmentedArrayHelper.cs +++ b/src/Dependencies/Collections/Internal/SegmentedArrayHelper.cs @@ -31,7 +31,7 @@ internal static int GetSegmentSize() 28 => 2048, 32 => 2048, 40 => 2048, -#if NETCOREAPP3_0_OR_NEWER +#if NETCOREAPP3_0_OR_GREATER _ => InlineCalculateSegmentSize(Unsafe.SizeOf()), #else _ => FallbackSegmentHelper.SegmentSize, @@ -55,7 +55,7 @@ internal static int GetSegmentShift() 28 => 11, 32 => 11, 40 => 11, -#if NETCOREAPP3_0_OR_NEWER +#if NETCOREAPP3_0_OR_GREATER _ => InlineCalculateSegmentShift(Unsafe.SizeOf()), #else _ => FallbackSegmentHelper.SegmentShift, @@ -79,7 +79,7 @@ internal static int GetOffsetMask() 28 => 2047, 32 => 2047, 40 => 2047, -#if NETCOREAPP3_0_OR_NEWER +#if NETCOREAPP3_0_OR_GREATER _ => InlineCalculateOffsetMask(Unsafe.SizeOf()), #else _ => FallbackSegmentHelper.OffsetMask, @@ -148,7 +148,7 @@ private static int CalculateOffsetMask(int segmentSize) // Faster inline implementation for NETCOREAPP to avoid static constructors and non-inlineable // generics with runtime lookups -#if NETCOREAPP3_0_OR_NEWER +#if NETCOREAPP3_0_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int InlineCalculateSegmentSize(int elementSize) { @@ -183,7 +183,7 @@ public static int CalculateOffsetMask(int segmentSize) => SegmentedArrayHelper.CalculateOffsetMask(segmentSize); } -#if !NETCOREAPP3_0_OR_NEWER +#if !NETCOREAPP3_0_OR_GREATER private static class FallbackSegmentHelper { public static readonly int SegmentSize = CalculateSegmentSize(Unsafe.SizeOf()); diff --git a/src/Dependencies/Collections/SegmentedArray`1.cs b/src/Dependencies/Collections/SegmentedArray`1.cs index ac7f5d9801ce2..ae0eb89b32c9a 100644 --- a/src/Dependencies/Collections/SegmentedArray`1.cs +++ b/src/Dependencies/Collections/SegmentedArray`1.cs @@ -355,7 +355,7 @@ int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) var ret = 0; for (var i = Length >= 8 ? Length - 8 : 0; i < Length; i++) { -#if NETCOREAPP +#if NET ret = HashCode.Combine(comparer.GetHashCode(this[i]!), ret); #else ret = unchecked((ret * (int)0xA5555529) + comparer.GetHashCode(this[i]!)); diff --git a/src/Dependencies/Collections/SegmentedDictionary`2.cs b/src/Dependencies/Collections/SegmentedDictionary`2.cs index aead46ec403a5..6a46b472a4cc8 100644 --- a/src/Dependencies/Collections/SegmentedDictionary`2.cs +++ b/src/Dependencies/Collections/SegmentedDictionary`2.cs @@ -35,7 +35,7 @@ internal sealed partial class SegmentedDictionary : IDictionary? _comparer; #else /// @@ -710,14 +710,14 @@ public bool Remove(TKey key) Debug.Assert((StartOfFreeList - _freeList) < 0, "shouldn't underflow because max hashtable length is MaxPrimeArrayLength = 0x7FEFFFFD(2146435069) _freelist underflow threshold 2147483646"); entry._next = StartOfFreeList - _freeList; -#if NETCOREAPP +#if NET if (RuntimeHelpers.IsReferenceOrContainsReferences()) #endif { entry._key = default!; } -#if NETCOREAPP +#if NET if (RuntimeHelpers.IsReferenceOrContainsReferences()) #endif { @@ -789,14 +789,14 @@ public bool Remove(TKey key, [MaybeNullWhen(false)] out TValue value) Debug.Assert((StartOfFreeList - _freeList) < 0, "shouldn't underflow because max hashtable length is MaxPrimeArrayLength = 0x7FEFFFFD(2146435069) _freelist underflow threshold 2147483646"); entry._next = StartOfFreeList - _freeList; -#if NETCOREAPP +#if NET if (RuntimeHelpers.IsReferenceOrContainsReferences()) #endif { entry._key = default!; } -#if NETCOREAPP +#if NET if (RuntimeHelpers.IsReferenceOrContainsReferences()) #endif { diff --git a/src/Dependencies/Collections/SegmentedHashSet`1.cs b/src/Dependencies/Collections/SegmentedHashSet`1.cs index 2e35a5ffae94a..c8792b3e9f5ed 100644 --- a/src/Dependencies/Collections/SegmentedHashSet`1.cs +++ b/src/Dependencies/Collections/SegmentedHashSet`1.cs @@ -27,7 +27,7 @@ internal class SegmentedHashSet : ICollection, ISet, IReadOnlyCollectio #endif { private const bool SupportsComparerDevirtualization -#if NETCOREAPP +#if NET = true; #else = false; @@ -57,7 +57,7 @@ private const bool SupportsComparerDevirtualization private int _freeList; private int _freeCount; private int _version; -#if NETCOREAPP +#if NET private readonly IEqualityComparer? _comparer; #else /// @@ -324,7 +324,7 @@ public bool Remove(T item) Debug.Assert((StartOfFreeList - _freeList) < 0, "shouldn't underflow because max hashtable length is MaxPrimeArrayLength = 0x7FEFFFFD(2146435069) _freelist underflow threshold 2147483646"); entry._next = StartOfFreeList - _freeList; -#if NETCOREAPP +#if NET if (RuntimeHelpers.IsReferenceOrContainsReferences()) #endif { diff --git a/src/Dependencies/Collections/SegmentedList`1.cs b/src/Dependencies/Collections/SegmentedList`1.cs index 4747f34ce1e75..4a5604cbefb39 100644 --- a/src/Dependencies/Collections/SegmentedList`1.cs +++ b/src/Dependencies/Collections/SegmentedList`1.cs @@ -359,7 +359,7 @@ public int BinarySearch(T item, IComparer? comparer) public void Clear() { _version++; -#if NETCOREAPP +#if NET if (!RuntimeHelpers.IsReferenceOrContainsReferences()) { _size = 0; @@ -1049,7 +1049,7 @@ public int RemoveAll(Predicate match) } } -#if NETCOREAPP +#if NET if (RuntimeHelpers.IsReferenceOrContainsReferences()) #endif { @@ -1075,7 +1075,7 @@ public void RemoveAt(int index) { SegmentedArray.Copy(_items, index + 1, _items, index, _size - index); } -#if NETCOREAPP +#if NET if (RuntimeHelpers.IsReferenceOrContainsReferences()) #endif { @@ -1109,7 +1109,7 @@ public void RemoveRange(int index, int count) } _version++; -#if NETCOREAPP +#if NET if (RuntimeHelpers.IsReferenceOrContainsReferences()) #endif { diff --git a/src/Dependencies/Directory.Build.props b/src/Dependencies/Directory.Build.props index 6eef643958f56..9dd0ddea9df26 100644 --- a/src/Dependencies/Directory.Build.props +++ b/src/Dependencies/Directory.Build.props @@ -1,6 +1,6 @@ - true + true diff --git a/src/Deployment/Directory.Build.props b/src/Deployment/Directory.Build.props index 6eef643958f56..9dd0ddea9df26 100644 --- a/src/Deployment/Directory.Build.props +++ b/src/Deployment/Directory.Build.props @@ -1,6 +1,6 @@ - true + true diff --git a/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs b/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs index 2182856f1451e..2e7dbe8bd7510 100644 --- a/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs +++ b/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs @@ -4,9 +4,18 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editor.Implementation.InlineRename; +using Microsoft.CodeAnalysis.GoToDefinition; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Editor.CSharp.InlineRename; @@ -16,4 +25,144 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.InlineRename; internal sealed class CSharpEditorInlineRenameService([ImportMany] IEnumerable refactorNotifyServices) : AbstractEditorInlineRenameService(refactorNotifyServices) { + private const int NumberOfContextLines = 20; + private const int MaxDefinitionCount = 10; + private const int MaxReferenceCount = 50; + + /// + /// Uses semantic information of renamed symbol to produce a map containing contextual information for use in Copilot rename feature + /// + /// Map where key indicates the kind of semantic information, and value is an array of relevant code snippets. + public override async Task>> GetRenameContextAsync( + IInlineRenameInfo inlineRenameInfo, IInlineRenameLocationSet inlineRenameLocationSet, CancellationToken cancellationToken) + { + using var _1 = PooledHashSet.GetInstance(out var seen); + using var _2 = ArrayBuilder<(string filePath, string content)>.GetInstance(out var definitions); + using var _3 = ArrayBuilder<(string filePath, string content)>.GetInstance(out var references); + using var _4 = ArrayBuilder<(string filePath, string content)>.GetInstance(out var docComments); + + foreach (var renameDefinition in inlineRenameInfo.DefinitionLocations.Take(MaxDefinitionCount)) + { + // Find largest snippet of code that represents the definition + var containingStatementOrDeclarationSpan = + await TryGetSurroundingNodeSpanAsync(renameDefinition.Document, renameDefinition.SourceSpan, cancellationToken).ConfigureAwait(false) ?? + await TryGetSurroundingNodeSpanAsync(renameDefinition.Document, renameDefinition.SourceSpan, cancellationToken).ConfigureAwait(false); + + // Find documentation comments of definitions + var symbolService = renameDefinition.Document.GetRequiredLanguageService(); + if (symbolService is not null) + { + var textSpan = inlineRenameInfo.TriggerSpan; + var (symbol, _, _) = await symbolService.GetSymbolProjectAndBoundSpanAsync( + renameDefinition.Document, textSpan.Start, cancellationToken) + .ConfigureAwait(true); + var docComment = symbol?.GetDocumentationCommentXml(expandIncludes: true, cancellationToken: cancellationToken); + if (!string.IsNullOrWhiteSpace(docComment)) + { + var filePath = renameDefinition.Document.FilePath; + if (filePath != null) + { + docComments.Add((filePath, docComment)); + } + } + } + + var documentText = await renameDefinition.Document.GetTextAsync(cancellationToken).ConfigureAwait(false); + if (renameDefinition.Document.FilePath is not null) + { + AddSpanOfInterest(documentText, renameDefinition.Document.FilePath, renameDefinition.SourceSpan, containingStatementOrDeclarationSpan, definitions); + } + } + + foreach (var renameLocation in inlineRenameLocationSet.Locations.Take(MaxReferenceCount)) + { + // Find largest snippet of code that represents the reference + var containingStatementOrDeclarationSpan = + await TryGetSurroundingNodeSpanAsync(renameLocation.Document, renameLocation.TextSpan, cancellationToken).ConfigureAwait(false) ?? + await TryGetSurroundingNodeSpanAsync(renameLocation.Document, renameLocation.TextSpan, cancellationToken).ConfigureAwait(false) ?? + await TryGetSurroundingNodeSpanAsync(renameLocation.Document, renameLocation.TextSpan, cancellationToken).ConfigureAwait(false); + + var documentText = await renameLocation.Document.GetTextAsync(cancellationToken).ConfigureAwait(false); + if (renameLocation.Document.FilePath is not null) + { + AddSpanOfInterest(documentText, renameLocation.Document.FilePath, renameLocation.TextSpan, containingStatementOrDeclarationSpan, references); + } + } + + var contextBuilder = ImmutableDictionary.CreateBuilder>(); + if (!definitions.IsEmpty) + { + contextBuilder.Add("definition", definitions.ToImmutable()); + } + if (!references.IsEmpty) + { + contextBuilder.Add("reference", references.ToImmutable()); + } + if (!docComments.IsEmpty) + { + contextBuilder.Add("documentation", docComments.ToImmutable()); + } + + return contextBuilder.ToImmutableDictionary(); + + void AddSpanOfInterest(SourceText documentText, string filePath, TextSpan fallbackSpan, TextSpan? surroundingSpanOfInterest, ArrayBuilder<(string filePath, string content)> resultBuilder) + { + int startPosition, endPosition, startLine = 0, endLine = 0, lineCount = 0; + if (surroundingSpanOfInterest is not null) + { + startPosition = surroundingSpanOfInterest.Value.Start; + endPosition = surroundingSpanOfInterest.Value.End; + startLine = documentText.Lines.GetLineFromPosition(surroundingSpanOfInterest.Value.Start).LineNumber; + endLine = documentText.Lines.GetLineFromPosition(surroundingSpanOfInterest.Value.End).LineNumber; + lineCount = endLine - startLine + 1; + + if (lineCount > NumberOfContextLines * 2) + { + // The computed span is too large, trim it such that the fallback span is included + // and no content is provided from before startLine or after endLine. + var fallbackStartLine = Math.Max(0, documentText.Lines.GetLineFromPosition(fallbackSpan.Start).LineNumber - NumberOfContextLines); + var fallbackEndLine = Math.Min(documentText.Lines.Count - 1, documentText.Lines.GetLineFromPosition(fallbackSpan.End).LineNumber + NumberOfContextLines); + var excessAtStart = startLine - fallbackStartLine; + var excessAtEnd = fallbackEndLine - endLine; + if (excessAtStart > 0) + { + // The fallback span extends before the relevant span (startLine) + endLine = Math.Min(documentText.Lines.Count - 1, fallbackEndLine + excessAtStart); + } + else if (excessAtEnd > 0) + { + // The fallback span extends after the relevant span (endLine) + startLine = Math.Max(0, fallbackStartLine - excessAtEnd); + } + else + { + // Fallback span surrounds the renamed identifier completely within startLine-endLine span. Use the fallback span as is. + startLine = fallbackStartLine; + endLine = fallbackEndLine; + } + lineCount = endLine - startLine + 1; + } + } + + // If a well defined surrounding span was not computed, + // select a span that encompasses NumberOfContextLines lines above and NumberOfContextLines lines below the identifier. + if (surroundingSpanOfInterest is null || lineCount <= 0) + { + startLine = Math.Max(0, documentText.Lines.GetLineFromPosition(fallbackSpan.Start).LineNumber - NumberOfContextLines); + endLine = Math.Min(documentText.Lines.Count - 1, documentText.Lines.GetLineFromPosition(fallbackSpan.End).LineNumber + NumberOfContextLines); + } + + // If the start and end positions are not at the beginning and end of the start and end lines respectively, + // expand to select the corresponding lines completely. + startPosition = documentText.Lines[startLine].Start; + endPosition = documentText.Lines[endLine].End; + var length = endPosition - startPosition; + + surroundingSpanOfInterest = new TextSpan(startPosition, length); + if (seen.Add(surroundingSpanOfInterest.Value)) + { + resultBuilder.Add((filePath, documentText.GetSubText(surroundingSpanOfInterest.Value).ToString())); + } + } + } } diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignatureTests.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignatureTests.cs index 1efd0baf65198..e53a26af4c59d 100644 --- a/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignatureTests.cs +++ b/src/EditorFeatures/CSharpTest/ChangeSignature/ChangeSignatureTests.cs @@ -63,7 +63,7 @@ static void M2(int x, int y, int z) { } await TestChangeSignatureViaCommandAsync( LanguageNames.CSharp, markup: markup, - updatedSignature: new[] { 1, 0 }, + updatedSignature: [1, 0], expectedUpdatedInvocationDocumentCode: expectedCode); } @@ -92,7 +92,7 @@ static void M() await TestChangeSignatureViaCommandAsync( LanguageNames.CSharp, markup: markup, - updatedSignature: new[] { 1, 0 }, + updatedSignature: [1, 0], expectedUpdatedInvocationDocumentCode: expectedCode); } diff --git a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs index 9176c5048ea32..2fbe62118fa0f 100644 --- a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs @@ -2857,7 +2857,7 @@ interface Bar } #endregion TaoRegion", testHost, - new[] { new CSharpParseOptions(LanguageVersion.CSharp8) }, + [new CSharpParseOptions(LanguageVersion.CSharp8)], Keyword("using"), Identifier("System"), Punctuation.Semicolon, @@ -5673,9 +5673,9 @@ public async Task TestXmlAttributeNameSpan1() using var workspace = CreateWorkspace(source, options: null, TestHost.InProcess); var document = workspace.CurrentSolution.Projects.First().Documents.First(); - var classifications = await GetSyntacticClassificationsAsync(document, ImmutableArray.Create(new TextSpan(0, source.Length))); - Assert.Equal(new[] - { + var classifications = await GetSyntacticClassificationsAsync(document, [new TextSpan(0, source.Length)]); + AssertEx.Equal( + [ new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentDelimiter, new TextSpan(0, 3)), new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentText, new TextSpan(3, 1)), new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentDelimiter, new TextSpan(4, 1)), @@ -5689,7 +5689,7 @@ public async Task TestXmlAttributeNameSpan1() new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentDelimiter, new TextSpan(24, 2)), new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentName, new TextSpan(26, 5)), new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentDelimiter, new TextSpan(31, 1)) - }, classifications); + ], classifications); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/48094")] @@ -5701,9 +5701,9 @@ public async Task TestXmlAttributeNameSpan2() using var workspace = CreateWorkspace(source, options: null, TestHost.InProcess); var document = workspace.CurrentSolution.Projects.First().Documents.First(); - var classifications = await GetSyntacticClassificationsAsync(document, ImmutableArray.Create(new TextSpan(0, source.Length))); - Assert.Equal(new[] - { + var classifications = await GetSyntacticClassificationsAsync(document, [new TextSpan(0, source.Length)]); + AssertEx.Equal( + [ new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentDelimiter, new TextSpan(2, 3)), new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentText, new TextSpan(5, 1)), new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentDelimiter, new TextSpan(6, 1)), @@ -5718,7 +5718,7 @@ public async Task TestXmlAttributeNameSpan2() new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentDelimiter, new TextSpan(31, 2)), new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentName, new TextSpan(33, 5)), new ClassifiedSpan(ClassificationTypeNames.XmlDocCommentDelimiter, new TextSpan(38, 1)) - }, classifications); + ], classifications); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/52290")] diff --git a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs index 63348914ce855..2870f25fa7870 100644 --- a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs @@ -3074,8 +3074,8 @@ void M() var actualFormatted = actualOrdered.Select(a => new FormattedClassification(allCode.Substring(a.Span.Span.Start, a.Span.Span.Length), a.Tag.ClassificationType.Classification)); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ Keyword("using"), Namespace("System"), Operators.Dot, @@ -3130,7 +3130,7 @@ void M() Punctuation.Semicolon, Punctuation.CloseCurly, Punctuation.CloseCurly, - }, actualFormatted); + ], actualFormatted); } [WpfFact] @@ -3175,8 +3175,8 @@ void M() var actualFormatted = actualOrdered.Select(a => new FormattedClassification(allCode.Substring(a.Span.Span.Start, a.Span.Span.Length), a.Tag.ClassificationType.Classification)); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ Keyword("using"), Namespace("System"), Operators.Dot, @@ -3231,6 +3231,6 @@ void M() Punctuation.Semicolon, Punctuation.CloseCurly, Punctuation.CloseCurly, - }, actualFormatted); + ], actualFormatted); } } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs index 032c2506eb394..b3260af748791 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/AddUsing/AddUsingTests.cs @@ -16,7 +16,7 @@ using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.AddUsing; @@ -2049,7 +2049,7 @@ public async Task TestWithReferenceDirective() { var resolver = new TestMetadataReferenceResolver(assemblyNames: new Dictionary() { - { "exprs", AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemCore).GetReference() } + { "exprs", AssemblyMetadata.CreateFromImage(Net461.Resources.SystemCore).GetReference() } }); await TestAsync( diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests.cs index 04d8bec81e4ea..669ac6f76c832 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests.cs @@ -4824,12 +4824,11 @@ static void Main(string[] args) "; await TestExactActionSetOfferedAsync(code, - new[] - { + [ string.Format(FeaturesResources.Generate_0_1_in_new_file, "class", "Goo"), string.Format(FeaturesResources.Generate_nested_0_1, "class", "Goo", "Program"), FeaturesResources.Generate_new_type - }); + ]); await TestInRegularAndScriptAsync(code, @" diff --git a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs index 5b16db8e75039..2da0b9dcaf527 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/GenerateType/GenerateTypeTests_Dialog.cs @@ -3012,7 +3012,7 @@ public class B accessibility: Accessibility.Public, typeKind: TypeKind.Class, isNewFile: false, -assertTypeKindAbsent: new[] { TypeKindOptions.Enum }); +assertTypeKindAbsent: [TypeKindOptions.Enum]); } [Fact] @@ -3049,7 +3049,7 @@ public class B accessibility: Accessibility.Public, typeKind: TypeKind.Class, isNewFile: false, -assertTypeKindAbsent: new[] { TypeKindOptions.Enum }); +assertTypeKindAbsent: [TypeKindOptions.Enum]); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/CodeActions/ImplementInterface/ImplementInterfaceTests_FixAllTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/ImplementInterface/ImplementInterfaceTests_FixAllTests.cs deleted file mode 100644 index 77ec85506e8e0..0000000000000 --- a/src/EditorFeatures/CSharpTest/CodeActions/ImplementInterface/ImplementInterfaceTests_FixAllTests.cs +++ /dev/null @@ -1,599 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Testing; -using Xunit; -using VerifyCS = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.CSharpCodeFixVerifier< - Microsoft.CodeAnalysis.Testing.EmptyDiagnosticAnalyzer, - Microsoft.CodeAnalysis.CSharp.ImplementInterface.CSharpImplementInterfaceCodeFixProvider>; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ImplementInterface; - -public class ImplementInterfaceTests_FixAllTests -{ - #region "Fix all occurrences tests" - - [Fact] - [Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] - [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] - public async Task TestFixAllInDocument() - { - await new VerifyCS.Test - { - TestState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C1 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - @"class B2 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C2 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - AdditionalProjects = - { - ["Assembly1"] = - { - Sources = - { - @"class B3 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C3 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - AdditionalProjectReferences = { "TestProject" }, - }, - }, - }, - FixedState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : I1, I2 -{ - public void F1() - { - throw new System.NotImplementedException(); - } - - class C1 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - @"class B2 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C2 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - MarkupHandling = MarkupMode.Allow, - }, - BatchFixedState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : I1, I2 -{ - public void F1() - { - throw new System.NotImplementedException(); - } - - class C1 : I1, I2 - { - public void F1() - { - throw new System.NotImplementedException(); - } - } -}", - @"class B2 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C2 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - MarkupHandling = MarkupMode.Allow, - }, - CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipFixAllInProjectCheck | CodeFixTestBehaviors.SkipFixAllInSolutionCheck, - CodeActionEquivalenceKey = "False;False;True:global::I1;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", - CodeActionIndex = 0, - }.RunAsync(); - } - - [Fact] - [Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] - [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] - public async Task TestFixAllInProject() - { - await new VerifyCS.Test - { - TestState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C1 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - @"class B2 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C2 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - AdditionalProjects = - { - ["Assembly1"] = - { - Sources = - { - @"class B3 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C3 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - AdditionalProjectReferences = { "TestProject" }, - }, - }, - }, - FixedState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : I1, I2 -{ - public void F1() - { - throw new System.NotImplementedException(); - } - - class C1 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - @"class B2 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C2 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - MarkupHandling = MarkupMode.Allow, - }, - BatchFixedState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : I1, I2 -{ - public void F1() - { - throw new System.NotImplementedException(); - } - - class C1 : I1, I2 - { - public void F1() - { - throw new System.NotImplementedException(); - } - } -}", - @"class B2 : I1, I2 -{ - public void F1() - { - throw new System.NotImplementedException(); - } - - class C2 : I1, I2 - { - public void F1() - { - throw new System.NotImplementedException(); - } - } -}", - }, - MarkupHandling = MarkupMode.Allow, - }, - CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipFixAllInDocumentCheck | CodeFixTestBehaviors.SkipFixAllInSolutionCheck, - CodeActionEquivalenceKey = "False;False;True:global::I1;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", - CodeActionIndex = 0, - }.RunAsync(); - } - - [Fact] - [Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] - [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] - public async Task TestFixAllInSolution() - { - await new VerifyCS.Test - { - TestState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C1 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - @"class B2 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C2 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - AdditionalProjects = - { - ["Assembly1"] = - { - Sources = - { - @"class B3 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C3 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - AdditionalProjectReferences = { "TestProject" }, - }, - }, - }, - FixedState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : {|CS0535:I1|}, I2 -{ - void I2.F1() - { - throw new System.NotImplementedException(); - } - - class C1 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - @"class B2 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C2 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - MarkupHandling = MarkupMode.Allow, - }, - BatchFixedState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : {|CS0535:I1|}, I2 -{ - void I2.F1() - { - throw new System.NotImplementedException(); - } - - class C1 : {|CS0535:I1|}, I2 - { - void I2.F1() - { - throw new System.NotImplementedException(); - } - } -}", - @"class B2 : {|CS0535:I1|}, I2 -{ - void I2.F1() - { - throw new System.NotImplementedException(); - } - - class C2 : {|CS0535:I1|}, I2 - { - void I2.F1() - { - throw new System.NotImplementedException(); - } - } -}", - }, - AdditionalProjects = - { - ["Assembly1"] = - { - Sources = - { - @"class B3 : {|CS0535:I1|}, I2 -{ - void I2.F1() - { - throw new System.NotImplementedException(); - } - - class C3 : {|CS0535:I1|}, I2 - { - void I2.F1() - { - throw new System.NotImplementedException(); - } - } -}", - }, - AdditionalProjectReferences = { "TestProject" }, - }, - }, - MarkupHandling = MarkupMode.Allow, - }, - CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipFixAllInDocumentCheck | CodeFixTestBehaviors.SkipFixAllInProjectCheck, - DiagnosticSelector = diagnostics => diagnostics[1], - CodeActionEquivalenceKey = "True;False;False:global::I2;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", - CodeActionIndex = 1, - }.RunAsync(); - } - - [Fact] - [Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] - [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] - public async Task TestFixAllInSolution_DifferentAssemblyWithSameTypeName() - { - await new VerifyCS.Test - { - TestState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C1 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - @"class B2 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C2 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - AdditionalProjects = - { - ["Assembly1"] = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B3 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C3 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - }, - }, - }, - FixedState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : {|CS0535:I1|}, I2 -{ - void I2.F1() - { - throw new System.NotImplementedException(); - } - - class C1 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - @"class B2 : {|CS0535:I1|}, {|CS0535:I2|} -{ - class C2 : {|CS0535:I1|}, {|CS0535:I2|} - { - } -}", - }, - MarkupHandling = MarkupMode.Allow, - }, - BatchFixedState = - { - Sources = - { - @"public interface I1 -{ - void F1(); -} - -public interface I2 -{ - void F1(); -} - -class B1 : {|CS0535:I1|}, I2 -{ - void I2.F1() - { - throw new System.NotImplementedException(); - } - - class C1 : {|CS0535:I1|}, I2 - { - void I2.F1() - { - throw new System.NotImplementedException(); - } - } -}", - @"class B2 : {|CS0535:I1|}, I2 -{ - void I2.F1() - { - throw new System.NotImplementedException(); - } - - class C2 : {|CS0535:I1|}, I2 - { - void I2.F1() - { - throw new System.NotImplementedException(); - } - } -}", - }, - MarkupHandling = MarkupMode.Allow, - }, - CodeFixTestBehaviors = CodeFixTestBehaviors.FixOne | CodeFixTestBehaviors.SkipFixAllInDocumentCheck | CodeFixTestBehaviors.SkipFixAllInProjectCheck, - DiagnosticSelector = diagnostics => diagnostics[1], - CodeActionEquivalenceKey = "True;False;False:global::I2;TestProject;Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction;", - CodeActionIndex = 1, - }.RunAsync(); - } - - #endregion -} diff --git a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.RenameFile.cs b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.RenameFile.cs index f33ea91fcc6cb..49dd16a8d1c70 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.RenameFile.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.RenameFile.cs @@ -72,7 +72,7 @@ class Inner { } var expectedDocumentName = "Class1.cs"; await TestRenameFileToMatchTypeAsync(code, expectedDocumentName, - destinationDocumentContainers: new[] { "A", "B" }); + destinationDocumentContainers: ["A", "B"]); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs index 6fdf8eac48fde..9ed96d8441b55 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs @@ -49,7 +49,7 @@ internal override CompletionService GetCompletionService(Project project) private protected override Task BaseVerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, - SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, + SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, char? deletedCharTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null, @@ -57,7 +57,7 @@ private protected override Task BaseVerifyWorkerAsync( { return base.VerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, - sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, + sourceCodeKind, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options, skipSpeculation: skipSpeculation); } @@ -65,23 +65,23 @@ private protected override Task BaseVerifyWorkerAsync( private protected override async Task VerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, - SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, + SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, char? deletedCharTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null, CompletionOptions options = null, bool skipSpeculation = false) { - await VerifyAtPositionAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags: null, options, skipSpeculation: skipSpeculation); - await VerifyInFrontOfCommentAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, options, skipSpeculation: skipSpeculation); - await VerifyAtEndOfFileAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags: null, options); + await VerifyAtPositionAsync(code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags: null, options, skipSpeculation: skipSpeculation); + await VerifyInFrontOfCommentAsync(code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, options, skipSpeculation: skipSpeculation); + await VerifyAtEndOfFileAsync(code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags: null, options); // Items cannot be partially written if we're checking for their absence, // or if we're verifying that the list will show up (without specifying an actual item) if (!checkForAbsence && expectedItemOrNull != null) { - await VerifyAtPosition_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags: null, options, skipSpeculation: skipSpeculation); - await VerifyInFrontOfComment_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, options, skipSpeculation: skipSpeculation); - await VerifyAtEndOfFile_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags: null, options); + await VerifyAtPosition_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags: null, options, skipSpeculation: skipSpeculation); + await VerifyInFrontOfComment_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, options, skipSpeculation: skipSpeculation); + await VerifyAtEndOfFile_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags: null, options); } } @@ -89,7 +89,7 @@ protected override string ItemPartiallyWritten(string expectedItemOrNull) => expectedItemOrNull[0] == '@' ? expectedItemOrNull.Substring(1, 1) : expectedItemOrNull[..1]; private async Task VerifyInFrontOfCommentAsync( - string code, int position, string insertText, bool usePreviousCharAsTrigger, + string code, int position, string insertText, bool usePreviousCharAsTrigger, char? deletedCharTrigger, string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, @@ -101,14 +101,14 @@ private async Task VerifyInFrontOfCommentAsync( await base.VerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, - sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, + sourceCodeKind, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags: null, options, skipSpeculation: skipSpeculation); } private async Task VerifyInFrontOfCommentAsync( - string code, int position, bool usePreviousCharAsTrigger, + string code, int position, bool usePreviousCharAsTrigger, char? deletedCharTrigger, string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, @@ -116,14 +116,14 @@ private async Task VerifyInFrontOfCommentAsync( List matchingFilters, CompletionOptions options, bool skipSpeculation = false) { await VerifyInFrontOfCommentAsync( - code, position, string.Empty, usePreviousCharAsTrigger, + code, position, string.Empty, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, options, skipSpeculation: skipSpeculation); } private protected async Task VerifyInFrontOfComment_ItemPartiallyWrittenAsync( - string code, int position, bool usePreviousCharAsTrigger, + string code, int position, bool usePreviousCharAsTrigger, char? deletedCharTrigger, string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, @@ -131,7 +131,7 @@ private protected async Task VerifyInFrontOfComment_ItemPartiallyWrittenAsync( List matchingFilters, CompletionOptions options, bool skipSpeculation = false) { await VerifyInFrontOfCommentAsync( - code, position, ItemPartiallyWritten(expectedItemOrNull), usePreviousCharAsTrigger, + code, position, ItemPartiallyWritten(expectedItemOrNull), usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, options, skipSpeculation: skipSpeculation); diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs index 73edf31fa1600..b320d23d02b88 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs @@ -28,19 +28,19 @@ internal override Type GetCompletionProviderType() => typeof(CrefCompletionProvider); private protected override async Task VerifyWorkerAsync(string code, int position, string expectedItemOrNull, - string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, + string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, char? deletedCharTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string? inlineDescription = null, bool? isComplexTextEdit = null, List? matchingFilters = null, CompletionItemFlags? flags = null, CompletionOptions? options = null, bool skipSpeculation = false) { await VerifyAtPositionAsync( - code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, + code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); await VerifyAtEndOfFileAsync( - code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, + code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); @@ -49,12 +49,12 @@ await VerifyAtEndOfFileAsync( if (!checkForAbsence && expectedItemOrNull != null) { await VerifyAtPosition_ItemPartiallyWrittenAsync( - code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, + code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags: null, options); await VerifyAtEndOfFile_ItemPartiallyWrittenAsync( - code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, + code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags: null, options); } @@ -441,7 +441,7 @@ class C { } """; - using var workspace = EditorTestWorkspace.Create(LanguageNames.CSharp, new CSharpCompilationOptions(OutputKind.ConsoleApplication), new CSharpParseOptions(), new[] { text }, composition: GetComposition()); + using var workspace = EditorTestWorkspace.Create(LanguageNames.CSharp, new CSharpCompilationOptions(OutputKind.ConsoleApplication), new CSharpParseOptions(), [text], composition: GetComposition()); var called = false; var hostDocument = workspace.DocumentWithCursor; diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs index 6a59b3af516b2..2c1975a5dbd0c 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs @@ -1170,7 +1170,7 @@ public class MyClass """; var items = await GetCompletionItemsAsync(markup, SourceCodeKind.Regular); Assert.Equal( - new[] { "myClass", "my", "@class", "MyClass", "My", "Class", "GetMyClass", "GetMy", "GetClass" }, + ["myClass", "my", "@class", "MyClass", "My", "Class", "GetMyClass", "GetMy", "GetClass"], items.Select(item => item.DisplayText)); } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs index ab29766f3d714..b02222b6148ee 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs @@ -30,14 +30,14 @@ protected override IEqualityComparer GetStringComparer() private protected override Task VerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, - SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, + SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, char? deletedCharTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null, CompletionOptions options = null, bool skipSpeculation = false) { return BaseVerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, - sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, + sourceCodeKind, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs index 6703e64824f1d..f5cad13cf7700 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs @@ -833,8 +833,8 @@ public class SomeClass : Base }"; MarkupTestFile.GetPosition(markup, out var code, out int position); - await BaseVerifyWorkerAsync(code, position, "@class()", "void Base.@class()", SourceCodeKind.Regular, false, false, null, null, null, null, null, null); - await BaseVerifyWorkerAsync(code, position, "@class()", "void Base.@class()", SourceCodeKind.Script, false, false, null, null, null, null, null, null); + await BaseVerifyWorkerAsync(code, position, "@class()", "void Base.@class()", SourceCodeKind.Regular, false, deletedCharTrigger: null, false, null, null, null, null, null, null); + await BaseVerifyWorkerAsync(code, position, "@class()", "void Base.@class()", SourceCodeKind.Script, false, deletedCharTrigger: null, false, null, null, null, null, null, null); } [WpfFact] @@ -851,8 +851,8 @@ public class SomeClass : Base }"; MarkupTestFile.GetPosition(markup, out var code, out int position); - await BaseVerifyWorkerAsync(code, position, "@class", "int Base.@class { get; set; }", SourceCodeKind.Regular, false, false, null, null, null, null, null, null); - await BaseVerifyWorkerAsync(code, position, "@class", "int Base.@class { get; set; }", SourceCodeKind.Script, false, false, null, null, null, null, null, null); + await BaseVerifyWorkerAsync(code, position, "@class", "int Base.@class { get; set; }", SourceCodeKind.Regular, false, deletedCharTrigger: null, false, null, null, null, null, null, null); + await BaseVerifyWorkerAsync(code, position, "@class", "int Base.@class { get; set; }", SourceCodeKind.Script, false, deletedCharTrigger: null, false, null, null, null, null, null, null); } [WpfFact] @@ -3055,7 +3055,7 @@ static void Main(string[] args) override $$ } }"; - using var workspace = EditorTestWorkspace.Create(LanguageNames.CSharp, new CSharpCompilationOptions(OutputKind.ConsoleApplication), new CSharpParseOptions(), new[] { text }, composition: GetComposition()); + using var workspace = EditorTestWorkspace.Create(LanguageNames.CSharp, new CSharpCompilationOptions(OutputKind.ConsoleApplication), new CSharpParseOptions(), [text], composition: GetComposition()); var provider = new OverrideCompletionProvider(); var testDocument = workspace.Documents.Single(); var document = workspace.CurrentSolution.GetRequiredDocument(testDocument.Id); diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs index bb4a486755566..6a451c6f6339e 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs @@ -33,14 +33,14 @@ protected override IEqualityComparer GetStringComparer() private protected override Task VerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, - SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, + SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, char? deletedCharTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null, CompletionOptions options = null, bool skipSpeculation = false) { return BaseVerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, - sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, + sourceCodeKind, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); } @@ -48,7 +48,7 @@ private protected override Task VerifyWorkerAsync( [Fact] public async Task IsCommitCharacterTest() { - var commitCharacters = PathUtilities.IsUnixLikePlatform ? new[] { '"', '/' } : new[] { '"', '\\', '/', ',' }; + var commitCharacters = PathUtilities.IsUnixLikePlatform ? new[] { '"', '/' } : ['"', '\\', '/', ',']; await VerifyCommitCharactersAsync("#r \"$$", textTypedSoFar: "", validChars: commitCharacters, sourceCodeKind: SourceCodeKind.Script); } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SemanticSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SemanticSnippetCompletionProviderTests.cs new file mode 100644 index 0000000000000..83eb82f956ba1 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SemanticSnippetCompletionProviderTests.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Completion.CompletionProviders.Snippets; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders; + +[Trait(Traits.Feature, Traits.Features.Completion)] +public sealed class SemanticSnippetCompletionProviderTests : AbstractCSharpCompletionProviderTests +{ + public SemanticSnippetCompletionProviderTests() + { + ShowNewSnippetExperience = true; + } + + internal override Type GetCompletionProviderType() + => typeof(CSharpSnippetCompletionProvider); + + [WpfFact] + public async Task InsertConsoleSnippetWithInvocationBeforeAndAfterCursorTest() + { + var markupBeforeCommit = """ + class Program + { + public void Method() + { + Wr$$Blah + } + } + """; + + var expectedCodeAfterCommit = """ + using System; + + class Program + { + public void Method() + { + Console.WriteLine($$); + } + } + """; + + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "cw", expectedCodeAfterCommit); + } + + [WpfFact] + public async Task InsertConsoleSnippetWithInvocationUnderscoreBeforeAndAfterCursorTest() + { + var markupBeforeCommit = + """ + class Program + { + public void Method() + { + _Wr$$Blah_ + } + } + """; + + var expectedCodeAfterCommit = + """ + using System; + + class Program + { + public void Method() + { + Console.WriteLine($$); + } + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "cw", expectedCodeAfterCommit); + } +} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpAutoPropertyCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpAutoPropertyCompletionProviderTests.cs deleted file mode 100644 index 9d689789446a6..0000000000000 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpAutoPropertyCompletionProviderTests.cs +++ /dev/null @@ -1,172 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Testing; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; - -public abstract class AbstractCSharpAutoPropertyCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests -{ - protected abstract string GetDefaultPropertyBlockText(); - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task MissingInNamespace() - { - await VerifyPropertyAbsenceAsync(""" - namespace Namespace - { - $$ - } - """); - } - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task MissingInFilescopedNamespace() - { - await VerifyPropertyAbsenceAsync(""" - namespace Namespace; - - $$ - """); - } - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task MissingInTopLevelContext() - { - await VerifyPropertyAbsenceAsync(""" - System.Console.WriteLine(); - $$ - """); - } - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task InsertSnippetInClass() - { - await VerifyDefaultPropertyAsync(""" - class MyClass - { - $$ - } - """); - } - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task InsertSnippetInRecord() - { - await VerifyDefaultPropertyAsync(""" - record MyRecord - { - $$ - } - """); - } - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task InsertSnippetInStruct() - { - await VerifyDefaultPropertyAsync(""" - struct MyStruct - { - $$ - } - """); - } - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public abstract Task InsertSnippetInReadonlyStruct(); - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public abstract Task InsertSnippetInReadonlyStruct_ReadonlyModifierInOtherPartialDeclaration(); - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public abstract Task InsertSnippetInReadonlyStruct_ReadonlyModifierInOtherPartialDeclaration_MissingPartialModifier(); - - // This case might produce non-default results for different snippets (e.g. no `set` accessor in 'propg' snippet), - // so it is tested separately for all of them - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public abstract Task InsertSnippetInInterface(); - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task InsertSnippetNaming() - { - await VerifyDefaultPropertyAsync(""" - class MyClass - { - public int MyProperty { get; set; } - $$ - } - """, "MyProperty1"); - } - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task MissingInEnum() - { - await VerifyPropertyAbsenceAsync(""" - enum MyEnum - { - $$ - } - """); - } - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task MissingInMethod() - { - await VerifyPropertyAbsenceAsync(""" - class Program - { - public void Method() - { - $$ - } - } - """); - } - - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task MissingInConstructor() - { - await VerifyPropertyAbsenceAsync(""" - class Program - { - public Program() - { - $$ - } - } - """); - } - - [WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task AfterAccessibilityModifier(string modifier) - { - await VerifyPropertyAsync($$""" - class Program - { - {{modifier}} $$ - } - """, $"int MyProperty {GetDefaultPropertyBlockText()}"); - } - - private Task VerifyPropertyAbsenceAsync(string markup) => VerifyItemIsAbsentAsync(markup, ItemToCommit); - - protected async Task VerifyPropertyAsync(string markup, string propertyText) - { - TestFileMarkupParser.GetPosition(markup, out var code, out var position); - var expectedCode = code.Insert(position, propertyText + "$$"); - await VerifyCustomCommitProviderAsync(markup, ItemToCommit, expectedCode); - } - - protected Task VerifyDefaultPropertyAsync(string markup, string propertyName = "MyProperty") - => VerifyPropertyAsync(markup, $"public int {propertyName} {GetDefaultPropertyBlockText()}"); -} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpSnippetCompletionProviderTests.cs deleted file mode 100644 index 64fe0106bb973..0000000000000 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpSnippetCompletionProviderTests.cs +++ /dev/null @@ -1,21 +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.CSharp.Completion.CompletionProviders.Snippets; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; - -public abstract class AbstractCSharpSnippetCompletionProviderTests : AbstractCSharpCompletionProviderTests -{ - protected abstract string ItemToCommit { get; } - - protected AbstractCSharpSnippetCompletionProviderTests() - { - ShowNewSnippetExperience = true; - } - - internal override Type GetCompletionProviderType() - => typeof(CSharpSnippetCompletionProvider); -} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpClassSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpClassSnippetCompletionProviderTests.cs deleted file mode 100644 index 4af897017458a..0000000000000 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpClassSnippetCompletionProviderTests.cs +++ /dev/null @@ -1,547 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; - -[Trait(Traits.Feature, Traits.Features.Completion)] -public class CSharpClassSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests -{ - protected override string ItemToCommit => "class"; - - [WpfFact] - public async Task InsertClassSnippetInNamespaceTest() - { - var markupBeforeCommit = - """ - namespace Namespace - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - namespace Namespace - { - class MyClass - { - $$ - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertClassSnippetInFileScopedNamespaceTest() - { - var markupBeforeCommit = - """ - namespace Namespace; - - $$ - """; - - var expectedCodeAfterCommit = - """ - namespace Namespace; - - class MyClass - { - $$ - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertClassSnippetTest() - { - var markupBeforeCommit = -@"$$"; - - var expectedCodeAfterCommit = - """ - class MyClass - { - $$ - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertClassTopLevelSnippetTest() - { - var markupBeforeCommit = - """ - System.Console.WriteLine(); - $$ - """; - - var expectedCodeAfterCommit = - """ - System.Console.WriteLine(); - class MyClass - { - $$ - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertClassSnippetInClassTest() - { - var markupBeforeCommit = - """ - class MyClass - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - class MyClass - { - class MyClass1 - { - $$ - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertClassSnippetInRecordTest() - { - var markupBeforeCommit = - """ - record MyRecord - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - record MyRecord - { - class MyClass - { - $$ - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertClassSnippetInStructTest() - { - var markupBeforeCommit = - """ - struct MyStruct - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - struct MyStruct - { - class MyClass - { - $$ - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertClassSnippetInInterfaceTest() - { - var markupBeforeCommit = - """ - interface MyInterface - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - interface MyInterface - { - class MyClass - { - $$ - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertClassSnippetWithModifiersTest() - { - var markupBeforeCommit = - $@" - - - -$$ - - -root = true - -[*] -# IDE0008: Use explicit type -dotnet_style_require_accessibility_modifiers = always - - -"; - var expectedCodeAfterCommit = - $@" -public class MyClass -{{ - $$ -}} -"; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task NoClassSnippetInEnumTest() - { - var markupBeforeCommit = - """ - enum MyEnum - { - $$ - } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoClassSnippetInMethodTest() - { - var markupBeforeCommit = - """ - class Program - { - public void Method() - { - $$ - } - } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoClassSnippetInConstructorTest() - { - var markupBeforeCommit = - """ - class Program - { - public Program() - { - $$ - } - } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task AfterAccessibilityModifier(string modifier) - { - var markupBeforeCommit = $"{modifier} $$"; - - var expectedCodeAfterCommit = $$""" - {{modifier}} class MyClass - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task AfterAccessibilityModifier_RequireAccessibilityModifiers(string modifier) - { - var markupBeforeCommit = $$""" - - - {{modifier}} $$ - - root = true - - [*] - # IDE0008: Use explicit type - dotnet_style_require_accessibility_modifiers = always - - - - """; - - var expectedCodeAfterCommit = $$""" - {{modifier}} class MyClass - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("abstract")] - [InlineData("sealed")] - [InlineData("static")] - [InlineData("unsafe")] - public async Task InsertClassSnippetAfterValidModifiersTest(string modifier) - { - var markupBeforeCommit = $"{modifier} $$"; - - var expectedCodeAfterCommit = $$""" - {{modifier}} class MyClass - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("ref")] - [InlineData("readonly")] - public async Task NoClassSnippetAfterInvalidModifiersTest(string modifier) - { - var markupBeforeCommit = $"{modifier} $$"; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task NoAdditionalAccessibilityModifiersIfAfterPartialKeywordTest(string modifier) - { - var markupBeforeCommit = $$""" - - - {{modifier}} partial $$ - - root = true - - [*] - # IDE0008: Use explicit type - dotnet_style_require_accessibility_modifiers = always - - - - """; - - var expectedCodeAfterCommit = $$""" - {{modifier}} partial class MyClass - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] - public async Task EnsureCorrectModifierOrderAfterPartialKeywordTest() - { - var markupBeforeCommit = """ - - - partial $$ - - root = true - - [*] - # IDE0008: Use explicit type - dotnet_style_require_accessibility_modifiers = always - - - - """; - - var expectedCodeAfterCommit = """ - public partial class MyClass - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] - public async Task EnsureCorrectModifierOrderAfterPartialKeywordTest_InvalidPreferredModifiersList() - { - var markupBeforeCommit = """ - - - partial $$ - - [*] - dotnet_style_require_accessibility_modifiers = always - - csharp_preferred_modifier_order = invalid! - - - - """; - - var expectedCodeAfterCommit = """ - public partial class MyClass - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBeforeAllOthers() - { - var markupBeforeCommit = """ - - - sealed unsafe $$ - - [*] - dotnet_style_require_accessibility_modifiers = always - - csharp_preferred_modifier_order = public,sealed,unsafe - - - - """; - - var expectedCodeAfterCommit = """ - public sealed unsafe class MyClass - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBeforeAllOthers_NotAllModifiersInTheList() - { - var markupBeforeCommit = """ - - - sealed unsafe $$ - - [*] - dotnet_style_require_accessibility_modifiers = always - - csharp_preferred_modifier_order = public,sealed - - - - """; - - var expectedCodeAfterCommit = """ - public sealed unsafe class MyClass - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBetweenOthers() - { - var markupBeforeCommit = """ - - - sealed unsafe $$ - - [*] - dotnet_style_require_accessibility_modifiers = always - - csharp_preferred_modifier_order = sealed,public,unsafe - - - - """; - - var expectedCodeAfterCommit = """ - sealed public unsafe class MyClass - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierAfterAllOthers() - { - var markupBeforeCommit = """ - - - sealed unsafe $$ - - [*] - dotnet_style_require_accessibility_modifiers = always - - csharp_preferred_modifier_order = sealed,unsafe,public - - - - """; - - var expectedCodeAfterCommit = """ - sealed unsafe public class MyClass - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } -} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpConsoleSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpConsoleSnippetCompletionProviderTests.cs deleted file mode 100644 index 43a98dac711ff..0000000000000 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpConsoleSnippetCompletionProviderTests.cs +++ /dev/null @@ -1,584 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; - -[Trait(Traits.Feature, Traits.Features.Completion)] -public class CSharpConsoleSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests -{ - protected override string ItemToCommit => "cw"; - - [WpfFact] - public async Task InsertConsoleSnippetInMethodTest() - { - var markupBeforeCommit = - """ - class Program - { - public void Method() - { - Wr$$ - } - } - """; - - var expectedCodeAfterCommit = - """ - using System; - - class Program - { - public void Method() - { - Console.WriteLine($$); - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertNormalConsoleSnippetInAsyncContextTest() - { - var markupBeforeCommit = - """ - class Program - { - public async Task MethodAsync() - { - Wr$$ - } - } - """; - - var expectedCodeAfterCommit = - """ - using System; - - class Program - { - public async Task MethodAsync() - { - Console.WriteLine($$); - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertConsoleSnippetGlobalTest() - { - var markupBeforeCommit = - """ - $$ - class Program - { - public async Task MethodAsync() - { - } - } - """; - - var expectedCodeAfterCommit = - """ - using System; - - Console.WriteLine($$); - class Program - { - public async Task MethodAsync() - { - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task NoConsoleSnippetInBlockNamespaceTest() - { - var markupBeforeCommit = - """ - namespace Namespace - { - $$ - class Program - { - public async Task MethodAsync() - { - } - } - } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoConsoleSnippetInFileScopedNamespaceTest() - { - var markupBeforeCommit = - """ - namespace Namespace; - $$ - class Program - { - public async Task MethodAsync() - { - } - } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task InsertConsoleSnippetInConstructorTest() - { - var markupBeforeCommit = - """ - class Program - { - public Program() - { - var x = 5; - $$ - } - } - """; - - var expectedCodeAfterCommit = - """ - using System; - - class Program - { - public Program() - { - var x = 5; - Console.WriteLine($$); - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertConsoleSnippetInLocalFunctionTest() - { - var markupBeforeCommit = - """ - class Program - { - public void Method() - { - var x = 5; - void LocalMethod() - { - $$ - } - } - } - """; - - var expectedCodeAfterCommit = - """ - using System; - - class Program - { - public void Method() - { - var x = 5; - void LocalMethod() - { - Console.WriteLine($$); - } - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertConsoleSnippetInAnonymousFunctionTest() - { - var markupBeforeCommit = - """ - public delegate void Print(int value); - - static void Main(string[] args) - { - Print print = delegate(int val) { - $$ - }; - - } - """; - - var expectedCodeAfterCommit = - """ - using System; - - public delegate void Print(int value); - - static void Main(string[] args) - { - Print print = delegate(int val) { - Console.WriteLine($$); - }; - - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertConsoleSnippetInParenthesizedLambdaExpressionTest() - { - var markupBeforeCommit = - """ - Func testForEquality = (x, y) => - { - $$ - return x == y; - }; - """; - - var expectedCodeAfterCommit = - """ - using System; - - Func testForEquality = (x, y) => - { - Console.WriteLine($$); - return x == y; - }; - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task NoConsoleSnippetInSwitchExpression() - { - var markupBeforeCommit = - """ - class Program - { - public void Method() - { - var operation = 2; - - var result = operation switch - { - $$ - 1 => "Case 1", - 2 => "Case 2", - 3 => "Case 3", - 4 => "Case 4", - }; - } - } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoConsoleSnippetInSingleLambdaExpression() - { - var markupBeforeCommit = - """ - class Program - { - public void Method() - { - Func f = x => $$; - } - } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoConsoleSnippetInStringTest() - { - var markupBeforeCommit = - """ - class Program - { - public void Method() - { - var str = "$$"; - } - } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoConsoleSnippetInObjectInitializerTest() - { - var markupBeforeCommit = - """ - class Program - { - public void Method() - { - var str = new Test($$); - } - } - - class Test - { - private string val; - - public Test(string val) - { - this.val = val; - } - } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoConsoleSnippetInParameterListTest() - { - var markupBeforeCommit = - """ - class Program - { - public void Method(int x, $$) - { - } - } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoConsoleSnippetInRecordDeclarationTest() - { - var markupBeforeCommit = - """ - public record Person - { - $$ - public string FirstName { get; init; } = default!; - public string LastName { get; init; } = default!; - }; - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoConsoleSnippetInVariableDeclarationTest() - { - var markupBeforeCommit = - """ - class Program - { - public void Method() - { - var x = $$ - } - } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task InsertConsoleSnippetWithInvocationBeforeAndAfterCursorTest() - { - var markupBeforeCommit = - """ - class Program - { - public void Method() - { - Wr$$Blah - } - } - """; - - var expectedCodeAfterCommit = - """ - using System; - - class Program - { - public void Method() - { - Console.WriteLine($$); - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertConsoleSnippetWithInvocationUnderscoreBeforeAndAfterCursorTest() - { - var markupBeforeCommit = - """ - class Program - { - public void Method() - { - _Wr$$Blah_ - } - } - """; - - var expectedCodeAfterCommit = - """ - using System; - - class Program - { - public void Method() - { - Console.WriteLine($$); - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - /// - /// We want to fix this case and insert the fully qualified namespace - /// in a future fix. - /// - [WpfFact] - public async Task InsertConsoleSnippetWithPropertyNamedConsoleTest() - { - var markupBeforeCommit = - """ - class Program - { - public int Console { get; set; } - - public void Method() - { - $$ - } - } - """; - - var expectedCodeAfterCommit = - """ - using System; - - class Program - { - public int Console { get; set; } - - public void Method() - { - Console.WriteLine($$); - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/72266")] - public async Task InsertConsoleSnippetInVoidReturningLambdaTest1() - { - var markupBeforeCommit = """ - using System; - - M(() => $$); - - void M(Action a) - { - } - """; - - var expectedCodeAfterCommit = """ - using System; - - M(() => Console.WriteLine($$)); - - void M(Action a) - { - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/72266")] - public async Task InsertConsoleSnippetInVoidReturningLambdaTest2() - { - var markupBeforeCommit = """ - using System; - - Action action = () => $$ - """; - - var expectedCodeAfterCommit = """ - using System; - - Action action = () => Console.WriteLine($$) - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/72266")] - public async Task InsertConsoleSnippetInVoidReturningLambdaTest_TypeInference() - { - var markupBeforeCommit = """ - using System; - - var action = () => $$ - """; - - var expectedCodeAfterCommit = """ - using System; - - var action = () => Console.WriteLine($$) - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/72266")] - public async Task NoConsoleSnippetInNonVoidReturningLambdaTest1() - { - var markupBeforeCommit = """ - using System; - - M(() => $$); - - void M(Func f) - { - } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/72266")] - public async Task NoConsoleSnippetInNonVoidReturningLambdaTest2() - { - var markupBeforeCommit = """ - using System; - - Func f = () => $$ - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } -} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpEnumSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpEnumSnippetCompletionProviderTests.cs deleted file mode 100644 index 98e1635773035..0000000000000 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpEnumSnippetCompletionProviderTests.cs +++ /dev/null @@ -1,285 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading.Tasks; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; - -public class CSharpEnumSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests -{ - protected override string ItemToCommit => "enum"; - - [WpfFact] - public async Task InsertEnumSnippetInNamespaceTest() - { - await VerifyCustomCommitProviderAsync(""" - namespace Namespace - { - $$ - } - """, ItemToCommit, """ - namespace Namespace - { - enum MyEnum - { - $$ - } - } - """); - } - - [WpfFact] - public async Task InsertEnumSnippetInFileScopedNamespaceTest() - { - await VerifyCustomCommitProviderAsync(""" - namespace Namespace; - - $$ - """, ItemToCommit, """ - namespace Namespace; - - enum MyEnum - { - $$ - } - """); - } - - [WpfFact] - public async Task InsertEnumSnippetTest() - { - await VerifyCustomCommitProviderAsync(""" - $$ - """, ItemToCommit, """ - enum MyEnum - { - $$ - } - """); - } - - [WpfFact] - public async Task InsertEnumTopLevelSnippetTest() - { - await VerifyCustomCommitProviderAsync(""" - System.Console.WriteLine(); - $$ - """, ItemToCommit, """ - System.Console.WriteLine(); - enum MyEnum - { - $$ - } - """); - } - - [WpfFact] - public async Task InsertEnumSnippetInClassTest() - { - await VerifyCustomCommitProviderAsync(""" - class MyClass - { - $$ - } - """, ItemToCommit, """ - class MyClass - { - enum MyEnum - { - $$ - } - } - """); - } - - [WpfFact] - public async Task InsertEnumSnippetInRecordTest() - { - await VerifyCustomCommitProviderAsync(""" - record MyRecord - { - $$ - } - """, ItemToCommit, """ - record MyRecord - { - enum MyEnum - { - $$ - } - } - """); - } - - [WpfFact] - public async Task InsertEnumSnippetInStructTest() - { - await VerifyCustomCommitProviderAsync(""" - struct MyStruct - { - $$ - } - """, ItemToCommit, """ - struct MyStruct - { - enum MyEnum - { - $$ - } - } - """); - } - - [WpfFact] - public async Task InsertEnumSnippetInInterfaceTest() - { - await VerifyCustomCommitProviderAsync(""" - interface MyInterface - { - $$ - } - """, ItemToCommit, """ - interface MyInterface - { - enum MyEnum - { - $$ - } - } - """); - } - - [WpfFact] - public async Task InsertEnumSnippetWithModifiersTest() - { - await VerifyCustomCommitProviderAsync(""" - - - $$ - - root = true - - [*] - # IDE0008: Use explicit type - dotnet_style_require_accessibility_modifiers = always - - - - """, ItemToCommit, """ - public enum MyEnum - { - $$ - } - """); - } - - [WpfFact] - public async Task NoEnumSnippetInEnumTest() - { - await VerifyItemIsAbsentAsync(""" - enum MyEnum - { - $$ - } - """, ItemToCommit); - } - - [WpfFact] - public async Task NoEnumSnippetInMethodTest() - { - await VerifyItemIsAbsentAsync(""" - class Program - { - public void Method() - { - $$ - } - } - """, ItemToCommit); - } - - [WpfFact] - public async Task NoEnumSnippetInConstructorTest() - { - await VerifyItemIsAbsentAsync(""" - class Program - { - public Program() - { - $$ - } - } - """, ItemToCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task AfterAccessibilityModifier(string modifier) - { - var markupBeforeCommit = $"{modifier} $$"; - - var expectedCodeAfterCommit = $$""" - {{modifier}} enum MyEnum - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task AfterAccessibilityModifier_RequireAccessibilityModifiers(string modifier) - { - var markupBeforeCommit = $$""" - - - {{modifier}} $$ - - root = true - - [*] - # IDE0008: Use explicit type - dotnet_style_require_accessibility_modifiers = always - - - - """; - - var expectedCodeAfterCommit = $$""" - {{modifier}} enum MyEnum - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("abstract")] - [InlineData("partial")] - [InlineData("sealed")] - [InlineData("static")] - [InlineData("ref")] - [InlineData("readonly")] - [InlineData("unsafe")] - public async Task NoEnumSnippetAfterInvalidModifiersTest(string modifier) - { - var markupBeforeCommit = $"{modifier} $$"; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } -} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpForSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpForSnippetCompletionProviderTests.cs deleted file mode 100644 index e8a806a99f557..0000000000000 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpForSnippetCompletionProviderTests.cs +++ /dev/null @@ -1,1281 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; - -[Trait(Traits.Feature, Traits.Features.Completion)] -public class CSharpForSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests -{ - protected override string ItemToCommit => "for"; - - [WpfFact] - public async Task InsertForSnippetInMethodTest() - { - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - $$ - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - for (int i = 0; i < length; i++) - { - $$ - } - } - } - """); - } - - [WpfFact] - public async Task InsertForSnippetInMethodUsedIncrementorTest() - { - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - int i; - $$ - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - int i; - for (int j = 0; j < length; j++) - { - $$ - } - } - } - """); - } - - [WpfFact] - public async Task InsertForSnippetInMethodUsedIncrementorsTest() - { - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - int i, j, k; - $$ - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - int i, j, k; - for (int i1 = 0; i1 < length; i1++) - { - $$ - } - } - } - """); - } - - [WpfFact] - public async Task InsertForSnippetInGlobalContextTest() - { - await VerifyCustomCommitProviderAsync(""" - $$ - """, ItemToCommit, """ - for (int i = 0; i < length; i++) - { - $$ - } - """); - } - - [WpfFact] - public async Task InsertForSnippetInConstructorTest() - { - await VerifyCustomCommitProviderAsync(""" - class Program - { - public Program() - { - $$ - } - } - """, ItemToCommit, """ - class Program - { - public Program() - { - for (int i = 0; i < length; i++) - { - $$ - } - } - } - """); - } - - [WpfFact] - public async Task InsertForSnippetInLocalFunctionTest() - { - // TODO: fix this test when bug with simplifier failing to find correct node is fixed - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - void LocalFunction() - { - $$ - } - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - void LocalFunction() - { - for (global::System.Int32 i = 0; i < length; i++) - { - $$ - } - } - } - } - """); - } - - [WpfFact] - public async Task InsertForSnippetInAnonymousFunctionTest() - { - // TODO: fix this test when bug with simplifier failing to find correct node is fixed - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - var action = delegate() - { - $$ - }; - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - var action = delegate() - { - for (global::System.Int32 i = 0; i < length; i++) - { - $$ - } - }; - } - } - """); - } - - [WpfFact] - public async Task InsertForSnippetInParenthesizedLambdaExpressionTest() - { - // TODO: fix this test when bug with simplifier failing to find correct node is fixed - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - var action = () => - { - $$ - }; - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - var action = () => - { - for (global::System.Int32 i = 0; i < length; i++) - { - $$ - } - }; - } - } - """); - } - - [WpfFact] - public async Task ProduceVarWithSpecificCodeStyleTest() - { - await VerifyCustomCommitProviderAsync(""" - - - class Program - { - public void Method() - { - $$ - } - } - - root = true - - [*] - # IDE0008: Use explicit type - csharp_style_var_for_built_in_types = true - - - - """, ItemToCommit, """ - class Program - { - public void Method() - { - for (var i = 0; i < length; i++) - { - $$ - } - } - } - """); - } - - [WpfTheory] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForSnippetInMethodTest(string inlineExpressionType) - { - await VerifyCustomCommitProviderAsync($$""" - class Program - { - public void Method({{inlineExpressionType}} l) - { - l.$$ - } - } - """, ItemToCommit, $$""" - class Program - { - public void Method({{inlineExpressionType}} l) - { - for ({{inlineExpressionType}} i = 0; i < l; i++) - { - $$ - } - } - } - """); - } - - [WpfTheory] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForSnippetInGlobalContextTest(string inlineExpressionType) - { - await VerifyCustomCommitProviderAsync($$""" - {{inlineExpressionType}} l; - l.$$ - """, ItemToCommit, $$""" - {{inlineExpressionType}} l; - for ({{inlineExpressionType}} i = 0; i < l; i++) - { - $$ - } - """); - } - - [WpfTheory] - [MemberData(nameof(NotIntegerTypes))] - public async Task NoInlineForSnippetForIncorrectTypeInMethodTest(string inlineExpressionType) - { - var markup = $$""" - class Program - { - public void Method({{inlineExpressionType}} l) - { - l.$$ - } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [MemberData(nameof(NotIntegerTypes))] - public async Task NoInlineForSnippetForIncorrectTypeInGlobalContextTest(string inlineExpressionType) - { - var markup = $$""" - {{inlineExpressionType}} l; - l.$$ - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfFact] - public async Task ProduceVarWithSpecificCodeStyleForInlineSnippetTest() - { - await VerifyCustomCommitProviderAsync(""" - - - class Program - { - public void Method(int l) - { - l.$$ - } - } - - root = true - - [*] - # IDE0008: Use explicit type - csharp_style_var_for_built_in_types = true - - - - """, ItemToCommit, """ - class Program - { - public void Method(int l) - { - for (var i = 0; i < l; i++) - { - $$ - } - } - } - """); - } - - [WpfFact] - public async Task NoInlineForSnippetNotDirectlyExpressionStatementTest() - { - var markup = """ - class Program - { - public void Method(int l) - { - System.Console.WriteLine(l.$$); - } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("// comment")] - [InlineData("/* comment */")] - [InlineData("#region test")] - public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest1(string trivia) - { - var markupBeforeCommit = $$""" - class Program - { - void M(int len) - { - {{trivia}} - len.$$ - } - } - """; - - var expectedCodeAfterCommit = $$""" - class Program - { - void M(int len) - { - {{trivia}} - for (int i = 0; i < len; i++) - { - $$ - } - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("#if true")] - [InlineData("#pragma warning disable CS0108")] - [InlineData("#nullable enable")] - public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest2(string trivia) - { - var markupBeforeCommit = $$""" - class Program - { - void M(int len) - { - {{trivia}} - len.$$ - } - } - """; - - var expectedCodeAfterCommit = $$""" - class Program - { - void M(int len) - { - {{trivia}} - for (int i = 0; i < len; i++) - { - $$ - } - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("// comment")] - [InlineData("/* comment */")] - public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest1(string trivia) - { - var markupBeforeCommit = $$""" - {{trivia}} - 10.$$ - """; - - var expectedCodeAfterCommit = $$""" - {{trivia}} - for (int i = 0; i < 10; i++) - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("#region test")] - [InlineData("#if true")] - [InlineData("#pragma warning disable CS0108")] - [InlineData("#nullable enable")] - public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest2(string trivia) - { - var markupBeforeCommit = $$""" - {{trivia}} - 10.$$ - """; - - var expectedCodeAfterCommit = $$""" - - {{trivia}} - for (int i = 0; i < 10; i++) - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForSnippetWhenDottingBeforeContextualKeywordTest1(string intType) - { - var markupBeforeCommit = $$""" - using System.Collections.Generic; - - class C - { - void M({{intType}} @int) - { - @int.$$ - var a = 0; - } - } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; - - class C - { - void M({{intType}} @int) - { - for ({{intType}} i = 0; i < @int; i++) - { - $$ - } - var a = 0; - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForSnippetWhenDottingBeforeContextualKeywordTest2(string intType) - { - var markupBeforeCommit = $$""" - using System.Collections.Generic; - - class C - { - void M({{intType}} @int, Task t) - { - @int.$$ - await t; - } - } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; - - class C - { - void M({{intType}} @int, Task t) - { - for ({{intType}} i = 0; i < @int; i++) - { - $$ - } - await t; - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] - [InlineData("Task")] - [InlineData("Task")] - [InlineData("System.Threading.Tasks.Task")] - public async Task InsertInlineForSnippetWhenDottingBeforeNameSyntaxTest(string nameSyntax) - { - var markupBeforeCommit = $$""" - using System.Collections.Generic; - - class C - { - void M(int @int) - { - @int.$$ - {{nameSyntax}} t = null; - } - } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; - - class C - { - void M(int @int) - { - for (int i = 0; i < @int; i++) - { - $$ - } - {{nameSyntax}} t = null; - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("int[]")] - [InlineData("Span")] - [InlineData("ReadOnlySpan")] - [InlineData("ImmutableArray")] - public async Task InsertInlineForSnippetForCommonTypesWithLengthPropertyTest(string type) - { - var markupBeforeCommit = $$""" - - - using System; - using System.Collections.Generic; - using System.Collections.Immutable; - - public class C - { - void M({{type.Replace("<", "<").Replace(">", ">")}} type) - { - type.$$ - } - } - - - """; - - var expectedCodeAfterCommit = $$""" - using System; - using System.Collections.Generic; - using System.Collections.Immutable; - - public class C - { - void M({{type}} type) - { - for (int i = 0; i < type.Length; i++) - { - $$ - } - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("internal")] - [InlineData("protected internal")] - public async Task InsertInlineForSnippetForTypeWithAccessibleLengthPropertyTest(string lengthPropertyAccessibility) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - {{lengthPropertyAccessibility}} int Length { get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for (int i = 0; i < type.Length; i++) - { - $$ - } - } - } - - public class MyType - { - {{lengthPropertyAccessibility}} int Length { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("")] - [InlineData("internal")] - [InlineData("protected internal")] - public async Task InsertInlineForSnippetForTypeWithAccessibleLengthPropertyGetterTest(string getterAccessibility) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Length { {{getterAccessibility}} get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for (int i = 0; i < type.Length; i++) - { - $$ - } - } - } - - public class MyType - { - public int Length { {{getterAccessibility}} get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForSnippetForTypesWithLengthPropertyOfDifferentIntegerTypesTest(string integerType) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public {{integerType}} Length { get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for ({{integerType}} i = 0; i < type.Length; i++) - { - $$ - } - } - } - - public class MyType - { - public {{integerType}} Length { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInlineForSnippetForTypeWithLengthPropertyInBaseClassTest() - { - var markupBeforeCommit = """ - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType : MyTypeBase - { - } - - public class MyTypeBase - { - public int Length { get; } - } - """; - - var expectedCodeAfterCommit = """ - class C - { - void M(MyType type) - { - for (int i = 0; i < type.Length; i++) - { - $$ - } - } - } - - public class MyType : MyTypeBase - { - } - - public class MyTypeBase - { - public int Length { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task NoInlineForSnippetWhenLengthPropertyHasNoGetterTest() - { - var markup = """ - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Length { set { } } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - public async Task NoInlineForSnippetForInaccessibleLengthPropertyTest(string lengthPropertyAccessibility) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - {{lengthPropertyAccessibility}} int Length { get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - public async Task NoInlineForSnippetForInaccessibleLengthPropertyGetterTest(string getterAccessibility) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Length { {{getterAccessibility}} get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [MemberData(nameof(NotIntegerTypes))] - public async Task NoInlineForSnippetForLengthPropertyOfIncorrectTypeTest(string notIntegerType) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public {{notIntegerType}} Length { get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("List")] - [InlineData("HashSet")] - [InlineData("Dictionary")] - [InlineData("ImmutableList")] - public async Task InsertInlineForSnippetForCommonTypesWithCountPropertyTest(string type) - { - var markupBeforeCommit = $$""" - - - using System; - using System.Collections.Generic; - using System.Collections.Immutable; - - public class C - { - void M({{type.Replace("<", "<").Replace(">", ">")}} type) - { - type.$$ - } - } - - - """; - - var expectedCodeAfterCommit = $$""" - using System; - using System.Collections.Generic; - using System.Collections.Immutable; - - public class C - { - void M({{type}} type) - { - for (int i = 0; i < type.Count; i++) - { - $$ - } - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("internal")] - [InlineData("protected internal")] - public async Task InsertInlineForSnippetForTypeWithAccessibleCountPropertyTest(string countPropertyAccessibility) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - {{countPropertyAccessibility}} int Count { get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for (int i = 0; i < type.Count; i++) - { - $$ - } - } - } - - public class MyType - { - {{countPropertyAccessibility}} int Count { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("")] - [InlineData("internal")] - [InlineData("protected internal")] - public async Task InsertInlineForSnippetForTypeWithAccessibleCountPropertyGetterTest(string getterAccessibility) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Count { {{getterAccessibility}} get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for (int i = 0; i < type.Count; i++) - { - $$ - } - } - } - - public class MyType - { - public int Count { {{getterAccessibility}} get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForSnippetForTypesWithCountPropertyOfDifferentIntegerTypesTest(string integerType) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public {{integerType}} Count { get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for ({{integerType}} i = 0; i < type.Count; i++) - { - $$ - } - } - } - - public class MyType - { - public {{integerType}} Count { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInlineForSnippetForTypeWithCountPropertyInBaseClassTest() - { - var markupBeforeCommit = """ - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType : MyTypeBase - { - } - - public class MyTypeBase - { - public int Count { get; } - } - """; - - var expectedCodeAfterCommit = """ - class C - { - void M(MyType type) - { - for (int i = 0; i < type.Count; i++) - { - $$ - } - } - } - - public class MyType : MyTypeBase - { - } - - public class MyTypeBase - { - public int Count { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task NoInlineForSnippetWhenCountPropertyHasNoGetterTest() - { - var markup = """ - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Count { set { } } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - public async Task NoInlineForSnippetForInaccessibleCountPropertyTest(string countPropertyAccessibility) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - {{countPropertyAccessibility}} int Count { get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - public async Task NoInlineForSnippetForInaccessibleCountPropertyGetterTest(string getterAccessibility) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Count { {{getterAccessibility}} get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [MemberData(nameof(NotIntegerTypes))] - public async Task NoInlineForSnippetForCountPropertyOfIncorrectTypeTest(string notIntegerType) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public {{notIntegerType}} Count { get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfFact] - public async Task NoInlineForSnippetForTypeWithBothLengthAndCountPropertyTest() - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Length { get; } - public int Count { get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - public static IEnumerable IntegerTypes - { - get - { - return - [ - ["byte"], - ["sbyte"], - ["short"], - ["ushort"], - ["int"], - ["uint"], - ["long"], - ["ulong"], - ["nint"], - ["nuint"] - ]; - } - } - - public static IEnumerable NotIntegerTypes - { - get - { - return - [ - ["string"], - ["System.DateTime"], - ["System.Action"] - ]; - } - } -} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpForrSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpForrSnippetCompletionProviderTests.cs deleted file mode 100644 index 4e8d250141331..0000000000000 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpForrSnippetCompletionProviderTests.cs +++ /dev/null @@ -1,1283 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; - -[Trait(Traits.Feature, Traits.Features.Completion)] -public class CSharpForrSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests -{ - protected override string ItemToCommit => "forr"; - - [WpfFact] - public async Task InsertForrSnippetInMethodTest() - { - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - $$ - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - for (int i = length - 1; i >= 0; i--) - { - $$ - } - } - } - """); - } - - [WpfFact] - public async Task InsertForrSnippetInMethodUsedIncrementorTest() - { - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - int i; - $$ - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - int i; - for (int j = length - 1; j >= 0; j--) - { - $$ - } - } - } - """); - } - - [WpfFact] - public async Task InsertForrSnippetInMethodUsedIncrementorsTest() - { - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - int i, j, k; - $$ - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - int i, j, k; - for (int i1 = length - 1; i1 >= 0; i1--) - { - $$ - } - } - } - """); - } - - [WpfFact] - public async Task InsertForrSnippetInGlobalContextTest() - { - await VerifyCustomCommitProviderAsync(""" - $$ - """, ItemToCommit, """ - for (int i = length - 1; i >= 0; i--) - { - $$ - } - """); - } - - [WpfFact] - public async Task InsertForrSnippetInConstructorTest() - { - await VerifyCustomCommitProviderAsync(""" - class Program - { - public Program() - { - $$ - } - } - """, ItemToCommit, """ - class Program - { - public Program() - { - for (int i = length - 1; i >= 0; i--) - { - $$ - } - } - } - """); - } - - [WpfFact] - public async Task InsertForrSnippetInLocalFunctionTest() - { - // TODO: fix this test when bug with simplifier failing to find correct node is fixed - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - void LocalFunction() - { - $$ - } - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - void LocalFunction() - { - for (global::System.Int32 i = (length) - (1); i >= 0; i--) - { - $$ - } - } - } - } - """); - } - - [WpfFact] - public async Task InsertForrSnippetInAnonymousFunctionTest() - { - // TODO: fix this test when bug with simplifier failing to find correct node is fixed - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - var action = delegate() - { - $$ - }; - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - var action = delegate() - { - for (global::System.Int32 i = (length) - (1); i >= 0; i--) - { - $$ - } - }; - } - } - """); - } - - [WpfFact] - public async Task InsertForrSnippetInParenthesizedLambdaExpressionTest() - { - // TODO: fix this test when bug with simplifier failing to find correct node is fixed - await VerifyCustomCommitProviderAsync(""" - class Program - { - public void Method() - { - var action = () => - { - $$ - }; - } - } - """, ItemToCommit, """ - class Program - { - public void Method() - { - var action = () => - { - for (global::System.Int32 i = (length) - (1); i >= 0; i--) - { - $$ - } - }; - } - } - """); - } - - [WpfFact] - public async Task TryToProduceVarWithSpecificCodeStyleTest() - { - // In non-inline reversed for snippet type of expression `length - 1` is unknown, - // so it cannot be simplified to `var`. Therefore having explicit `int` type here is expected - await VerifyCustomCommitProviderAsync(""" - - - class Program - { - public void Method() - { - $$ - } - } - - root = true - - [*] - # IDE0008: Use explicit type - csharp_style_var_for_built_in_types = true - - - - """, ItemToCommit, """ - class Program - { - public void Method() - { - for (int i = length - 1; i >= 0; i--) - { - $$ - } - } - } - """); - } - - [WpfTheory] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForrSnippetInMethodTest(string inlineExpressionType) - { - await VerifyCustomCommitProviderAsync($$""" - class Program - { - public void Method({{inlineExpressionType}} l) - { - l.$$ - } - } - """, ItemToCommit, $$""" - class Program - { - public void Method({{inlineExpressionType}} l) - { - for ({{inlineExpressionType}} i = l - 1; i >= 0; i--) - { - $$ - } - } - } - """); - } - - [WpfTheory] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForrSnippetInGlobalContextTest(string inlineExpressionType) - { - await VerifyCustomCommitProviderAsync($$""" - {{inlineExpressionType}} l; - l.$$ - """, ItemToCommit, $$""" - {{inlineExpressionType}} l; - for ({{inlineExpressionType}} i = l - 1; i >= 0; i--) - { - $$ - } - """); - } - - [WpfTheory] - [MemberData(nameof(NotIntegerTypes))] - public async Task NoInlineForrSnippetForIncorrectTypeInMethodTest(string inlineExpressionType) - { - var markup = $$""" - class Program - { - public void Method({{inlineExpressionType}} l) - { - l.$$ - } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [MemberData(nameof(NotIntegerTypes))] - public async Task NoInlineForrSnippetForIncorrectTypeInGlobalContextTest(string inlineExpressionType) - { - var markup = $$""" - {{inlineExpressionType}} l; - l.$$ - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfFact] - public async Task ProduceVarWithSpecificCodeStyleForInlineSnippetTest() - { - await VerifyCustomCommitProviderAsync(""" - - - class Program - { - public void Method(int l) - { - l.$$ - } - } - - root = true - - [*] - # IDE0008: Use explicit type - csharp_style_var_for_built_in_types = true - - - - """, ItemToCommit, """ - class Program - { - public void Method(int l) - { - for (var i = l - 1; i >= 0; i--) - { - $$ - } - } - } - """); - } - - [WpfFact] - public async Task NoInlineForrSnippetNotDirectlyExpressionStatementTest() - { - var markup = """ - class Program - { - public void Method(int l) - { - System.Console.WriteLine(l.$$); - } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("// comment")] - [InlineData("/* comment */")] - [InlineData("#region test")] - public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest1(string trivia) - { - var markupBeforeCommit = $$""" - class Program - { - void M(int len) - { - {{trivia}} - len.$$ - } - } - """; - - var expectedCodeAfterCommit = $$""" - class Program - { - void M(int len) - { - {{trivia}} - for (int i = len - 1; i >= 0; i--) - { - $$ - } - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("#if true")] - [InlineData("#pragma warning disable CS0108")] - [InlineData("#nullable enable")] - public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest2(string trivia) - { - var markupBeforeCommit = $$""" - class Program - { - void M(int len) - { - {{trivia}} - len.$$ - } - } - """; - - var expectedCodeAfterCommit = $$""" - class Program - { - void M(int len) - { - {{trivia}} - for (int i = len - 1; i >= 0; i--) - { - $$ - } - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("// comment")] - [InlineData("/* comment */")] - public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest1(string trivia) - { - var markupBeforeCommit = $$""" - {{trivia}} - 10.$$ - """; - - var expectedCodeAfterCommit = $$""" - {{trivia}} - for (int i = 10 - 1; i >= 0; i--) - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("#region test")] - [InlineData("#if true")] - [InlineData("#pragma warning disable CS0108")] - [InlineData("#nullable enable")] - public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest2(string trivia) - { - var markupBeforeCommit = $$""" - {{trivia}} - 10.$$ - """; - - var expectedCodeAfterCommit = $$""" - - {{trivia}} - for (int i = 10 - 1; i >= 0; i--) - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForrSnippetWhenDottingBeforeContextualKeywordTest1(string intType) - { - var markupBeforeCommit = $$""" - using System.Collections.Generic; - - class C - { - void M({{intType}} @int) - { - @int.$$ - var a = 0; - } - } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; - - class C - { - void M({{intType}} @int) - { - for ({{intType}} i = @int - 1; i >= 0; i--) - { - $$ - } - var a = 0; - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForrSnippetWhenDottingBeforeContextualKeywordTest2(string intType) - { - var markupBeforeCommit = $$""" - using System.Collections.Generic; - - class C - { - void M({{intType}} @int, Task t) - { - @int.$$ - await t; - } - } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; - - class C - { - void M({{intType}} @int, Task t) - { - for ({{intType}} i = @int - 1; i >= 0; i--) - { - $$ - } - await t; - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] - [InlineData("Task")] - [InlineData("Task")] - [InlineData("System.Threading.Tasks.Task")] - public async Task InsertInlineForrSnippetWhenDottingBeforeNameSyntaxTest(string nameSyntax) - { - var markupBeforeCommit = $$""" - using System.Collections.Generic; - - class C - { - void M(int @int) - { - @int.$$ - {{nameSyntax}} t = null; - } - } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; - - class C - { - void M(int @int) - { - for (int i = @int - 1; i >= 0; i--) - { - $$ - } - {{nameSyntax}} t = null; - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("int[]")] - [InlineData("Span")] - [InlineData("ReadOnlySpan")] - [InlineData("ImmutableArray")] - public async Task InsertInlineForrSnippetForCommonTypesWithLengthPropertyTest(string type) - { - var markupBeforeCommit = $$""" - - - using System; - using System.Collections.Generic; - using System.Collections.Immutable; - - public class C - { - void M({{type.Replace("<", "<").Replace(">", ">")}} type) - { - type.$$ - } - } - - - """; - - var expectedCodeAfterCommit = $$""" - using System; - using System.Collections.Generic; - using System.Collections.Immutable; - - public class C - { - void M({{type}} type) - { - for (int i = type.Length - 1; i >= 0; i--) - { - $$ - } - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("internal")] - [InlineData("protected internal")] - public async Task InsertInlineForrSnippetForTypeWithAccessibleLengthPropertyTest(string lengthPropertyAccessibility) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - {{lengthPropertyAccessibility}} int Length { get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for (int i = type.Length - 1; i >= 0; i--) - { - $$ - } - } - } - - public class MyType - { - {{lengthPropertyAccessibility}} int Length { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("")] - [InlineData("internal")] - [InlineData("protected internal")] - public async Task InsertInlineForrSnippetForTypeWithAccessibleLengthPropertyGetterTest(string getterAccessibility) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Length { {{getterAccessibility}} get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for (int i = type.Length - 1; i >= 0; i--) - { - $$ - } - } - } - - public class MyType - { - public int Length { {{getterAccessibility}} get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForrSnippetForTypesWithLengthPropertyOfDifferentIntegerTypesTest(string integerType) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public {{integerType}} Length { get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for ({{integerType}} i = type.Length - 1; i >= 0; i--) - { - $$ - } - } - } - - public class MyType - { - public {{integerType}} Length { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInlineForrSnippetForTypeWithLengthPropertyInBaseClassTest() - { - var markupBeforeCommit = """ - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType : MyTypeBase - { - } - - public class MyTypeBase - { - public int Length { get; } - } - """; - - var expectedCodeAfterCommit = """ - class C - { - void M(MyType type) - { - for (int i = type.Length - 1; i >= 0; i--) - { - $$ - } - } - } - - public class MyType : MyTypeBase - { - } - - public class MyTypeBase - { - public int Length { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task NoInlineForrSnippetWhenLengthPropertyHasNoGetterTest() - { - var markup = """ - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Length { set { } } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - public async Task NoInlineForrSnippetForInaccessibleLengthPropertyTest(string lengthPropertyAccessibility) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - {{lengthPropertyAccessibility}} int Length { get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - public async Task NoInlineForrSnippetForInaccessibleLengthPropertyGetterTest(string getterAccessibility) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Length { {{getterAccessibility}} get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [MemberData(nameof(NotIntegerTypes))] - public async Task NoInlineForrSnippetForLengthPropertyOfIncorrectTypeTest(string notIntegerType) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public {{notIntegerType}} Length { get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("List")] - [InlineData("HashSet")] - [InlineData("Dictionary")] - [InlineData("ImmutableList")] - public async Task InsertInlineForrSnippetForCommonTypesWithCountPropertyTest(string type) - { - var markupBeforeCommit = $$""" - - - using System; - using System.Collections.Generic; - using System.Collections.Immutable; - - public class C - { - void M({{type.Replace("<", "<").Replace(">", ">")}} type) - { - type.$$ - } - } - - - """; - - var expectedCodeAfterCommit = $$""" - using System; - using System.Collections.Generic; - using System.Collections.Immutable; - - public class C - { - void M({{type}} type) - { - for (int i = type.Count - 1; i >= 0; i--) - { - $$ - } - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("internal")] - [InlineData("protected internal")] - public async Task InsertInlineForrSnippetForTypeWithAccessibleCountPropertyTest(string countPropertyAccessibility) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - {{countPropertyAccessibility}} int Count { get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for (int i = type.Count - 1; i >= 0; i--) - { - $$ - } - } - } - - public class MyType - { - {{countPropertyAccessibility}} int Count { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("")] - [InlineData("internal")] - [InlineData("protected internal")] - public async Task InsertInlineForrSnippetForTypeWithAccessibleCountPropertyGetterTest(string getterAccessibility) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Count { {{getterAccessibility}} get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for (int i = type.Count - 1; i >= 0; i--) - { - $$ - } - } - } - - public class MyType - { - public int Count { {{getterAccessibility}} get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [MemberData(nameof(IntegerTypes))] - public async Task InsertInlineForrSnippetForTypesWithCountPropertyOfDifferentIntegerTypesTest(string integerType) - { - var markupBeforeCommit = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public {{integerType}} Count { get; } - } - """; - - var expectedCodeAfterCommit = $$""" - class C - { - void M(MyType type) - { - for ({{integerType}} i = type.Count - 1; i >= 0; i--) - { - $$ - } - } - } - - public class MyType - { - public {{integerType}} Count { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInlineForrSnippetForTypeWithCountPropertyInBaseClassTest() - { - var markupBeforeCommit = """ - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType : MyTypeBase - { - } - - public class MyTypeBase - { - public int Count { get; } - } - """; - - var expectedCodeAfterCommit = """ - class C - { - void M(MyType type) - { - for (int i = type.Count - 1; i >= 0; i--) - { - $$ - } - } - } - - public class MyType : MyTypeBase - { - } - - public class MyTypeBase - { - public int Count { get; } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task NoInlineForrSnippetWhenCountPropertyHasNoGetterTest() - { - var markup = """ - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Count { set { } } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - public async Task NoInlineForrSnippetForInaccessibleCountPropertyTest(string countPropertyAccessibility) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - {{countPropertyAccessibility}} int Count { get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - public async Task NoInlineForrSnippetForInaccessibleCountPropertyGetterTest(string getterAccessibility) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Count { {{getterAccessibility}} get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfTheory] - [MemberData(nameof(NotIntegerTypes))] - public async Task NoInlineForrSnippetForCountPropertyOfIncorrectTypeTest(string notIntegerType) - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public {{notIntegerType}} Count { get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - [WpfFact] - public async Task NoInlineForrSnippetForTypeWithBothLengthAndCountPropertyTest() - { - var markup = $$""" - class C - { - void M(MyType type) - { - type.$$ - } - } - - public class MyType - { - public int Length { get; } - public int Count { get; } - } - """; - - await VerifyItemIsAbsentAsync(markup, ItemToCommit); - } - - public static IEnumerable IntegerTypes - { - get - { - return - [ - ["byte"], - ["sbyte"], - ["short"], - ["ushort"], - ["int"], - ["uint"], - ["long"], - ["ulong"], - ["nint"], - ["nuint"] - ]; - } - } - - public static IEnumerable NotIntegerTypes - { - get - { - return - [ - ["string"], - ["System.DateTime"], - ["System.Action"] - ]; - } - } -} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpIfSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpIfSnippetCompletionProviderTests.cs deleted file mode 100644 index 4b1021190adc4..0000000000000 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpIfSnippetCompletionProviderTests.cs +++ /dev/null @@ -1,10 +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.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; - -public class CSharpIfSnippetCompletionProviderTests : AbstractCSharpConditionalBlockSnippetCompletionProviderTests -{ - protected override string ItemToCommit => "if"; -} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpInterfaceSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpInterfaceSnippetCompletionProviderTests.cs deleted file mode 100644 index 046e72a7a43f2..0000000000000 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpInterfaceSnippetCompletionProviderTests.cs +++ /dev/null @@ -1,412 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; - -[Trait(Traits.Feature, Traits.Features.Completion)] -public class CSharpInterfaceSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests -{ - protected override string ItemToCommit => "interface"; - - [WpfFact] - public async Task InsertInterfaceSnippetInNamespaceTest() - { - var markupBeforeCommit = - """ - namespace Namespace - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - namespace Namespace - { - interface MyInterface - { - $$ - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInterfaceSnippetInFileScopedNamespaceTest() - { - var markupBeforeCommit = - """ - namespace Namespace; - - $$ - """; - - var expectedCodeAfterCommit = - """ - namespace Namespace; - - interface MyInterface - { - $$ - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInterfaceSnippetTest() - { - var markupBeforeCommit = -@"$$"; - - var expectedCodeAfterCommit = - """ - interface MyInterface - { - $$ - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInterfaceTopLevelSnippetTest() - { - var markupBeforeCommit = - """ - System.Console.WriteLine(); - $$ - """; - - var expectedCodeAfterCommit = - """ - System.Console.WriteLine(); - interface MyInterface - { - $$ - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInterfaceSnippetInClassTest() - { - var markupBeforeCommit = - """ - class MyClass - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - class MyClass - { - interface MyInterface - { - $$ - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInterfaceSnippetInRecordTest() - { - var markupBeforeCommit = - """ - record MyRecord - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - record MyRecord - { - interface MyInterface - { - $$ - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInterfaceSnippetInStructTest() - { - var markupBeforeCommit = - """ - struct MyStruct - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - struct MyStruct - { - interface MyInterface - { - $$ - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInterfaceSnippetInInterfaceTest() - { - var markupBeforeCommit = - """ - interface MyInterface - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - interface MyInterface - { - interface MyInterface1 - { - $$ - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertInterfaceSnippetWithModifiersTest() - { - var markupBeforeCommit = - $@" - - - -$$ - - -root = true - -[*] -# IDE0008: Use explicit type -dotnet_style_require_accessibility_modifiers = always - - -"; - var expectedCodeAfterCommit = - $@" -public interface MyInterface -{{ - $$ -}} -"; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task NoInterfaceSnippetInEnumTest() - { - var markupBeforeCommit = - """ - enum MyEnum - { - $$ - } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoInteraceSnippetInMethodTest() - { - var markupBeforeCommit = - """ - class Program - { - public void Method() - { - $$ - } - } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoInterfaceSnippetInConstructorTest() - { - var markupBeforeCommit = - """ - class Program - { - public Program() - { - $$ - } - } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task AfterAccessibilityModifier(string modifier) - { - var markupBeforeCommit = $"{modifier} $$"; - - var expectedCodeAfterCommit = $$""" - {{modifier}} interface MyInterface - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task AfterAccessibilityModifier_RequireAccessibilityModifiers(string modifier) - { - var markupBeforeCommit = $$""" - - - {{modifier}} $$ - - root = true - - [*] - # IDE0008: Use explicit type - dotnet_style_require_accessibility_modifiers = always - - - - """; - - var expectedCodeAfterCommit = $$""" - {{modifier}} interface MyInterface - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("unsafe")] - public async Task InsertInterfaceSnippetAfterValidModifiersTest(string modifier) - { - var markupBeforeCommit = $"{modifier} $$"; - - var expectedCodeAfterCommit = $$""" - {{modifier}} interface MyInterface - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("abstract")] - [InlineData("sealed")] - [InlineData("static")] - [InlineData("ref")] - [InlineData("readonly")] - public async Task NoInterfaceSnippetAfterInvalidModifiersTest(string modifier) - { - var markupBeforeCommit = $"{modifier} $$"; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task NoAdditionalAccessibilityModifiersIfAfterPartialKeywordTest(string modifier) - { - var markupBeforeCommit = $$""" - - - {{modifier}} partial $$ - - root = true - - [*] - # IDE0008: Use explicit type - dotnet_style_require_accessibility_modifiers = always - - - - """; - - var expectedCodeAfterCommit = $$""" - {{modifier}} partial interface MyInterface - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] - public async Task EnsureCorrectModifierOrderAfterPartialKeywordTest() - { - var markupBeforeCommit = """ - - - partial $$ - - root = true - - [*] - # IDE0008: Use explicit type - dotnet_style_require_accessibility_modifiers = always - - - - """; - - var expectedCodeAfterCommit = """ - public partial interface MyInterface - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } -} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpStructSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpStructSnippetCompletionProviderTests.cs deleted file mode 100644 index f09a3bc6e900e..0000000000000 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpStructSnippetCompletionProviderTests.cs +++ /dev/null @@ -1,558 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; - -[Trait(Traits.Feature, Traits.Features.Completion)] -public class CSharpStructSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests -{ - protected override string ItemToCommit => "struct"; - - [WpfFact] - public async Task InsertStructSnippetInNamespaceTest() - { - var markupBeforeCommit = - """ - namespace Namespace - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - namespace Namespace - { - struct MyStruct - { - $$ - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertStructSnippetInFileScopedNamespaceTest() - { - var markupBeforeCommit = - """ - namespace Namespace; - - $$ - """; - - var expectedCodeAfterCommit = - """ - namespace Namespace; - - struct MyStruct - { - $$ - } - """ -; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertStructSnippetTest() - { - var markupBeforeCommit = -@"$$"; - - var expectedCodeAfterCommit = - """ - struct MyStruct - { - $$ - } - """ -; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertStructTopLevelSnippetTest() - { - var markupBeforeCommit = - """ - System.Console.WriteLine(); - $$ - """; - - var expectedCodeAfterCommit = - """ - System.Console.WriteLine(); - struct MyStruct - { - $$ - } - """ -; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertStructSnippetInClassTest() - { - var markupBeforeCommit = - """ - struct MyClass - { - $$ - } - """ -; - - var expectedCodeAfterCommit = - """ - struct MyClass - { - struct MyStruct - { - $$ - } - } - """ -; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertStructSnippetInRecordTest() - { - var markupBeforeCommit = - """ - record MyRecord - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - record MyRecord - { - struct MyStruct - { - $$ - } - } - """ -; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertStructSnippetInStructTest() - { - var markupBeforeCommit = - """ - struct MyStruct - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - struct MyStruct - { - struct MyStruct1 - { - $$ - } - } - """ -; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertStructSnippetInInterfaceTest() - { - var markupBeforeCommit = - """ - interface MyInterface - { - $$ - } - """; - - var expectedCodeAfterCommit = - """ - interface MyInterface - { - struct MyStruct - { - $$ - } - } - """ -; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertStructSnippetWithModifiersTest() - { - var markupBeforeCommit = - $@" - - - -$$ - - -root = true - -[*] -# IDE0008: Use explicit type -dotnet_style_require_accessibility_modifiers = always - - -"; - var expectedCodeAfterCommit = - $@" -public struct MyStruct -{{ - $$ -}} -"; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task NoStructSnippetInEnumTest() - { - var markupBeforeCommit = - """ - enum MyEnum - { - $$ - } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoStructSnippetInMethodTest() - { - var markupBeforeCommit = - """ - struct Program - { - public void Method() - { - $$ - } - } - """ -; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task NoStructSnippetInConstructorTest() - { - var markupBeforeCommit = - """ - struct Program - { - public Program() - { - $$ - } - } - """ -; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task AfterAccessibilityModifier(string modifier) - { - var markupBeforeCommit = $"{modifier} $$"; - - var expectedCodeAfterCommit = $$""" - {{modifier}} struct MyStruct - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task AfterAccessibilityModifier_RequireAccessibilityModifiers(string modifier) - { - var markupBeforeCommit = $$""" - - - {{modifier}} $$ - - root = true - - [*] - # IDE0008: Use explicit type - dotnet_style_require_accessibility_modifiers = always - - - - """; - - var expectedCodeAfterCommit = $$""" - {{modifier}} struct MyStruct - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("ref")] - [InlineData("readonly")] - [InlineData("unsafe")] - public async Task InsertStructSnippetAfterValidModifiersTest(string modifier) - { - var markupBeforeCommit = $"{modifier} $$"; - - var expectedCodeAfterCommit = $$""" - {{modifier}} struct MyStruct - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfTheory] - [InlineData("abstract")] - [InlineData("sealed")] - [InlineData("static")] - public async Task NoStructSnippetAfterInvalidModifiersTest(string modifier) - { - var markupBeforeCommit = $"{modifier} $$"; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] - public async Task NoAdditionalAccessibilityModifiersIfAfterPartialKeywordTest(string modifier) - { - var markupBeforeCommit = $$""" - - - {{modifier}} partial $$ - - root = true - - [*] - # IDE0008: Use explicit type - dotnet_style_require_accessibility_modifiers = always - - - - """; - - var expectedCodeAfterCommit = $$""" - {{modifier}} partial struct MyStruct - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] - public async Task EnsureCorrectModifierOrderAfterPartialKeywordTest() - { - var markupBeforeCommit = """ - - - partial $$ - - root = true - - [*] - # IDE0008: Use explicit type - dotnet_style_require_accessibility_modifiers = always - - - - """; - - var expectedCodeAfterCommit = """ - public partial struct MyStruct - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] - public async Task EnsureCorrectModifierOrderAfterPartialKeywordTest_InvalidPreferredModifiersList() - { - var markupBeforeCommit = """ - - - partial $$ - - [*] - dotnet_style_require_accessibility_modifiers = always - - csharp_preferred_modifier_order = invalid! - - - - """; - - var expectedCodeAfterCommit = """ - public partial struct MyStruct - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBeforeAllOthers() - { - var markupBeforeCommit = """ - - - readonly ref $$ - - [*] - dotnet_style_require_accessibility_modifiers = always - - csharp_preferred_modifier_order = public,readonly,ref - - - - """; - - var expectedCodeAfterCommit = """ - public readonly ref struct MyStruct - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBeforeAllOthers_NotAllModifiersInTheList() - { - var markupBeforeCommit = """ - - - readonly ref $$ - - [*] - dotnet_style_require_accessibility_modifiers = always - - csharp_preferred_modifier_order = public,readonly - - - - """; - - var expectedCodeAfterCommit = """ - public readonly ref struct MyStruct - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBetweenOthers() - { - var markupBeforeCommit = """ - - - readonly ref $$ - - [*] - dotnet_style_require_accessibility_modifiers = always - - csharp_preferred_modifier_order = readonly,public,ref - - - - """; - - var expectedCodeAfterCommit = """ - readonly public ref struct MyStruct - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierAfterAllOthers() - { - var markupBeforeCommit = """ - - - readonly ref $$ - - [*] - dotnet_style_require_accessibility_modifiers = always - - csharp_preferred_modifier_order = readonly,ref,public - - - - """; - - var expectedCodeAfterCommit = """ - readonly ref public struct MyStruct - { - $$ - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } -} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpWhileSnippetCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpWhileSnippetCompletionProviderTests.cs deleted file mode 100644 index e22eaa9e5df21..0000000000000 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpWhileSnippetCompletionProviderTests.cs +++ /dev/null @@ -1,10 +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.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; - -public class CSharpWhileSnippetCompletionProviderTests : AbstractCSharpConditionalBlockSnippetCompletionProviderTests -{ - protected override string ItemToCommit => "while"; -} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs index 3bbf2a4d98f73..d67c3246a10e5 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs @@ -29,14 +29,14 @@ internal override Type GetCompletionProviderType() private protected override Task VerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, - SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, + SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, char? deletedCharTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, List matchingFilters, CompletionItemFlags? flags = null, CompletionOptions options = null, bool skipSpeculation = false) { return base.VerifyWorkerAsync(code, position, expectedItemOrNull, expectedDescriptionOrNull, - SourceCodeKind.Regular, usePreviousCharAsTrigger, checkForAbsence, + SourceCodeKind.Regular, usePreviousCharAsTrigger, deletedCharTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs index 85c37e11d095d..b5ac6976a7fb6 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs @@ -41,19 +41,19 @@ private async Task VerifyItemsAbsentAsync(string markup, params string[] items) private protected override async Task VerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, - SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, + SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, char? deletedCharTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null, CompletionOptions options = null, bool skipSpeculation = false) { // We don't need to try writing comments in from of items in doc comments. await VerifyAtPositionAsync( - code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, + code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); await VerifyAtEndOfFileAsync( - code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, + code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); @@ -62,12 +62,12 @@ await VerifyAtEndOfFileAsync( if (!checkForAbsence && expectedItemOrNull != null) { await VerifyAtPosition_ItemPartiallyWrittenAsync( - code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, + code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); await VerifyAtEndOfFile_ItemPartiallyWrittenAsync( - code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, + code, position, usePreviousCharAsTrigger, deletedCharTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, options); } @@ -1195,4 +1195,56 @@ public struct Goo(string MyParameter); typeparamref name="T" """); } + + [Fact] + public async Task TriggerOnDeletion_DeleteInsideAttributeName() + { + TriggerOnDeletion = true; + + await VerifyItemExistsAsync(""" + /// + """, + "langword", + deletedCharTrigger: 'w'); + } + + [Fact] + public async Task TriggerOnDeletion_DeleteInsideAttributeValue() + { + TriggerOnDeletion = true; + + await VerifyItemExistsAsync(""" + /// + """, + "true", + deletedCharTrigger: 'r'); + } + + [Fact] + public async Task TriggerOnDeletion_DeleteInsideTagName_DoesntSuggest() + { + TriggerOnDeletion = true; + + await VerifyItemIsAbsentAsync(""" + /// + /// + /// + """, + "see", + deletedCharTrigger: 'a'); + } + + [Fact] + public async Task TriggerOnDeletion_DeleteInXmlText_DoesntSuggest() + { + TriggerOnDeletion = true; + + await VerifyItemIsAbsentAsync(""" + /// + /// a$$c + /// + """, + "see", + deletedCharTrigger: 'b'); + } } diff --git a/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.Lines.cs b/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.Lines.cs index 7090920dd6471..aad5a4613810b 100644 --- a/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.Lines.cs +++ b/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.Lines.cs @@ -132,7 +132,7 @@ public void TestAtStartOfLine_11() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 339, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -144,7 +144,7 @@ public void TestAtStartOfLine_12() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 350, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -156,7 +156,7 @@ public void TestAtStartOfLine_13() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 410, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -201,7 +201,7 @@ public void TestAtStartOfLine_17() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 584, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms"], terms); } [Fact] @@ -213,7 +213,7 @@ public void TestAtStartOfLine_18() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 595, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "position", "terms" }, terms); + AssertEx.SetEqual(["expression", "position", "terms"], terms); } [Fact] @@ -225,7 +225,7 @@ public void TestAtStartOfLine_19() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 659, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "position", "terms" }, terms); + AssertEx.SetEqual(["expression", "position", "terms"], terms); } [Fact] @@ -237,7 +237,7 @@ public void TestAtStartOfLine_20() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 696, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -249,7 +249,7 @@ public void TestAtStartOfLine_21() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 711, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -272,7 +272,7 @@ public void TestAtStartOfLine_23() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 751, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expression", "expressionType" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expression", "expressionType"], terms); } [Fact] @@ -284,7 +284,7 @@ public void TestAtStartOfLine_24() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 753, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expression", "expressionType" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expression", "expressionType"], terms); } [Fact] @@ -296,7 +296,7 @@ public void TestAtStartOfLine_25() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 849, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expression", "expressionType" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expression", "expressionType"], terms); } [Fact] @@ -308,7 +308,7 @@ public void TestAtStartOfLine_26() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 896, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expression", "expressionType" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expression", "expressionType"], terms); } [Fact] @@ -320,7 +320,7 @@ public void TestAtStartOfLine_27() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 954, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectExpressionTerms", "ExpressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectExpressionTerms", "ExpressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -332,7 +332,7 @@ public void TestAtStartOfLine_28() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1040, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "expression", "terms", "expressionType", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "expression", "terms", "expressionType", "CollectExpressionTerms"], terms); } [Fact] @@ -344,7 +344,7 @@ public void TestAtStartOfLine_29() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1042, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "expression", "terms", "expressionType", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "expression", "terms", "expressionType", "CollectExpressionTerms"], terms); } [Fact] @@ -356,7 +356,7 @@ public void TestAtStartOfLine_30() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1132, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -368,7 +368,7 @@ public void TestAtStartOfLine_31() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1147, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expressionType", "terms", "expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["expressionType", "terms", "expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -380,7 +380,7 @@ public void TestAtStartOfLine_32() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1235, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expressionType", "terms", "expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["expressionType", "terms", "expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -392,7 +392,7 @@ public void TestAtStartOfLine_33() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1266, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expressionType", "terms", "expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["expressionType", "terms", "expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -404,7 +404,7 @@ public void TestAtStartOfLine_34() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1323, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["terms", "expression", "ConvertToString"], terms); } [Fact] @@ -416,7 +416,7 @@ public void TestAtStartOfLine_35() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1338, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidTerm", "terms", "expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidTerm", "terms", "expression", "ConvertToString"], terms); } [Fact] @@ -450,7 +450,7 @@ public void TestAtStartOfLine_38() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1502, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -462,7 +462,7 @@ public void TestAtStartOfLine_39() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1513, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "position", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["expression", "position", "terms", "expressionType"], terms); } [Fact] @@ -474,7 +474,7 @@ public void TestAtStartOfLine_40() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1577, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "position", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["expression", "position", "terms", "expressionType"], terms); } [Fact] @@ -486,7 +486,7 @@ public void TestAtStartOfLine_41() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1614, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -498,7 +498,7 @@ public void TestAtStartOfLine_42() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1629, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -521,7 +521,7 @@ public void TestAtStartOfLine_44() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1669, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -533,7 +533,7 @@ public void TestAtStartOfLine_45() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1671, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -545,7 +545,7 @@ public void TestAtStartOfLine_46() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1709, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -557,7 +557,7 @@ public void TestAtStartOfLine_47() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1724, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -569,7 +569,7 @@ public void TestAtStartOfLine_48() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1773, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -581,7 +581,7 @@ public void TestAtStartOfLine_49() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1822, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind"], terms); } [Fact] @@ -593,7 +593,7 @@ public void TestAtStartOfLine_50() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1913, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind"], terms); } [Fact] @@ -605,7 +605,7 @@ public void TestAtStartOfLine_51() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2010, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind"], terms); } [Fact] @@ -617,7 +617,7 @@ public void TestAtStartOfLine_52() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2085, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind"], terms); } [Fact] @@ -629,7 +629,7 @@ public void TestAtStartOfLine_53() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2155, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression"], terms); } [Fact] @@ -641,7 +641,7 @@ public void TestAtStartOfLine_54() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2184, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -653,7 +653,7 @@ public void TestAtStartOfLine_55() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2186, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -665,7 +665,7 @@ public void TestAtStartOfLine_56() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2235, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidTerm", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidTerm", "expression", "expression.Kind"], terms); } [Fact] @@ -677,7 +677,7 @@ public void TestAtStartOfLine_57() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2293, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidTerm", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidTerm", "expression", "expression.Kind"], terms); } [Fact] @@ -689,7 +689,7 @@ public void TestAtStartOfLine_58() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2357, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -701,7 +701,7 @@ public void TestAtStartOfLine_59() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2386, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -713,7 +713,7 @@ public void TestAtStartOfLine_60() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2388, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -725,7 +725,7 @@ public void TestAtStartOfLine_61() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2449, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -737,7 +737,7 @@ public void TestAtStartOfLine_62() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2506, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -749,7 +749,7 @@ public void TestAtStartOfLine_63() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2562, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -761,7 +761,7 @@ public void TestAtStartOfLine_64() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2621, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -773,7 +773,7 @@ public void TestAtStartOfLine_65() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2679, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -785,7 +785,7 @@ public void TestAtStartOfLine_66() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2735, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind"], terms); } [Fact] @@ -797,7 +797,7 @@ public void TestAtStartOfLine_67() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2828, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind"], terms); } [Fact] @@ -809,7 +809,7 @@ public void TestAtStartOfLine_68() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2926, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind"], terms); } [Fact] @@ -821,7 +821,7 @@ public void TestAtStartOfLine_69() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2965, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind"], terms); } [Fact] @@ -833,7 +833,7 @@ public void TestAtStartOfLine_70() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3035, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression"], terms); } [Fact] @@ -845,7 +845,7 @@ public void TestAtStartOfLine_71() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3064, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -857,7 +857,7 @@ public void TestAtStartOfLine_72() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3066, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -869,7 +869,7 @@ public void TestAtStartOfLine_73() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3115, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "terms", "expressionType", "CollectExpressionTerms", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "terms", "expressionType", "CollectExpressionTerms", "expression", "expression.Kind"], terms); } [Fact] @@ -881,7 +881,7 @@ public void TestAtStartOfLine_74() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3210, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "terms", "expressionType", "CollectExpressionTerms", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "terms", "expressionType", "CollectExpressionTerms", "expression", "expression.Kind"], terms); } [Fact] @@ -893,7 +893,7 @@ public void TestAtStartOfLine_75() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3308, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "terms", "expressionType", "CollectExpressionTerms", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "terms", "expressionType", "CollectExpressionTerms", "expression", "expression.Kind"], terms); } [Fact] @@ -905,7 +905,7 @@ public void TestAtStartOfLine_76() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3403, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "terms", "expressionType", "CollectExpressionTerms", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "terms", "expressionType", "CollectExpressionTerms", "expression", "expression.Kind"], terms); } [Fact] @@ -917,7 +917,7 @@ public void TestAtStartOfLine_77() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3532, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectExpressionTerms"], terms); } [Fact] @@ -929,7 +929,7 @@ public void TestAtStartOfLine_78() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3561, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -941,7 +941,7 @@ public void TestAtStartOfLine_79() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3563, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -953,7 +953,7 @@ public void TestAtStartOfLine_80() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3620, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -965,7 +965,7 @@ public void TestAtStartOfLine_81() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3684, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectMemberAccessExpressionTerms", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectMemberAccessExpressionTerms", "expression.Kind"], terms); } [Fact] @@ -977,7 +977,7 @@ public void TestAtStartOfLine_82() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3790, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectMemberAccessExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectMemberAccessExpressionTerms"], terms); } [Fact] @@ -989,7 +989,7 @@ public void TestAtStartOfLine_83() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3819, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -1001,7 +1001,7 @@ public void TestAtStartOfLine_84() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3821, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -1013,7 +1013,7 @@ public void TestAtStartOfLine_85() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3880, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectObjectCreationExpressionTerms", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectObjectCreationExpressionTerms", "expression.Kind"], terms); } [Fact] @@ -1025,7 +1025,7 @@ public void TestAtStartOfLine_86() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3988, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectObjectCreationExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectObjectCreationExpressionTerms"], terms); } [Fact] @@ -1037,7 +1037,7 @@ public void TestAtStartOfLine_87() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4017, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -1049,7 +1049,7 @@ public void TestAtStartOfLine_88() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4019, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -1061,7 +1061,7 @@ public void TestAtStartOfLine_89() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4077, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectArrayCreationExpressionTerms", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectArrayCreationExpressionTerms", "expression.Kind"], terms); } [Fact] @@ -1073,7 +1073,7 @@ public void TestAtStartOfLine_90() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4184, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectArrayCreationExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectArrayCreationExpressionTerms"], terms); } [Fact] @@ -1085,7 +1085,7 @@ public void TestAtStartOfLine_91() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4213, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -1097,7 +1097,7 @@ public void TestAtStartOfLine_92() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4215, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -1109,7 +1109,7 @@ public void TestAtStartOfLine_93() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4270, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectInvocationExpressionTerms", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectInvocationExpressionTerms", "expression.Kind"], terms); } [Fact] @@ -1121,7 +1121,7 @@ public void TestAtStartOfLine_94() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4374, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectInvocationExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectInvocationExpressionTerms"], terms); } [Fact] @@ -1133,7 +1133,7 @@ public void TestAtStartOfLine_95() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4403, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -1145,7 +1145,7 @@ public void TestAtStartOfLine_96() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4418, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PrefixUnaryExpressionSyntax", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "PrefixUnaryExpressionSyntax", "expression.Kind"], terms); } [Fact] @@ -1157,7 +1157,7 @@ public void TestAtStartOfLine_97() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4420, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PrefixUnaryExpressionSyntax", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "PrefixUnaryExpressionSyntax", "expression.Kind"], terms); } [Fact] @@ -1169,7 +1169,7 @@ public void TestAtStartOfLine_98() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4458, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PrefixUnaryExpressionSyntax", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "PrefixUnaryExpressionSyntax", "expression.Kind"], terms); } [Fact] @@ -1181,7 +1181,7 @@ public void TestAtStartOfLine_99() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4474, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PrefixUnaryExpressionSyntax", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "PrefixUnaryExpressionSyntax", "expression.Kind"], terms); } [Fact] @@ -1193,7 +1193,7 @@ public void TestAtStartOfLine_100() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4571, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PrefixUnaryExpressionSyntax", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "PrefixUnaryExpressionSyntax", "expression.Kind"], terms); } [Fact] @@ -1205,7 +1205,7 @@ public void TestAtStartOfLine_101() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4631, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PrefixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "PrefixUnaryExpressionSyntax"], terms); } [Fact] @@ -1217,7 +1217,7 @@ public void TestAtStartOfLine_102() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4646, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectPrefixUnaryExpressionTerms", "PrefixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectPrefixUnaryExpressionTerms", "PrefixUnaryExpressionSyntax"], terms); } [Fact] @@ -1229,7 +1229,7 @@ public void TestAtStartOfLine_103() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4747, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectPrefixUnaryExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectPrefixUnaryExpressionTerms"], terms); } [Fact] @@ -1252,7 +1252,7 @@ public void TestAtStartOfLine_105() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4787, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PostfixUnaryExpressionSyntax", "PrefixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "PostfixUnaryExpressionSyntax", "PrefixUnaryExpressionSyntax"], terms); } [Fact] @@ -1264,7 +1264,7 @@ public void TestAtStartOfLine_106() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4789, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PostfixUnaryExpressionSyntax", "PrefixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "PostfixUnaryExpressionSyntax", "PrefixUnaryExpressionSyntax"], terms); } [Fact] @@ -1276,7 +1276,7 @@ public void TestAtStartOfLine_107() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4850, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PostfixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "PostfixUnaryExpressionSyntax"], terms); } [Fact] @@ -1288,7 +1288,7 @@ public void TestAtStartOfLine_108() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4865, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectPostfixUnaryExpressionTerms", "PostfixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectPostfixUnaryExpressionTerms", "PostfixUnaryExpressionSyntax"], terms); } [Fact] @@ -1300,7 +1300,7 @@ public void TestAtStartOfLine_109() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4967, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectPostfixUnaryExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectPostfixUnaryExpressionTerms"], terms); } [Fact] @@ -1323,7 +1323,7 @@ public void TestAtStartOfLine_111() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5007, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "BinaryExpressionSyntax", "PostfixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "BinaryExpressionSyntax", "PostfixUnaryExpressionSyntax"], terms); } [Fact] @@ -1335,7 +1335,7 @@ public void TestAtStartOfLine_112() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5009, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "BinaryExpressionSyntax", "PostfixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "BinaryExpressionSyntax", "PostfixUnaryExpressionSyntax"], terms); } [Fact] @@ -1347,7 +1347,7 @@ public void TestAtStartOfLine_113() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5064, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "BinaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "BinaryExpressionSyntax"], terms); } [Fact] @@ -1359,7 +1359,7 @@ public void TestAtStartOfLine_114() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5079, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectBinaryExpressionTerms", "BinaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectBinaryExpressionTerms", "BinaryExpressionSyntax"], terms); } [Fact] @@ -1371,7 +1371,7 @@ public void TestAtStartOfLine_115() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5175, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectBinaryExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectBinaryExpressionTerms"], terms); } [Fact] @@ -1394,7 +1394,7 @@ public void TestAtStartOfLine_117() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5215, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "expression", "BinaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "expression", "BinaryExpressionSyntax"], terms); } [Fact] @@ -1406,7 +1406,7 @@ public void TestAtStartOfLine_118() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5217, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "expression", "BinaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "expression", "BinaryExpressionSyntax"], terms); } [Fact] @@ -1418,7 +1418,7 @@ public void TestAtStartOfLine_119() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5271, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -1452,7 +1452,7 @@ public void TestAtStartOfLine_122() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5447, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -1464,7 +1464,7 @@ public void TestAtStartOfLine_123() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5458, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "flags", "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "flags", "position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -1476,7 +1476,7 @@ public void TestAtStartOfLine_124() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5507, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess" }, terms); + AssertEx.SetEqual(["expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess"], terms); } [Fact] @@ -1488,7 +1488,7 @@ public void TestAtStartOfLine_125() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5509, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess" }, terms); + AssertEx.SetEqual(["expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess"], terms); } [Fact] @@ -1500,7 +1500,7 @@ public void TestAtStartOfLine_126() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5595, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess" }, terms); + AssertEx.SetEqual(["expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess"], terms); } [Fact] @@ -1512,7 +1512,7 @@ public void TestAtStartOfLine_127() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5681, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess" }, terms); + AssertEx.SetEqual(["expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess"], terms); } [Fact] @@ -1524,7 +1524,7 @@ public void TestAtStartOfLine_128() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5753, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess" }, terms); + AssertEx.SetEqual(["expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess"], terms); } [Fact] @@ -1536,7 +1536,7 @@ public void TestAtStartOfLine_129() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5827, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "memberAccess", "memberAccess.Expression", "terms", "flags", "CollectExpressionTerms", "expression", "(MemberAccessExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "memberAccess", "memberAccess.Expression", "terms", "flags", "CollectExpressionTerms", "expression", "(MemberAccessExpressionSyntax)expression"], terms); } [Fact] @@ -1548,7 +1548,7 @@ public void TestAtStartOfLine_130() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5917, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms"], terms); } [Fact] @@ -1560,7 +1560,7 @@ public void TestAtStartOfLine_131() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5919, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms"], terms); } [Fact] @@ -1572,7 +1572,7 @@ public void TestAtStartOfLine_132() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6004, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms"], terms); } [Fact] @@ -1584,7 +1584,7 @@ public void TestAtStartOfLine_133() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6087, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms"], terms); } [Fact] @@ -1596,7 +1596,7 @@ public void TestAtStartOfLine_134() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6158, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms"], terms); } [Fact] @@ -1608,7 +1608,7 @@ public void TestAtStartOfLine_135() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6241, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms"], terms); } [Fact] @@ -1620,7 +1620,7 @@ public void TestAtStartOfLine_136() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6321, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "CollectExpressionTerms"], terms); } [Fact] @@ -1632,7 +1632,7 @@ public void TestAtStartOfLine_137() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6406, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression"], terms); } [Fact] @@ -1644,7 +1644,7 @@ public void TestAtStartOfLine_138() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6421, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "memberAccess", "memberAccess.Expression", "ConvertToString", "ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression" }, terms); + AssertEx.SetEqual(["terms", "memberAccess", "memberAccess.Expression", "ConvertToString", "ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression"], terms); } [Fact] @@ -1656,7 +1656,7 @@ public void TestAtStartOfLine_139() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6491, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "memberAccess", "memberAccess.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["terms", "memberAccess", "memberAccess.Expression", "ConvertToString"], terms); } [Fact] @@ -1668,7 +1668,7 @@ public void TestAtStartOfLine_140() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6506, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString"], terms); } [Fact] @@ -1680,7 +1680,7 @@ public void TestAtStartOfLine_141() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6508, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString"], terms); } [Fact] @@ -1692,7 +1692,7 @@ public void TestAtStartOfLine_142() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6589, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString"], terms); } [Fact] @@ -1704,7 +1704,7 @@ public void TestAtStartOfLine_143() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6654, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString"], terms); } [Fact] @@ -1716,7 +1716,7 @@ public void TestAtStartOfLine_144() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6749, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString"], terms); } [Fact] @@ -1728,7 +1728,7 @@ public void TestAtStartOfLine_145() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6825, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression"], terms); } [Fact] @@ -1740,7 +1740,7 @@ public void TestAtStartOfLine_146() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6840, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "expressionType", "ExpressionType.ValidTerm", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "expressionType", "ExpressionType.ValidTerm", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression"], terms); } [Fact] @@ -1752,7 +1752,7 @@ public void TestAtStartOfLine_147() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6900, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1764,7 +1764,7 @@ public void TestAtStartOfLine_148() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6915, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString"], terms); } [Fact] @@ -1776,7 +1776,7 @@ public void TestAtStartOfLine_149() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6933, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression"], terms); } [Fact] @@ -1788,7 +1788,7 @@ public void TestAtStartOfLine_150() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6948, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "flags", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "flags", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression"], terms); } [Fact] @@ -1800,7 +1800,7 @@ public void TestAtStartOfLine_151() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7014, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression"], terms); } [Fact] @@ -1812,7 +1812,7 @@ public void TestAtStartOfLine_152() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7029, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "expressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "expressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1846,7 +1846,7 @@ public void TestAtStartOfLine_155() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7207, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -1858,7 +1858,7 @@ public void TestAtStartOfLine_156() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7218, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -1870,7 +1870,7 @@ public void TestAtStartOfLine_157() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7304, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -1882,7 +1882,7 @@ public void TestAtStartOfLine_158() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7388, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -1894,7 +1894,7 @@ public void TestAtStartOfLine_159() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7439, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -1906,7 +1906,7 @@ public void TestAtStartOfLine_160() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7493, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(ObjectCreationExpressionSyntax)expression", "ExpressionType", "expressionType", "ExpressionType.Invalid", "objectionCreation" }, terms); + AssertEx.SetEqual(["expression", "(ObjectCreationExpressionSyntax)expression", "ExpressionType", "expressionType", "ExpressionType.Invalid", "objectionCreation"], terms); } [Fact] @@ -1918,7 +1918,7 @@ public void TestAtStartOfLine_161() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7495, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(ObjectCreationExpressionSyntax)expression", "ExpressionType", "expressionType", "ExpressionType.Invalid", "objectionCreation" }, terms); + AssertEx.SetEqual(["expression", "(ObjectCreationExpressionSyntax)expression", "ExpressionType", "expressionType", "ExpressionType.Invalid", "objectionCreation"], terms); } [Fact] @@ -1930,7 +1930,7 @@ public void TestAtStartOfLine_162() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7576, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "objectionCreation", "objectionCreation.ArgumentListOpt", "expression", "(ObjectCreationExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["objectionCreation", "objectionCreation.ArgumentListOpt", "expression", "(ObjectCreationExpressionSyntax)expression"], terms); } [Fact] @@ -1942,7 +1942,7 @@ public void TestAtStartOfLine_163() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7636, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "objectionCreation", "objectionCreation.ArgumentListOpt" }, terms); + AssertEx.SetEqual(["objectionCreation", "objectionCreation.ArgumentListOpt"], terms); } [Fact] @@ -1954,7 +1954,7 @@ public void TestAtStartOfLine_164() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7651, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "objectionCreation", "objectionCreation.ArgumentListOpt", "flags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "objectionCreation", "objectionCreation.ArgumentListOpt", "flags"], terms); } [Fact] @@ -1966,7 +1966,7 @@ public void TestAtStartOfLine_165() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7704, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms", "ExpressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms", "ExpressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -1978,7 +1978,7 @@ public void TestAtStartOfLine_166() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7806, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms"], terms); } [Fact] @@ -1990,7 +1990,7 @@ public void TestAtStartOfLine_167() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7808, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms"], terms); } [Fact] @@ -2002,7 +2002,7 @@ public void TestAtStartOfLine_168() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7891, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms"], terms); } [Fact] @@ -2014,7 +2014,7 @@ public void TestAtStartOfLine_169() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7959, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms"], terms); } [Fact] @@ -2026,7 +2026,7 @@ public void TestAtStartOfLine_170() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8044, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -2038,7 +2038,7 @@ public void TestAtStartOfLine_171() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8063, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "flags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "flags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -2050,7 +2050,7 @@ public void TestAtStartOfLine_172() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8133, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression"], terms); } [Fact] @@ -2062,7 +2062,7 @@ public void TestAtStartOfLine_173() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8152, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "expressionType", "ExpressionType.ValidExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "expressionType", "ExpressionType.ValidExpression"], terms); } [Fact] @@ -2074,7 +2074,7 @@ public void TestAtStartOfLine_174() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8167, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "objectionCreation", "objectionCreation.ArgumentListOpt", "ExpressionType", "expressionType", "ExpressionType.ValidExpression" }, terms); + AssertEx.SetEqual(["objectionCreation", "objectionCreation.ArgumentListOpt", "ExpressionType", "expressionType", "ExpressionType.ValidExpression"], terms); } [Fact] @@ -2108,7 +2108,7 @@ public void TestAtStartOfLine_177() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8344, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -2120,7 +2120,7 @@ public void TestAtStartOfLine_178() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8355, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validTerm", "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["validTerm", "position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -2132,7 +2132,7 @@ public void TestAtStartOfLine_179() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8390, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(ArrayCreationExpressionSyntax)expression", "validTerm", "arrayCreation" }, terms); + AssertEx.SetEqual(["expression", "(ArrayCreationExpressionSyntax)expression", "validTerm", "arrayCreation"], terms); } [Fact] @@ -2144,7 +2144,7 @@ public void TestAtStartOfLine_180() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8466, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arrayCreation", "arrayCreation.InitializerOpt", "expression", "(ArrayCreationExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["arrayCreation", "arrayCreation.InitializerOpt", "expression", "(ArrayCreationExpressionSyntax)expression"], terms); } [Fact] @@ -2156,7 +2156,7 @@ public void TestAtStartOfLine_181() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8468, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arrayCreation", "arrayCreation.InitializerOpt", "expression", "(ArrayCreationExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["arrayCreation", "arrayCreation.InitializerOpt", "expression", "(ArrayCreationExpressionSyntax)expression"], terms); } [Fact] @@ -2168,7 +2168,7 @@ public void TestAtStartOfLine_182() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8523, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arrayCreation", "arrayCreation.InitializerOpt" }, terms); + AssertEx.SetEqual(["arrayCreation", "arrayCreation.InitializerOpt"], terms); } [Fact] @@ -2180,7 +2180,7 @@ public void TestAtStartOfLine_183() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8538, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "arrayCreation", "arrayCreation.InitializerOpt", "flags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "arrayCreation", "arrayCreation.InitializerOpt", "flags"], terms); } [Fact] @@ -2192,7 +2192,7 @@ public void TestAtStartOfLine_184() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8591, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arrayCreation.InitializerOpt.Expressions", "flags", "ExpressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["arrayCreation.InitializerOpt.Expressions", "flags", "ExpressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -2204,7 +2204,7 @@ public void TestAtStartOfLine_185() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8713, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "validTerm", "arrayCreation.InitializerOpt.Expressions" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "validTerm", "arrayCreation.InitializerOpt.Expressions"], terms); } [Fact] @@ -2216,7 +2216,7 @@ public void TestAtStartOfLine_186() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8715, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "validTerm", "arrayCreation.InitializerOpt.Expressions" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "validTerm", "arrayCreation.InitializerOpt.Expressions"], terms); } [Fact] @@ -2228,7 +2228,7 @@ public void TestAtStartOfLine_187() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8809, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "validTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "validTerm"], terms); } [Fact] @@ -2240,7 +2240,7 @@ public void TestAtStartOfLine_188() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8824, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validTerm", "arrayCreation", "arrayCreation.InitializerOpt", "ExpressionType", "flags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["validTerm", "arrayCreation", "arrayCreation.InitializerOpt", "ExpressionType", "flags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -2252,7 +2252,7 @@ public void TestAtStartOfLine_189() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8826, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validTerm", "arrayCreation", "arrayCreation.InitializerOpt", "ExpressionType", "flags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["validTerm", "arrayCreation", "arrayCreation.InitializerOpt", "ExpressionType", "flags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -2264,7 +2264,7 @@ public void TestAtStartOfLine_190() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8854, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validTerm" }, terms); + AssertEx.SetEqual(["validTerm"], terms); } [Fact] @@ -2276,7 +2276,7 @@ public void TestAtStartOfLine_191() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8869, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "validTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "validTerm"], terms); } [Fact] @@ -2288,7 +2288,7 @@ public void TestAtStartOfLine_192() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8935, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression"], terms); } [Fact] @@ -2300,7 +2300,7 @@ public void TestAtStartOfLine_193() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8950, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validTerm", "arrayCreation", "arrayCreation.InitializerOpt", "ExpressionType", "flags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["validTerm", "arrayCreation", "arrayCreation.InitializerOpt", "ExpressionType", "flags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -2312,7 +2312,7 @@ public void TestAtStartOfLine_194() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8968, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validTerm" }, terms); + AssertEx.SetEqual(["validTerm"], terms); } [Fact] @@ -2324,7 +2324,7 @@ public void TestAtStartOfLine_195() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8983, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "validTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "validTerm"], terms); } [Fact] @@ -2336,7 +2336,7 @@ public void TestAtStartOfLine_196() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9041, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -2348,7 +2348,7 @@ public void TestAtStartOfLine_197() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9056, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validTerm", "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["validTerm", "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "ExpressionType.Invalid"], terms); } [Fact] @@ -2382,7 +2382,7 @@ public void TestAtStartOfLine_200() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9230, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -2394,7 +2394,7 @@ public void TestAtStartOfLine_201() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9241, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -2406,7 +2406,7 @@ public void TestAtStartOfLine_202() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9318, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -2418,7 +2418,7 @@ public void TestAtStartOfLine_203() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9355, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -2430,7 +2430,7 @@ public void TestAtStartOfLine_204() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9409, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expressionType", "leftFlags", "rightFlags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expressionType", "leftFlags", "rightFlags"], terms); } [Fact] @@ -2442,7 +2442,7 @@ public void TestAtStartOfLine_205() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9510, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(InvocationExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "invocation" }, terms); + AssertEx.SetEqual(["expression", "(InvocationExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "invocation"], terms); } [Fact] @@ -2454,7 +2454,7 @@ public void TestAtStartOfLine_206() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9512, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(InvocationExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "invocation" }, terms); + AssertEx.SetEqual(["expression", "(InvocationExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "invocation"], terms); } [Fact] @@ -2466,7 +2466,7 @@ public void TestAtStartOfLine_207() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9582, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "invocation", "invocation.Expression", "terms", "leftFlags", "CollectExpressionTerms", "expression", "(InvocationExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "invocation", "invocation.Expression", "terms", "leftFlags", "CollectExpressionTerms", "expression", "(InvocationExpressionSyntax)expression"], terms); } [Fact] @@ -2478,7 +2478,7 @@ public void TestAtStartOfLine_208() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9674, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "invocation", "invocation.ArgumentList", "terms", "rightFlags", "CollectArgumentTerms", "invocation.Expression", "leftFlags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "invocation", "invocation.ArgumentList", "terms", "rightFlags", "CollectArgumentTerms", "invocation.Expression", "leftFlags", "CollectExpressionTerms"], terms); } [Fact] @@ -2490,7 +2490,7 @@ public void TestAtStartOfLine_209() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9767, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "invocation", "invocation.ArgumentList", "terms", "rightFlags", "CollectArgumentTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "invocation", "invocation.ArgumentList", "terms", "rightFlags", "CollectArgumentTerms"], terms); } [Fact] @@ -2502,7 +2502,7 @@ public void TestAtStartOfLine_210() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9769, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "invocation", "invocation.ArgumentList", "terms", "rightFlags", "CollectArgumentTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "invocation", "invocation.ArgumentList", "terms", "rightFlags", "CollectArgumentTerms"], terms); } [Fact] @@ -2514,7 +2514,7 @@ public void TestAtStartOfLine_211() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9854, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "leftFlags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "leftFlags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -2526,7 +2526,7 @@ public void TestAtStartOfLine_212() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9869, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "invocation", "invocation.Expression", "ConvertToString", "ExpressionType", "leftFlags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["terms", "invocation", "invocation.Expression", "ConvertToString", "ExpressionType", "leftFlags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -2538,7 +2538,7 @@ public void TestAtStartOfLine_213() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9937, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "invocation", "invocation.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["terms", "invocation", "invocation.Expression", "ConvertToString"], terms); } [Fact] @@ -2550,7 +2550,7 @@ public void TestAtStartOfLine_214() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9952, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "leftFlags", "rightFlags", "ExpressionType.ValidExpression", "expressionType", "ExpressionType.ValidTerm", "terms", "invocation", "invocation.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["ExpressionType", "leftFlags", "rightFlags", "ExpressionType.ValidExpression", "expressionType", "ExpressionType.ValidTerm", "terms", "invocation", "invocation.Expression", "ConvertToString"], terms); } [Fact] @@ -2562,7 +2562,7 @@ public void TestAtStartOfLine_215() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9954, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "ExpressionType.ValidTerm", "terms", "invocation", "invocation.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "ExpressionType.ValidTerm", "terms", "invocation", "invocation.Expression", "ConvertToString"], terms); } [Fact] @@ -2574,7 +2574,7 @@ public void TestAtStartOfLine_216() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10006, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "ExpressionType.ValidTerm", "terms", "invocation", "invocation.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "ExpressionType.ValidTerm", "terms", "invocation", "invocation.Expression", "ConvertToString"], terms); } [Fact] @@ -2586,7 +2586,7 @@ public void TestAtStartOfLine_217() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10095, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType"], terms); } [Fact] @@ -2620,7 +2620,7 @@ public void TestAtStartOfLine_220() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10270, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -2632,7 +2632,7 @@ public void TestAtStartOfLine_221() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10281, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -2644,7 +2644,7 @@ public void TestAtStartOfLine_222() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10335, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expressionType", "flags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expressionType", "flags"], terms); } [Fact] @@ -2656,7 +2656,7 @@ public void TestAtStartOfLine_223() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10384, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(PrefixUnaryExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "prefixUnaryExpression" }, terms); + AssertEx.SetEqual(["expression", "(PrefixUnaryExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "prefixUnaryExpression"], terms); } [Fact] @@ -2668,7 +2668,7 @@ public void TestAtStartOfLine_224() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10466, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PrefixUnaryExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PrefixUnaryExpressionSyntax)expression"], terms); } [Fact] @@ -2680,7 +2680,7 @@ public void TestAtStartOfLine_225() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10468, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PrefixUnaryExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PrefixUnaryExpressionSyntax)expression"], terms); } [Fact] @@ -2692,7 +2692,7 @@ public void TestAtStartOfLine_226() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10516, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PrefixUnaryExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PrefixUnaryExpressionSyntax)expression"], terms); } [Fact] @@ -2704,7 +2704,7 @@ public void TestAtStartOfLine_227() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10612, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms"], terms); } [Fact] @@ -2716,7 +2716,7 @@ public void TestAtStartOfLine_228() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10614, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms"], terms); } [Fact] @@ -2728,7 +2728,7 @@ public void TestAtStartOfLine_229() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10662, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms"], terms); } [Fact] @@ -2740,7 +2740,7 @@ public void TestAtStartOfLine_230() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10743, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -2752,7 +2752,7 @@ public void TestAtStartOfLine_231() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10758, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["flags", "terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -2764,7 +2764,7 @@ public void TestAtStartOfLine_232() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10834, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString" }, terms); + AssertEx.SetEqual(["terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString"], terms); } [Fact] @@ -2776,7 +2776,7 @@ public void TestAtStartOfLine_233() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10849, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression", "ExpressionType", "ExpressionType.ValidTerm", "terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString" }, terms); + AssertEx.SetEqual(["flags", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression", "ExpressionType", "ExpressionType.ValidTerm", "terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString"], terms); } [Fact] @@ -2788,7 +2788,7 @@ public void TestAtStartOfLine_234() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10851, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression", "ExpressionType", "ExpressionType.ValidTerm", "terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString" }, terms); + AssertEx.SetEqual(["flags", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression", "ExpressionType", "ExpressionType.ValidTerm", "terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString"], terms); } [Fact] @@ -2800,7 +2800,7 @@ public void TestAtStartOfLine_235() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11014, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression" }, terms); + AssertEx.SetEqual(["expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression"], terms); } [Fact] @@ -2812,7 +2812,7 @@ public void TestAtStartOfLine_236() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11029, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expressionType", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expressionType", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression"], terms); } [Fact] @@ -2824,7 +2824,7 @@ public void TestAtStartOfLine_237() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11101, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expressionType", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expressionType", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression"], terms); } [Fact] @@ -2836,7 +2836,7 @@ public void TestAtStartOfLine_238() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11175, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expressionType" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expressionType"], terms); } [Fact] @@ -2848,7 +2848,7 @@ public void TestAtStartOfLine_239() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11190, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression", "ExpressionType", "flags", "ExpressionType.ValidExpression", "expressionType" }, terms); + AssertEx.SetEqual(["expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression", "ExpressionType", "flags", "ExpressionType.ValidExpression", "expressionType"], terms); } [Fact] @@ -2882,7 +2882,7 @@ public void TestAtStartOfLine_242() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11366, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -2894,7 +2894,7 @@ public void TestAtStartOfLine_243() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11377, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -2906,7 +2906,7 @@ public void TestAtStartOfLine_244() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11464, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -2918,7 +2918,7 @@ public void TestAtStartOfLine_245() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11527, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -2930,7 +2930,7 @@ public void TestAtStartOfLine_246() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11581, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expressionType", "flags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expressionType", "flags"], terms); } [Fact] @@ -2942,7 +2942,7 @@ public void TestAtStartOfLine_247() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11583, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expressionType", "flags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expressionType", "flags"], terms); } [Fact] @@ -2954,7 +2954,7 @@ public void TestAtStartOfLine_248() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11632, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(PostfixUnaryExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "postfixUnaryExpression" }, terms); + AssertEx.SetEqual(["expression", "(PostfixUnaryExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "postfixUnaryExpression"], terms); } [Fact] @@ -2966,7 +2966,7 @@ public void TestAtStartOfLine_249() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11716, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PostfixUnaryExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PostfixUnaryExpressionSyntax)expression"], terms); } [Fact] @@ -2978,7 +2978,7 @@ public void TestAtStartOfLine_250() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11718, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PostfixUnaryExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PostfixUnaryExpressionSyntax)expression"], terms); } [Fact] @@ -2990,7 +2990,7 @@ public void TestAtStartOfLine_251() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11766, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PostfixUnaryExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PostfixUnaryExpressionSyntax)expression"], terms); } [Fact] @@ -3002,7 +3002,7 @@ public void TestAtStartOfLine_252() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11863, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms"], terms); } [Fact] @@ -3014,7 +3014,7 @@ public void TestAtStartOfLine_253() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11865, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms"], terms); } [Fact] @@ -3026,7 +3026,7 @@ public void TestAtStartOfLine_254() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11913, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms"], terms); } [Fact] @@ -3038,7 +3038,7 @@ public void TestAtStartOfLine_255() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11994, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -3050,7 +3050,7 @@ public void TestAtStartOfLine_256() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12009, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "terms", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["flags", "terms", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -3062,7 +3062,7 @@ public void TestAtStartOfLine_257() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12086, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "ConvertToString" }, terms); + AssertEx.SetEqual(["terms", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "ConvertToString"], terms); } [Fact] @@ -3074,7 +3074,7 @@ public void TestAtStartOfLine_258() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12101, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "ExpressionType.ValidTerm", "terms", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "ConvertToString" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "ExpressionType.ValidTerm", "terms", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "ConvertToString"], terms); } [Fact] @@ -3108,7 +3108,7 @@ public void TestAtStartOfLine_261() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12271, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -3120,7 +3120,7 @@ public void TestAtStartOfLine_262() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12282, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "leftFlags", "rightFlags", "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "leftFlags", "rightFlags", "position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -3132,7 +3132,7 @@ public void TestAtStartOfLine_263() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12383, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(BinaryExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "binaryExpression" }, terms); + AssertEx.SetEqual(["expression", "(BinaryExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "binaryExpression"], terms); } [Fact] @@ -3144,7 +3144,7 @@ public void TestAtStartOfLine_264() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12385, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(BinaryExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "binaryExpression" }, terms); + AssertEx.SetEqual(["expression", "(BinaryExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "binaryExpression"], terms); } [Fact] @@ -3156,7 +3156,7 @@ public void TestAtStartOfLine_265() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12457, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "binaryExpression", "binaryExpression.Left", "terms", "leftFlags", "CollectExpressionTerms", "expression", "(BinaryExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "binaryExpression", "binaryExpression.Left", "terms", "leftFlags", "CollectExpressionTerms", "expression", "(BinaryExpressionSyntax)expression"], terms); } [Fact] @@ -3168,7 +3168,7 @@ public void TestAtStartOfLine_266() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12549, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "binaryExpression", "binaryExpression.Right", "terms", "rightFlags", "CollectExpressionTerms", "binaryExpression.Left", "leftFlags" }, terms); + AssertEx.SetEqual(["position", "binaryExpression", "binaryExpression.Right", "terms", "rightFlags", "CollectExpressionTerms", "binaryExpression.Left", "leftFlags"], terms); } [Fact] @@ -3180,7 +3180,7 @@ public void TestAtStartOfLine_267() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12643, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "binaryExpression", "binaryExpression.Right", "terms", "rightFlags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "binaryExpression", "binaryExpression.Right", "terms", "rightFlags", "CollectExpressionTerms"], terms); } [Fact] @@ -3192,7 +3192,7 @@ public void TestAtStartOfLine_268() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12645, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "binaryExpression", "binaryExpression.Right", "terms", "rightFlags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "binaryExpression", "binaryExpression.Right", "terms", "rightFlags", "CollectExpressionTerms"], terms); } [Fact] @@ -3204,7 +3204,7 @@ public void TestAtStartOfLine_269() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12730, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "leftFlags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "leftFlags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -3216,7 +3216,7 @@ public void TestAtStartOfLine_270() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12745, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "terms", "binaryExpression", "binaryExpression.Left", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["leftFlags", "terms", "binaryExpression", "binaryExpression.Left", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -3228,7 +3228,7 @@ public void TestAtStartOfLine_271() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12813, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "binaryExpression", "binaryExpression.Left", "ConvertToString" }, terms); + AssertEx.SetEqual(["terms", "binaryExpression", "binaryExpression.Left", "ConvertToString"], terms); } [Fact] @@ -3240,7 +3240,7 @@ public void TestAtStartOfLine_272() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12828, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression", "binaryExpression.Left", "ConvertToString" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression", "binaryExpression.Left", "ConvertToString"], terms); } [Fact] @@ -3252,7 +3252,7 @@ public void TestAtStartOfLine_273() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12830, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression", "binaryExpression.Left", "ConvertToString" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression", "binaryExpression.Left", "ConvertToString"], terms); } [Fact] @@ -3264,7 +3264,7 @@ public void TestAtStartOfLine_274() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12916, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["rightFlags", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -3276,7 +3276,7 @@ public void TestAtStartOfLine_275() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12931, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "terms", "binaryExpression", "binaryExpression.Right", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["rightFlags", "terms", "binaryExpression", "binaryExpression.Right", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -3288,7 +3288,7 @@ public void TestAtStartOfLine_276() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 13000, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "binaryExpression", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["terms", "binaryExpression", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3300,7 +3300,7 @@ public void TestAtStartOfLine_277() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 13015, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3312,7 +3312,7 @@ public void TestAtStartOfLine_278() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 13017, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3324,7 +3324,7 @@ public void TestAtStartOfLine_279() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 13108, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3336,7 +3336,7 @@ public void TestAtStartOfLine_280() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 13188, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3348,7 +3348,7 @@ public void TestAtStartOfLine_281() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 13190, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3360,7 +3360,7 @@ public void TestAtStartOfLine_282() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 13234, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3372,7 +3372,7 @@ public void TestAtStartOfLine_283() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 13249, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3384,7 +3384,7 @@ public void TestAtStartOfLine_284() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 13297, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } // Tests 285-302 removed because they were redundant. @@ -3397,7 +3397,7 @@ public void TestAtStartOfLine_303() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14319, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3409,7 +3409,7 @@ public void TestAtStartOfLine_304() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14372, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "binaryExpression", "binaryExpression.Kind" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "binaryExpression", "binaryExpression.Kind"], terms); } [Fact] @@ -3421,7 +3421,7 @@ public void TestAtStartOfLine_305() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14432, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "binaryExpression", "binaryExpression.Kind" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "binaryExpression", "binaryExpression.Kind"], terms); } [Fact] @@ -3433,7 +3433,7 @@ public void TestAtStartOfLine_306() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14529, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType"], terms); } [Fact] @@ -3445,7 +3445,7 @@ public void TestAtStartOfLine_307() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14558, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3457,7 +3457,7 @@ public void TestAtStartOfLine_308() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14560, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3469,7 +3469,7 @@ public void TestAtStartOfLine_309() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14586, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "binaryExpression", "binaryExpression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "binaryExpression", "binaryExpression.Kind"], terms); } [Fact] @@ -3481,7 +3481,7 @@ public void TestAtStartOfLine_310() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14648, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -3493,7 +3493,7 @@ public void TestAtStartOfLine_311() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14677, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -3505,7 +3505,7 @@ public void TestAtStartOfLine_312() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14692, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "binaryExpression", "binaryExpression.Kind" }, terms); + AssertEx.SetEqual(["binaryExpression", "binaryExpression.Kind"], terms); } [Fact] @@ -3539,7 +3539,7 @@ public void TestAtStartOfLine_315() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14858, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "argumentList", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "argumentList", "terms", "expressionType"], terms); } [Fact] @@ -3551,7 +3551,7 @@ public void TestAtStartOfLine_316() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14869, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validExpr", "position", "argumentList", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["validExpr", "position", "argumentList", "terms", "expressionType"], terms); } [Fact] @@ -3563,7 +3563,7 @@ public void TestAtStartOfLine_317() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14904, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arg", "argumentList", "argumentList.Arguments", "validExpr" }, terms); + AssertEx.SetEqual(["arg", "argumentList", "argumentList.Arguments", "validExpr"], terms); } [Fact] @@ -3575,7 +3575,7 @@ public void TestAtStartOfLine_318() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14906, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arg", "argumentList", "argumentList.Arguments", "validExpr" }, terms); + AssertEx.SetEqual(["arg", "argumentList", "argumentList.Arguments", "validExpr"], terms); } [Fact] @@ -3587,7 +3587,7 @@ public void TestAtStartOfLine_319() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14983, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arg", "argumentList", "argumentList.Arguments", "validExpr" }, terms); + AssertEx.SetEqual(["arg", "argumentList", "argumentList.Arguments", "validExpr"], terms); } [Fact] @@ -3599,7 +3599,7 @@ public void TestAtStartOfLine_320() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15066, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arg", "argumentList", "argumentList.Arguments", "validExpr" }, terms); + AssertEx.SetEqual(["arg", "argumentList", "argumentList.Arguments", "validExpr"], terms); } [Fact] @@ -3611,7 +3611,7 @@ public void TestAtStartOfLine_321() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15123, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arg", "argumentList", "argumentList.Arguments" }, terms); + AssertEx.SetEqual(["arg", "argumentList", "argumentList.Arguments"], terms); } [Fact] @@ -3623,7 +3623,7 @@ public void TestAtStartOfLine_322() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15138, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "arg", "argumentList", "argumentList.Arguments", "flags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "arg", "argumentList", "argumentList.Arguments", "flags"], terms); } [Fact] @@ -3635,7 +3635,7 @@ public void TestAtStartOfLine_323() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15191, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "arg", "arg.Expression", "terms", "flags", "CollectExpressionTerms", "ExpressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["position", "arg", "arg.Expression", "terms", "flags", "CollectExpressionTerms", "ExpressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -3647,7 +3647,7 @@ public void TestAtStartOfLine_324() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15193, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "arg", "arg.Expression", "terms", "flags", "CollectExpressionTerms", "ExpressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["position", "arg", "arg.Expression", "terms", "flags", "CollectExpressionTerms", "ExpressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -3659,7 +3659,7 @@ public void TestAtStartOfLine_325() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15278, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "arg", "arg.Expression", "terms", "flags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "arg", "arg.Expression", "terms", "flags", "CollectExpressionTerms"], terms); } [Fact] @@ -3671,7 +3671,7 @@ public void TestAtStartOfLine_326() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15363, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -3683,7 +3683,7 @@ public void TestAtStartOfLine_327() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15382, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "terms", "arg", "arg.Expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["flags", "terms", "arg", "arg.Expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -3695,7 +3695,7 @@ public void TestAtStartOfLine_328() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15447, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "arg", "arg.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["terms", "arg", "arg.Expression", "ConvertToString"], terms); } [Fact] @@ -3707,7 +3707,7 @@ public void TestAtStartOfLine_329() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15466, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "ExpressionType.ValidExpression", "validExpr", "ExpressionType.ValidTerm", "terms", "arg", "arg.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "ExpressionType.ValidExpression", "validExpr", "ExpressionType.ValidTerm", "terms", "arg", "arg.Expression", "ConvertToString"], terms); } [Fact] @@ -3719,7 +3719,7 @@ public void TestAtStartOfLine_330() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15468, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "ExpressionType.ValidExpression", "validExpr", "ExpressionType.ValidTerm", "terms", "arg", "arg.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "ExpressionType.ValidExpression", "validExpr", "ExpressionType.ValidTerm", "terms", "arg", "arg.Expression", "ConvertToString"], terms); } [Fact] @@ -3731,7 +3731,7 @@ public void TestAtStartOfLine_331() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15574, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "ExpressionType.ValidExpression", "validExpr" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "ExpressionType.ValidExpression", "validExpr"], terms); } [Fact] @@ -3743,7 +3743,7 @@ public void TestAtStartOfLine_332() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15589, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType", "arg", "argumentList", "argumentList.Arguments" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType", "arg", "argumentList", "argumentList.Arguments"], terms); } [Fact] @@ -3755,7 +3755,7 @@ public void TestAtStartOfLine_333() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15591, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType", "arg", "argumentList", "argumentList.Arguments" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType", "arg", "argumentList", "argumentList.Arguments"], terms); } [Fact] @@ -3767,7 +3767,7 @@ public void TestAtStartOfLine_334() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15669, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType", "arg", "argumentList", "argumentList.Arguments" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType", "arg", "argumentList", "argumentList.Arguments"], terms); } [Fact] @@ -3779,7 +3779,7 @@ public void TestAtStartOfLine_335() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15710, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType", "arg", "argumentList", "argumentList.Arguments" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType", "arg", "argumentList", "argumentList.Arguments"], terms); } [Fact] @@ -3791,7 +3791,7 @@ public void TestAtStartOfLine_336() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15788, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType" }, terms); + AssertEx.SetEqual(["ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType"], terms); } [Fact] @@ -3825,7 +3825,7 @@ public void TestAtStartOfLine_339() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15944, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "declarators", "terms" }, terms); + AssertEx.SetEqual(["position", "declarators", "terms"], terms); } [Fact] @@ -3837,7 +3837,7 @@ public void TestAtStartOfLine_340() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15955, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "declarator", "declarators", "position", "terms" }, terms); + AssertEx.SetEqual(["declarator", "declarators", "position", "terms"], terms); } [Fact] @@ -3849,7 +3849,7 @@ public void TestAtStartOfLine_341() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 16008, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "declarator", "declarators" }, terms); + AssertEx.SetEqual(["declarator", "declarators"], terms); } [Fact] @@ -3861,7 +3861,7 @@ public void TestAtStartOfLine_342() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 16023, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "declarator", "declarator.InitializerOpt", "declarators" }, terms); + AssertEx.SetEqual(["declarator", "declarator.InitializerOpt", "declarators"], terms); } [Fact] @@ -3873,7 +3873,7 @@ public void TestAtStartOfLine_343() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 16079, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "declarator", "declarator.InitializerOpt" }, terms); + AssertEx.SetEqual(["declarator", "declarator.InitializerOpt"], terms); } [Fact] @@ -3885,7 +3885,7 @@ public void TestAtStartOfLine_344() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 16098, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "declarator.InitializerOpt", "declarator.InitializerOpt.Value", "terms", "CollectExpressionTerms", "declarator" }, terms); + AssertEx.SetEqual(["position", "declarator.InitializerOpt", "declarator.InitializerOpt.Value", "terms", "CollectExpressionTerms", "declarator"], terms); } [Fact] @@ -3897,7 +3897,7 @@ public void TestAtStartOfLine_345() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 16193, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "declarator.InitializerOpt", "declarator.InitializerOpt.Value", "terms", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "declarator.InitializerOpt", "declarator.InitializerOpt.Value", "terms", "CollectExpressionTerms"], terms); } [Fact] @@ -3909,7 +3909,7 @@ public void TestAtStartOfLine_346() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 16212, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "declarator", "declarator.InitializerOpt", "position", "declarator.InitializerOpt.Value", "terms", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["declarator", "declarator.InitializerOpt", "position", "declarator.InitializerOpt.Value", "terms", "CollectExpressionTerms"], terms); } [Fact] @@ -3921,7 +3921,7 @@ public void TestAtStartOfLine_347() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 16227, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "declarator", "declarators", "position", "declarator.InitializerOpt", "declarator.InitializerOpt.Value", "terms", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["declarator", "declarators", "position", "declarator.InitializerOpt", "declarator.InitializerOpt.Value", "terms", "CollectExpressionTerms"], terms); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.Statements.cs b/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.Statements.cs index 35361c7b5ea35..c0112a88b5c25 100644 --- a/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.Statements.cs +++ b/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.Statements.cs @@ -25,7 +25,7 @@ public void TestAtStartOfStatement_0() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 347, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -39,7 +39,7 @@ public void TestAtStartOfStatement_1() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 422, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -53,7 +53,7 @@ public void TestAtStartOfStatement_2() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 592, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms"], terms); } [Fact] @@ -67,7 +67,7 @@ public void TestAtStartOfStatement_3() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 671, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "position", "terms" }, terms); + AssertEx.SetEqual(["expression", "position", "terms"], terms); } [Fact] @@ -81,7 +81,7 @@ public void TestAtStartOfStatement_4() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 708, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -95,7 +95,7 @@ public void TestAtStartOfStatement_5() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 727, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -109,7 +109,7 @@ public void TestAtStartOfStatement_6() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 908, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expression", "expressionType" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expression", "expressionType"], terms); } [Fact] @@ -123,7 +123,7 @@ public void TestAtStartOfStatement_7() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 966, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectExpressionTerms", "ExpressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectExpressionTerms", "ExpressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -137,7 +137,7 @@ public void TestAtStartOfStatement_8() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1054, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "expression", "terms", "expressionType", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "expression", "terms", "expressionType", "CollectExpressionTerms"], terms); } [Fact] @@ -151,7 +151,7 @@ public void TestAtStartOfStatement_9() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1144, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -165,7 +165,7 @@ public void TestAtStartOfStatement_10() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1282, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "expressionType", "expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["terms", "expressionType", "expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -179,7 +179,7 @@ public void TestAtStartOfStatement_11() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1510, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -193,7 +193,7 @@ public void TestAtStartOfStatement_12() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1589, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "position", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["expression", "position", "terms", "expressionType"], terms); } [Fact] @@ -207,7 +207,7 @@ public void TestAtStartOfStatement_13() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1626, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -221,7 +221,7 @@ public void TestAtStartOfStatement_14() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1645, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression" }, terms); + AssertEx.SetEqual(["expression"], terms); } [Fact] @@ -235,7 +235,7 @@ public void TestAtStartOfStatement_15() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 1683, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "expression.Kind"], terms); } [Fact] @@ -249,7 +249,7 @@ public void TestAtStartOfStatement_16() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2105, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind"], terms); } [Fact] @@ -263,7 +263,7 @@ public void TestAtStartOfStatement_17() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2175, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression"], terms); } [Fact] @@ -277,7 +277,7 @@ public void TestAtStartOfStatement_18() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2313, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidTerm", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidTerm", "expression", "expression.Kind"], terms); } [Fact] @@ -291,7 +291,7 @@ public void TestAtStartOfStatement_19() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2377, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -305,7 +305,7 @@ public void TestAtStartOfStatement_20() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 2985, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "expression", "expression.Kind"], terms); } [Fact] @@ -319,7 +319,7 @@ public void TestAtStartOfStatement_21() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3055, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression"], terms); } [Fact] @@ -333,7 +333,7 @@ public void TestAtStartOfStatement_22() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3423, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "terms", "expressionType", "CollectExpressionTerms", "expression", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "terms", "expressionType", "CollectExpressionTerms", "expression", "expression.Kind"], terms); } [Fact] @@ -347,7 +347,7 @@ public void TestAtStartOfStatement_23() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3552, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "position", "terms", "expressionType", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["expression", "position", "terms", "expressionType", "CollectExpressionTerms"], terms); } [Fact] @@ -361,7 +361,7 @@ public void TestAtStartOfStatement_24() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3704, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectMemberAccessExpressionTerms", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectMemberAccessExpressionTerms", "expression.Kind"], terms); } [Fact] @@ -375,7 +375,7 @@ public void TestAtStartOfStatement_25() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3810, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectMemberAccessExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectMemberAccessExpressionTerms"], terms); } [Fact] @@ -389,7 +389,7 @@ public void TestAtStartOfStatement_26() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 3900, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectObjectCreationExpressionTerms", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectObjectCreationExpressionTerms", "expression.Kind"], terms); } [Fact] @@ -403,7 +403,7 @@ public void TestAtStartOfStatement_27() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4008, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectObjectCreationExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectObjectCreationExpressionTerms"], terms); } [Fact] @@ -417,7 +417,7 @@ public void TestAtStartOfStatement_28() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4097, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectArrayCreationExpressionTerms", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectArrayCreationExpressionTerms", "expression.Kind"], terms); } [Fact] @@ -431,7 +431,7 @@ public void TestAtStartOfStatement_29() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4204, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectArrayCreationExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectArrayCreationExpressionTerms"], terms); } [Fact] @@ -445,7 +445,7 @@ public void TestAtStartOfStatement_30() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4290, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectInvocationExpressionTerms", "expression.Kind" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectInvocationExpressionTerms", "expression.Kind"], terms); } [Fact] @@ -459,7 +459,7 @@ public void TestAtStartOfStatement_31() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4394, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectInvocationExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectInvocationExpressionTerms"], terms); } [Fact] @@ -473,7 +473,7 @@ public void TestAtStartOfStatement_32() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4583, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PrefixUnaryExpressionSyntax", "expression.Kind" }, terms); + AssertEx.SetEqual(["expression", "PrefixUnaryExpressionSyntax", "expression.Kind"], terms); } [Fact] @@ -487,7 +487,7 @@ public void TestAtStartOfStatement_33() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4643, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PrefixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "PrefixUnaryExpressionSyntax"], terms); } [Fact] @@ -501,7 +501,7 @@ public void TestAtStartOfStatement_34() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4662, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectPrefixUnaryExpressionTerms", "PrefixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectPrefixUnaryExpressionTerms", "PrefixUnaryExpressionSyntax"], terms); } [Fact] @@ -515,7 +515,7 @@ public void TestAtStartOfStatement_35() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4763, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectPrefixUnaryExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectPrefixUnaryExpressionTerms"], terms); } [Fact] @@ -529,7 +529,7 @@ public void TestAtStartOfStatement_36() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4801, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PostfixUnaryExpressionSyntax", "PrefixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "PostfixUnaryExpressionSyntax", "PrefixUnaryExpressionSyntax"], terms); } [Fact] @@ -543,7 +543,7 @@ public void TestAtStartOfStatement_37() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4862, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "PostfixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "PostfixUnaryExpressionSyntax"], terms); } [Fact] @@ -557,7 +557,7 @@ public void TestAtStartOfStatement_38() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4881, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectPostfixUnaryExpressionTerms", "PostfixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectPostfixUnaryExpressionTerms", "PostfixUnaryExpressionSyntax"], terms); } [Fact] @@ -571,7 +571,7 @@ public void TestAtStartOfStatement_39() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 4983, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectPostfixUnaryExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectPostfixUnaryExpressionTerms"], terms); } [Fact] @@ -585,7 +585,7 @@ public void TestAtStartOfStatement_40() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5021, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "BinaryExpressionSyntax", "PostfixUnaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "BinaryExpressionSyntax", "PostfixUnaryExpressionSyntax"], terms); } [Fact] @@ -599,7 +599,7 @@ public void TestAtStartOfStatement_41() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5076, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "BinaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["expression", "BinaryExpressionSyntax"], terms); } [Fact] @@ -613,7 +613,7 @@ public void TestAtStartOfStatement_42() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5095, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectBinaryExpressionTerms", "BinaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectBinaryExpressionTerms", "BinaryExpressionSyntax"], terms); } [Fact] @@ -627,7 +627,7 @@ public void TestAtStartOfStatement_43() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5191, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType", "CollectBinaryExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType", "CollectBinaryExpressionTerms"], terms); } [Fact] @@ -641,7 +641,7 @@ public void TestAtStartOfStatement_44() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5229, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "expression", "BinaryExpressionSyntax" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "expression", "BinaryExpressionSyntax"], terms); } [Fact] @@ -655,7 +655,7 @@ public void TestAtStartOfStatement_45() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5455, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -669,7 +669,7 @@ public void TestAtStartOfStatement_46() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5470, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "flags", "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "flags", "position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -683,7 +683,7 @@ public void TestAtStartOfStatement_47() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5765, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess" }, terms); + AssertEx.SetEqual(["expression", "(MemberAccessExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "memberAccess"], terms); } [Fact] @@ -697,7 +697,7 @@ public void TestAtStartOfStatement_48() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 5839, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "memberAccess", "memberAccess.Expression", "terms", "flags", "CollectExpressionTerms", "expression", "(MemberAccessExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "memberAccess", "memberAccess.Expression", "terms", "flags", "CollectExpressionTerms", "expression", "(MemberAccessExpressionSyntax)expression"], terms); } [Fact] @@ -711,7 +711,7 @@ public void TestAtStartOfStatement_49() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6170, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "flags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "position", "memberAccess", "memberAccess.Expression", "terms", "flags", "CollectExpressionTerms"], terms); } [Fact] @@ -725,7 +725,7 @@ public void TestAtStartOfStatement_50() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6418, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression"], terms); } [Fact] @@ -739,7 +739,7 @@ public void TestAtStartOfStatement_51() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6437, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression" }, terms); + AssertEx.SetEqual(["flags", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm", "expression", "SyntaxKind", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression"], terms); } [Fact] @@ -753,7 +753,7 @@ public void TestAtStartOfStatement_52() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6666, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression", "ExpressionType.ValidTerm", "SyntaxKind.MemberAccessExpression", "SyntaxKind.PointerMemberAccessExpression", "terms", "memberAccess", "memberAccess.Expression", "ConvertToString"], terms); } [Fact] @@ -767,7 +767,7 @@ public void TestAtStartOfStatement_53() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6837, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression"], terms); } [Fact] @@ -781,7 +781,7 @@ public void TestAtStartOfStatement_54() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6856, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "expressionType", "ExpressionType.ValidTerm", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "expressionType", "ExpressionType.ValidTerm", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression"], terms); } [Fact] @@ -795,7 +795,7 @@ public void TestAtStartOfStatement_55() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6945, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression"], terms); } [Fact] @@ -809,7 +809,7 @@ public void TestAtStartOfStatement_56() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 6964, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "expressionType", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "expressionType", "ExpressionType.ValidExpression", "expression", "SyntaxKind", "SyntaxKind.InvocationExpression"], terms); } [Fact] @@ -823,7 +823,7 @@ public void TestAtStartOfStatement_57() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7215, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -837,7 +837,7 @@ public void TestAtStartOfStatement_58() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7451, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -851,7 +851,7 @@ public void TestAtStartOfStatement_59() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7507, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(ObjectCreationExpressionSyntax)expression", "ExpressionType", "expressionType", "ExpressionType.Invalid", "objectionCreation" }, terms); + AssertEx.SetEqual(["expression", "(ObjectCreationExpressionSyntax)expression", "ExpressionType", "expressionType", "ExpressionType.Invalid", "objectionCreation"], terms); } [Fact] @@ -865,7 +865,7 @@ public void TestAtStartOfStatement_60() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7588, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "objectionCreation", "objectionCreation.ArgumentListOpt", "expression", "(ObjectCreationExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["objectionCreation", "objectionCreation.ArgumentListOpt", "expression", "(ObjectCreationExpressionSyntax)expression"], terms); } [Fact] @@ -879,7 +879,7 @@ public void TestAtStartOfStatement_61() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7648, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "objectionCreation", "objectionCreation.ArgumentListOpt" }, terms); + AssertEx.SetEqual(["objectionCreation", "objectionCreation.ArgumentListOpt"], terms); } [Fact] @@ -893,7 +893,7 @@ public void TestAtStartOfStatement_62() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7667, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "objectionCreation", "objectionCreation.ArgumentListOpt", "flags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "objectionCreation", "objectionCreation.ArgumentListOpt", "flags"], terms); } [Fact] @@ -907,7 +907,7 @@ public void TestAtStartOfStatement_63() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7720, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms", "ExpressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms", "ExpressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -921,7 +921,7 @@ public void TestAtStartOfStatement_64() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 7975, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "objectionCreation", "objectionCreation.ArgumentListOpt", "terms", "flags", "CollectArgumentTerms"], terms); } [Fact] @@ -935,7 +935,7 @@ public void TestAtStartOfStatement_65() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8060, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -949,7 +949,7 @@ public void TestAtStartOfStatement_66() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8083, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "expressionType", "ExpressionType.ValidExpression", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "expressionType", "ExpressionType.ValidExpression", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -963,7 +963,7 @@ public void TestAtStartOfStatement_67() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8352, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -977,7 +977,7 @@ public void TestAtStartOfStatement_68() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8367, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validTerm", "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["validTerm", "position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -991,7 +991,7 @@ public void TestAtStartOfStatement_69() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8402, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(ArrayCreationExpressionSyntax)expression", "validTerm", "arrayCreation" }, terms); + AssertEx.SetEqual(["expression", "(ArrayCreationExpressionSyntax)expression", "validTerm", "arrayCreation"], terms); } [Fact] @@ -1005,7 +1005,7 @@ public void TestAtStartOfStatement_70() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8480, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arrayCreation", "arrayCreation.InitializerOpt", "expression", "(ArrayCreationExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["arrayCreation", "arrayCreation.InitializerOpt", "expression", "(ArrayCreationExpressionSyntax)expression"], terms); } [Fact] @@ -1019,7 +1019,7 @@ public void TestAtStartOfStatement_71() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8535, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arrayCreation", "arrayCreation.InitializerOpt" }, terms); + AssertEx.SetEqual(["arrayCreation", "arrayCreation.InitializerOpt"], terms); } [Fact] @@ -1033,7 +1033,7 @@ public void TestAtStartOfStatement_72() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8554, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "arrayCreation", "arrayCreation.InitializerOpt", "flags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "arrayCreation", "arrayCreation.InitializerOpt", "flags"], terms); } [Fact] @@ -1047,7 +1047,7 @@ public void TestAtStartOfStatement_73() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8607, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arrayCreation.InitializerOpt.Expressions", "flags", "ExpressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["arrayCreation.InitializerOpt.Expressions", "flags", "ExpressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -1061,7 +1061,7 @@ public void TestAtStartOfStatement_74() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8731, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm", "validTerm", "arrayCreation.InitializerOpt.Expressions" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm", "validTerm", "arrayCreation.InitializerOpt.Expressions"], terms); } [Fact] @@ -1075,7 +1075,7 @@ public void TestAtStartOfStatement_75() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8838, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "validTerm", "arrayCreation", "arrayCreation.InitializerOpt", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["flags", "validTerm", "arrayCreation", "arrayCreation.InitializerOpt", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1089,7 +1089,7 @@ public void TestAtStartOfStatement_76() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8866, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validTerm" }, terms); + AssertEx.SetEqual(["validTerm"], terms); } [Fact] @@ -1103,7 +1103,7 @@ public void TestAtStartOfStatement_77() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8885, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.ValidExpression", "validTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.ValidExpression", "validTerm"], terms); } [Fact] @@ -1117,7 +1117,7 @@ public void TestAtStartOfStatement_78() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8980, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validTerm" }, terms); + AssertEx.SetEqual(["validTerm"], terms); } [Fact] @@ -1131,7 +1131,7 @@ public void TestAtStartOfStatement_79() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 8999, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "validTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "validTerm"], terms); } [Fact] @@ -1145,7 +1145,7 @@ public void TestAtStartOfStatement_80() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9238, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -1159,7 +1159,7 @@ public void TestAtStartOfStatement_81() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9367, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -1173,7 +1173,7 @@ public void TestAtStartOfStatement_82() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9421, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expressionType", "leftFlags", "rightFlags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expressionType", "leftFlags", "rightFlags"], terms); } [Fact] @@ -1187,7 +1187,7 @@ public void TestAtStartOfStatement_83() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9524, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(InvocationExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "invocation" }, terms); + AssertEx.SetEqual(["expression", "(InvocationExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "invocation"], terms); } [Fact] @@ -1201,7 +1201,7 @@ public void TestAtStartOfStatement_84() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9594, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "invocation", "invocation.Expression", "terms", "leftFlags", "CollectExpressionTerms", "expression", "(InvocationExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "invocation", "invocation.Expression", "terms", "leftFlags", "CollectExpressionTerms", "expression", "(InvocationExpressionSyntax)expression"], terms); } [Fact] @@ -1215,7 +1215,7 @@ public void TestAtStartOfStatement_85() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9686, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "invocation", "invocation.ArgumentList", "terms", "rightFlags", "CollectArgumentTerms", "invocation.Expression", "leftFlags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["position", "invocation", "invocation.ArgumentList", "terms", "rightFlags", "CollectArgumentTerms", "invocation.Expression", "leftFlags", "CollectExpressionTerms"], terms); } [Fact] @@ -1229,7 +1229,7 @@ public void TestAtStartOfStatement_86() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9781, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "invocation", "invocation.ArgumentList", "terms", "rightFlags", "CollectArgumentTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "invocation", "invocation.ArgumentList", "terms", "rightFlags", "CollectArgumentTerms"], terms); } [Fact] @@ -1243,7 +1243,7 @@ public void TestAtStartOfStatement_87() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9866, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "leftFlags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "leftFlags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1257,7 +1257,7 @@ public void TestAtStartOfStatement_88() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 9885, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "terms", "invocation", "invocation.Expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["leftFlags", "terms", "invocation", "invocation.Expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1271,7 +1271,7 @@ public void TestAtStartOfStatement_89() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10018, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "ExpressionType.ValidTerm", "terms", "invocation", "invocation.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "ExpressionType.ValidTerm", "terms", "invocation", "invocation.Expression", "ConvertToString"], terms); } [Fact] @@ -1285,7 +1285,7 @@ public void TestAtStartOfStatement_90() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10278, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -1299,7 +1299,7 @@ public void TestAtStartOfStatement_91() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10293, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -1313,7 +1313,7 @@ public void TestAtStartOfStatement_92() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10347, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expressionType", "flags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expressionType", "flags"], terms); } [Fact] @@ -1327,7 +1327,7 @@ public void TestAtStartOfStatement_93() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10396, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(PrefixUnaryExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "prefixUnaryExpression" }, terms); + AssertEx.SetEqual(["expression", "(PrefixUnaryExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "prefixUnaryExpression"], terms); } [Fact] @@ -1341,7 +1341,7 @@ public void TestAtStartOfStatement_94() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10528, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PrefixUnaryExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PrefixUnaryExpressionSyntax)expression"], terms); } [Fact] @@ -1355,7 +1355,7 @@ public void TestAtStartOfStatement_95() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10674, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms"], terms); } [Fact] @@ -1369,7 +1369,7 @@ public void TestAtStartOfStatement_96() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10755, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1383,7 +1383,7 @@ public void TestAtStartOfStatement_97() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10774, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["flags", "terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1397,7 +1397,7 @@ public void TestAtStartOfStatement_98() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 10863, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression", "ExpressionType", "ExpressionType.ValidTerm", "terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString" }, terms); + AssertEx.SetEqual(["flags", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression", "ExpressionType", "ExpressionType.ValidTerm", "terms", "prefixUnaryExpression", "prefixUnaryExpression.Operand", "ConvertToString"], terms); } [Fact] @@ -1411,7 +1411,7 @@ public void TestAtStartOfStatement_99() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11026, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression" }, terms); + AssertEx.SetEqual(["expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression"], terms); } [Fact] @@ -1425,7 +1425,7 @@ public void TestAtStartOfStatement_100() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11117, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "expression", "SyntaxKind", "SyntaxKind.LogicalNotExpression", "SyntaxKind.BitwiseNotExpression", "SyntaxKind.NegateExpression", "SyntaxKind.PlusExpression"], terms); } [Fact] @@ -1439,7 +1439,7 @@ public void TestAtStartOfStatement_101() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11374, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -1453,7 +1453,7 @@ public void TestAtStartOfStatement_102() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11539, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "position", "expression", "terms"], terms); } [Fact] @@ -1467,7 +1467,7 @@ public void TestAtStartOfStatement_103() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11595, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "expressionType", "flags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "expressionType", "flags"], terms); } [Fact] @@ -1481,7 +1481,7 @@ public void TestAtStartOfStatement_104() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11644, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(PostfixUnaryExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "postfixUnaryExpression" }, terms); + AssertEx.SetEqual(["expression", "(PostfixUnaryExpressionSyntax)expression", "flags", "ExpressionType", "ExpressionType.Invalid", "postfixUnaryExpression"], terms); } [Fact] @@ -1495,7 +1495,7 @@ public void TestAtStartOfStatement_105() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11778, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PostfixUnaryExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms", "expression", "(PostfixUnaryExpressionSyntax)expression"], terms); } [Fact] @@ -1509,7 +1509,7 @@ public void TestAtStartOfStatement_106() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 11925, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "terms", "flags", "CollectExpressionTerms"], terms); } [Fact] @@ -1523,7 +1523,7 @@ public void TestAtStartOfStatement_107() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12006, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1537,7 +1537,7 @@ public void TestAtStartOfStatement_108() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12025, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "terms", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["flags", "terms", "postfixUnaryExpression", "postfixUnaryExpression.Operand", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1551,7 +1551,7 @@ public void TestAtStartOfStatement_109() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12279, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -1565,7 +1565,7 @@ public void TestAtStartOfStatement_110() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12294, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "leftFlags", "rightFlags", "position", "expression", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "leftFlags", "rightFlags", "position", "expression", "terms", "expressionType"], terms); } [Fact] @@ -1579,7 +1579,7 @@ public void TestAtStartOfStatement_111() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12397, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "expression", "(BinaryExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "binaryExpression" }, terms); + AssertEx.SetEqual(["expression", "(BinaryExpressionSyntax)expression", "leftFlags", "ExpressionType", "ExpressionType.Invalid", "rightFlags", "binaryExpression"], terms); } [Fact] @@ -1593,7 +1593,7 @@ public void TestAtStartOfStatement_112() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12469, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "binaryExpression", "binaryExpression.Left", "terms", "leftFlags", "CollectExpressionTerms", "expression", "(BinaryExpressionSyntax)expression" }, terms); + AssertEx.SetEqual(["position", "binaryExpression", "binaryExpression.Left", "terms", "leftFlags", "CollectExpressionTerms", "expression", "(BinaryExpressionSyntax)expression"], terms); } [Fact] @@ -1607,7 +1607,7 @@ public void TestAtStartOfStatement_113() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12561, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "binaryExpression", "binaryExpression.Right", "terms", "rightFlags", "CollectExpressionTerms", "binaryExpression.Left", "leftFlags" }, terms); + AssertEx.SetEqual(["position", "binaryExpression", "binaryExpression.Right", "terms", "rightFlags", "CollectExpressionTerms", "binaryExpression.Left", "leftFlags"], terms); } [Fact] @@ -1621,7 +1621,7 @@ public void TestAtStartOfStatement_114() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12657, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "binaryExpression", "binaryExpression.Right", "terms", "rightFlags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "leftFlags", "ExpressionType.ValidTerm", "position", "binaryExpression", "binaryExpression.Right", "terms", "rightFlags", "CollectExpressionTerms"], terms); } [Fact] @@ -1635,7 +1635,7 @@ public void TestAtStartOfStatement_115() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12742, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "leftFlags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "leftFlags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1649,7 +1649,7 @@ public void TestAtStartOfStatement_116() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12761, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "terms", "binaryExpression", "binaryExpression.Left", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["leftFlags", "terms", "binaryExpression", "binaryExpression.Left", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1663,7 +1663,7 @@ public void TestAtStartOfStatement_117() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12842, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression", "binaryExpression.Left", "ConvertToString" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression", "binaryExpression.Left", "ConvertToString"], terms); } [Fact] @@ -1677,7 +1677,7 @@ public void TestAtStartOfStatement_118() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12928, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["rightFlags", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1691,7 +1691,7 @@ public void TestAtStartOfStatement_119() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 12947, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "terms", "rightFlags", "binaryExpression", "binaryExpression.Right", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["terms", "rightFlags", "binaryExpression", "binaryExpression.Right", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1705,7 +1705,7 @@ public void TestAtStartOfStatement_120() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 13202, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString" }, terms); + AssertEx.SetEqual(["rightFlags", "binaryExpression", "binaryExpression.Kind", "ExpressionType", "ExpressionType.ValidTerm", "terms", "binaryExpression.Right", "ConvertToString"], terms); } [Fact] @@ -1719,7 +1719,7 @@ public void TestAtStartOfStatement_121() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14452, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "binaryExpression", "binaryExpression.Kind" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType", "binaryExpression", "binaryExpression.Kind"], terms); } [Fact] @@ -1733,7 +1733,7 @@ public void TestAtStartOfStatement_122() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14549, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType" }, terms); + AssertEx.SetEqual(["leftFlags", "rightFlags", "ExpressionType", "ExpressionType.ValidExpression", "expressionType"], terms); } [Fact] @@ -1747,7 +1747,7 @@ public void TestAtStartOfStatement_123() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14606, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid", "binaryExpression", "binaryExpression.Kind" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid", "binaryExpression", "binaryExpression.Kind"], terms); } [Fact] @@ -1761,7 +1761,7 @@ public void TestAtStartOfStatement_124() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14668, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "expressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["ExpressionType", "expressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -1775,7 +1775,7 @@ public void TestAtStartOfStatement_125() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14866, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "argumentList", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["position", "argumentList", "terms", "expressionType"], terms); } [Fact] @@ -1789,7 +1789,7 @@ public void TestAtStartOfStatement_126() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 14881, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "validExpr", "position", "argumentList", "terms", "expressionType" }, terms); + AssertEx.SetEqual(["validExpr", "position", "argumentList", "terms", "expressionType"], terms); } [Fact] @@ -1803,7 +1803,7 @@ public void TestAtStartOfStatement_127() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15078, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arg", "argumentList", "argumentList.Arguments", "validExpr" }, terms); + AssertEx.SetEqual(["arg", "argumentList", "argumentList.Arguments", "validExpr"], terms); } [Fact] @@ -1817,7 +1817,7 @@ public void TestAtStartOfStatement_128() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15135, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "arg", "argumentList", "argumentList.Arguments" }, terms); + AssertEx.SetEqual(["arg", "argumentList", "argumentList.Arguments"], terms); } [Fact] @@ -1831,7 +1831,7 @@ public void TestAtStartOfStatement_129() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15154, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.Invalid", "arg", "argumentList", "argumentList.Arguments", "flags" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.Invalid", "arg", "argumentList", "argumentList.Arguments", "flags"], terms); } [Fact] @@ -1845,7 +1845,7 @@ public void TestAtStartOfStatement_130() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15209, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "arg", "arg.Expression", "terms", "flags", "CollectExpressionTerms", "ExpressionType", "ExpressionType.Invalid" }, terms); + AssertEx.SetEqual(["position", "arg", "arg.Expression", "terms", "flags", "CollectExpressionTerms", "ExpressionType", "ExpressionType.Invalid"], terms); } [Fact] @@ -1859,7 +1859,7 @@ public void TestAtStartOfStatement_131() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15294, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "ExpressionType.ValidTerm", "position", "arg", "arg.Expression", "terms", "flags", "CollectExpressionTerms" }, terms); + AssertEx.SetEqual(["ExpressionType", "ExpressionType.ValidTerm", "position", "arg", "arg.Expression", "terms", "flags", "CollectExpressionTerms"], terms); } [Fact] @@ -1873,7 +1873,7 @@ public void TestAtStartOfStatement_132() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15379, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1887,7 +1887,7 @@ public void TestAtStartOfStatement_133() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15402, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "terms", "arg", "arg.Expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm" }, terms); + AssertEx.SetEqual(["flags", "terms", "arg", "arg.Expression", "ConvertToString", "ExpressionType", "ExpressionType.ValidTerm"], terms); } [Fact] @@ -1901,7 +1901,7 @@ public void TestAtStartOfStatement_134() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15484, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "ExpressionType", "flags", "ExpressionType.ValidExpression", "validExpr", "ExpressionType.ValidTerm", "terms", "arg", "arg.Expression", "ConvertToString" }, terms); + AssertEx.SetEqual(["ExpressionType", "flags", "ExpressionType.ValidExpression", "validExpr", "ExpressionType.ValidTerm", "terms", "arg", "arg.Expression", "ConvertToString"], terms); } [Fact] @@ -1915,7 +1915,7 @@ public void TestAtStartOfStatement_135() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15722, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "flags", "ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType", "arg", "argumentList", "argumentList.Arguments" }, terms); + AssertEx.SetEqual(["flags", "ExpressionType", "validExpr", "ExpressionType.ValidExpression", "expressionType", "arg", "argumentList", "argumentList.Arguments"], terms); } [Fact] @@ -1929,7 +1929,7 @@ public void TestAtStartOfStatement_136() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15952, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "declarators", "terms" }, terms); + AssertEx.SetEqual(["position", "declarators", "terms"], terms); } [Fact] @@ -1943,7 +1943,7 @@ public void TestAtStartOfStatement_137() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 15967, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "declarator", "declarators", "position", "terms" }, terms); + AssertEx.SetEqual(["declarator", "declarators", "position", "terms"], terms); } [Fact] @@ -1957,7 +1957,7 @@ public void TestAtStartOfStatement_138() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 16020, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "declarator", "declarators" }, terms); + AssertEx.SetEqual(["declarator", "declarators"], terms); } [Fact] @@ -1971,7 +1971,7 @@ public void TestAtStartOfStatement_139() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 16039, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "declarator", "declarator.InitializerOpt", "declarators" }, terms); + AssertEx.SetEqual(["declarator", "declarator.InitializerOpt", "declarators"], terms); } [Fact] @@ -1985,7 +1985,7 @@ public void TestAtStartOfStatement_140() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 16095, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "declarator", "declarator.InitializerOpt" }, terms); + AssertEx.SetEqual(["declarator", "declarator.InitializerOpt"], terms); } [Fact] @@ -1999,6 +1999,6 @@ public void TestAtStartOfStatement_141() var tree = GetTree(); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 16118, cancellationToken: default); Assert.NotNull(terms); - AssertEx.SetEqual(new[] { "position", "declarator.InitializerOpt", "declarator.InitializerOpt.Value", "terms", "CollectExpressionTerms", "declarator" }, terms); + AssertEx.SetEqual(["position", "declarator.InitializerOpt", "declarator.InitializerOpt.Value", "terms", "CollectExpressionTerms", "declarator"], terms); } } diff --git a/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.cs b/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.cs index 6ae55e2951ca7..fc906ca80093e 100644 --- a/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.cs +++ b/src/EditorFeatures/CSharpTest/Debugging/ProximityExpressionsGetterTests.cs @@ -61,7 +61,7 @@ static void Main(string[] args) }"); var terms = CSharpProximityExpressionsService.GetProximityExpressions(tree, 245, cancellationToken: default); Assert.NotNull(terms); - AssertEx.Equal(new[] { "yy", "xx" }, terms); + AssertEx.Equal((string[])["yy", "xx"], terms); } private static async Task TestProximityExpressionGetterAsync( diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs index 94eda2b4424d4..c4f33d130bbb8 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs @@ -56,7 +56,7 @@ public async Task DiagnosticAnalyzerDriverAllInOne() using var workspace = EditorTestWorkspace.CreateCSharp(source, TestOptions.Regular, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService); var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); - var newSolution = workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference }) + var newSolution = workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference]) .Projects.Single().AddAdditionalDocument(name: "dummy.txt", text: "", filePath: "dummy.txt").Project.Solution; workspace.TryApplyChanges(newSolution); @@ -87,7 +87,7 @@ class C using (var ideEngineWorkspace = EditorTestWorkspace.CreateCSharp(source, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService)) { var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(ideEngineAnalyzer)); - ideEngineWorkspace.TryApplyChanges(ideEngineWorkspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + ideEngineWorkspace.TryApplyChanges(ideEngineWorkspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var ideEngineDocument = ideEngineWorkspace.CurrentSolution.Projects.Single().Documents.Single(); await DiagnosticProviderTestUtilities.GetAllDiagnosticsAsync(ideEngineWorkspace, ideEngineDocument, new TextSpan(0, ideEngineDocument.GetTextAsync().Result.Length)); @@ -103,7 +103,7 @@ class C var compilerEngineAnalyzer = new CSharpTrackingDiagnosticAnalyzer(); using var compilerEngineWorkspace = EditorTestWorkspace.CreateCSharp(source, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService); var compilerEngineCompilation = (CSharpCompilation)compilerEngineWorkspace.CurrentSolution.Projects.Single().GetRequiredCompilationAsync(CancellationToken.None).Result; - compilerEngineCompilation.GetAnalyzerDiagnostics(new[] { compilerEngineAnalyzer }); + compilerEngineCompilation.GetAnalyzerDiagnostics([compilerEngineAnalyzer]); foreach (var method in methodNames) { Assert.False(compilerEngineAnalyzer.CallLog.Any(e => e.CallerName == method && e.MethodKind == MethodKind.DelegateInvoke && e.ReturnsVoid)); @@ -123,7 +123,7 @@ await ThrowingDiagnosticAnalyzer.VerifyAnalyzerEngineIsSafeAgainstEx using var workspace = EditorTestWorkspace.CreateCSharp(source, TestOptions.Regular, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService); var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var document = workspace.CurrentSolution.Projects.Single().Documents.Single(); return await DiagnosticProviderTestUtilities.GetAllDiagnosticsAsync(workspace, document, new TextSpan(0, document.GetTextAsync().Result.Length)); @@ -168,7 +168,7 @@ public async Task AnalyzerOptionsArePassedToAllAnalyzers() var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); workspace.TryApplyChanges(workspace.CurrentSolution - .WithAnalyzerReferences(new[] { analyzerReference }) + .WithAnalyzerReferences([analyzerReference]) .AddAdditionalDocument(additionalDocId, "add.config", additionalText.GetText()!)); var sourceDocument = workspace.CurrentSolution.Projects.Single().Documents.Single(); @@ -178,7 +178,7 @@ public async Task AnalyzerOptionsArePassedToAllAnalyzers() private static void AccessSupportedDiagnostics(DiagnosticAnalyzer analyzer) { - var diagnosticService = new HostDiagnosticAnalyzers(new[] { new AnalyzerImageReference(ImmutableArray.Create(analyzer)) }); + var diagnosticService = new HostDiagnosticAnalyzers([new AnalyzerImageReference(ImmutableArray.Create(analyzer))]); diagnosticService.GetDiagnosticDescriptorsPerReference(new DiagnosticAnalyzerInfoCache()); } @@ -199,7 +199,7 @@ public async Task AnalyzerCreatedAtCompilationLevelNeedNotBeCompilationAnalyzer( var analyzer = new CompilationAnalyzerWithSyntaxTreeAnalyzer(); var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var ideEngineDocument = workspace.CurrentSolution.Projects.Single().Documents.Single(); var diagnostics = await DiagnosticProviderTestUtilities.GetAllDiagnosticsAsync(workspace, ideEngineDocument, new TextSpan(0, ideEngineDocument.GetTextAsync().Result.Length)); @@ -255,7 +255,7 @@ void F(int x = 0) using (var ideEngineWorkspace = EditorTestWorkspace.CreateCSharp(source, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService)) { var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); - ideEngineWorkspace.TryApplyChanges(ideEngineWorkspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + ideEngineWorkspace.TryApplyChanges(ideEngineWorkspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var ideEngineDocument = ideEngineWorkspace.CurrentSolution.Projects.Single().Documents.Single(); var diagnostics = await DiagnosticProviderTestUtilities.GetAllDiagnosticsAsync(ideEngineWorkspace, ideEngineDocument, new TextSpan(0, ideEngineDocument.GetTextAsync().Result.Length)); @@ -277,7 +277,7 @@ void F(int x = 0, int y = 1, int z = 2) using (var compilerEngineWorkspace = EditorTestWorkspace.CreateCSharp(source, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService)) { var compilerEngineCompilation = (CSharpCompilation)compilerEngineWorkspace.CurrentSolution.Projects.Single().GetRequiredCompilationAsync(CancellationToken.None).Result; - var diagnostics = compilerEngineCompilation.GetAnalyzerDiagnostics(new[] { analyzer }); + var diagnostics = compilerEngineCompilation.GetAnalyzerDiagnostics([analyzer]); var diagnosticsFromAnalyzer = diagnostics.Where(d => d.Id == CodeBlockAnalyzerFactory.Descriptor.Id); Assert.Equal(4, diagnosticsFromAnalyzer.Count()); } @@ -337,7 +337,7 @@ public async Task TestDiagnosticSpan() using var compilerEngineWorkspace = EditorTestWorkspace.CreateCSharp(source); var compilerEngineCompilation = (CSharpCompilation)(await compilerEngineWorkspace.CurrentSolution.Projects.Single().GetRequiredCompilationAsync(CancellationToken.None)); - var diagnostics = compilerEngineCompilation.GetAnalyzerDiagnostics(new[] { analyzer }); + var diagnostics = compilerEngineCompilation.GetAnalyzerDiagnostics([analyzer]); AssertEx.Any(diagnostics, d => d.Id == DocumentAnalysisExecutor.AnalyzerExceptionDiagnosticId); } @@ -771,10 +771,10 @@ private static async Task TestNuGetAndVsixAnalyzerCoreAsync( var vsixAnalyzerReferences = new List(vsixAnalyzers.CastArray()); vsixAnalyzerReferences.AddRange(vsixSuppressors.CastArray()); - Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] - { + Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences( + [ new AnalyzerImageReference(vsixAnalyzerReferences.ToImmutableArray()) - }))); + ]))); var project = workspace.CurrentSolution.Projects.Single(); @@ -791,7 +791,7 @@ private static async Task TestNuGetAndVsixAnalyzerCoreAsync( if (nugetAnalyzerReferences.Count > 0) { - project = project.WithAnalyzerReferences(new[] { new AnalyzerImageReference(nugetAnalyzerReferences.ToImmutableArray()) }); + project = project.WithAnalyzerReferences([new AnalyzerImageReference(nugetAnalyzerReferences.ToImmutableArray())]); } var document = project.Documents.Single(); diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs index c900f79ec295d..f8849caff44b1 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs @@ -54,7 +54,7 @@ public async Task TrackingService_GetLatestSpansAsync(bool scheduleInitialTracki var testDocument1 = new EditorTestHostDocument(text: source1, displayName: "1.cs", exportProvider: workspace.ExportProvider, filePath: "1.cs"); var testDocument2 = new EditorTestHostDocument(text: source2, displayName: "2.cs", exportProvider: workspace.ExportProvider, filePath: "2.cs"); - workspace.AddTestProject(new EditorTestHostProject(workspace, documents: new[] { testDocument1, testDocument2 })); + workspace.AddTestProject(new EditorTestHostProject(workspace, documents: [testDocument1, testDocument2])); // opens the documents var textBuffer1 = testDocument1.GetTextBuffer(); @@ -76,25 +76,25 @@ public async Task TrackingService_GetLatestSpansAsync(bool scheduleInitialTracki await trackingSession.TrackActiveSpansAsync(solution); var spans1 = trackingSession.Test_GetTrackingSpans(); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"V0 →←@[10..15): NonLeafFrame", $"V0 →←@[20..25): LeafFrame" - }, spans1[document1.FilePath].Select(s => $"{s.Span}: {s.Flags}")); + ], spans1[document1.FilePath].Select(s => $"{s.Span}: {s.Flags}")); var spans2 = await trackingSession.GetSpansAsync(solution, document1.Id, document1.FilePath, CancellationToken.None); - AssertEx.Equal(new[] { "(0,10)-(0,15)", "(0,20)-(0,25)" }, spans2.Select(s => s.LineSpan.ToString())); + AssertEx.Equal(["(0,10)-(0,15)", "(0,20)-(0,25)"], spans2.Select(s => s.LineSpan.ToString())); var spans3 = await trackingSession.GetSpansAsync(solution, document2.Id, document2.FilePath, CancellationToken.None); Assert.Empty(spans3); } var spans4 = await trackingSession.GetAdjustedTrackingSpansAsync(document1, snapshot1, CancellationToken.None); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"V0 →←@[11..16): NonLeafFrame", $"V0 →←@[21..26): LeafFrame" - }, spans4.Select(s => $"{s.Span}: {s.Flags}")); + ], spans4.Select(s => $"{s.Span}: {s.Flags}")); AssertEx.Empty(await trackingSession.GetAdjustedTrackingSpansAsync(document2, snapshot2, CancellationToken.None)); @@ -103,21 +103,21 @@ public async Task TrackingService_GetLatestSpansAsync(bool scheduleInitialTracki await trackingSession.TrackActiveSpansAsync(solution); var spans5 = trackingSession.Test_GetTrackingSpans(); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"V0 →←@[11..16): NonLeafFrame", $"V0 →←@[21..26): LeafFrame" - }, spans5[document1.FilePath].Select(s => $"{s.Span}: {s.Flags}")); + ], spans5[document1.FilePath].Select(s => $"{s.Span}: {s.Flags}")); } // we are not able to determine active statements in a document: spanProvider.GetAdjustedActiveStatementSpansImpl = (_, _) => ImmutableArray.Empty; var spans6 = await trackingSession.GetAdjustedTrackingSpansAsync(document1, snapshot1, CancellationToken.None); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"V0 →←@[11..16): NonLeafFrame", $"V0 →←@[21..26): LeafFrame" - }, spans6.Select(s => $"{s.Span}: {s.Flags}")); + ], spans6.Select(s => $"{s.Span}: {s.Flags}")); } } diff --git a/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs index fe9b9ffa0305d..a8c549930d700 100644 --- a/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs +++ b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs @@ -333,7 +333,7 @@ public async Task TestAnalyzerSettingsUpdaterService() var analyzerSetting = new AnalyzerSetting(descriptor, ReportDiagnostic.Suppress, updater, Language.CSharp, new SettingLocation(EditorConfigSettings.LocationKind.VisualStudio, null)); analyzerSetting.ChangeSeverity(ReportDiagnostic.Error); var updates = await updater.GetChangedEditorConfigAsync(default); - var update = Assert.Single(updates); + var update = AssertEx.Single(updates); Assert.Equal($"[*.cs]\r\ndotnet_diagnostic.{id}.severity = error", update.NewText); } @@ -356,7 +356,7 @@ public async Task TestCodeStyleSettingUpdaterService() var setting = CodeStyleSetting.Create(CSharpCodeStyleOptions.AllowBlankLineAfterColonInConstructorInitializer, "description", options, updater); setting.ChangeSeverity(ReportDiagnostic.Error); var updates = await updater.GetChangedEditorConfigAsync(default); - var update = Assert.Single(updates); + var update = AssertEx.Single(updates); Assert.Equal("[*.cs]\r\ncsharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false:error", update.NewText); value = "false:error"; @@ -369,7 +369,7 @@ public async Task TestCodeStyleSettingUpdaterService() setting.ChangeValue(0); updates = await updater.GetChangedEditorConfigAsync(default); - update = Assert.Single(updates); + update = AssertEx.Single(updates); Assert.Equal("[*.cs]\r\ncsharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:error", update.NewText); } @@ -389,7 +389,7 @@ public async Task TestWhitespaceSettingUpdaterService() var setting = Setting.Create(CSharpFormattingOptions2.NewLineForElse, "description", options, updater); setting.SetValue(false); var updates = await updater.GetChangedEditorConfigAsync(default); - var update = Assert.Single(updates); + var update = AssertEx.Single(updates); Assert.Equal("[*.cs]\r\ncsharp_new_line_before_else = false", update.NewText); } diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs index c370c7cf0e1e5..01ff3aaa94105 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs @@ -120,8 +120,8 @@ protected static async Task ExtractMethodAsync( var options = new ExtractMethodGenerationOptions() { - CodeGenerationOptions = CodeGenerationOptions.GetDefault(document.Project.Services), - CodeCleanupOptions = CodeCleanupOptions.GetDefault(document.Project.Services), + CodeGenerationOptions = CodeGenerationOptionsProviders.GetDefault(document.Project.Services), + CodeCleanupOptions = await document.GetCodeCleanupOptionsAsync(CancellationToken.None), }; var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None); diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs index 6b59deb117a8e..58490388c89cc 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs @@ -11214,7 +11214,7 @@ public async Task ExtractMethod_Argument2() var projectId = ProjectId.CreateNewId(); var project = solution.AddProject(projectId, "Project", "Project.dll", LanguageNames.CSharp).GetProject(projectId); - var document = project.AddMetadataReference(TestMetadata.Net451.mscorlib) + var document = project.AddMetadataReference(NetFramework.mscorlib) .AddDocument("Document", SourceText.From("")); var service = new CSharpExtractMethodService() as IExtractMethodService; diff --git a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs index df7f3b889c6ed..e17ddcc4dd94c 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs @@ -795,8 +795,6 @@ private static async Task TestThirdPartyCodeFixer(string co using var workspace = EditorTestWorkspace.CreateCSharp(code, composition: EditorTestCompositions.EditorFeaturesWpf.AddParts(typeof(TCodefix))); - var options = CodeActionOptions.DefaultProvider; - var project = workspace.CurrentSolution.Projects.Single(); var analyzer = (DiagnosticAnalyzer)new TAnalyzer(); var diagnosticIds = analyzer.SupportedDiagnostics.SelectAsArray(d => d.Id); @@ -824,7 +822,7 @@ private static async Task TestThirdPartyCodeFixer(string co var enabledDiagnostics = codeCleanupService.GetAllDiagnostics(); var newDoc = await codeCleanupService.CleanupAsync( - document, enabledDiagnostics, CodeAnalysisProgress.None, options, CancellationToken.None); + document, enabledDiagnostics, CodeAnalysisProgress.None, CancellationToken.None); var actual = await newDoc.GetTextAsync(); Assert.Equal(expected, actual.ToString()); @@ -894,11 +892,11 @@ private protected static async Task AssertCodeCleanupResult(string expected, str { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, preferredImportPlacement }, }); - var solution = workspace.CurrentSolution.WithAnalyzerReferences(new[] - { + var solution = workspace.CurrentSolution.WithAnalyzerReferences( + [ new AnalyzerFileReference(typeof(CSharpCompilerDiagnosticAnalyzer).Assembly.Location, TestAnalyzerAssemblyLoader.LoadFromFile), new AnalyzerFileReference(typeof(UseExpressionBodyDiagnosticAnalyzer).Assembly.Location, TestAnalyzerAssemblyLoader.LoadFromFile) - }); + ]); if (diagnosticIdsWithSeverity != null) { @@ -926,7 +924,7 @@ private protected static async Task AssertCodeCleanupResult(string expected, str enabledDiagnostics = VisualStudio.LanguageServices.Implementation.CodeCleanup.AbstractCodeCleanUpFixer.AdjustDiagnosticOptions(enabledDiagnostics, enabledFixIdsFilter); var newDoc = await codeCleanupService.CleanupAsync( - document, enabledDiagnostics, CodeAnalysisProgress.None, workspace.GlobalOptions.CreateProvider(), CancellationToken.None); + document, enabledDiagnostics, CodeAnalysisProgress.None, CancellationToken.None); var actual = await newDoc.GetTextAsync(); diff --git a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs index c22e46e883c31..84361e3511f51 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs @@ -2221,7 +2221,7 @@ public void FormatGeneratedNodeInInitializer() var root = tree.GetRoot(); var entry = SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression), SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression)); - var newRoot = root.InsertNodesBefore(root.DescendantNodes().Last(), new[] { entry }); + var newRoot = root.InsertNodesBefore(root.DescendantNodes().Last(), [entry]); AssertFormatOnArbitraryNode(newRoot, expected); } diff --git a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs index a1df91aa2c143..fcfe43cdb2966 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/Indentation/SmartIndenterTests.cs @@ -2646,7 +2646,7 @@ public override void Execute() { }"; AssertSmartIndentInProjection(markup, - expectedIndentation: 16); + expectedIndentation: 24); } [WpfFact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530948"), Trait(Traits.Feature, Traits.Features.SmartIndent)] diff --git a/src/EditorFeatures/CSharpTest/GenerateConstructorFromMembers/GenerateConstructorFromMembersTests.cs b/src/EditorFeatures/CSharpTest/GenerateConstructorFromMembers/GenerateConstructorFromMembersTests.cs index 48789445b12e7..128bc7615150e 100644 --- a/src/EditorFeatures/CSharpTest/GenerateConstructorFromMembers/GenerateConstructorFromMembersTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateConstructorFromMembers/GenerateConstructorFromMembersTests.cs @@ -741,7 +741,7 @@ class Program HashSet s;|] } """, -string.Format(FeaturesResources.Generate_constructor_0_1, "Program", "bool b, HashSet s")); +string.Format(CodeFixesResources.Generate_constructor_0_1, "Program", "bool b, HashSet s")); } [Fact] @@ -762,7 +762,7 @@ public Program(bool b) } } """, -string.Format(FeaturesResources.Generate_field_assigning_constructor_0_1, "Program", "bool b, HashSet s")); +string.Format(CodeFixesResources.Generate_field_assigning_constructor_0_1, "Program", "bool b, HashSet s")); } [Fact] @@ -1044,7 +1044,7 @@ public Z(int a{|Navigation:)|} } } """, -chosenSymbols: new[] { "a" }); +chosenSymbols: ["a"]); } [Fact] @@ -1072,7 +1072,7 @@ public Z(int a{|Navigation:)|} } } """, -chosenSymbols: new[] { "a" }); +chosenSymbols: ["a"]); } [Fact] @@ -1115,7 +1115,7 @@ public Z({|Navigation:)|} } } """, -chosenSymbols: new string[] { }); +chosenSymbols: []); } [Fact] @@ -1147,7 +1147,7 @@ public Z(string b, int a{|Navigation:)|} } } """, -chosenSymbols: new string[] { "b", "a" }); +chosenSymbols: ["b", "a"]); } [Fact] @@ -1181,7 +1181,7 @@ public Z(int a, string b{|Navigation:)|} } } """, -chosenSymbols: new string[] { "a", "b" }, +chosenSymbols: ["a", "b"], optionsCallback: options => options[0].Value = true); } @@ -1221,7 +1221,7 @@ public Z(int a, string b, string? c{|Navigation:)|} } } """, -chosenSymbols: new string[] { "a", "b", "c" }, +chosenSymbols: ["a", "b", "c"], optionsCallback: options => options[0].Value = true); } @@ -1261,7 +1261,7 @@ public Z(int a, string b, T? c{|Navigation:)|} } } """, -chosenSymbols: new string[] { "a", "b", "c" }, +chosenSymbols: ["a", "b", "c"], optionsCallback: options => options[0].Value = true); } @@ -1301,7 +1301,7 @@ public Z(int a, string b{|Navigation:)|} } } """, -chosenSymbols: new string[] { "a", "b" }, +chosenSymbols: ["a", "b"], optionsCallback: options => options[0].Value = true, parameters: new TestParameters(options: Option(CSharpCodeStyleOptions.PreferThrowExpression, CodeStyleOption2.FalseWithSilentEnforcement))); @@ -1338,7 +1338,7 @@ public Z(int a, int? b{|Navigation:)|} } } """, -chosenSymbols: new string[] { "a", "b" }, +chosenSymbols: ["a", "b"], optionsCallback: options => options[0].Value = true, parameters: new TestParameters(options: Option(CSharpCodeStyleOptions.PreferThrowExpression, CodeStyleOption2.FalseWithSilentEnforcement))); @@ -1380,7 +1380,7 @@ public Z(int a, string b{|Navigation:)|} } } """, -chosenSymbols: new string[] { "a", "b" }, +chosenSymbols: ["a", "b"], optionsCallback: options => options[0].Value = true, parameters: new TestParameters( parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6), diff --git a/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs b/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs index cffcb7f9b2344..479be726714e5 100644 --- a/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/InlineDiagnostics/InlineDiagnosticsTaggerProviderTests.cs @@ -44,7 +44,7 @@ private static async Task>> GetTagS { using var workspace = EditorTestWorkspace.CreateCSharp( files: [], - sourceGeneratedFiles: new[] { content }, + sourceGeneratedFiles: [content], composition: SquiggleUtilities.WpfCompositionWithSolutionCrawler); return await GetTagSpansAsync(workspace); diff --git a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs index 9fd69aa3ff078..ea68e9a3618be 100644 --- a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs +++ b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs @@ -39,8 +39,8 @@ public class MoveToNamespaceTests : AbstractMoveToNamespaceTests public static IEnumerable SupportedKeywords => new[] { new[] { "class" }, - new[] { "enum" }, - new[] { "interface"} + ["enum"], + ["interface"] }; [Fact] diff --git a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs index 429d27899a731..cae098cf81b3e 100644 --- a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs +++ b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs @@ -1615,8 +1615,8 @@ public async Task DoIncludeSymbolsFromMultipleSourceGeneratedFiles() { using var workspace = EditorTestWorkspace.CreateCSharp( files: [], - sourceGeneratedFiles: new[] - { + sourceGeneratedFiles: + [ """ public partial class C { @@ -1627,7 +1627,7 @@ public partial class C { } """, - }, + ], composition: DefaultComposition); _provider = CreateProvider(workspace); diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs index 1e12366cfe7c1..678b8b0fd99a4 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/AbstractPdbSourceDocumentTests.cs @@ -155,7 +155,18 @@ protected static async Task GenerateFileAndVerifyAsync( var masWorkspace = service.TryGetWorkspace(); - var document = masWorkspace!.CurrentSolution.Projects.First().Documents.First(d => d.FilePath == file.FilePath); + var pdbService = (PdbSourceDocumentMetadataAsSourceFileProvider)workspace.ExportProvider.GetExportedValues().Single(s => s is PdbSourceDocumentMetadataAsSourceFileProvider); + + // Add the document to the workspace. We provide an empty static source text as the API requires it to open the document. + // We're not really trying to verify that the source text the editor hands to us is the right encoding - just that the document we added has the right encoding. + var result = pdbService.TryAddDocumentToWorkspace((MetadataAsSourceWorkspace)masWorkspace!, file.FilePath, new StaticSourceTextContainer(SourceText.From(string.Empty)), out _); + Assert.True(result); + + // Immediately close the document so that we get the source text provided by the workspace (instead of the empty one we passed). + var info = pdbService.GetTestAccessor().Documents[file.FilePath]; + masWorkspace!.OnDocumentClosed(info.DocumentId, new WorkspaceFileTextLoader(workspace.Services.SolutionServices, file.FilePath, info.Encoding)); + + var document = masWorkspace!.CurrentSolution.GetRequiredDocument(info.DocumentId); // Mapping the project from the generated document should map back to the original project var provider = workspace.ExportProvider.GetExportedValues().OfType().Single(); @@ -330,4 +341,15 @@ protected static string GetPdbPath(string path) { return Path.Combine(path, "reference.pdb"); } + + protected class StaticSourceTextContainer(SourceText sourceText) : SourceTextContainer + { + public override SourceText CurrentText => sourceText; + + public override event EventHandler TextChanged + { + add { } + remove { } + } + } } diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/NullResultMetadataAsSourceFileProvider.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/NullResultMetadataAsSourceFileProvider.cs index 65dc2ed4d5d44..ddc805beef25f 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/NullResultMetadataAsSourceFileProvider.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/NullResultMetadataAsSourceFileProvider.cs @@ -4,6 +4,7 @@ using System; using System.Composition; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Formatting; @@ -47,8 +48,9 @@ public void CleanupGeneratedFiles(MetadataAsSourceWorkspace workspace) return null; } - public bool TryAddDocumentToWorkspace(MetadataAsSourceWorkspace workspace, string filePath, Text.SourceTextContainer sourceTextContainer) + public bool TryAddDocumentToWorkspace(MetadataAsSourceWorkspace workspace, string filePath, Text.SourceTextContainer sourceTextContainer, [NotNullWhen(true)] out DocumentId? documentId) { + documentId = null!; return true; } diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs index 5b6456133778e..14c90546f64c3 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentTests.cs @@ -951,4 +951,113 @@ await RunTestAsync(async path => await GenerateFileAndVerifyAsync(project, symbol, Location.Embedded, source2.ToString(), expectedSpan, expectNullResult: false); }); } + + [Fact, WorkItem("https://github.com/dotnet/vscode-csharp/issues/7532")] + public async Task OpenFileWithDifferentCase() + { + var source = """ + public class C + { + public int P { get; set; } + } + """; + + await RunTestAsync(async path => + { + var (project, symbol) = await CompileAndFindSymbolAsync(path, Location.Embedded, Location.Embedded, source, c => c.GetMember("C.P")); + + using var workspace = (EditorTestWorkspace)project.Solution.Workspace; + var service = workspace.GetService(); + var file = await service.GetGeneratedFileAsync(project.Solution.Workspace, project, symbol, signaturesOnly: false, options: MetadataAsSourceOptions.Default, cancellationToken: CancellationToken.None); + + var requestPath = file.FilePath.ToUpperInvariant(); + + var result = service.TryAddDocumentToWorkspace(requestPath, new StaticSourceTextContainer(SourceText.From(string.Empty)), out var documentId); + Assert.True(result); + }); + } + + [Fact] + public async Task OpenThenClose() + { + var source = """ + public class C + { + public int P { get; set; } + } + """; + + await RunTestAsync(async path => + { + var (project, symbol) = await CompileAndFindSymbolAsync(path, Location.Embedded, Location.Embedded, source, c => c.GetMember("C.P")); + + using var workspace = (EditorTestWorkspace)project.Solution.Workspace; + var service = workspace.GetService(); + var file = await service.GetGeneratedFileAsync(project.Solution.Workspace, project, symbol, signaturesOnly: false, options: MetadataAsSourceOptions.Default, cancellationToken: CancellationToken.None); + + var openResult = service.TryAddDocumentToWorkspace(file.FilePath, new StaticSourceTextContainer(SourceText.From(string.Empty)), out var documentId); + Assert.True(openResult); + + var closeResult = service.TryRemoveDocumentFromWorkspace(file.FilePath); + Assert.True(closeResult); + }); + } + + [Fact, WorkItem("https://github.com/dotnet/vscode-csharp/issues/7514")] + public async Task CloseWithoutOpenDoesNotThrow() + { + var source = """ + public class C + { + public int P { get; set; } + } + """; + + await RunTestAsync(async path => + { + var (project, symbol) = await CompileAndFindSymbolAsync(path, Location.Embedded, Location.Embedded, source, c => c.GetMember("C.P")); + + using var workspace = (EditorTestWorkspace)project.Solution.Workspace; + var service = workspace.GetService(); + var file = await service.GetGeneratedFileAsync(project.Solution.Workspace, project, symbol, signaturesOnly: false, options: MetadataAsSourceOptions.Default, cancellationToken: CancellationToken.None); + + var result = service.TryRemoveDocumentFromWorkspace(file.FilePath); + Assert.False(result); + }); + } + + [Fact, WorkItem("https://github.com/dotnet/vscode-csharp/issues/7514")] + public async Task OpenSameDocument() + { + var source = """ + public class C + { + public int P1 { get; set; } + + public int P2 { get; set; } + } + """; + + await RunTestAsync(async path => + { + var (project, symbol) = await CompileAndFindSymbolAsync(path, Location.Embedded, Location.Embedded, source, c => c.GetMember("C.P1")); + + using var workspace = (EditorTestWorkspace)project.Solution.Workspace; + var service = workspace.GetService(); + var fileOne = await service.GetGeneratedFileAsync(project.Solution.Workspace, project, symbol, signaturesOnly: false, options: MetadataAsSourceOptions.Default, cancellationToken: CancellationToken.None); + + var openResult = service.TryAddDocumentToWorkspace(fileOne.FilePath, new StaticSourceTextContainer(SourceText.From(string.Empty)), out var documentId); + Assert.True(openResult); + + var compilation = await project.GetCompilationAsync(CancellationToken.None); + var symbolTwo = compilation.GetMember("C.P2"); + var fileTwo = await service.GetGeneratedFileAsync(project.Solution.Workspace, project, symbolTwo, signaturesOnly: false, MetadataAsSourceOptions.Default, CancellationToken.None); + Assert.Equal(fileOne.FilePath, fileTwo.FilePath); + Assert.NotEqual(fileOne.IdentifierLocation, fileTwo.IdentifierLocation); + + // Opening should still throw (should never be called as we should be able to find the previously + // opened document in the MAS workspace). + Assert.Throws(() => service.TryAddDocumentToWorkspace(fileTwo.FilePath, new StaticSourceTextContainer(SourceText.From(string.Empty)), out var documentIdTwo)); + }); + } } diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs index 0b8ef1cd99c04..e63654db9546d 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/DiagnosticAnalyzerQuickInfoSourceTests.cs @@ -210,7 +210,7 @@ protected static async Task TestAsync( var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create( new CSharpCompilerDiagnosticAnalyzer(), new CSharpRemoveUnusedMembersDiagnosticAnalyzer())); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var testDocument = workspace.Documents.Single(); var position = testDocument.CursorPosition.Value; diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs index 63e399bb43a27..9d115944f6a70 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.QuickInfo; using Microsoft.CodeAnalysis.Editor.Host; +using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.QuickInfo; @@ -551,14 +552,19 @@ protected override async Task AssertContentIsAsync( Assert.NotEqual(0, info.RelatedSpans.Length); var trackingSpan = new Mock(MockBehavior.Strict); - var threadingContext = workspace.ExportProvider.GetExportedValue(); - var operationExecutor = workspace.ExportProvider.GetExportedValue(); - var streamingPresenter = workspace.ExportProvider.GetExport(); + + var navigationActionFactory = new NavigationActionFactory( + document, + threadingContext: workspace.ExportProvider.GetExportedValue(), + operationExecutor: workspace.ExportProvider.GetExportedValue(), + AsynchronousOperationListenerProvider.NullListener, + streamingPresenter: workspace.ExportProvider.GetExport()); + var quickInfoItem = await IntellisenseQuickInfoBuilder.BuildItemAsync( trackingSpan.Object, info, document, - ClassificationOptions.Default, LineFormattingOptions.Default, threadingContext, operationExecutor, - AsynchronousOperationListenerProvider.NullListener, - streamingPresenter, CancellationToken.None); + ClassificationOptions.Default, LineFormattingOptions.Default, + navigationActionFactory, CancellationToken.None); + var containerElement = quickInfoItem.Item as ContainerElement; var textElements = containerElement.Elements.OfType(); diff --git a/src/EditorFeatures/CSharpTest/Rename/CSharpInlineRenameServiceTests.cs b/src/EditorFeatures/CSharpTest/Rename/CSharpInlineRenameServiceTests.cs new file mode 100644 index 0000000000000..b1d9a20568333 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/Rename/CSharpInlineRenameServiceTests.cs @@ -0,0 +1,96 @@ +// 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.Hashing; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.UnitTests; +using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Rename +{ + [UseExportProvider] + [Trait(Traits.Feature, Traits.Features.Rename)] + public class CSharpInlineRenameServiceTests + { + private class ContextDictionaryComparer : IEqualityComparer>?> + { + public static ContextDictionaryComparer Instance = new(); + + public bool Equals(ImmutableDictionary>? x, ImmutableDictionary>? y) + { + if (x == y) + return true; + + if (x is null || y is null) + return false; + + if (x.Count != y.Count) + return false; + + foreach (var (elementFromX, elementFromY) in x.Zip(y, (elementFromX, elementFromY) => (elementFromX, elementFromY))) + { + var (keyFromX, valueFromX) = elementFromX; + var (keyFromY, valueFromY) = elementFromY; + + if (keyFromX != keyFromY || !valueFromX.SequenceEqual(valueFromY)) + return false; + } + + return true; + } + + public int GetHashCode(ImmutableDictionary>? obj) + => EqualityComparer>?>.Default.GetHashCode(obj); + } + + private static async Task VerifyGetRenameContextAsync( + string markup, string expectedContextJson, SymbolRenameOptions options, CancellationToken cancellationToken) + { + using var workspace = TestWorkspace.CreateCSharp(markup, composition: EditorTestCompositions.EditorFeatures); + var documentId = workspace.Documents.Single().Id; + var document = workspace.CurrentSolution.GetRequiredDocument(documentId); + var inlineRenameService = document.GetRequiredLanguageService(); + MarkupTestFile.GetPosition(markup, out _, out int cursorPosition); + var inlineRenameInfo = await inlineRenameService.GetRenameInfoAsync(document, cursorPosition, cancellationToken).ConfigureAwait(false); + var inlineRenameLocationSet = await inlineRenameInfo.FindRenameLocationsAsync(options, cancellationToken).ConfigureAwait(false); + var context = await inlineRenameService.GetRenameContextAsync(inlineRenameInfo, inlineRenameLocationSet, cancellationToken).ConfigureAwait(false); + var serializationOptions = new JsonSerializerOptions + { + IncludeFields = true, + }; + var expectedContext = JsonSerializer.Deserialize>>(expectedContextJson, serializationOptions); + AssertEx.AreEqual>?>(expectedContext, context, comparer: ContextDictionaryComparer.Instance); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/74545")] + public async Task VerifyContextReachEndOfFile() + { + var markup = @" +public class Sampl$$eClass() +{ +}"; + await VerifyGetRenameContextAsync( + markup, + @" +{ + ""definition"" : [ {""Item1"":""test1.cs"", ""Item2"":""public class SampleClass()\r\n{\r\n}""} ] +}", + new SymbolRenameOptions(), + CancellationToken.None); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/Semantics/SpeculationAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/Semantics/SpeculationAnalyzerTests.cs index fd3917a8adc00..e905c29774979 100644 --- a/src/EditorFeatures/CSharpTest/Semantics/SpeculationAnalyzerTests.cs +++ b/src/EditorFeatures/CSharpTest/Semantics/SpeculationAnalyzerTests.cs @@ -528,9 +528,9 @@ protected override Compilation CreateCompilation(SyntaxTree tree) { return CSharpCompilation.Create( CompilationName, - new[] { tree }, + [tree], References, - TestOptions.ReleaseDll.WithSpecificDiagnosticOptions(new[] { KeyValuePairUtil.Create("CS0219", ReportDiagnostic.Suppress) })); + TestOptions.ReleaseDll.WithSpecificDiagnosticOptions([KeyValuePairUtil.Create("CS0219", ReportDiagnostic.Suppress)])); } protected override bool CompilationSucceeded(Compilation compilation, Stream temporaryStream) diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs index ef487427f23be..9e6969a7ce52f 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs @@ -1000,7 +1000,7 @@ void Goo() """; var expectedDescription = new SignatureHelpTestItem($"Secret()\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, new[] { expectedDescription }, false); + await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } [Fact] @@ -1038,7 +1038,7 @@ void Goo() """; var expectedDescription = new SignatureHelpTestItem($"Secret()\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, new[] { expectedDescription }, false); + await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1067933")] diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs index 0d10f3fe4f384..b8a323b019de4 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs @@ -598,7 +598,7 @@ public SuperSecret(int secret) : base($$ """; var expectedDescription = new SignatureHelpTestItem($"Secret(int secret)\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, new[] { expectedDescription }, false); + await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } [Fact] @@ -639,7 +639,7 @@ public SuperSecret(int secret) : base($$ """; var expectedDescription = new SignatureHelpTestItem($"Secret(int secret)\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, new[] { expectedDescription }, false); + await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1067933")] diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/ElementAccessExpressionSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/ElementAccessExpressionSignatureHelpProviderTests.cs index 6c53d42ac28ae..4b571283cf6cd 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/ElementAccessExpressionSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/ElementAccessExpressionSignatureHelpProviderTests.cs @@ -817,7 +817,7 @@ void goo() """; var expectedDescription = new SignatureHelpTestItem($"int C[int z]\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, new[] { expectedDescription }, false); + await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } [Fact] @@ -859,7 +859,7 @@ void goo() """; var expectedDescription = new SignatureHelpTestItem($"int C[int z]\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, new[] { expectedDescription }, false); + await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } [Trait(Traits.Feature, Traits.Features.SignatureHelp)] @@ -979,7 +979,7 @@ void M() { (null as System.Collections.Generic.List)?[$$ } } - """, new[] { new SignatureHelpTestItem("int System.Collections.Generic.List[int index]") }); + """, [new SignatureHelpTestItem("int System.Collections.Generic.List[int index]")]); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1067933")] @@ -1012,7 +1012,7 @@ public void Method(TestClass tc) } } """; - await TestAsync(markup, new[] { new SignatureHelpTestItem("int WithIndexer[int index]") }, usePreviousCharAsTrigger: true); + await TestAsync(markup, [new SignatureHelpTestItem("int WithIndexer[int index]")], usePreviousCharAsTrigger: true); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20507")] @@ -1032,7 +1032,7 @@ static void Main(string[] args) } } """; - await TestAsync(markup, new[] { new SignatureHelpTestItem("Indexable Indexable[int x]") }, usePreviousCharAsTrigger: false); + await TestAsync(markup, [new SignatureHelpTestItem("Indexable Indexable[int x]")], usePreviousCharAsTrigger: false); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/20507")] @@ -1052,7 +1052,7 @@ static void Main(string[] args) } } """; - await TestAsync(markup, new[] { new SignatureHelpTestItem("Indexable Indexable[int x]") }, usePreviousCharAsTrigger: false); + await TestAsync(markup, [new SignatureHelpTestItem("Indexable Indexable[int x]")], usePreviousCharAsTrigger: false); } } } diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/GenericNameSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/GenericNameSignatureHelpProviderTests.cs index 67db1dd5a47b8..e6127d8bd4136 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/GenericNameSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/GenericNameSignatureHelpProviderTests.cs @@ -783,7 +783,7 @@ void goo() """; var expectedDescription = new SignatureHelpTestItem($"D\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, new[] { expectedDescription }, false); + await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } [Fact] @@ -821,7 +821,7 @@ void goo() """; var expectedDescription = new SignatureHelpTestItem($"D\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, new[] { expectedDescription }, false); + await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } #endregion diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs index fd04f97a5b916..a65cf5418357e 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs @@ -703,7 +703,7 @@ void goo() """; var expectedDescription = new SignatureHelpTestItem($"D()\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, new[] { expectedDescription }, false); + await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } [Fact] @@ -741,7 +741,7 @@ void goo() """; var expectedDescription = new SignatureHelpTestItem($"D()\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, new[] { expectedDescription }, false); + await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1067933")] diff --git a/src/EditorFeatures/CSharpTest/SignatureHelp/TupleConstructionSignatureHelpProviderTests.cs b/src/EditorFeatures/CSharpTest/SignatureHelp/TupleConstructionSignatureHelpProviderTests.cs index 32db754eb985c..7233e31edad96 100644 --- a/src/EditorFeatures/CSharpTest/SignatureHelp/TupleConstructionSignatureHelpProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/SignatureHelp/TupleConstructionSignatureHelpProviderTests.cs @@ -296,6 +296,6 @@ void goo() """; var expectedDescription = new SignatureHelpTestItem($"(int, string)", currentParameterIndex: 0); - await VerifyItemWithReferenceWorkerAsync(markup, new[] { expectedDescription }, false); + await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } } diff --git a/src/EditorFeatures/CSharpTest/StringIndentation/StringIndentationTests.cs b/src/EditorFeatures/CSharpTest/StringIndentation/StringIndentationTests.cs index 6b1f2451bfd02..28cd0cd096982 100644 --- a/src/EditorFeatures/CSharpTest/StringIndentation/StringIndentationTests.cs +++ b/src/EditorFeatures/CSharpTest/StringIndentation/StringIndentationTests.cs @@ -25,7 +25,7 @@ private static async Task TestAsync(string contents) { using var workspace = TestWorkspace.CreateWorkspace( TestWorkspace.CreateWorkspaceElement(LanguageNames.CSharp, - files: new[] { contents.Replace("|", " ") }, + files: [contents.Replace("|", " ")], isMarkup: false)); var document = workspace.CurrentSolution.GetRequiredDocument(workspace.Documents.First().Id); var root = await document.GetRequiredSyntaxRootAsync(default); diff --git a/src/EditorFeatures/CSharpTest/Structure/CommentStructureTests.cs b/src/EditorFeatures/CSharpTest/Structure/CommentStructureTests.cs index 91fa4245c73d4..9071be18f4622 100644 --- a/src/EditorFeatures/CSharpTest/Structure/CommentStructureTests.cs +++ b/src/EditorFeatures/CSharpTest/Structure/CommentStructureTests.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Structure; using Microsoft.CodeAnalysis.Editor.UnitTests.Structure; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Structure; @@ -25,8 +26,8 @@ public class CommentStructureTests : AbstractSyntaxStructureProviderTests private static ImmutableArray CreateCommentBlockSpan( SyntaxTriviaList triviaList) { - using var result = TemporaryArray.Empty; - CSharpStructureHelpers.CollectCommentBlockSpans(triviaList, ref result.AsRef()); + using var _ = ArrayBuilder.GetInstance(out var result); + CSharpStructureHelpers.CollectCommentBlockSpans(triviaList, result); return result.ToImmutableAndClear(); } diff --git a/src/EditorFeatures/CSharpTest/Structure/MetadataAsSource/InvalidIdentifierStructureTests.cs b/src/EditorFeatures/CSharpTest/Structure/MetadataAsSource/InvalidIdentifierStructureTests.cs index 4c7aa49f62348..e68df4f868815 100644 --- a/src/EditorFeatures/CSharpTest/Structure/MetadataAsSource/InvalidIdentifierStructureTests.cs +++ b/src/EditorFeatures/CSharpTest/Structure/MetadataAsSource/InvalidIdentifierStructureTests.cs @@ -72,6 +72,7 @@ public async Task IdentifierThatLooksLikeCode() await VerifyBlockSpansAsync(code, Region("textspan3", "/* now everything is commented (); ...", autoCollapse: true), + Region("textspan2", "hint2", CSharpStructureHelpers.Ellipsis, autoCollapse: false), Region("textspan1", "hint1", CSharpStructureHelpers.Ellipsis, autoCollapse: false)); } } diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs index b9f1ec2e3ae6c..a7882ee2881ef 100644 --- a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyCompilationsTests.cs @@ -160,7 +160,6 @@ public partial void M() { } var implementation = definition.PartialImplementationPart; // Assert that both the definition and implementation resolve back to themselves - // https://github.com/dotnet/roslyn/issues/73772: add a similar test for properties Assert.Equal(definition, ResolveSymbol(definition, comp, SymbolKeyComparison.None)); Assert.Equal(implementation, ResolveSymbol(implementation, comp, SymbolKeyComparison.None)); } @@ -328,8 +327,8 @@ file class C { } // note that the IDE can only distinguish file-local type symbols with the same name when they have distinct file paths. // We are OK with this as we will require file types with identical names to have distinct file paths later in the preview. // See https://github.com/dotnet/roslyn/issues/61999 - var originalComp = CreateCompilation(new[] { SyntaxFactory.ParseSyntaxTree(src1, path: "file1.cs"), SyntaxFactory.ParseSyntaxTree(src1, path: "file2.cs") }, assemblyName: "Test"); - var newComp = CreateCompilation(new[] { SyntaxFactory.ParseSyntaxTree(src1, path: "file1.cs"), SyntaxFactory.ParseSyntaxTree(src1, path: "file2.cs") }, assemblyName: "Test"); + var originalComp = CreateCompilation([SyntaxFactory.ParseSyntaxTree(src1, path: "file1.cs"), SyntaxFactory.ParseSyntaxTree(src1, path: "file2.cs")], assemblyName: "Test"); + var newComp = CreateCompilation([SyntaxFactory.ParseSyntaxTree(src1, path: "file1.cs"), SyntaxFactory.ParseSyntaxTree(src1, path: "file2.cs")], assemblyName: "Test"); var originalSymbols = GetSourceSymbols(originalComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); var newSymbols = GetSourceSymbols(newComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); @@ -357,8 +356,8 @@ namespace N1.N2 class C { } } """, path: "File2.cs"); - var originalComp = CreateCompilation(new[] { src1, src2 }, assemblyName: "Test"); - var newComp = CreateCompilation(new[] { src1, src2 }, assemblyName: "Test"); + var originalComp = CreateCompilation([src1, src2], assemblyName: "Test"); + var newComp = CreateCompilation([src1, src2], assemblyName: "Test"); var originalSymbols = GetSourceSymbols(originalComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); var newSymbols = GetSourceSymbols(newComp, SymbolCategory.DeclaredType | SymbolCategory.DeclaredNamespace).OrderBy(s => s.Name).ToArray(); diff --git a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs index 72492f37a0af1..c7c42b2a38239 100644 --- a/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyMetadataVsSourceTests.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; +using Basic.Reference.Assemblies; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SymbolId; @@ -61,7 +61,7 @@ protected C.S.E this[int x] { set { } } var comp1 = CreateCompilation(src1); // Compilation to Compilation - var comp2 = (Compilation)CreateCompilation(src2, new MetadataReference[] { new CSharpCompilationReference(comp1) }); + var comp2 = (Compilation)CreateCompilation(src2, [new CSharpCompilationReference(comp1)]); var originalSymbols = GetSourceSymbols(comp1, SymbolCategory.DeclaredType).OrderBy(s => s.Name).ToList(); Assert.Equal(5, originalSymbols.Count); @@ -145,7 +145,7 @@ static void EH(AN.S s) { } var comp1 = CreateCompilation(src1); // Compilation to Assembly - var comp2 = CreateCompilation(src2, new MetadataReference[] { comp1.EmitToImageReference() }); + var comp2 = CreateCompilation(src2, [comp1.EmitToImageReference()]); // --------------------------- // Source symbols @@ -231,10 +231,10 @@ static void Main() } } """; - var comp20 = (Compilation)CreateEmptyCompilation(src1, new[] { Net40.mscorlib }); + var comp20 = (Compilation)CreateEmptyCompilation(src1, [Net40.References.mscorlib]); // "Compilation 2 Assembly" - var comp40 = (Compilation)CreateCompilation(src2, new MetadataReference[] { comp20.EmitToImageReference() }); + var comp40 = (Compilation)CreateCompilation(src2, [comp20.EmitToImageReference()]); var typeA = comp20.SourceModule.GlobalNamespace.GetTypeMembers("A").Single(); var mem20_1 = typeA.GetMembers("GetFileInfo").Single() as IMethodSymbol; @@ -331,10 +331,10 @@ public IDisposable M() public void MyEveHandler(object o) { } } """; - var comp20 = CreateEmptyCompilation(src1, new[] { Net40.mscorlib }); + var comp20 = CreateEmptyCompilation(src1, [Net40.References.mscorlib]); // "Compilation ref Compilation" - var comp40 = CreateCompilation(src2, new[] { new CSharpCompilationReference(comp20) }); + var comp40 = CreateCompilation(src2, [new CSharpCompilationReference(comp20)]); var originals = GetSourceSymbols(comp20, SymbolCategory.NonTypeMember | SymbolCategory.Parameter); var originalSymbols = originals.Where(s => !s.IsAccessor() && s.Kind != SymbolKind.Parameter).OrderBy(s => s.Name).ToList(); @@ -415,10 +415,10 @@ public IDisposable M() } } """; - var comp20 = CreateEmptyCompilation(src1, new[] { Net40.mscorlib }); + var comp20 = CreateEmptyCompilation(src1, [Net40.References.mscorlib]); // "Compilation ref Compilation" - var comp40 = CreateCompilation(src2, new[] { new CSharpCompilationReference(comp20) }); + var comp40 = CreateCompilation(src2, [new CSharpCompilationReference(comp20)]); var originals = GetSourceSymbols(comp20, SymbolCategory.NonTypeMember | SymbolCategory.Parameter); var originalSymbols = originals.Where(s => !s.IsAccessor() && s.Kind != SymbolKind.Parameter).OrderBy(s => s.Name).ToList(); diff --git a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs index a28658f5dd195..27f3d213052c5 100644 --- a/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs +++ b/src/EditorFeatures/CSharpTest/Workspaces/WorkspaceTests_EditorFeatures.cs @@ -172,7 +172,7 @@ class D { } await VerifyRootTypeNameAsync(workspace, "D"); workspace.OnParseOptionsChanged(document.Id.ProjectId, - new CSharpParseOptions(preprocessorSymbols: new[] { "GOO" })); + new CSharpParseOptions(preprocessorSymbols: ["GOO"])); await VerifyRootTypeNameAsync(workspace, "C"); } @@ -200,7 +200,7 @@ class D { } await VerifyRootTypeNameAsync(workspace, "D"); workspace.OnParseOptionsChanged(document.Id.ProjectId, - new CSharpParseOptions(preprocessorSymbols: new[] { "GOO" })); + new CSharpParseOptions(preprocessorSymbols: ["GOO"])); await VerifyRootTypeNameAsync(workspace, "C"); @@ -425,7 +425,7 @@ public async Task TestGetCompilationOnDependentProject() var project1 = new EditorTestHostProject(workspace, document1, name: "project1"); var document2 = new EditorTestHostDocument(@"class D : C { }"); - var project2 = new EditorTestHostProject(workspace, document2, name: "project2", projectReferences: new[] { project1 }); + var project2 = new EditorTestHostProject(workspace, document2, name: "project2", projectReferences: [project1]); workspace.AddTestProject(project1); workspace.AddTestProject(project2); @@ -453,7 +453,7 @@ Public Class D Inherits C End Class """); - var project2 = new EditorTestHostProject(workspace, document2, language: LanguageNames.VisualBasic, name: "project2", projectReferences: new[] { project1 }); + var project2 = new EditorTestHostProject(workspace, document2, language: LanguageNames.VisualBasic, name: "project2", projectReferences: [project1]); workspace.AddTestProject(project1); workspace.AddTestProject(project2); @@ -486,7 +486,7 @@ Public Class D Inherits C End Class """); - var project2 = new EditorTestHostProject(workspace, document2, language: LanguageNames.VisualBasic, name: "project2", projectReferences: new[] { project1 }); + var project2 = new EditorTestHostProject(workspace, document2, language: LanguageNames.VisualBasic, name: "project2", projectReferences: [project1]); workspace.AddTestProject(project1); workspace.AddTestProject(project2); @@ -540,7 +540,7 @@ Public Class D Inherits C End Class """); - var project2 = new EditorTestHostProject(workspace, document2, language: LanguageNames.VisualBasic, name: "project2", projectReferences: new[] { project1 }); + var project2 = new EditorTestHostProject(workspace, document2, language: LanguageNames.VisualBasic, name: "project2", projectReferences: [project1]); workspace.AddTestProject(project1); workspace.AddTestProject(project2); @@ -608,7 +608,7 @@ Public Class D Inherits C End Class """); - var project2 = new EditorTestHostProject(workspace, document2, language: LanguageNames.VisualBasic, name: "project2", projectReferences: new[] { project1 }); + var project2 = new EditorTestHostProject(workspace, document2, language: LanguageNames.VisualBasic, name: "project2", projectReferences: [project1]); workspace.AddTestProject(project1); workspace.AddTestProject(project2); @@ -923,7 +923,7 @@ public async Task TestAdditionalDocumentEvents() { using var workspace = CreateWorkspace(); var document = new EditorTestHostDocument(); - var project1 = new EditorTestHostProject(workspace, additionalDocuments: new[] { document }, name: "project1"); + var project1 = new EditorTestHostProject(workspace, additionalDocuments: [document], name: "project1"); var longEventTimeout = TimeSpan.FromMinutes(5); var shortEventTimeout = TimeSpan.FromSeconds(5); @@ -984,7 +984,7 @@ public async Task TestAnalyzerConfigDocumentEvents() { using var workspace = CreateWorkspace(); var document = new EditorTestHostDocument(); - var project1 = new EditorTestHostProject(workspace, analyzerConfigDocuments: new[] { document }, name: "project1"); + var project1 = new EditorTestHostProject(workspace, analyzerConfigDocuments: [document], name: "project1"); var longEventTimeout = TimeSpan.FromMinutes(5); var shortEventTimeout = TimeSpan.FromSeconds(5); @@ -1046,7 +1046,7 @@ public async Task TestAdditionalFile_Properties() using var workspace = CreateWorkspace(); var document = new EditorTestHostDocument("public class C { }"); var additionalDoc = new EditorTestHostDocument("some text"); - var project1 = new EditorTestHostProject(workspace, name: "project1", documents: new[] { document }, additionalDocuments: new[] { additionalDoc }); + var project1 = new EditorTestHostProject(workspace, name: "project1", documents: [document], additionalDocuments: [additionalDoc]); workspace.AddTestProject(project1); @@ -1070,7 +1070,7 @@ public async Task TestAnalyzerConfigFile_Properties() using var workspace = CreateWorkspace(); var document = new EditorTestHostDocument("public class C { }"); var analyzerConfigDoc = new EditorTestHostDocument("root = true"); - var project1 = new EditorTestHostProject(workspace, name: "project1", documents: new[] { document }, analyzerConfigDocuments: new[] { analyzerConfigDoc }); + var project1 = new EditorTestHostProject(workspace, name: "project1", documents: [document], analyzerConfigDocuments: [analyzerConfigDoc]); workspace.AddTestProject(project1); @@ -1100,7 +1100,7 @@ public async Task TestAdditionalFile_DocumentChanged() """; var document = new EditorTestHostDocument("public class C { }"); var additionalDoc = new EditorTestHostDocument(startText); - var project1 = new EditorTestHostProject(workspace, name: "project1", documents: new[] { document }, additionalDocuments: new[] { additionalDoc }); + var project1 = new EditorTestHostProject(workspace, name: "project1", documents: [document], additionalDocuments: [additionalDoc]); workspace.AddTestProject(project1); @@ -1133,7 +1133,7 @@ public async Task TestAnalyzerConfigFile_DocumentChanged() var document = new EditorTestHostDocument("public class C { }"); var analyzerConfigPath = PathUtilities.CombineAbsoluteAndRelativePaths(Temp.CreateDirectory().Path, ".editorconfig"); var analyzerConfigDoc = new EditorTestHostDocument(startText, filePath: analyzerConfigPath); - var project1 = new EditorTestHostProject(workspace, name: "project1", documents: new[] { document }, analyzerConfigDocuments: new[] { analyzerConfigDoc }); + var project1 = new EditorTestHostProject(workspace, name: "project1", documents: [document], analyzerConfigDocuments: [analyzerConfigDoc]); workspace.AddTestProject(project1); @@ -1166,7 +1166,7 @@ public void TestAdditionalFile_OpenClose() """; var document = new EditorTestHostDocument("public class C { }"); var additionalDoc = new EditorTestHostDocument(startText); - var project1 = new EditorTestHostProject(workspace, name: "project1", documents: new[] { document }, additionalDocuments: new[] { additionalDoc }); + var project1 = new EditorTestHostProject(workspace, name: "project1", documents: [document], additionalDocuments: [additionalDoc]); workspace.AddTestProject(project1); @@ -1195,7 +1195,7 @@ public void TestAnalyzerConfigFile_OpenClose() var startText = @"root = true"; var document = new EditorTestHostDocument("public class C { }"); var analyzerConfigDoc = new EditorTestHostDocument(startText); - var project1 = new EditorTestHostProject(workspace, name: "project1", documents: new[] { document }, analyzerConfigDocuments: new[] { analyzerConfigDoc }); + var project1 = new EditorTestHostProject(workspace, name: "project1", documents: [document], analyzerConfigDocuments: [analyzerConfigDoc]); workspace.AddTestProject(project1); @@ -1226,7 +1226,7 @@ public void TestAdditionalFile_AddRemove() """; var document = new EditorTestHostDocument("public class C { }"); var additionalDoc = new EditorTestHostDocument(startText, "original.config"); - var project1 = new EditorTestHostProject(workspace, name: "project1", documents: new[] { document }, additionalDocuments: new[] { additionalDoc }); + var project1 = new EditorTestHostProject(workspace, name: "project1", documents: [document], additionalDocuments: [additionalDoc]); workspace.AddTestProject(project1); var project = workspace.CurrentSolution.Projects.Single(); @@ -1262,7 +1262,7 @@ public void TestAnalyzerConfigFile_AddRemove() var startText = @"root = true"; var document = new EditorTestHostDocument("public class C { }"); var analyzerConfigDoc = new EditorTestHostDocument(startText, "original.config"); - var project1 = new EditorTestHostProject(workspace, name: "project1", documents: new[] { document }, analyzerConfigDocuments: new[] { analyzerConfigDoc }); + var project1 = new EditorTestHostProject(workspace, name: "project1", documents: [document], analyzerConfigDocuments: [analyzerConfigDoc]); workspace.AddTestProject(project1); var project = workspace.CurrentSolution.Projects.Single(); @@ -1300,7 +1300,7 @@ public void TestAdditionalFile_AddRemove_FromProject() """; var document = new EditorTestHostDocument("public class C { }"); var additionalDoc = new EditorTestHostDocument(startText, "original.config"); - var project1 = new EditorTestHostProject(workspace, name: "project1", documents: new[] { document }, additionalDocuments: new[] { additionalDoc }); + var project1 = new EditorTestHostProject(workspace, name: "project1", documents: [document], additionalDocuments: [additionalDoc]); workspace.AddTestProject(project1); var project = workspace.CurrentSolution.Projects.Single(); @@ -1328,7 +1328,7 @@ public void TestAnalyzerConfigFile_AddRemove_FromProject() var startText = @"root = true"; var document = new EditorTestHostDocument("public class C { }"); var analyzerConfigDoc = new EditorTestHostDocument(startText, "original.config"); - var project1 = new EditorTestHostProject(workspace, name: "project1", documents: new[] { document }, analyzerConfigDocuments: new[] { analyzerConfigDoc }); + var project1 = new EditorTestHostProject(workspace, name: "project1", documents: [document], analyzerConfigDocuments: [analyzerConfigDoc]); workspace.AddTestProject(project1); var project = workspace.CurrentSolution.Projects.Single(); @@ -1358,7 +1358,7 @@ public void TestAdditionalFile_GetDocumentIdsWithFilePath() var additionalDoc = new EditorTestHostDocument(""" [ - 07777777777777777777777777777777 + + """ + + // [SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="this is not a credential")] + " 07777777777777777777777777777777" + + """ + ] diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/FieldKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/FieldKeywordRecommenderTests.cs index 89385d382c921..e762383d458fc 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/FieldKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/FieldKeywordRecommenderTests.cs @@ -7,222 +7,509 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations; + +[Trait(Traits.Feature, Traits.Features.KeywordRecommending)] +public sealed class FieldKeywordRecommenderTests : KeywordRecommenderTests { - [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public class FieldKeywordRecommenderTests : KeywordRecommenderTests - { - [Fact] - public async Task TestNotAtRoot_Interactive() - { - await VerifyAbsenceAsync(SourceCodeKind.Script, -@"$$"); - } - - [Fact] - public async Task TestNotAfterClass_Interactive() - { - await VerifyAbsenceAsync(SourceCodeKind.Script, - """ - class C { } - $$ - """); - } - - [Fact] - public async Task TestNotAfterGlobalStatement_Interactive() - { - await VerifyAbsenceAsync(SourceCodeKind.Script, - """ - System.Console.WriteLine(); - $$ - """); - } - - [Fact] - public async Task TestNotAfterGlobalVariableDeclaration_Interactive() - { - await VerifyAbsenceAsync(SourceCodeKind.Script, - """ - int i = 0; - $$ - """); - } - - [Fact] - public async Task TestNotInUsingAlias() - { - await VerifyAbsenceAsync( -@"using Goo = $$"); - } - - [Fact] - public async Task TestNotInGlobalUsingAlias() - { - await VerifyAbsenceAsync( -@"global using Goo = $$"); - } - - [Fact] - public async Task TestNotInEmptyStatement() - { - await VerifyAbsenceAsync(AddInsideMethod( -@"$$")); - } - - [Fact] - public async Task TestInAttributeInsideClass() - { - await VerifyKeywordAsync( - """ - class C { - [$$ - """); - } - - [Theory] - [InlineData("record")] - [InlineData("record class")] - [InlineData("record struct")] - public async Task TestInAttributeInsideRecord(string record) - { - // The recommender doesn't work in record in script - // Tracked by https://github.com/dotnet/roslyn/issues/44865 - await VerifyWorkerAsync( -$@"{record} C {{ - [$$", absent: false, TestOptions.RegularPreview); - } - - [Fact] - public async Task TestInAttributeAfterAttributeInsideClass() - { - await VerifyKeywordAsync( - """ - class C { - [Goo] - [$$ - """); - } - - [Fact] - public async Task TestInAttributeAfterMethod() - { - await VerifyKeywordAsync( - """ - class C { - void Goo() { + [Fact] + public async Task TestNotAtRoot_Interactive() + { + await VerifyAbsenceAsync(SourceCodeKind.Script, + """$$"""); + } + + [Fact] + public async Task TestNotAfterClass_Interactive() + { + await VerifyAbsenceAsync(SourceCodeKind.Script, + """ + class C { } + $$ + """); + } + + [Fact] + public async Task TestNotAfterGlobalStatement_Interactive() + { + await VerifyAbsenceAsync(SourceCodeKind.Script, + """ + System.Console.WriteLine(); + $$ + """); + } + + [Fact] + public async Task TestNotAfterGlobalVariableDeclaration_Interactive() + { + await VerifyAbsenceAsync(SourceCodeKind.Script, + """ + int i = 0; + $$ + """); + } + + [Fact] + public async Task TestNotInUsingAlias() + { + await VerifyAbsenceAsync( + """using Goo = $$"""); + } + + [Fact] + public async Task TestNotInGlobalUsingAlias() + { + await VerifyAbsenceAsync( + """global using Goo = $$"""); + } + + [Fact] + public async Task TestNotInEmptyStatement() + { + await VerifyAbsenceAsync(AddInsideMethod( + """$$""")); + } + + [Fact] + public async Task TestInAttributeInsideClass() + { + await VerifyKeywordAsync( + """ + class C { + [$$ + """); + } + + [Fact] + public async Task TestNotInAttributeArgumentInsideClass1() + { + await VerifyAbsenceAsync( + """ + class C { + [field: $$ + """); + } + + [Fact] + public async Task TestNotInAttributeArgumentInsideClass2() + { + await VerifyAbsenceAsync( + """ + class C { + [field: Goo($$)] + """); + } + + [Fact] + public async Task TestNotInAttributeArgumentInsideClass3() + { + await VerifyAbsenceAsync( + """ + class C { + [field: Goo($$)] int Prop { get; } + """); + } + + [Theory] + [InlineData("record")] + [InlineData("record class")] + [InlineData("record struct")] + public async Task TestInAttributeInsideRecord(string record) + { + // The recommender doesn't work in record in script + // Tracked by https://github.com/dotnet/roslyn/issues/44865 + await VerifyWorkerAsync( + $$""" + {{record}} C { + [$$ + """, absent: false, TestOptions.RegularPreview); + } + + [Fact] + public async Task TestInAttributeAfterAttributeInsideClass() + { + await VerifyKeywordAsync( + """ + class C { + [Goo] + [$$ + """); + } + + [Fact] + public async Task TestInAttributeAfterMethod() + { + await VerifyKeywordAsync( + """ + class C { + void Goo() { + } + [$$ + """); + } + + [Fact] + public async Task TestInAttributeAfterProperty() + { + await VerifyKeywordAsync( + """ + class C { + int Goo { + get; + } + [$$ + """); + } + + [Fact] + public async Task TestInAttributeAfterField() + { + await VerifyKeywordAsync( + """ + class C { + int Goo; + [$$ + """); + } + + [Fact] + public async Task TestInAttributeAfterEvent() + { + await VerifyKeywordAsync( + """ + class C { + event Action Goo; + [$$ + """); + } + + [Fact] + public async Task TestNotInOuterAttribute() + { + await VerifyAbsenceAsync( + """[$$"""); + } + + [Fact] + public async Task TestNotInParameterAttribute() + { + await VerifyAbsenceAsync( + """ + class C { + void Goo([$$ + """); + } + + [Fact] + public async Task TestNotInPropertyAttribute() + { + await VerifyAbsenceAsync( + """ + class C { + int Goo { [$$ + """); + } + + [Fact] + public async Task TestNotInEventAttribute() + { + await VerifyAbsenceAsync( + """ + class C { + event Action Goo { [$$ + """); + } + + [Fact] + public async Task TestNotInTypeParameters() + { + await VerifyAbsenceAsync( + """class C<[$$"""); + } + + [Fact] + public async Task TestNotInInterface() + { + await VerifyAbsenceAsync( + """ + interface I { + [$$ + """); + } + + [Fact] + public async Task TestInStruct() + { + await VerifyKeywordAsync( + """ + struct S { + [$$ + """); + } + + [Fact] + public async Task TestInEnum() + { + await VerifyKeywordAsync( + """ + enum E { + [$$ + """); + } + + [Fact] + public async Task TestNotInPropertyInitializer() + { + await VerifyAbsenceAsync( + """ + class C + { + int Goo { get; } = $$ + } + """); + } + + [Fact] + public async Task TestInPropertyExpressionBody() + { + await VerifyKeywordAsync( + """ + class C + { + int Goo => $$ + } + """); + } + + [Fact] + public async Task TestNotInPropertyExpressionBody_NotPrimary() + { + await VerifyAbsenceAsync( + """ + class C + { + int Goo => this.$$ + } + """); + } + + [Fact] + public async Task TestInPropertyAccessor1() + { + await VerifyKeywordAsync( + """ + class C + { + int Goo { get => $$ } + } + """); + } + + [Fact] + public async Task TestInPropertyAccessor2() + { + await VerifyKeywordAsync( + """ + class C + { + int Goo { get { return $$ } } + } + """); + } + + [Fact] + public async Task TestInPropertyStatement() + { + await VerifyKeywordAsync( + """ + class C + { + int Goo { get { $$ } } + } + """); + } + + [Fact] + public async Task TestInPropertyExpressionContext() + { + await VerifyKeywordAsync( + """ + class C + { + int Goo { get { var v = 1 + $$ } } + } + """); + } + + [Fact] + public async Task TestInPropertyArgument1() + { + await VerifyKeywordAsync( + """ + class C + { + int Goo { get { Bar($$) } } + } + """); + } + + [Fact] + public async Task TestInPropertyArgument2() + { + await VerifyKeywordAsync( + """ + class C + { + int Goo { get { Bar(ref $$) } } + } + """); + } + + [Fact] + public async Task TestNotInPropertyNameof() + { + await VerifyAbsenceAsync( + """ + class C + { + int Goo { get { Bar(nameof($$)) } } + } + """); + } + + [Fact] + public async Task TestInLocalFunctionInProperty() + { + await VerifyKeywordAsync( + """ + class C + { + int Goo + { + get + { + void Bar() { return $$ } } - [$$ - """); - } - - [Fact] - public async Task TestInAttributeAfterProperty() - { - await VerifyKeywordAsync( - """ - class C { - int Goo { - get; + } + } + """); + } + + [Fact] + public async Task TestInLambdaInProperty() + { + await VerifyKeywordAsync( + """ + class C + { + int Goo + { + get + { + var v = customers.Where(c => c.Age > $$); } - [$$ - """); - } - - [Fact] - public async Task TestInAttributeAfterField() - { - await VerifyKeywordAsync( - """ - class C { - int Goo; - [$$ - """); - } - - [Fact] - public async Task TestInAttributeAfterEvent() - { - await VerifyKeywordAsync( - """ - class C { - event Action Goo; - [$$ - """); - } - - [Fact] - public async Task TestNotInOuterAttribute() - { - await VerifyAbsenceAsync( -@"[$$"); - } - - [Fact] - public async Task TestNotInParameterAttribute() - { - await VerifyAbsenceAsync( - """ - class C { - void Goo([$$ - """); - } - - [Fact] - public async Task TestNotInPropertyAttribute() - { - await VerifyAbsenceAsync( - """ - class C { - int Goo { [$$ - """); - } - - [Fact] - public async Task TestNotInEventAttribute() - { - await VerifyAbsenceAsync( - """ - class C { - event Action Goo { [$$ - """); - } - - [Fact] - public async Task TestNotInTypeParameters() - { - await VerifyAbsenceAsync( -@"class C<[$$"); - } - - [Fact] - public async Task TestNotInInterface() - { - await VerifyAbsenceAsync( - """ - interface I { - [$$ - """); - } - - [Fact] - public async Task TestInStruct() - { - await VerifyKeywordAsync( - """ - struct S { - [$$ - """); - } - - [Fact] - public async Task TestInEnum() - { - await VerifyKeywordAsync( - """ - enum E { - [$$ - """); - } + } + } + """); + } + + [Fact] + public async Task TestNotInAccessorAttribute() + { + await VerifyAbsenceAsync( + """ + class C + { + [Bar($$)] + int Goo { get; } + } + """); + } + + [Fact] + public async Task TestNotInIndexer1() + { + await VerifyAbsenceAsync( + """ + class C + { + int this[int index] => $$ + } + """); + } + + [Fact] + public async Task TestNotInIndexer2() + { + await VerifyAbsenceAsync( + """ + class C + { + int this[int index] { get => $$ } + } + """); + } + + [Fact] + public async Task TestNotInIndexer3() + { + await VerifyAbsenceAsync( + """ + class C + { + int this[int index] { get { return $$ } } + } + """); + } + + [Fact] + public async Task TestNotInEvent1() + { + await VerifyAbsenceAsync( + """ + class C + { + event Action E { add { $$ } } + } + """); + } + + [Fact] + public async Task TestNotInMethodContext() + { + await VerifyAbsenceAsync( + """ + class C + { + void M() + { + $$ + } + } + """); + } + + [Fact] + public async Task TestNotInMethodExpressionContext() + { + await VerifyAbsenceAsync( + """ + class C + { + void M() + { + Goo($$); + } + } + """); + } + + [Fact] + public async Task TestNotInGlobalStatement() + { + await VerifyAbsenceAsync( + """ + $$ + """); } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs index 89ca1dc86f303..c27ef93bb9f76 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/RecommenderTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading; @@ -62,8 +63,8 @@ private Task CheckResultAsync(string text, int position, bool absent, CSharpPars var tree = SyntaxFactory.ParseSyntaxTree(text, options: options); var compilation = CSharpCompilation.Create( "test", - syntaxTrees: new[] { tree }, - references: new[] { TestMetadata.Net451.mscorlib }); + syntaxTrees: [tree], + references: [NetFramework.mscorlib]); if (tree.IsInNonUserCode(position, CancellationToken.None) && !absent) { @@ -158,7 +159,10 @@ private Task VerifyAtEndOfFileAsync(string text, int position, bool absent, CSha private Task VerifyAtEndOfFile_KeywordPartiallyWrittenAsync(string text, int position, bool absent, CSharpParseOptions? options, int? matchPriority) => VerifyAtEndOfFileAsync(text, position, absent, KeywordText[..1], options: options, matchPriority: matchPriority); - internal async Task VerifyKeywordAsync(string text, CSharpParseOptions? options = null, CSharpParseOptions? scriptOptions = null) + internal async Task VerifyKeywordAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string text, + CSharpParseOptions? options = null, + CSharpParseOptions? scriptOptions = null) { // run the verification in both context(normal and script) await VerifyWorkerAsync(text, absent: false, options: options); @@ -179,14 +183,19 @@ protected async Task VerifyKeywordAsync(SourceCodeKind kind, string text) } } - protected async Task VerifyAbsenceAsync(string text, CSharpParseOptions? options = null, CSharpParseOptions? scriptOptions = null) + protected async Task VerifyAbsenceAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string text, + CSharpParseOptions? options = null, + CSharpParseOptions? scriptOptions = null) { // run the verification in both context(normal and script) await VerifyWorkerAsync(text, absent: true, options: options); await VerifyWorkerAsync(text, absent: true, options: scriptOptions ?? Options.Script); } - protected async Task VerifyAbsenceAsync(SourceCodeKind kind, string text) + protected async Task VerifyAbsenceAsync( + SourceCodeKind kind, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string text) { switch (kind) { diff --git a/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs b/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs index 0299864071d49..3e0d7dd893555 100644 --- a/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs +++ b/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs @@ -239,7 +239,7 @@ async ValueTask UpdateUIAsync() // Todo: build a richer tool-tip that makes use of things like the progress reported, and perhaps has a // close button. _toolTipPresenter.StartOrUpdate( - _trackingSpan, new[] { string.Format(EditorFeaturesResources._0_Esc_to_cancel, data.description) }); + _trackingSpan, [string.Format(EditorFeaturesResources._0_Esc_to_cancel, data.description)]); } } diff --git a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTag.cs b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTag.cs index 3f0061ae429f4..a73547efd1009 100644 --- a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTag.cs +++ b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTag.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. -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; @@ -13,12 +11,9 @@ using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; -using Microsoft.CodeAnalysis.Classification; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; +using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.InlineHints; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -97,30 +92,27 @@ public static InlineHintsTag Create( textView, span, hint, taggerProvider); } - public async Task> CreateDescriptionAsync(CancellationToken cancellationToken) + public async Task> CreateDescriptionAsync(CancellationToken cancellationToken) { - var document = _span.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document != null) + if (_span.Snapshot.GetOpenDocumentInCurrentContextWithChanges() is not Document document) { - var taggedText = await _hint.GetDescriptionAsync(document, cancellationToken).ConfigureAwait(false); - if (!taggedText.IsDefaultOrEmpty) - { - var classificationOptions = _taggerProvider.EditorOptionsService.GlobalOptions.GetClassificationOptions(document.Project.Language); - var lineFormattingOptions = _span.Snapshot.TextBuffer.GetLineFormattingOptions(_taggerProvider.EditorOptionsService, explicitFormat: false); - - var context = new IntellisenseQuickInfoBuilderContext( - document, - classificationOptions, - lineFormattingOptions, - _taggerProvider.ThreadingContext, - _taggerProvider.OperationExecutor, - _taggerProvider.AsynchronousOperationListener, - _taggerProvider.StreamingFindUsagesPresenter); - return Implementation.IntelliSense.Helpers.BuildInteractiveTextElements(taggedText, context); - } + return []; + } + + var taggedText = await _hint.GetDescriptionAsync(document, cancellationToken).ConfigureAwait(false); + if (taggedText.IsDefaultOrEmpty) + { + return []; } - return Array.Empty(); + var navigationActionFactory = new NavigationActionFactory( + document, + _taggerProvider.ThreadingContext, + _taggerProvider.OperationExecutor, + _taggerProvider.AsynchronousOperationListener, + _taggerProvider.StreamingFindUsagesPresenter); + + return taggedText.ToInteractiveVsTextAdornments(navigationActionFactory); } private static FrameworkElement CreateElement( diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs index 57f249768fa80..0b74fdaf53a24 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs @@ -28,18 +28,14 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename [Order(Before = PredefinedCommandHandlerNames.ChangeSignature)] [Order(Before = PredefinedCommandHandlerNames.ExtractInterface)] [Order(Before = PredefinedCommandHandlerNames.EncapsulateField)] - internal partial class RenameCommandHandler : AbstractRenameCommandHandler + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + internal partial class RenameCommandHandler( + IThreadingContext threadingContext, + InlineRenameService renameService, + IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider) + : AbstractRenameCommandHandler(threadingContext, renameService, asynchronousOperationListenerProvider.GetListener(FeatureAttribute.Rename)) { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RenameCommandHandler( - IThreadingContext threadingContext, - InlineRenameService renameService, - IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider) - : base(threadingContext, renameService, asynchronousOperationListenerProvider) - { - } - protected override bool AdornmentShouldReceiveKeyboardNavigation(ITextView textView) => GetAdornment(textView) switch { @@ -94,11 +90,11 @@ protected override void SetAdornmentFocusToPreviousElement(ITextView textView) } } - protected override void Commit(InlineRenameSession activeSession, ITextView textView) + protected override void CommitAndSetFocus(InlineRenameSession activeSession, ITextView textView, IUIThreadOperationContext operationContext) { try { - base.Commit(activeSession, textView); + base.CommitAndSetFocus(activeSession, textView, operationContext); } catch (NotSupportedException ex) { diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameConflictTagDefinition.cs b/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameConflictTagDefinition.cs index 8981524053d7b..51152b5db8ac4 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameConflictTagDefinition.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameConflictTagDefinition.cs @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename.HighlightTag internal class RenameConflictTagDefinition : MarkerFormatDefinition { public static double StrokeThickness => 1.5; - public static double[] StrokeDashArray => new[] { 8.0, 4.0 }; + public static double[] StrokeDashArray => [8.0, 4.0]; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameFixupTagDefinition.cs b/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameFixupTagDefinition.cs index 6e7465ddc4ceb..731d9b0c71185 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameFixupTagDefinition.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameFixupTagDefinition.cs @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename.HighlightTag internal class RenameFixupTagDefinition : MarkerFormatDefinition { public static double StrokeThickness => 1.0; - public static double[] StrokeDashArray => new[] { 4.0, 4.0 }; + public static double[] StrokeDashArray => [4.0, 4.0]; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml index 1809edb0025e0..be642b6dfac18 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml @@ -20,6 +20,7 @@ Focusable="False" UseLayoutRounding="True" Cursor="Arrow" + Visibility="{Binding Path=Visibility}" x:Name="control"> diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs index d3c7a03928798..073bbc74a5850 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; +using System.Windows; using System.Windows.Interop; using Microsoft.CodeAnalysis.Editor.InlineRename; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; @@ -28,7 +29,6 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename { internal class RenameFlyoutViewModel : INotifyPropertyChanged, IDisposable { - private readonly InlineRenameSession _session; private readonly bool _registerOleComponent; private readonly IGlobalOptionService _globalOptionService; private OleComponent? _oleComponent; @@ -47,15 +47,16 @@ public RenameFlyoutViewModel( Lazy? smartRenameSessionFactory) #pragma warning restore CS0618 { - _session = session; + Session = session; _registerOleComponent = registerOleComponent; _globalOptionService = globalOptionService; - _session.ReplacementTextChanged += OnReplacementTextChanged; - _session.ReplacementsComputed += OnReplacementsComputed; - _session.ReferenceLocationsChanged += OnReferenceLocationsChanged; + Session.ReplacementTextChanged += OnReplacementTextChanged; + Session.ReplacementsComputed += OnReplacementsComputed; + Session.ReferenceLocationsChanged += OnReferenceLocationsChanged; + Session.CommitStateChange += CommitStateChange; StartingSelection = selectionSpan; InitialTrackingSpan = session.TriggerSpan.CreateTrackingSpan(SpanTrackingMode.EdgeInclusive); - var smartRenameSession = smartRenameSessionFactory?.Value.CreateSmartRenameSession(_session.TriggerSpan); + var smartRenameSession = smartRenameSessionFactory?.Value.CreateSmartRenameSession(Session.TriggerSpan); if (smartRenameSession is not null) { SmartRenameViewModel = new SmartRenameViewModel(globalOptionService, threadingContext, listenerProvider, smartRenameSession.Value, this); @@ -64,29 +65,32 @@ public RenameFlyoutViewModel( RegisterOleComponent(); } + private void CommitStateChange(object sender, EventArgs args) + => Visibility = this.Session.IsCommitInProgress ? Visibility.Collapsed : Visibility.Visible; + public SmartRenameViewModel? SmartRenameViewModel { get; } public string IdentifierText { - get => _session.ReplacementText; + get => Session.ReplacementText; set { - if (value != _session.ReplacementText) + if (value != Session.ReplacementText) { - _session.ApplyReplacementText(value, propagateEditImmediately: true, updateSelection: false); + Session.ApplyReplacementText(value, propagateEditImmediately: true, updateSelection: false); NotifyPropertyChanged(nameof(IdentifierText)); } } } - public InlineRenameSession Session => _session; + public InlineRenameSession Session { get; } public ITrackingSpan InitialTrackingSpan { get; } - public bool AllowFileRename => _session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed && _isReplacementTextValid; - public bool ShowFileRename => _session.FileRenameInfo != InlineRenameFileRenameInfo.NotAllowed; + public bool AllowFileRename => Session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed && _isReplacementTextValid; + public bool ShowFileRename => Session.FileRenameInfo != InlineRenameFileRenameInfo.NotAllowed; - public string FileRenameString => _session.FileRenameInfo switch + public string FileRenameString => Session.FileRenameInfo switch { InlineRenameFileRenameInfo.TypeDoesNotMatchFileName => EditorFeaturesResources.Rename_file_name_doesnt_match, InlineRenameFileRenameInfo.TypeWithMultipleLocations => EditorFeaturesResources.Rename_file_partial_type, @@ -133,51 +137,51 @@ public Severity StatusSeverity public bool RenameInCommentsFlag { - get => _session.Options.RenameInComments; + get => Session.Options.RenameInComments; set { _globalOptionService.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInComments, value); - _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInComments = value }); + Session.RefreshRenameSessionWithOptionsChanged(Session.Options with { RenameInComments = value }); } } public bool RenameInStringsFlag { - get => _session.Options.RenameInStrings; + get => Session.Options.RenameInStrings; set { _globalOptionService.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameInStrings, value); - _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInStrings = value }); + Session.RefreshRenameSessionWithOptionsChanged(Session.Options with { RenameInStrings = value }); } } public bool RenameFileFlag { - get => _session.Options.RenameFile; + get => Session.Options.RenameFile; set { _globalOptionService.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameFile, value); - _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameFile = value }); + Session.RefreshRenameSessionWithOptionsChanged(Session.Options with { RenameFile = value }); } } public bool PreviewChangesFlag { - get => _session.PreviewChanges; + get => Session.PreviewChanges; set { _globalOptionService.SetGlobalOption(InlineRenameSessionOptionsStorage.PreviewChanges, value); - _session.SetPreviewChanges(value); + Session.SetPreviewChanges(value); } } public bool RenameOverloadsFlag { - get => _session.Options.RenameOverloads; + get => Session.Options.RenameOverloads; set { _globalOptionService.SetGlobalOption(InlineRenameSessionOptionsStorage.RenameOverloads, value); - _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameOverloads = value }); + Session.RefreshRenameSessionWithOptionsChanged(Session.Options with { RenameOverloads = value }); } } @@ -202,13 +206,20 @@ public bool IsExpanded } public bool IsRenameOverloadsEditable - => !_session.MustRenameOverloads; + => !Session.MustRenameOverloads; public bool IsRenameOverloadsVisible - => _session.HasRenameOverloads; + => Session.HasRenameOverloads; public TextSpan StartingSelection { get; } + private Visibility _visibility; + public Visibility Visibility + { + get => _visibility; + set => Set(ref _visibility, value); + } + public bool Submit() { if (StatusSeverity == Severity.Error) @@ -217,14 +228,14 @@ public bool Submit() } SmartRenameViewModel?.Commit(IdentifierText); - _session.Commit(); + Session.Commit(); return true; } public void Cancel() { SmartRenameViewModel?.Cancel(); - _session.Cancel(); + Session.Cancel(); } public void Dispose() @@ -309,8 +320,9 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - _session.ReplacementTextChanged -= OnReplacementTextChanged; - _session.ReplacementsComputed -= OnReplacementsComputed; + Session.ReplacementTextChanged -= OnReplacementTextChanged; + Session.ReplacementsComputed -= OnReplacementsComputed; + Session.CommitStateChange -= CommitStateChange; if (SmartRenameViewModel is not null) { diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml index 6e78eb41115aa..eb6c3697b6af2 100644 --- a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml +++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/RenameDashboard.xaml @@ -13,6 +13,7 @@ Focusable="True" x:Name="dashboard" AutomationProperties.AutomationId="Microsoft.CodeAnalysis.EditorFeatures.InlineRenameDialog" + Visibility="{Binding Path=Visibility}" UseLayoutRounding="True"> $(NoWarn);NU5123 diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb index c407b7dc1bd4d..f3837978bc0db 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb @@ -81,6 +81,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator End Get End Property + Public Overrides Function TryGetOrCreateSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal + Return Nothing + End Function + + Public Overrides Function GetOrCreateHotReloadExceptionConstructorDefinition() As IMethodSymbolInternal + ' Should only be called when compiling EnC delta. + Throw ExceptionUtilities.Unreachable + End Function + + Public Overrides Function GetUsedSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal + Return Nothing + End Function + Friend Overrides Function TryCreateVariableSlotAllocator(symbol As MethodSymbol, topLevelMethod As MethodSymbol, diagnostics As DiagnosticBag) As VariableSlotAllocator Dim method = TryCast(symbol, EEMethodSymbol) If method IsNot Nothing Then diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicResultProvider.vb b/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicResultProvider.vb index af66dd33feaf2..29ae52fe59dfc 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicResultProvider.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ResultProvider/VisualBasicResultProvider.vb @@ -2,6 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.ExpressionEvaluator Imports Microsoft.VisualStudio.Debugger.ComponentInterfaces Imports Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation @@ -41,6 +42,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator Return type.IsPredefinedType() End Function + Friend Overrides Function TryGetGeneratedMemberDisplay(metadataName As String, ByRef displayName As String) As Boolean + displayName = Nothing + Return False + End Function End Class - End Namespace diff --git a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/CompileExpressionsTests.vb b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/CompileExpressionsTests.vb index d6015e6c9cf7d..515ccde05624f 100644 --- a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/CompileExpressionsTests.vb +++ b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/CompileExpressionsTests.vb @@ -39,7 +39,7 @@ End Class" ' Test with CompileExpression rather than CompileExpressions ' so field references in IL are named. ' Debug build. - Dim comp = CreateCompilationWithMscorlib45AndVBRuntime( + Dim comp = CreateCompilationWithMscorlib461AndVBRuntime( {VisualBasicSyntaxTree.ParseText(source)}, options:=TestOptions.DebugDll, references:={SystemCoreRef}) @@ -74,7 +74,7 @@ End Class" }") End Sub) ' Release build. - comp = CreateCompilationWithMscorlib45AndVBRuntime( + comp = CreateCompilationWithMscorlib461AndVBRuntime( {VisualBasicSyntaxTree.ParseText(source)}, options:=TestOptions.ReleaseDll, references:={SystemCoreRef}) diff --git a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ExpressionCompilerTests.vb b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ExpressionCompilerTests.vb index 75d70493eb82a..fdc9a9d470428 100644 --- a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ExpressionCompilerTests.vb +++ b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ExpressionCompilerTests.vb @@ -1474,7 +1474,7 @@ Class C Shared Sub M(o As C, i As Integer, a As Action, obj As Object) End Sub End Class" - Dim compilation0 = CreateCompilationWithMscorlib45AndVBRuntime({Parse(source)}, options:=TestOptions.DebugDll) + Dim compilation0 = CreateCompilationWithMscorlib461AndVBRuntime({Parse(source)}, options:=TestOptions.DebugDll) WithRuntimeInstance(compilation0, Sub(runtime) Dim context = CreateMethodContext(runtime, methodName:="C.M") @@ -4669,7 +4669,7 @@ Class C End Sub End Sub End Class" - Dim compilation0 = CreateCompilationWithMscorlib45AndVBRuntime({Parse(source)}, options:=TestOptions.DebugDll, references:={SystemCoreRef}) + Dim compilation0 = CreateCompilationWithMscorlib461AndVBRuntime({Parse(source)}, options:=TestOptions.DebugDll, references:={SystemCoreRef}) WithRuntimeInstance(compilation0, Sub(runtime) Dim context = CreateMethodContext(runtime, "C._Closure$__.VB$StateMachine___Lambda$__1-0.MoveNext") diff --git a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/LocalsTests.vb b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/LocalsTests.vb index 9a15179c5aff8..06b0ccd3d7737 100644 --- a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/LocalsTests.vb +++ b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/LocalsTests.vb @@ -14,6 +14,7 @@ Imports Microsoft.VisualStudio.Debugger.Evaluation Imports Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation Imports Roslyn.Test.Utilities Imports Xunit +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.UnitTests Public Class LocalsTests @@ -2015,7 +2016,7 @@ End Module } " - Dim comp = CreateCompilationWithMscorlib40({source}, {TestMetadata.Net40.SystemCore, TestMetadata.Net40.MicrosoftVisualBasic}, TestOptions.DebugDll) + Dim comp = CreateCompilationWithMscorlib40({source}, {Net40.References.SystemCore, Net40.References.MicrosoftVisualBasic}, TestOptions.DebugDll) WithRuntimeInstance(comp, Sub(runtime) Dim context = CreateMethodContext(runtime, "M.VB$StateMachine_0_F.MoveNext") diff --git a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/MissingAssemblyTests.vb b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/MissingAssemblyTests.vb index 18338763d72f1..9a76d1d8ab6c1 100644 --- a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/MissingAssemblyTests.vb +++ b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/MissingAssemblyTests.vb @@ -16,6 +16,7 @@ Imports Microsoft.VisualStudio.Debugger.Evaluation Imports Roslyn.Test.Utilities Imports Roslyn.Utilities Imports Xunit +Imports Basic.Reference.Assemblies Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator.UnitTests Public Class MissingAssemblyTests @@ -668,10 +669,10 @@ End Class" Private Shared Sub TupleContextNoSystemRuntime(source As String, methodName As String, expression As String, expectedIL As String, Optional languageVersion As LanguageVersion = LanguageVersion.VisualBasic15) - Dim comp = CreateCompilationWithMscorlib40({source}, references:={ValueTupleRef, SystemRuntimeFacadeRef}, options:=TestOptions.DebugDll, + Dim comp = CreateEmptyCompilation({source}, references:={Net461.References.mscorlib, Net461.References.SystemRuntime, ValueTupleLegacyRef}, options:=TestOptions.DebugDll, parseOptions:=TestOptions.Regular.WithLanguageVersion(languageVersion)) - Using systemRuntime = SystemRuntimeFacadeRef.ToModuleInstance() - WithRuntimeInstance(comp, {MscorlibRef, ValueTupleRef}, + Using systemRuntime = Net461.References.SystemRuntime.ToModuleInstance() + WithRuntimeInstance(comp, {Net461.References.mscorlib, ValueTupleLegacyRef}, Sub(runtime) Dim methodBlocks As ImmutableArray(Of MetadataBlock) = Nothing Dim moduleVersionId As Guid = Nothing diff --git a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ReferencedModulesTests.vb b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ReferencedModulesTests.vb index de9a9e018619d..73177efc24708 100644 --- a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ReferencedModulesTests.vb +++ b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ReferencedModulesTests.vb @@ -986,6 +986,18 @@ End Class" Protected Overrides Sub AddEmbeddedResourcesFromAddedModules(builder As ArrayBuilder(Of Cci.ManagedResource), diagnostics As DiagnosticBag) End Sub + Public Overrides Function GetOrCreateHotReloadExceptionConstructorDefinition() As IMethodSymbolInternal + Throw New NotImplementedException() + End Function + + Public Overrides Function TryGetOrCreateSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal + Return Nothing + End Function + + Public Overrides Function GetUsedSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal + Return Nothing + End Function + Friend Overrides ReadOnly Property AllowOmissionOfConditionalCalls As Boolean Get Return True diff --git a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/TupleTests.vb b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/TupleTests.vb index a8629e8bd01f9..392a6a0893c11 100644 --- a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/TupleTests.vb +++ b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/TupleTests.vb @@ -429,8 +429,8 @@ End Class" Shared Sub M() End Sub End Class" - Dim comp = CreateCompilationWithMscorlib40({source}, references:={ValueTupleRef, SystemRuntimeFacadeRef}, options:=TestOptions.DebugDll) - WithRuntimeInstance(comp, {MscorlibRef, ValueTupleRef, SystemRuntimeFacadeRef}, + Dim comp = CreateCompilationWithMscorlib40({source}, references:={ValueTupleLegacyRef, SystemRuntimeFacadeRef}, options:=TestOptions.DebugDll) + WithRuntimeInstance(comp, {MscorlibRef, ValueTupleLegacyRef, SystemRuntimeFacadeRef}, Sub(runtime) Dim context = CreateMethodContext(runtime, "C.M") Dim locals = ArrayBuilder(Of LocalAndMethod).GetInstance() @@ -487,9 +487,9 @@ End Class" Shared Sub M() End Sub End Class" - Dim comp = CreateCompilationWithMscorlib40({source}, references:={SystemRuntimeFacadeRef, ValueTupleRef}, options:=TestOptions.DebugDll) + Dim comp = CreateCompilationWithMscorlib40({source}, references:={SystemRuntimeFacadeRef, ValueTupleLegacyRef}, options:=TestOptions.DebugDll) WithRuntimeInstance(comp, - {MscorlibRef, SystemCoreRef, SystemRuntimeFacadeRef, ValueTupleRef}, + {MscorlibRef, SystemCoreRef, SystemRuntimeFacadeRef, ValueTupleLegacyRef}, Sub(runtime) Dim context = CreateMethodContext(runtime, "C.M") Dim [alias] = New [Alias]( diff --git a/src/Features/CSharp/Portable/AddMissingReference/CSharpAddMissingReferenceCodeFixProvider.cs b/src/Features/CSharp/Portable/AddMissingReference/CSharpAddMissingReferenceCodeFixProvider.cs index abe2730970a06..7e558684bfa07 100644 --- a/src/Features/CSharp/Portable/AddMissingReference/CSharpAddMissingReferenceCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/AddMissingReference/CSharpAddMissingReferenceCodeFixProvider.cs @@ -9,8 +9,6 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.AddMissingReference; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Packaging; -using Microsoft.CodeAnalysis.SymbolSearch; namespace Microsoft.CodeAnalysis.CSharp.AddMissingReference; @@ -28,13 +26,4 @@ internal class CSharpAddMissingReferenceCodeFixProvider : AbstractAddMissingRefe public CSharpAddMissingReferenceCodeFixProvider() { } - - /// For testing purposes only (so that tests can pass in mock values) - [SuppressMessage("RoslynDiagnosticsReliability", "RS0034:Exported parts should have [ImportingConstructor]", Justification = "Used incorrectly by tests")] - internal CSharpAddMissingReferenceCodeFixProvider( - IPackageInstallerService installerService, - ISymbolSearchService symbolSearchService) - : base(installerService, symbolSearchService) - { - } } diff --git a/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs index 21bcd3afc307f..9a90207361727 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/AbstractCurlyBraceOrBracketCompletionService.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.Diagnostics; using System.Linq; @@ -120,7 +121,8 @@ private static bool ContainsOnlyWhitespace(SourceText text, int openingPosition, var rootToFormat = document.Root.ReplaceToken(closingToken, newClosingToken); annotatedNewline = rootToFormat.GetAnnotatedTrivia(s_closingBraceNewlineAnnotation).Single(); - document = document.WithChangedRoot(rootToFormat, cancellationToken); + + document = GetUpdatedDocument(document, [new TextChange(closingToken.FullSpan, newClosingToken.ToFullString())], rootToFormat); // Calculate text change for adding a newline and adjust closing point location. closingPoint = annotatedNewline.Token.Span.End; @@ -136,7 +138,7 @@ private static bool ContainsOnlyWhitespace(SourceText text, int openingPosition, options, cancellationToken); - var newDocument = document.WithChangedRoot(formattedRoot, cancellationToken); + var newDocument = GetUpdatedDocument(document, formattingChanges, formattedRoot); // Get the empty line between the curly braces. var desiredCaretLine = GetLineBetweenCurlys(newClosingPoint, newDocument.Text); @@ -147,6 +149,17 @@ private static bool ContainsOnlyWhitespace(SourceText text, int openingPosition, return new BraceCompletionResult(GetMergedChanges(newLineEdit, formattingChanges, newDocument.Text), caretPosition); + // Create a new ParsedDocument given an old document, a set of changes and the new root. Typically, creating a new ParsedDocument is + // done with either a call to ParsedDocument.WithChangedRoot or ParsedDocument.WithChangedText. The former ends up creating + // a SourceText, while the latter parses the document. For performance reasons, we don't want to do either of those, so + // we'll just created the ParsedDocument directly with the information we already have. + static ParsedDocument GetUpdatedDocument(ParsedDocument oldDocument, IEnumerable changes, SyntaxNode newRoot) + { + var newText = oldDocument.Text.WithChanges(changes); + + return new ParsedDocument(oldDocument.Id, newText, newRoot, oldDocument.HostLanguageServices); + } + static TextLine GetLineBetweenCurlys(int closingPosition, SourceText text) { var closingBraceLineNumber = text.Lines.GetLineFromPosition(closingPosition - 1).LineNumber; diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx index 13d4e8e6195ea..e14e82032ac9c 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx @@ -211,12 +211,6 @@ Organize Usings - - Generate explicit conversion operator in '{0}' - - - Generate implicit conversion operator in '{0}' - try block {Locked="try"} "try" is a C# keyword and should not be localized. diff --git a/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs index 9178dc16f1f98..347374fd1813c 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -159,7 +160,7 @@ private static (SyntaxNode root, SyntaxToken firstToken) RewriteExistingDirectiv private static async Task DisableNullableReferenceTypesInExistingDocumentIfNecessaryAsync(Document document, SyntaxNode root, SyntaxToken firstToken, CancellationToken cancellationToken) { - var options = await document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetCSharpSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var newLine = SyntaxFactory.EndOfLine(options.NewLine); // Add a new '#nullable disable' to the top of each file diff --git a/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs index d87e358100bfb..49757d74e2e07 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs @@ -583,7 +583,6 @@ protected override async Task FixAllAsync( Document document, ImmutableArray fixAllSpans, SyntaxEditor editor, - CodeActionOptionsProvider optionsProvider, string? equivalenceKey, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs index f4a7ef5437256..34e88256a3d72 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs @@ -129,6 +129,13 @@ public override bool IsInsertionTrigger(SourceText text, int characterPosition, // too aggressive at suggesting tags, so exit early before degrading the experience return null; } + else if (trigger.Kind == CompletionTriggerKind.Deletion) + { + // Do not show completion in xml text or tags when TriggerOnDeletion is true. Attribute + // names and values are handled above. This differs slightly from the vb implementation + // as it better handles completion in tags. + return null; + } var items = new List(); diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FieldKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FieldKeywordRecommender.cs index 40e75cb897832..d0a726ffe7ebc 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FieldKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FieldKeywordRecommender.cs @@ -5,10 +5,12 @@ using System.Collections.Generic; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class FieldKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +internal sealed class FieldKeywordRecommender() + : AbstractSyntacticSingleKeywordRecommender(SyntaxKind.FieldKeyword) { // interfaces don't have members that you can put a [field:] attribute on private static readonly ISet s_validTypeDeclarations = new HashSet(SyntaxFacts.EqualityComparer) @@ -20,11 +22,36 @@ internal class FieldKeywordRecommender : AbstractSyntacticSingleKeywordRecommend SyntaxKind.EnumDeclaration, }; - public FieldKeywordRecommender() - : base(SyntaxKind.FieldKeyword) + protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { + // `[field:` is legal in an attribute within a type. + if (context.IsMemberAttributeContext(s_validTypeDeclarations, cancellationToken)) + return true; + + // Check if we're within a property accessor where the `field` keyword is legal. Note: we do not do a lang + // version check here. We do not want to interfere with users trying to use/learn this feature. The user will + // get a clear message if they're not on the right lang version telling them about the issue, and offering to + // upgrade their project if they way. + if (context.IsAnyExpressionContext || context.IsStatementContext) + { + if (!context.IsNameOfContext && IsInPropertyAccessor(context.TargetToken)) + return true; + } + + return false; } - protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) - => context.IsMemberAttributeContext(s_validTypeDeclarations, cancellationToken); + private static bool IsInPropertyAccessor(SyntaxToken targetToken) + { + for (var node = targetToken.Parent; node != null; node = node.Parent) + { + if (node is ArrowExpressionClauseSyntax { Parent: PropertyDeclarationSyntax }) + return true; + + if (node is AccessorDeclarationSyntax { Parent: AccessorListSyntax { Parent: PropertyDeclarationSyntax } }) + return true; + } + + return false; + } } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs index 5a9a0c468585e..37f5011ee1f69 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs @@ -11,13 +11,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; -internal class IntKeywordRecommender : AbstractSpecialTypePreselectingKeywordRecommender +internal sealed class IntKeywordRecommender() : AbstractSpecialTypePreselectingKeywordRecommender(SyntaxKind.IntKeyword) { - public IntKeywordRecommender() - : base(SyntaxKind.IntKeyword) - { - } - protected override bool IsValidContextWorker(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) { var syntaxTree = context.SyntaxTree; diff --git a/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs b/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs index ea9130d85ec3a..675bd9c88ee5e 100644 --- a/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs +++ b/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs @@ -766,7 +766,7 @@ private bool TryConvertIfInReturnStatement( // add an yield break to avoid throws after the return. var yieldBreakStatement = YieldStatement(SyntaxKind.YieldBreakStatement); - documentUpdateInfo = new DocumentUpdateInfo(returnStatement, statements.Concat(new[] { yieldBreakStatement })); + documentUpdateInfo = new DocumentUpdateInfo(returnStatement, statements.Concat([yieldBreakStatement])); return true; } diff --git a/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs index 5449604678af5..fd2273161d404 100644 --- a/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -47,18 +48,18 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (!IsValidPosition(namespaceDecl, position)) return; - var options = await document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetCSharpSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); if (!CanOfferRefactoring(namespaceDecl, root, options, out var info)) return; context.RegisterRefactoring(CodeAction.Create( - info.Value.title, c => ConvertAsync(document, namespaceDecl, options.GetFormattingOptions(), c), info.Value.equivalenceKey)); + info.Value.title, c => ConvertAsync(document, namespaceDecl, options, c), info.Value.equivalenceKey)); } private static bool CanOfferRefactoring( [NotNullWhen(true)] BaseNamespaceDeclarationSyntax? namespaceDecl, CompilationUnitSyntax root, - CSharpCodeFixOptionsProvider options, + CSharpSyntaxFormattingOptions options, [NotNullWhen(true)] out (string title, string equivalenceKey)? info) { info = @@ -87,12 +88,11 @@ protected override async Task FixAllAsync( Document document, ImmutableArray fixAllSpans, SyntaxEditor editor, - CodeActionOptionsProvider optionsProvider, string? equivalenceKey, CancellationToken cancellationToken) { var root = (CompilationUnitSyntax)await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var options = await document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetCSharpSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var namespaceDecl = root.DescendantNodes().OfType().FirstOrDefault(); if (!CanOfferRefactoring(namespaceDecl, root, options, out var info) || info.Value.equivalenceKey != equivalenceKey) @@ -100,7 +100,7 @@ protected override async Task FixAllAsync( return; } - document = await ConvertAsync(document, namespaceDecl, options.GetFormattingOptions(), cancellationToken).ConfigureAwait(false); + document = await ConvertAsync(document, namespaceDecl, options, cancellationToken).ConfigureAwait(false); var newRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); editor.ReplaceNode(editor.OriginalRoot, newRoot); } diff --git a/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_TopLevelStatements.cs b/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_TopLevelStatements.cs index d56c030d2ee27..384f28f7892ea 100644 --- a/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_TopLevelStatements.cs +++ b/src/Features/CSharp/Portable/ConvertProgram/ConvertProgramTransform_TopLevelStatements.cs @@ -83,7 +83,7 @@ private static async Task AddUsingDirectivesAsync( cancellationToken)); return await removeImportsService.RemoveUnnecessaryImportsAsync( - documentWithImportsAdded, n => n.HasAnnotation(annotation), options.FormattingOptions, cancellationToken).ConfigureAwait(false); + documentWithImportsAdded, n => n.HasAnnotation(annotation), cancellationToken).ConfigureAwait(false); } private static void AddUsingDirectives(NameSyntax name, SyntaxAnnotation annotation, ArrayBuilder directives) diff --git a/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeFixProvider.cs b/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeFixProvider.cs index 3da827966e8c0..66fb3d762e5c3 100644 --- a/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeFixProvider.cs @@ -9,8 +9,10 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -35,7 +37,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var document = context.Document; var cancellationToken = context.CancellationToken; - var options = await document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetCSharpSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var priority = options.PreferTopLevelStatements.Notification.Severity == ReportDiagnostic.Hidden ? CodeActionPriority.Low : CodeActionPriority.Default; @@ -46,7 +48,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) protected override async Task FixAllAsync( Document document, ImmutableArray diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) { - var options = await document.GetCodeFixOptionsAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var fixedDocument = await ConvertToProgramMainAsync(document, options.AccessibilityModifiersRequired, cancellationToken).ConfigureAwait(false); var fixedRoot = await fixedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeRefactoringProvider.cs index ffaa168778071..fccadd6b9fda5 100644 --- a/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeRefactoringProvider.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.Analyzers.ConvertProgram; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -46,7 +47,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (!acceptableLocation.SourceSpan.IntersectsWith(position)) return; - var options = await document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetCSharpSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); if (!CanOfferUseProgramMain(options.PreferTopLevelStatements, root, compilation, forAnalyzer: false)) @@ -54,7 +55,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte context.RegisterRefactoring(CodeAction.Create( CSharpAnalyzersResources.Convert_to_Program_Main_style_program, - c => ConvertToProgramMainAsync(document, options.AccessibilityModifiersRequired.Value, c), + c => ConvertToProgramMainAsync(document, options.AccessibilityModifiersRequired, c), nameof(CSharpAnalyzersResources.Convert_to_Program_Main_style_program), CodeActionPriority.Low)); } diff --git a/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeFixProvider.cs b/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeFixProvider.cs index a39e3138992d6..aa3dbd4a0b1fe 100644 --- a/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeFixProvider.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; @@ -36,7 +37,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var document = context.Document; var cancellationToken = context.CancellationToken; - var options = await document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetCSharpSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); var priority = options.PreferTopLevelStatements.Notification.Severity == ReportDiagnostic.Hidden ? CodeActionPriority.Low : CodeActionPriority.Default; diff --git a/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeRefactoringProvider.cs index 997ca9cfad008..41952a70f6a69 100644 --- a/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeRefactoringProvider.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.Analyzers.ConvertProgram; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -42,7 +43,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (methodDeclaration is null) return; - var options = await document.GetCSharpCodeFixOptionsProviderAsync(cancellationToken).ConfigureAwait(false); + var options = await document.GetCSharpSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); if (!CanOfferUseTopLevelStatements(options.PreferTopLevelStatements, forAnalyzer: false)) return; diff --git a/src/Features/CSharp/Portable/ConvertToRawString/ConvertStringToRawStringCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertToRawString/ConvertStringToRawStringCodeRefactoringProvider.cs index 90c1735d4be85..60b4f36e23a24 100644 --- a/src/Features/CSharp/Portable/ConvertToRawString/ConvertStringToRawStringCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertToRawString/ConvertStringToRawStringCodeRefactoringProvider.cs @@ -136,7 +136,6 @@ protected override async Task FixAllAsync( Document document, ImmutableArray fixAllSpans, SyntaxEditor editor, - CodeActionOptionsProvider optionsProvider, string? equivalenceKey, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs index a4952cf559764..16d3ce94a3b63 100644 --- a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs +++ b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Differencing; using Microsoft.CodeAnalysis.EditAndContinue; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; @@ -1165,22 +1166,18 @@ newContainingMemberOrType is IPropertySymbol newPropertySymbol && case EditKind.Reorder: Contract.ThrowIfNull(oldNode); + // When global statements are reordered, we issue an update edit for the synthesized main method, which is what + // oldSymbol and newSymbol will point to. if (IsGlobalStatement(oldNode)) { - // When global statements are reordered, we issue an update edit for the synthesized main method, which is what - // oldSymbol and newSymbol will point to result.Add((oldSymbol, newSymbol, EditKind.Update)); return; } - // Otherwise, we don't do any semantic checks for reordering - // and we don't need to report them to the compiler either. - // Consider: Currently symbol ordering changes are not reflected in metadata (Reflection will report original order). + // Reordering of data members is only allowed if the layout of the type doesn't change. + // Reordering of other members is a no-op, although the new order won't be reflected in metadata (Reflection will report original order). + result.Add((oldSymbol, newSymbol, EditKind.Reorder)); - // Consider: Reordering of fields is not allowed since it changes the layout of the type. - // This ordering should however not matter unless the type has explicit layout so we might want to allow it. - // We do not check changes to the order if they occur across multiple documents (the containing type is partial). - Debug.Assert(!IsDeclarationWithInitializer(oldNode!) && !IsDeclarationWithInitializer(newNode!)); return; case EditKind.Update: @@ -1198,6 +1195,10 @@ newContainingMemberOrType is IPropertySymbol newPropertySymbol && // int this[...] { get => expr; } // int P => expr; // int P { get => expr; } = init + // + // Note: An update of a partial property/indexer definition can only affect its attributes. The partial definition does not have a body. + // In that case we do not need to update/analyze the accessors since attribute update has no impact on them. + // // 2) Property/indexer declarations differ in readonly keyword. // 3) Property signature changes // 4) Property name changes @@ -2386,14 +2387,6 @@ private void ClassifyReorder(SyntaxNode newNode) switch (newNode.Kind()) { - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.FieldDeclaration: - case SyntaxKind.EventFieldDeclaration: - case SyntaxKind.VariableDeclarator: - // Maybe we could allow changing order of field declarations unless the containing type layout is sequential. - ReportError(RudeEditKind.Move); - return; - case SyntaxKind.EnumMemberDeclaration: // To allow this change we would need to check that values of all fields of the enum // are preserved, or make sure we can update all method bodies that accessed those that changed. @@ -2851,12 +2844,15 @@ internal override void ReportOtherRudeEditsAroundActiveStatement( IReadOnlyDictionary reverseMap, SyntaxNode oldActiveStatement, DeclarationBody oldBody, + SemanticModel oldModel, SyntaxNode newActiveStatement, DeclarationBody newBody, - bool isNonLeaf) + SemanticModel newModel, + bool isNonLeaf, + CancellationToken cancellationToken) { ReportRudeEditsForSwitchWhenClauses(diagnostics, oldActiveStatement, newActiveStatement); - ReportRudeEditsForAncestorsDeclaringInterStatementTemps(diagnostics, reverseMap, oldActiveStatement, oldBody.EncompassingAncestor, newActiveStatement, newBody.EncompassingAncestor); + ReportRudeEditsForAncestorsDeclaringInterStatementTemps(diagnostics, reverseMap, oldActiveStatement, oldBody.EncompassingAncestor, oldModel, newActiveStatement, newBody.EncompassingAncestor, newModel, cancellationToken); ReportRudeEditsForCheckedStatements(diagnostics, oldActiveStatement, newActiveStatement, isNonLeaf); } @@ -2982,8 +2978,11 @@ private void ReportRudeEditsForAncestorsDeclaringInterStatementTemps( IReadOnlyDictionary reverseMap, SyntaxNode oldActiveStatement, SyntaxNode oldEncompassingAncestor, + SemanticModel oldModel, SyntaxNode newActiveStatement, - SyntaxNode newEncompassingAncestor) + SyntaxNode newEncompassingAncestor, + SemanticModel newModel, + CancellationToken cancellationToken) { // Rude Edits for fixed/using/lock/foreach statements that are added/updated around an active statement. // Although such changes are technically possible, they might lead to confusion since @@ -2997,47 +2996,68 @@ private void ReportRudeEditsForAncestorsDeclaringInterStatementTemps( ReportUnmatchedStatements( diagnostics, reverseMap, - n => n.IsKind(SyntaxKind.LockStatement), oldActiveStatement, oldEncompassingAncestor, + oldModel, newActiveStatement, newEncompassingAncestor, + newModel, + nodeSelector: static n => n.IsKind(SyntaxKind.LockStatement), + getTypedNodes: static n => OneOrMany.OneOrNone(n.Expression), areEquivalent: AreEquivalentActiveStatements, - areSimilar: null); + areSimilar: null, + cancellationToken: cancellationToken); ReportUnmatchedStatements( diagnostics, reverseMap, - n => n.IsKind(SyntaxKind.FixedStatement), oldActiveStatement, oldEncompassingAncestor, + oldModel, newActiveStatement, newEncompassingAncestor, + newModel, + nodeSelector: static n => n.IsKind(SyntaxKind.FixedStatement), + getTypedNodes: static n => GetTypedNodes(n.Declaration), areEquivalent: AreEquivalentActiveStatements, - areSimilar: (n1, n2) => DeclareSameIdentifiers(n1.Declaration.Variables, n2.Declaration.Variables)); + areSimilar: static (n1, n2) => DeclareSameIdentifiers(n1.Declaration.Variables, n2.Declaration.Variables), + cancellationToken: cancellationToken); // Using statements with declaration do not introduce compiler generated temporary. ReportUnmatchedStatements( diagnostics, reverseMap, - n => n is UsingStatementSyntax usingStatement && usingStatement.Declaration is null, oldActiveStatement, oldEncompassingAncestor, + oldModel, newActiveStatement, newEncompassingAncestor, + newModel, + nodeSelector: static n => n is UsingStatementSyntax { Declaration: null } usingStatement, + getTypedNodes: static n => OneOrMany.Create(n.Expression!), areEquivalent: AreEquivalentActiveStatements, - areSimilar: null); + areSimilar: null, + cancellationToken: cancellationToken); ReportUnmatchedStatements( diagnostics, reverseMap, - n => n.Kind() is SyntaxKind.ForEachStatement or SyntaxKind.ForEachVariableStatement, oldActiveStatement, oldEncompassingAncestor, + oldModel, newActiveStatement, newEncompassingAncestor, + newModel, + nodeSelector: static n => n.Kind() is SyntaxKind.ForEachStatement or SyntaxKind.ForEachVariableStatement, + getTypedNodes: static n => OneOrMany.OneOrNone(n.Expression), areEquivalent: AreEquivalentActiveStatements, - areSimilar: AreSimilarActiveStatements); + areSimilar: AreSimilarActiveStatements, + cancellationToken: cancellationToken); + + static OneOrMany GetTypedNodes(VariableDeclarationSyntax declaration) + => (declaration.Variables is [{ Initializer: { } initializer }]) + ? OneOrMany.Create(initializer.Value) + : OneOrMany.Create(declaration.Variables.Select(static v => (SyntaxNode?)v.Initializer?.Value).WhereNotNull().ToImmutableArray()); } private static bool DeclareSameIdentifiers(SeparatedSyntaxList oldVariables, SeparatedSyntaxList newVariables) diff --git a/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs b/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs index 242aac9f9c563..d5693fd6c9ac3 100644 --- a/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs +++ b/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs @@ -28,15 +28,11 @@ namespace Microsoft.CodeAnalysis.CSharp.EncapsulateField; using static CSharpSyntaxTokens; using static SyntaxFactory; -[ExportLanguageService(typeof(AbstractEncapsulateFieldService), LanguageNames.CSharp), Shared] -internal class CSharpEncapsulateFieldService : AbstractEncapsulateFieldService +[ExportLanguageService(typeof(IEncapsulateFieldService), LanguageNames.CSharp), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpEncapsulateFieldService() : AbstractEncapsulateFieldService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpEncapsulateFieldService() - { - } - protected override async Task RewriteFieldNameAndAccessibilityAsync(string originalFieldName, bool makePrivate, Document document, SyntaxAnnotation declarationAnnotation, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -129,9 +125,10 @@ protected override async Task> GetFieldsAsync(Docum var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var fields = root.DescendantNodes(d => d.Span.IntersectsWith(span)) - .OfType() - .Where(n => n.Span.IntersectsWith(span)); + var fields = root + .DescendantNodes(d => d.Span.IntersectsWith(span)) + .OfType() + .Where(n => n.Span.IntersectsWith(span)); var declarations = fields.Where(CanEncapsulate).Select(f => f.Declaration); @@ -196,12 +193,13 @@ private static bool IsNew(IFieldSymbol field) private static string GenerateFieldName(string correspondingPropertyName) => char.ToLower(correspondingPropertyName[0]).ToString() + correspondingPropertyName[1..]; - protected static string MakeUnique(string baseName, INamedTypeSymbol containingType) + private static string MakeUnique(string baseName, INamedTypeSymbol containingType) { var containingTypeMemberNames = containingType.GetAccessibleMembersInThisAndBaseTypes(containingType).Select(m => m.Name); return NameGenerator.GenerateUniqueName(baseName, containingTypeMemberNames.ToSet(), StringComparer.Ordinal); } - protected override IEnumerable GetConstructorNodes(INamedTypeSymbol containingType) - => containingType.Constructors.SelectMany(c => c.DeclaringSyntaxReferences.Select(d => d.GetSyntax())); + protected override IEnumerable GetConstructorNodes(INamedTypeSymbol containingType) + => containingType.Constructors.SelectMany( + c => c.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).OfType()); } diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.Analyzer.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.Analyzer.cs index 030509decb409..7526424e24719 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.Analyzer.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.Analyzer.cs @@ -16,7 +16,7 @@ internal partial class CSharpMethodExtractor { private class CSharpAnalyzer(CSharpSelectionResult selectionResult, bool localFunction, CancellationToken cancellationToken) : Analyzer(selectionResult, localFunction, cancellationToken) { - private static readonly HashSet s_nonNoisySyntaxKindSet = new HashSet(new int[] { (int)SyntaxKind.WhitespaceTrivia, (int)SyntaxKind.EndOfLineTrivia }); + private static readonly HashSet s_nonNoisySyntaxKindSet = new HashSet([(int)SyntaxKind.WhitespaceTrivia, (int)SyntaxKind.EndOfLineTrivia]); public static AnalyzerResult Analyze(CSharpSelectionResult selectionResult, bool localFunction, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs index 46fc988d86f19..2d3700ed684fc 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.ExpressionResult.cs @@ -2,10 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -80,7 +80,7 @@ public override (ITypeSymbol? returnType, bool returnsByRef) GetReturnType() private static (ITypeSymbol? typeSymbol, bool returnsByRef) GetRegularExpressionType(SemanticModel semanticModel, ExpressionSyntax node) { // regular case. always use ConvertedType to get implicit conversion right. - var expression = node.GetUnparenthesizedExpression(); + var expression = node.WalkDownParentheses(); var returnsByRef = false; if (expression is RefExpressionSyntax refExpression) { diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.cs index dc66109b8074d..833cf5c601851 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionResult.cs @@ -39,11 +39,10 @@ public static async Task CreateAsync( var root = await document.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var newDocument = await SemanticDocument.CreateAsync(document.Document.WithSyntaxRoot(AddAnnotations( root, - new[] - { + [ (firstToken, firstTokenAnnotation), (lastToken, lastTokenAnnotation) - })), cancellationToken).ConfigureAwait(false); + ])), cancellationToken).ConfigureAwait(false); if (selectionInExpression) { diff --git a/src/Features/CSharp/Portable/ExtractMethod/Extensions.cs b/src/Features/CSharp/Portable/ExtractMethod/Extensions.cs index ee19ba02b367b..04a82c64c2ab2 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/Extensions.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/Extensions.cs @@ -16,17 +16,6 @@ namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod; internal static class Extensions { - [return: NotNullIfNotNull(nameof(node))] - public static ExpressionSyntax? GetUnparenthesizedExpression(this ExpressionSyntax? node) - { - if (node is not ParenthesizedExpressionSyntax parenthesizedExpression) - { - return node; - } - - return GetUnparenthesizedExpression(parenthesizedExpression.Expression); - } - public static StatementSyntax? GetStatementUnderContainer(this SyntaxNode node) { Contract.ThrowIfNull(node); diff --git a/src/Features/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Features.csproj b/src/Features/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Features.csproj index 1e220b1528fa9..700525f239a5b 100644 --- a/src/Features/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Features.csproj +++ b/src/Features/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.Features.csproj @@ -36,7 +36,7 @@ - + diff --git a/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs b/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs index 58d9692f01e4a..e9ff906e3cee4 100644 --- a/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs +++ b/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs @@ -3,7 +3,6 @@ // 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; @@ -15,6 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.GoToDefinition; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -135,7 +135,7 @@ protected override NullableFlowState GetNullabilityAnalysis(SemanticModel semant return typeInfo.Nullability.FlowState; } - protected override async Task GetOnTheFlyDocsElementAsync(QuickInfoContext context, CancellationToken cancellationToken) + protected override async Task GetOnTheFlyDocsInfoAsync(QuickInfoContext context, CancellationToken cancellationToken) { var document = context.Document; var position = context.Position; @@ -146,13 +146,6 @@ protected override NullableFlowState GetNullabilityAnalysis(SemanticModel semant return null; } - // Checks to see if there have been any files excluded at the workspace level - // since the copilot service passes along symbol information. - if (await copilotService.IsAnyExclusionAsync(cancellationToken).ConfigureAwait(false)) - { - return null; - } - if (document.GetLanguageService() is not { } service || !await service.IsOnTheFlyDocsOptionEnabledAsync().ConfigureAwait(false)) { @@ -182,6 +175,19 @@ protected override NullableFlowState GetNullabilityAnalysis(SemanticModel semant return null; } + // Checks to see if any of the files containing the symbol are excluded. + var hasContentExcluded = false; + var symbolFilePaths = symbol.DeclaringSyntaxReferences.Select(reference => reference.SyntaxTree.FilePath); + foreach (var symbolFilePath in symbolFilePaths) + { + if (await copilotService.IsFileExcludedAsync(symbolFilePath, cancellationToken).ConfigureAwait(false)) + { + hasContentExcluded = true; + Logger.Log(FunctionId.Copilot_On_The_Fly_Docs_Content_Excluded, logLevel: LogLevel.Information); + break; + } + } + var maxLength = 1000; var symbolStrings = symbol.DeclaringSyntaxReferences.Select(reference => { @@ -190,6 +196,6 @@ protected override NullableFlowState GetNullabilityAnalysis(SemanticModel semant return sourceText.GetSubText(new Text.TextSpan(span.Start, Math.Min(maxLength, span.Length))).ToString(); }).ToImmutableArray(); - return new OnTheFlyDocsElement(symbol.ToDisplayString(), symbolStrings, symbol.Language); + return new OnTheFlyDocsInfo(symbol.ToDisplayString(), symbolStrings, symbol.Language, hasContentExcluded); } } diff --git a/src/Features/CSharp/Portable/RelatedDocuments/CSharpRelatedDocumentsService.cs b/src/Features/CSharp/Portable/RelatedDocuments/CSharpRelatedDocumentsService.cs new file mode 100644 index 0000000000000..4bfd056709c66 --- /dev/null +++ b/src/Features/CSharp/Portable/RelatedDocuments/CSharpRelatedDocumentsService.cs @@ -0,0 +1,82 @@ +// 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.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.RelatedDocuments; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.CSharp.RelatedDocuments; + +[ExportLanguageService(typeof(IRelatedDocumentsService), LanguageNames.CSharp), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpRelatedDocumentsService() : AbstractRelatedDocumentsService< + ExpressionSyntax, + NameSyntax> +{ + protected override IEnumerable<(ExpressionSyntax expression, SyntaxToken nameToken)> IteratePotentialTypeNodes(SyntaxNode root) + { + using var _ = ArrayBuilder.GetInstance(out var stack); + stack.Push(root); + + while (stack.TryPop(out var current)) + { + if (current is MemberAccessExpressionSyntax memberAccess) + { + // Could be a static member access off of a type name. Check the left side, and if it's just a + // dotted name, return that. + + if (IsPossibleTypeName(memberAccess.Expression, out var nameToken)) + { + // Something like `X.Y.Z` where `X.Y` is a type name. Bind X.Y + yield return (memberAccess.Expression, nameToken); + } + else + { + // Something like `(...).Y`. Recurse down the left side of the member access to see if there + // are types in there. We don't want to recurse down the name portion as it will never be a + // type. + stack.Push(memberAccess.Expression); + } + + continue; + } + else if (current is NameSyntax name) + { + yield return (name, name.GetNameToken()); + + // Intentionally continue to recurse down the name so that if we have things like `X` we'll bind + // the inner `Y` as well. + } + + // Don't need to recurse in order as our caller is ordering results anyways. + foreach (var child in current.ChildNodesAndTokens()) + { + if (child.AsNode(out var childNode)) + stack.Push(childNode); + } + } + + static bool IsPossibleTypeName(ExpressionSyntax expression, out SyntaxToken nameToken) + { + while (expression is MemberAccessExpressionSyntax memberAccessExpression) + expression = memberAccessExpression.Expression; + + if (expression is not NameSyntax name) + { + nameToken = default; + return false; + } + + nameToken = name.GetNameToken(); + return true; + } + } +} diff --git a/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs b/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs index 590c1ec98e9d6..b12dbdb0eea3f 100644 --- a/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs +++ b/src/Features/CSharp/Portable/ReplaceMethodWithProperty/CSharpReplaceMethodWithPropertyService.cs @@ -185,6 +185,7 @@ private static AccessorDeclarationSyntax UseExpressionOrBlockBodyIfDesired( return accessorDeclaration.WithBody(null) .WithExpressionBody(arrowExpression) .WithSemicolonToken(semicolonToken) + .WithTrailingTrivia(accessorDeclaration.Body.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); } } diff --git a/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs b/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs index 766205edbf442..7af026af494b5 100644 --- a/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs +++ b/src/Features/CSharp/Portable/SignatureHelp/TupleConstructionSignatureHelpProvider.cs @@ -50,10 +50,10 @@ public TupleConstructionSignatureHelpProvider() if (currentSpan.Start == parenthesizedExpression.SpanStart) { return new SignatureHelpState( - argumentIndex: 0, - argumentCount: 0, - argumentName: string.Empty, - argumentNames: default); + SemanticParameterIndex: 0, + SyntacticArgumentCount: 0, + ArgumentName: string.Empty, + ArgumentNames: default); } } diff --git a/src/Features/CSharp/Portable/Snippets/AbstractCSharpAutoPropertySnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/AbstractCSharpAutoPropertySnippetProvider.cs index 954a85488b311..9e6a532dd26f2 100644 --- a/src/Features/CSharp/Portable/Snippets/AbstractCSharpAutoPropertySnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/AbstractCSharpAutoPropertySnippetProvider.cs @@ -30,7 +30,7 @@ internal abstract class AbstractCSharpAutoPropertySnippetProvider : AbstractProp protected virtual AccessorDeclarationSyntax? GenerateSetAccessorDeclaration(CSharpSyntaxContext syntaxContext, SyntaxGenerator generator, CancellationToken cancellationToken) => (AccessorDeclarationSyntax)generator.SetAccessorDeclaration(); - protected override bool IsValidSnippetLocation(in SnippetContext context, CancellationToken cancellationToken) + protected override bool IsValidSnippetLocationCore(SnippetContext context, CancellationToken cancellationToken) { return context.SyntaxContext.SyntaxTree.IsMemberDeclarationContext(context.Position, (CSharpSyntaxContext)context.SyntaxContext, SyntaxKindSet.AllMemberModifiers, SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, canBePartial: true, cancellationToken); diff --git a/src/Features/CSharp/Portable/Snippets/AbstractCSharpForLoopSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/AbstractCSharpForLoopSnippetProvider.cs index ac339ddcd4b0f..96e5075f2a99d 100644 --- a/src/Features/CSharp/Portable/Snippets/AbstractCSharpForLoopSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/AbstractCSharpForLoopSnippetProvider.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageService; @@ -38,6 +39,9 @@ internal abstract class AbstractCSharpForLoopSnippetProvider : AbstractForLoopSn protected abstract void AddSpecificPlaceholders(MultiDictionary placeholderBuilder, ExpressionSyntax initializer, ExpressionSyntax rightOfCondition); + protected override bool CanInsertStatementAfterToken(SyntaxToken token) + => token.IsBeginningOfStatementContext() || token.IsBeginningOfGlobalStatementContext(); + protected override ForStatementSyntax GenerateStatement(SyntaxGenerator generator, SyntaxContext syntaxContext, InlineExpressionInfo? inlineExpressionInfo) { var semanticModel = syntaxContext.SemanticModel; diff --git a/src/Features/CSharp/Portable/Snippets/AbstractCSharpMainMethodSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/AbstractCSharpMainMethodSnippetProvider.cs index aa84a9a5061c8..cc9cce7497814 100644 --- a/src/Features/CSharp/Portable/Snippets/AbstractCSharpMainMethodSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/AbstractCSharpMainMethodSnippetProvider.cs @@ -15,9 +15,9 @@ namespace Microsoft.CodeAnalysis.CSharp.Snippets; internal abstract class AbstractCSharpMainMethodSnippetProvider : AbstractMainMethodSnippetProvider { - protected override bool IsValidSnippetLocation(in SnippetContext context, CancellationToken cancellationToken) + protected override bool IsValidSnippetLocationCore(SnippetContext context, CancellationToken cancellationToken) { - var semanticModel = context.SyntaxContext.SemanticModel; + var semanticModel = context.SemanticModel; var syntaxContext = (CSharpSyntaxContext)context.SyntaxContext; if (!syntaxContext.IsMemberDeclarationContext( diff --git a/src/Features/CSharp/Portable/Snippets/AbstractCSharpTypeSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/AbstractCSharpTypeSnippetProvider.cs index 6569ef7bdd066..322ae299d7923 100644 --- a/src/Features/CSharp/Portable/Snippets/AbstractCSharpTypeSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/AbstractCSharpTypeSnippetProvider.cs @@ -27,7 +27,9 @@ internal abstract class AbstractCSharpTypeSnippetProvider ValidModifiers { get; } - protected override bool IsValidSnippetLocation(in SnippetContext context, CancellationToken cancellationToken) + protected virtual bool CanBePartial => true; + + protected override bool IsValidSnippetLocationCore(SnippetContext context, CancellationToken cancellationToken) { var syntaxContext = (CSharpSyntaxContext)context.SyntaxContext; @@ -36,7 +38,7 @@ protected override bool IsValidSnippetLocation(in SnippetContext context, Cancel syntaxContext.IsTypeDeclarationContext( validModifiers: ValidModifiers, validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructRecordTypeDeclarations, - canBePartial: true, + canBePartial: CanBePartial, cancellationToken: cancellationToken); } diff --git a/src/Features/CSharp/Portable/Snippets/CSharpConsoleSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpConsoleSnippetProvider.cs index cf175e08e78a8..0a91a98893177 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpConsoleSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpConsoleSnippetProvider.cs @@ -21,11 +21,12 @@ internal sealed class CSharpConsoleSnippetProvider() : AbstractConsoleSnippetPro ArgumentListSyntax, LambdaExpressionSyntax> { - protected override bool IsValidSnippetLocation(in SnippetContext context, CancellationToken cancellationToken) + protected override bool IsValidSnippetLocationCore(SnippetContext context, CancellationToken cancellationToken) { var syntaxContext = context.SyntaxContext; + var semanticModel = context.SemanticModel; - var consoleSymbol = GetConsoleSymbolFromMetaDataName(syntaxContext.SemanticModel.Compilation); + var consoleSymbol = GetConsoleSymbolFromMetaDataName(semanticModel.Compilation); if (consoleSymbol is null) return false; @@ -33,7 +34,6 @@ protected override bool IsValidSnippetLocation(in SnippetContext context, Cancel // Action a = () => Console.WriteLine("Action called"); if (syntaxContext.TargetToken is { RawKind: (int)SyntaxKind.EqualsGreaterThanToken, Parent: LambdaExpressionSyntax lambda }) { - var semanticModel = syntaxContext.SemanticModel; var lambdaSymbol = semanticModel.GetSymbolInfo(lambda, cancellationToken).Symbol; // Given that we are in a partially written lambda state compiler might not always infer return type correctly. diff --git a/src/Features/CSharp/Portable/Snippets/CSharpConstructorSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpConstructorSnippetProvider.cs index 1e7ab1e7817bc..f885a980d0a48 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpConstructorSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpConstructorSnippetProvider.cs @@ -36,7 +36,7 @@ internal sealed class CSharpConstructorSnippetProvider() : AbstractConstructorSn SyntaxKind.StaticKeyword, }; - protected override bool IsValidSnippetLocation(in SnippetContext context, CancellationToken cancellationToken) + protected override bool IsValidSnippetLocationCore(SnippetContext context, CancellationToken cancellationToken) { var syntaxContext = (CSharpSyntaxContext)context.SyntaxContext; diff --git a/src/Features/CSharp/Portable/Snippets/CSharpDoWhileLoopStatementProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpDoWhileLoopSnippetProvider.cs similarity index 88% rename from src/Features/CSharp/Portable/Snippets/CSharpDoWhileLoopStatementProvider.cs rename to src/Features/CSharp/Portable/Snippets/CSharpDoWhileLoopSnippetProvider.cs index 4e8154e17b8a4..6c98a8bd41729 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpDoWhileLoopStatementProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpDoWhileLoopSnippetProvider.cs @@ -6,6 +6,7 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host.Mef; @@ -19,13 +20,16 @@ namespace Microsoft.CodeAnalysis.CSharp.Snippets; [ExportSnippetProvider(nameof(ISnippetProvider), LanguageNames.CSharp), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal sealed class CSharpDoWhileLoopStatementProvider() +internal sealed class CSharpDoWhileLoopSnippetProvider() : AbstractConditionalBlockSnippetProvider { public override string Identifier => CSharpSnippetIdentifiers.Do; public override string Description => CSharpFeaturesResources.do_while_loop; + protected override bool CanInsertStatementAfterToken(SyntaxToken token) + => token.IsBeginningOfStatementContext() || token.IsBeginningOfGlobalStatementContext(); + protected override DoStatementSyntax GenerateStatement(SyntaxGenerator generator, SyntaxContext syntaxContext, InlineExpressionInfo? inlineExpressionInfo) { return SyntaxFactory.DoStatement( diff --git a/src/Features/CSharp/Portable/Snippets/CSharpElseSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpElseSnippetProvider.cs index 4fdf90a78525c..a720e79571b8d 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpElseSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpElseSnippetProvider.cs @@ -24,7 +24,7 @@ internal sealed class CSharpElseSnippetProvider() : AbstractElseSnippetProvider< public override string Description => FeaturesResources.else_statement; - protected override bool IsValidSnippetLocation(in SnippetContext context, CancellationToken cancellationToken) + protected override bool IsValidSnippetLocationCore(SnippetContext context, CancellationToken cancellationToken) { var syntaxContext = context.SyntaxContext; var token = syntaxContext.TargetToken; @@ -51,7 +51,7 @@ protected override bool IsValidSnippetLocation(in SnippetContext context, Cancel } } - return isAfterIfStatement && base.IsValidSnippetLocation(in context, cancellationToken); + return isAfterIfStatement && base.IsValidSnippetLocationCore(context, cancellationToken); } protected override Task GenerateSnippetTextChangeAsync(Document document, int position, CancellationToken cancellationToken) diff --git a/src/Features/CSharp/Portable/Snippets/CSharpEnumSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpEnumSnippetProvider.cs index 1ffa575749b5a..84ad261a5de86 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpEnumSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpEnumSnippetProvider.cs @@ -37,6 +37,8 @@ internal sealed class CSharpEnumSnippetProvider() : AbstractCSharpTypeSnippetPro protected override ISet ValidModifiers => s_validModifiers; + protected override bool CanBePartial => false; + protected override async Task GenerateTypeDeclarationAsync(Document document, int position, CancellationToken cancellationToken) { var generator = SyntaxGenerator.GetGenerator(document); diff --git a/src/Features/CSharp/Portable/Snippets/CSharpForEachLoopSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpForEachLoopSnippetProvider.cs index 1ff99c4351f6d..e0c8b4e7a5dec 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpForEachLoopSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpForEachLoopSnippetProvider.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host.Mef; @@ -34,7 +35,7 @@ internal sealed class CSharpForEachLoopSnippetProvider() : AbstractForEachLoopSn public override string Description => FeaturesResources.foreach_loop; - protected override bool IsValidSnippetLocation(in SnippetContext context, CancellationToken cancellationToken) + protected override bool IsValidSnippetLocationCore(SnippetContext context, CancellationToken cancellationToken) { var syntaxContext = context.SyntaxContext; var token = syntaxContext.TargetToken; @@ -48,9 +49,12 @@ protected override bool IsValidSnippetLocation(in SnippetContext context, Cancel return true; } - return base.IsValidSnippetLocation(in context, cancellationToken); + return base.IsValidSnippetLocationCore(context, cancellationToken); } + protected override bool CanInsertStatementAfterToken(SyntaxToken token) + => token.IsBeginningOfStatementContext() || token.IsBeginningOfGlobalStatementContext(); + protected override ForEachStatementSyntax GenerateStatement(SyntaxGenerator generator, SyntaxContext syntaxContext, InlineExpressionInfo? inlineExpressionInfo) { var semanticModel = syntaxContext.SemanticModel; diff --git a/src/Features/CSharp/Portable/Snippets/CSharpIfSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpIfSnippetProvider.cs index a93cfd6468c69..e657d23918c07 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpIfSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpIfSnippetProvider.cs @@ -6,6 +6,7 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Snippets; @@ -23,6 +24,9 @@ internal sealed class CSharpIfSnippetProvider() : AbstractIfSnippetProvider FeaturesResources.if_statement; + protected override bool CanInsertStatementAfterToken(SyntaxToken token) + => token.IsBeginningOfStatementContext() || token.IsBeginningOfGlobalStatementContext(); + protected override ExpressionSyntax GetCondition(IfStatementSyntax node) => node.Condition; diff --git a/src/Features/CSharp/Portable/Snippets/CSharpWhileLoopSnippetProvider.cs b/src/Features/CSharp/Portable/Snippets/CSharpWhileLoopSnippetProvider.cs index 28121dccb802a..9884811b76bcc 100644 --- a/src/Features/CSharp/Portable/Snippets/CSharpWhileLoopSnippetProvider.cs +++ b/src/Features/CSharp/Portable/Snippets/CSharpWhileLoopSnippetProvider.cs @@ -6,6 +6,7 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Snippets; @@ -23,6 +24,9 @@ internal sealed class CSharpWhileLoopSnippetProvider() : AbstractWhileLoopSnippe public override string Description => FeaturesResources.while_loop; + protected override bool CanInsertStatementAfterToken(SyntaxToken token) + => token.IsBeginningOfStatementContext() || token.IsBeginningOfGlobalStatementContext(); + protected override ExpressionSyntax GetCondition(WhileStatementSyntax node) => node.Condition; diff --git a/src/Features/CSharp/Portable/Structure/CSharpStructureHelpers.cs b/src/Features/CSharp/Portable/Structure/CSharpStructureHelpers.cs index 86e90bacf9db5..e7b9ea1f7f0b0 100644 --- a/src/Features/CSharp/Portable/Structure/CSharpStructureHelpers.cs +++ b/src/Features/CSharp/Portable/Structure/CSharpStructureHelpers.cs @@ -7,6 +7,7 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Structure; @@ -161,7 +162,7 @@ private static BlockSpan CreateCommentBlockSpan( } public static void CollectCommentBlockSpans( - SyntaxTriviaList triviaList, ref TemporaryArray spans) + SyntaxTriviaList triviaList, ArrayBuilder spans) { if (triviaList.Count > 0) { @@ -186,14 +187,14 @@ public static void CollectCommentBlockSpans( else if (trivia is not SyntaxTrivia( SyntaxKind.WhitespaceTrivia or SyntaxKind.EndOfLineTrivia or SyntaxKind.EndOfFileToken)) { - completeSingleLineCommentGroup(ref spans); + completeSingleLineCommentGroup(spans); } } - completeSingleLineCommentGroup(ref spans); + completeSingleLineCommentGroup(spans); return; - void completeSingleLineCommentGroup(ref TemporaryArray spans) + void completeSingleLineCommentGroup(ArrayBuilder spans) { if (startComment != null) { @@ -208,7 +209,7 @@ void completeSingleLineCommentGroup(ref TemporaryArray spans) public static void CollectCommentBlockSpans( SyntaxNode node, - ref TemporaryArray spans, + ArrayBuilder spans, in BlockStructureOptions options) { if (node == null) @@ -223,7 +224,7 @@ public static void CollectCommentBlockSpans( else { var triviaList = node.GetLeadingTrivia(); - CollectCommentBlockSpans(triviaList, ref spans); + CollectCommentBlockSpans(triviaList, spans); } return; diff --git a/src/Features/CSharp/Portable/Structure/Providers/AccessorDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/AccessorDeclarationStructureProvider.cs index 1ba98fef67012..4d772c3ffee73 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/AccessorDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/AccessorDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,11 +14,11 @@ internal class AccessorDeclarationStructureProvider : AbstractSyntaxNodeStructur protected override void CollectBlockSpans( SyntaxToken previousToken, AccessorDeclarationSyntax accessorDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(accessorDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(accessorDeclaration, spans, options); // fault tolerance if (accessorDeclaration.Body == null || diff --git a/src/Features/CSharp/Portable/Structure/Providers/AnonymousMethodExpressionStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/AnonymousMethodExpressionStructureProvider.cs index 2d755c981f82f..e92318e259785 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/AnonymousMethodExpressionStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/AnonymousMethodExpressionStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,7 +14,7 @@ internal class AnonymousMethodExpressionStructureProvider : AbstractSyntaxNodeSt protected override void CollectBlockSpans( SyntaxToken previousToken, AnonymousMethodExpressionSyntax anonymousMethod, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/AnonymousObjectCreationExpressionStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/AnonymousObjectCreationExpressionStructureProvider.cs index 757221af257a2..c19569125435c 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/AnonymousObjectCreationExpressionStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/AnonymousObjectCreationExpressionStructureProvider.cs @@ -6,7 +6,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; @@ -17,7 +17,7 @@ internal class AnonymousObjectCreationExpressionStructureProvider : AbstractSynt protected override void CollectBlockSpans( SyntaxToken previousToken, AnonymousObjectCreationExpressionSyntax node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/ArgumentListStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/ArgumentListStructureProvider.cs index 9ae60a9abe8f0..13309f2775456 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/ArgumentListStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/ArgumentListStructureProvider.cs @@ -4,14 +4,14 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; internal sealed class ArgumentListStructureProvider : AbstractSyntaxNodeStructureProvider { - protected override void CollectBlockSpans(SyntaxToken previousToken, ArgumentListSyntax node, ref TemporaryArray spans, BlockStructureOptions options, CancellationToken cancellationToken) + protected override void CollectBlockSpans(SyntaxToken previousToken, ArgumentListSyntax node, ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { if (!IsCandidate(node, cancellationToken)) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/ArrowExpressionClauseStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/ArrowExpressionClauseStructureProvider.cs index 9b71b124c82f8..1f192ca31d718 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/ArrowExpressionClauseStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/ArrowExpressionClauseStructureProvider.cs @@ -7,7 +7,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; @@ -18,7 +18,7 @@ internal class ArrowExpressionClauseStructureProvider : AbstractSyntaxNodeStruct protected override void CollectBlockSpans( SyntaxToken previousToken, ArrowExpressionClauseSyntax node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/BlockSyntaxStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/BlockSyntaxStructureProvider.cs index 3ed97bd48e71c..7b8d2062f5c84 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/BlockSyntaxStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/BlockSyntaxStructureProvider.cs @@ -6,6 +6,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Structure; @@ -19,7 +20,7 @@ internal sealed class BlockSyntaxStructureProvider : AbstractSyntaxNodeStructure protected override void CollectBlockSpans( SyntaxToken previousToken, BlockSyntax node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/CollectionExpressionStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/CollectionExpressionStructureProvider.cs index 1d1ef5a3914b8..ed1bbfee2fd3a 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/CollectionExpressionStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/CollectionExpressionStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; @@ -15,7 +15,7 @@ internal class CollectionExpressionStructureProvider : AbstractSyntaxNodeStructu protected override void CollectBlockSpans( SyntaxToken previousToken, CollectionExpressionSyntax node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/CompilationUnitStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/CompilationUnitStructureProvider.cs index 2d9e552b8d744..2726822ff59ae 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/CompilationUnitStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/CompilationUnitStructureProvider.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -17,11 +17,11 @@ internal class CompilationUnitStructureProvider : AbstractSyntaxNodeStructurePro protected override void CollectBlockSpans( SyntaxToken previousToken, CompilationUnitSyntax compilationUnit, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(compilationUnit, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(compilationUnit, spans, options); // extern aliases and usings are outlined in a single region var externsAndUsings = new List(); @@ -42,7 +42,7 @@ protected override void CollectBlockSpans( compilationUnit.Members.Count > 0 || compilationUnit.AttributeLists.Count > 0) { - CSharpStructureHelpers.CollectCommentBlockSpans(compilationUnit.EndOfFileToken.LeadingTrivia, ref spans); + CSharpStructureHelpers.CollectCommentBlockSpans(compilationUnit.EndOfFileToken.LeadingTrivia, spans); } } } diff --git a/src/Features/CSharp/Portable/Structure/Providers/ConstructorDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/ConstructorDeclarationStructureProvider.cs index fb8a0c224fc40..33c52f641c38f 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/ConstructorDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/ConstructorDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,11 +14,11 @@ internal class ConstructorDeclarationStructureProvider : AbstractSyntaxNodeStruc protected override void CollectBlockSpans( SyntaxToken previousToken, ConstructorDeclarationSyntax constructorDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(constructorDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(constructorDeclaration, spans, options); // fault tolerance if (constructorDeclaration.Body == null || diff --git a/src/Features/CSharp/Portable/Structure/Providers/ConversionOperatorDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/ConversionOperatorDeclarationStructureProvider.cs index 75e3e39affc47..6779b441d768e 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/ConversionOperatorDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/ConversionOperatorDeclarationStructureProvider.cs @@ -6,7 +6,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -16,11 +16,11 @@ internal class ConversionOperatorDeclarationStructureProvider : AbstractSyntaxNo protected override void CollectBlockSpans( SyntaxToken previousToken, ConversionOperatorDeclarationSyntax operatorDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(operatorDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(operatorDeclaration, spans, options); // fault tolerance if (operatorDeclaration.Body == null || diff --git a/src/Features/CSharp/Portable/Structure/Providers/DelegateDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/DelegateDeclarationStructureProvider.cs index bc46e8d5e1cec..b2e0d58a886ff 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/DelegateDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/DelegateDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,10 +14,10 @@ internal class DelegateDeclarationStructureProvider : AbstractSyntaxNodeStructur protected override void CollectBlockSpans( SyntaxToken previousToken, DelegateDeclarationSyntax delegateDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(delegateDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(delegateDeclaration, spans, options); } } diff --git a/src/Features/CSharp/Portable/Structure/Providers/DestructorDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/DestructorDeclarationStructureProvider.cs index effc47dd6864b..115f427986abe 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/DestructorDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/DestructorDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,11 +14,11 @@ internal class DestructorDeclarationStructureProvider : AbstractSyntaxNodeStruct protected override void CollectBlockSpans( SyntaxToken previousToken, DestructorDeclarationSyntax destructorDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(destructorDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(destructorDeclaration, spans, options); // fault tolerance if (destructorDeclaration.Body == null || diff --git a/src/Features/CSharp/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.cs index 82848583e45f4..eaba300c303c9 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -14,17 +14,17 @@ internal sealed class DisabledTextTriviaStructureProvider : AbstractSyntaxTrivia { public override void CollectBlockSpans( SyntaxTrivia trivia, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { Contract.ThrowIfNull(trivia.SyntaxTree); - CollectBlockSpans(trivia.SyntaxTree, trivia, ref spans, cancellationToken); + CollectBlockSpans(trivia.SyntaxTree, trivia, spans, cancellationToken); } public static void CollectBlockSpans( SyntaxTree syntaxTree, SyntaxTrivia trivia, - ref TemporaryArray spans, CancellationToken cancellationToken) + ArrayBuilder spans, CancellationToken cancellationToken) { // We'll always be leading trivia of some token. var startPos = trivia.FullSpan.Start; diff --git a/src/Features/CSharp/Portable/Structure/Providers/DocumentationCommentStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/DocumentationCommentStructureProvider.cs index bc8e968162f8f..5664ed38e22a8 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/DocumentationCommentStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/DocumentationCommentStructureProvider.cs @@ -5,7 +5,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; @@ -16,7 +16,7 @@ internal class DocumentationCommentStructureProvider : AbstractSyntaxNodeStructu protected override void CollectBlockSpans( SyntaxToken previousToken, DocumentationCommentTriviaSyntax documentationComment, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/EnumDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/EnumDeclarationStructureProvider.cs index 00a2a12e79c7e..1ef210872e7e1 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/EnumDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/EnumDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,11 +14,11 @@ internal class EnumDeclarationStructureProvider : AbstractSyntaxNodeStructurePro protected override void CollectBlockSpans( SyntaxToken previousToken, EnumDeclarationSyntax enumDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(enumDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(enumDeclaration, spans, options); if (!enumDeclaration.OpenBraceToken.IsMissing && !enumDeclaration.CloseBraceToken.IsMissing) @@ -45,7 +45,7 @@ protected override void CollectBlockSpans( if (!enumDeclaration.CloseBraceToken.IsMissing) { var leadingTrivia = enumDeclaration.CloseBraceToken.LeadingTrivia; - CSharpStructureHelpers.CollectCommentBlockSpans(leadingTrivia, ref spans); + CSharpStructureHelpers.CollectCommentBlockSpans(leadingTrivia, spans); } } } diff --git a/src/Features/CSharp/Portable/Structure/Providers/EnumMemberDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/EnumMemberDeclarationStructureProvider.cs index 6dfe41ae72637..758b0d18ab2a1 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/EnumMemberDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/EnumMemberDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,10 +14,10 @@ internal class EnumMemberDeclarationStructureProvider : AbstractSyntaxNodeStruct protected override void CollectBlockSpans( SyntaxToken previousToken, EnumMemberDeclarationSyntax enumMemberDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(enumMemberDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(enumMemberDeclaration, spans, options); } } diff --git a/src/Features/CSharp/Portable/Structure/Providers/EventDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/EventDeclarationStructureProvider.cs index 1ad4a2cf5945a..e814736411e3e 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/EventDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/EventDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,11 +14,11 @@ internal class EventDeclarationStructureProvider : AbstractSyntaxNodeStructurePr protected override void CollectBlockSpans( SyntaxToken previousToken, EventDeclarationSyntax eventDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(eventDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(eventDeclaration, spans, options); // fault tolerance if (eventDeclaration.AccessorList == null || diff --git a/src/Features/CSharp/Portable/Structure/Providers/EventFieldDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/EventFieldDeclarationStructureProvider.cs index 8267a10bfb6cf..5cb802a5eb247 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/EventFieldDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/EventFieldDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,10 +14,10 @@ internal class EventFieldDeclarationStructureProvider : AbstractSyntaxNodeStruct protected override void CollectBlockSpans( SyntaxToken previousToken, EventFieldDeclarationSyntax eventFieldDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(eventFieldDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(eventFieldDeclaration, spans, options); } } diff --git a/src/Features/CSharp/Portable/Structure/Providers/FieldDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/FieldDeclarationStructureProvider.cs index 95c8d81fcc6bd..14c9eb78315e8 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/FieldDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/FieldDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,10 +14,10 @@ internal class FieldDeclarationStructureProvider : AbstractSyntaxNodeStructurePr protected override void CollectBlockSpans( SyntaxToken previousToken, FieldDeclarationSyntax fieldDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(fieldDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(fieldDeclaration, spans, options); } } diff --git a/src/Features/CSharp/Portable/Structure/Providers/FileScopedNamespaceDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/FileScopedNamespaceDeclarationStructureProvider.cs index 824b70afdfad5..c0dbcd33d6c77 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/FileScopedNamespaceDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/FileScopedNamespaceDeclarationStructureProvider.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Structure; @@ -16,12 +17,12 @@ internal class FileScopedNamespaceDeclarationStructureProvider : AbstractSyntaxN protected override void CollectBlockSpans( SyntaxToken previousToken, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { // add leading comments - CSharpStructureHelpers.CollectCommentBlockSpans(fileScopedNamespaceDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(fileScopedNamespaceDeclaration, spans, options); // extern aliases and usings are outlined in a single region var externsAndUsings = Enumerable.Union(fileScopedNamespaceDeclaration.Externs, fileScopedNamespaceDeclaration.Usings).ToImmutableArray(); @@ -29,7 +30,7 @@ protected override void CollectBlockSpans( // add any leading comments before the extern aliases and usings if (externsAndUsings.Any()) { - CSharpStructureHelpers.CollectCommentBlockSpans(externsAndUsings.First(), ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(externsAndUsings.First(), spans, options); } spans.AddIfNotNull(CSharpStructureHelpers.CreateBlockSpan( diff --git a/src/Features/CSharp/Portable/Structure/Providers/IfDirectiveTriviaStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/IfDirectiveTriviaStructureProvider.cs index d2972162767f6..5daa919d80a36 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/IfDirectiveTriviaStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/IfDirectiveTriviaStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; @@ -19,7 +19,7 @@ internal sealed class IfDirectiveTriviaStructureProvider : AbstractSyntaxNodeStr protected override void CollectBlockSpans( SyntaxToken previousToken, IfDirectiveTriviaSyntax node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/IndexerDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/IndexerDeclarationStructureProvider.cs index 7ce664545f141..00284b782fe7d 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/IndexerDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/IndexerDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,11 +14,11 @@ internal class IndexerDeclarationStructureProvider : AbstractSyntaxNodeStructure protected override void CollectBlockSpans( SyntaxToken previousToken, IndexerDeclarationSyntax indexerDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(indexerDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(indexerDeclaration, spans, options); // fault tolerance if (indexerDeclaration.AccessorList == null || diff --git a/src/Features/CSharp/Portable/Structure/Providers/InitializerExpressionStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/InitializerExpressionStructureProvider.cs index 4e169180072cb..0892f9066d334 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/InitializerExpressionStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/InitializerExpressionStructureProvider.cs @@ -6,7 +6,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; @@ -17,7 +17,7 @@ internal class InitializerExpressionStructureProvider : AbstractSyntaxNodeStruct protected override void CollectBlockSpans( SyntaxToken previousToken, InitializerExpressionSyntax node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/InterpolatedStringExpressionStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/InterpolatedStringExpressionStructureProvider.cs index 844b8cf20af1d..550aa99abe246 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/InterpolatedStringExpressionStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/InterpolatedStringExpressionStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,7 +14,7 @@ internal sealed class InterpolatedStringExpressionStructureProvider : AbstractSy protected override void CollectBlockSpans( SyntaxToken previousToken, InterpolatedStringExpressionSyntax node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/MethodDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/MethodDeclarationStructureProvider.cs index 8416d83a3eb3f..21d0595fe7d14 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/MethodDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/MethodDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,11 +14,11 @@ internal class MethodDeclarationStructureProvider : AbstractSyntaxNodeStructureP protected override void CollectBlockSpans( SyntaxToken previousToken, MethodDeclarationSyntax methodDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(methodDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(methodDeclaration, spans, options); // fault tolerance if (methodDeclaration.Body == null || diff --git a/src/Features/CSharp/Portable/Structure/Providers/MultilineCommentBlockStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/MultilineCommentBlockStructureProvider.cs index ab54809b4a235..16e7fe2488245 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/MultilineCommentBlockStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/MultilineCommentBlockStructureProvider.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -12,7 +12,7 @@ internal class MultilineCommentBlockStructureProvider : AbstractSyntaxTriviaStru { public override void CollectBlockSpans( SyntaxTrivia trivia, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/NamespaceDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/NamespaceDeclarationStructureProvider.cs index fef2227d66a83..c249997616baf 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/NamespaceDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/NamespaceDeclarationStructureProvider.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -15,12 +15,12 @@ internal class NamespaceDeclarationStructureProvider : AbstractSyntaxNodeStructu protected override void CollectBlockSpans( SyntaxToken previousToken, NamespaceDeclarationSyntax namespaceDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { // add leading comments - CSharpStructureHelpers.CollectCommentBlockSpans(namespaceDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(namespaceDeclaration, spans, options); if (!namespaceDeclaration.OpenBraceToken.IsMissing && !namespaceDeclaration.CloseBraceToken.IsMissing) @@ -42,7 +42,7 @@ protected override void CollectBlockSpans( // add any leading comments before the extern aliases and usings if (externsAndUsings.Count > 0) { - CSharpStructureHelpers.CollectCommentBlockSpans(externsAndUsings.First(), ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(externsAndUsings.First(), spans, options); } spans.AddIfNotNull(CSharpStructureHelpers.CreateBlockSpan( @@ -53,7 +53,7 @@ protected override void CollectBlockSpans( if (!namespaceDeclaration.CloseBraceToken.IsMissing) { CSharpStructureHelpers.CollectCommentBlockSpans( - namespaceDeclaration.CloseBraceToken.LeadingTrivia, ref spans); + namespaceDeclaration.CloseBraceToken.LeadingTrivia, spans); } } } diff --git a/src/Features/CSharp/Portable/Structure/Providers/OperatorDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/OperatorDeclarationStructureProvider.cs index c1ea008c6cdc9..d06d41eaa1541 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/OperatorDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/OperatorDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,11 +14,11 @@ internal class OperatorDeclarationStructureProvider : AbstractSyntaxNodeStructur protected override void CollectBlockSpans( SyntaxToken previousToken, OperatorDeclarationSyntax operatorDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(operatorDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(operatorDeclaration, spans, options); // fault tolerance if (operatorDeclaration.Body == null || diff --git a/src/Features/CSharp/Portable/Structure/Providers/ParenthesizedLambdaExpressionStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/ParenthesizedLambdaExpressionStructureProvider.cs index f5713569db889..bf166cca97466 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/ParenthesizedLambdaExpressionStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/ParenthesizedLambdaExpressionStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,7 +14,7 @@ internal class ParenthesizedLambdaExpressionStructureProvider : AbstractSyntaxNo protected override void CollectBlockSpans( SyntaxToken previousToken, ParenthesizedLambdaExpressionSyntax lambdaExpression, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/PropertyDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/PropertyDeclarationStructureProvider.cs index e06ca522d4034..50f5c215b59e3 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/PropertyDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/PropertyDeclarationStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,11 +14,11 @@ internal class PropertyDeclarationStructureProvider : AbstractSyntaxNodeStructur protected override void CollectBlockSpans( SyntaxToken previousToken, PropertyDeclarationSyntax propertyDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(propertyDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(propertyDeclaration, spans, options); // fault tolerance if (propertyDeclaration.AccessorList == null || diff --git a/src/Features/CSharp/Portable/Structure/Providers/RegionDirectiveStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/RegionDirectiveStructureProvider.cs index 210b657c1f1b5..fc209e66075b0 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/RegionDirectiveStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/RegionDirectiveStructureProvider.cs @@ -5,7 +5,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; @@ -32,7 +32,7 @@ private static string GetBannerText(DirectiveTriviaSyntax simpleDirective) protected override void CollectBlockSpans( SyntaxToken previousToken, RegionDirectiveTriviaSyntax regionDirective, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/SimpleLambdaExpressionStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/SimpleLambdaExpressionStructureProvider.cs index 365b8844df246..f1dd972b70b8f 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/SimpleLambdaExpressionStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/SimpleLambdaExpressionStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,7 +14,7 @@ internal class SimpleLambdaExpressionStructureProvider : AbstractSyntaxNodeStruc protected override void CollectBlockSpans( SyntaxToken previousToken, SimpleLambdaExpressionSyntax lambdaExpression, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.cs index cf8da0c3eb1b9..2e3f14d80f49d 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -14,7 +14,7 @@ internal sealed class StringLiteralExpressionStructureProvider : AbstractSyntaxN protected override void CollectBlockSpans( SyntaxToken previousToken, LiteralExpressionSyntax node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/SwitchStatementStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/SwitchStatementStructureProvider.cs index 49a8fc1f1ad66..68c6aafa8493d 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/SwitchStatementStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/SwitchStatementStructureProvider.cs @@ -4,7 +4,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; using Microsoft.CodeAnalysis.Text; @@ -15,7 +15,7 @@ internal class SwitchStatementStructureProvider : AbstractSyntaxNodeStructurePro protected override void CollectBlockSpans( SyntaxToken previousToken, SwitchStatementSyntax node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Structure/Providers/TypeDeclarationStructureProvider.cs b/src/Features/CSharp/Portable/Structure/Providers/TypeDeclarationStructureProvider.cs index 05f135efd39b7..11ed11b058e17 100644 --- a/src/Features/CSharp/Portable/Structure/Providers/TypeDeclarationStructureProvider.cs +++ b/src/Features/CSharp/Portable/Structure/Providers/TypeDeclarationStructureProvider.cs @@ -6,7 +6,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Structure; namespace Microsoft.CodeAnalysis.CSharp.Structure; @@ -16,11 +16,11 @@ internal class TypeDeclarationStructureProvider : AbstractSyntaxNodeStructurePro protected override void CollectBlockSpans( SyntaxToken previousToken, TypeDeclarationSyntax typeDeclaration, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { - CSharpStructureHelpers.CollectCommentBlockSpans(typeDeclaration, ref spans, options); + CSharpStructureHelpers.CollectCommentBlockSpans(typeDeclaration, spans, options); if (!typeDeclaration.OpenBraceToken.IsMissing && !typeDeclaration.CloseBraceToken.IsMissing) @@ -53,7 +53,7 @@ protected override void CollectBlockSpans( if (!typeDeclaration.CloseBraceToken.IsMissing) { var leadingTrivia = typeDeclaration.CloseBraceToken.LeadingTrivia; - CSharpStructureHelpers.CollectCommentBlockSpans(leadingTrivia, ref spans); + CSharpStructureHelpers.CollectCommentBlockSpans(leadingTrivia, spans); } } } diff --git a/src/Features/CSharp/Portable/UseAutoProperty/CSharpUseAutoPropertyCodeFixProvider.cs b/src/Features/CSharp/Portable/UseAutoProperty/CSharpUseAutoPropertyCodeFixProvider.cs index adf0adae32d83..28991bf64838a 100644 --- a/src/Features/CSharp/Portable/UseAutoProperty/CSharpUseAutoPropertyCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/UseAutoProperty/CSharpUseAutoPropertyCodeFixProvider.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; using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; @@ -17,7 +16,11 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.UseAutoProperty; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UseAutoProperty; @@ -25,159 +28,222 @@ namespace Microsoft.CodeAnalysis.CSharp.UseAutoProperty; using static SyntaxFactory; [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.UseAutoProperty), Shared] -internal class CSharpUseAutoPropertyCodeFixProvider - : AbstractUseAutoPropertyCodeFixProvider +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed partial class CSharpUseAutoPropertyCodeFixProvider() + : AbstractUseAutoPropertyCodeFixProvider< + TypeDeclarationSyntax, + PropertyDeclarationSyntax, + VariableDeclaratorSyntax, + ConstructorDeclarationSyntax, + ExpressionSyntax> { - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public CSharpUseAutoPropertyCodeFixProvider() - { - } - protected override PropertyDeclarationSyntax GetPropertyDeclaration(SyntaxNode node) => (PropertyDeclarationSyntax)node; + private static bool SupportsReadOnlyProperties(Compilation compilation) + => compilation.LanguageVersion() >= LanguageVersion.CSharp6; + + private static bool IsSetOrInitAccessor(AccessorDeclarationSyntax accessor) + => accessor.Kind() is SyntaxKind.SetAccessorDeclaration or SyntaxKind.InitAccessorDeclaration; + + private static FieldDeclarationSyntax GetFieldDeclaration(VariableDeclaratorSyntax declarator) + => (FieldDeclarationSyntax)declarator.GetRequiredParent().GetRequiredParent(); + protected override SyntaxNode GetNodeToRemove(VariableDeclaratorSyntax declarator) { - var fieldDeclaration = (FieldDeclarationSyntax)declarator.Parent.Parent; - var nodeToRemove = fieldDeclaration.Declaration.Variables.Count > 1 ? declarator : (SyntaxNode)fieldDeclaration; - return nodeToRemove; + var fieldDeclaration = GetFieldDeclaration(declarator); + return fieldDeclaration.Declaration.Variables.Count > 1 ? declarator : fieldDeclaration; } - protected override async Task UpdatePropertyAsync( - Document propertyDocument, Compilation compilation, IFieldSymbol fieldSymbol, IPropertySymbol propertySymbol, - PropertyDeclarationSyntax propertyDeclaration, bool isWrittenOutsideOfConstructor, CancellationToken cancellationToken) + protected override PropertyDeclarationSyntax RewriteFieldReferencesInProperty( + PropertyDeclarationSyntax property, + LightweightRenameLocations fieldLocations, + CancellationToken cancellationToken) + { + // We're going to walk this property body, converting most reference of the field to use the `field` keyword + // instead. However, not all reference can be updated. For example, reference through another instance. Those + // we update to point at the property instead. So we grab that property name here to use in the rewriter. + var propertyIdentifier = property.Identifier.WithoutTrivia(); + var propertyIdentifierName = IdentifierName(propertyIdentifier); + + var identifierNames = fieldLocations.Locations + .Select(loc => loc.Location.FindNode(cancellationToken) as IdentifierNameSyntax) + .WhereNotNull() + .ToSet(); + + var rewriter = new UseAutoPropertyRewriter(propertyIdentifierName, identifierNames); + return (PropertyDeclarationSyntax)rewriter.Visit(property); + } + + protected override Task UpdatePropertyAsync( + Document propertyDocument, + Compilation compilation, + IFieldSymbol fieldSymbol, + IPropertySymbol propertySymbol, + VariableDeclaratorSyntax fieldDeclarator, + PropertyDeclarationSyntax propertyDeclaration, + bool isWrittenOutsideOfConstructor, + bool isTrivialGetAccessor, + bool isTrivialSetAccessor, + CancellationToken cancellationToken) { var project = propertyDocument.Project; - var trailingTrivia = propertyDeclaration.GetTrailingTrivia(); + var generator = SyntaxGenerator.GetGenerator(project); - var updatedProperty = propertyDeclaration.WithAccessorList(UpdateAccessorList(propertyDeclaration.AccessorList)) - .WithExpressionBody(null) - .WithSemicolonToken(Token(SyntaxKind.None)); + // Ensure that any attributes on the field are moved over to the property. + propertyDeclaration = MoveAttributes(propertyDeclaration, GetFieldDeclaration(fieldDeclarator)); // We may need to add a setter if the field is written to outside of the constructor // of it's class. - if (NeedsSetter(compilation, propertyDeclaration, isWrittenOutsideOfConstructor)) + var needsSetter = NeedsSetter(compilation, propertyDeclaration, isWrittenOutsideOfConstructor); + var fieldInitializer = fieldDeclarator.Initializer?.Value; + + if (!isTrivialGetAccessor && !isTrivialSetAccessor && !needsSetter && fieldInitializer == null) { - var accessor = AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) - .WithSemicolonToken(SemicolonToken); - var generator = SyntaxGenerator.GetGenerator(project); + // Nothing to actually do. We're not changing the accessors to `get;set;` accessors, and we didn't have to + // add an setter. We also had no field initializer to move over. This can happen when we're converting to + // using `field` and that rewrite already happened. + return Task.FromResult(propertyDeclaration); + } + + // 1. If we have a trivial getters/setter then we want to convert to an accessor list to have `get;set;` + // 2. If we need a setter, we have to convert to having an accessor list to place the setter in. + // 3. If we have a field initializer, we need to convert to an accessor list to add the initializer expression after. + var updatedProperty = propertyDeclaration + .WithExpressionBody(null) + .WithSemicolonToken(default) + .WithAccessorList(ConvertToAccessorList( + propertyDeclaration, isTrivialGetAccessor, isTrivialSetAccessor)); + + if (needsSetter) + { + var accessor = AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SemicolonToken); if (fieldSymbol.DeclaredAccessibility != propertySymbol.DeclaredAccessibility) - { accessor = (AccessorDeclarationSyntax)generator.WithAccessibility(accessor, fieldSymbol.DeclaredAccessibility); - } - - var modifiers = TokenList( - updatedProperty.Modifiers.Where(token => !token.IsKind(SyntaxKind.ReadOnlyKeyword))); - updatedProperty = updatedProperty.WithModifiers(modifiers) - .AddAccessorListAccessors(accessor); + updatedProperty = updatedProperty + .AddAccessorListAccessors(accessor) + .WithModifiers(TokenList(updatedProperty.Modifiers.Where(token => !token.IsKind(SyntaxKind.ReadOnlyKeyword)))); } - var fieldInitializer = await GetFieldInitializerAsync(fieldSymbol, cancellationToken).ConfigureAwait(false); + // Move any field initializer over to the property as well. if (fieldInitializer != null) { - updatedProperty = updatedProperty.WithInitializer(EqualsValueClause(fieldInitializer)) - .WithSemicolonToken(SemicolonToken); + updatedProperty = updatedProperty + .WithInitializer(EqualsValueClause(fieldInitializer)) + .WithSemicolonToken(SemicolonToken); } - return updatedProperty.WithTrailingTrivia(trailingTrivia).WithAdditionalAnnotations(SpecializedFormattingAnnotation); - } + var finalProperty = updatedProperty + .WithTrailingTrivia(propertyDeclaration.GetTrailingTrivia()) + .WithAdditionalAnnotations(SpecializedFormattingAnnotation); + return Task.FromResult(finalProperty); - protected override ImmutableArray GetFormattingRules(Document document) - => [new SingleLinePropertyFormattingRule(), .. Formatter.GetDefaultFormattingRules(document)]; - - private class SingleLinePropertyFormattingRule : AbstractFormattingRule - { - private static bool ForceSingleSpace(SyntaxToken previousToken, SyntaxToken currentToken) + static PropertyDeclarationSyntax MoveAttributes( + PropertyDeclarationSyntax property, + FieldDeclarationSyntax field) { - if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentToken.Parent.IsKind(SyntaxKind.AccessorList)) - { - return true; - } + var fieldAttributes = field.AttributeLists; + if (fieldAttributes.Count == 0) + return property; - if (previousToken.IsKind(SyntaxKind.OpenBraceToken) && previousToken.Parent.IsKind(SyntaxKind.AccessorList)) - { - return true; - } + var leadingTrivia = property.GetLeadingTrivia(); + var indentation = leadingTrivia is [.., (kind: SyntaxKind.WhitespaceTrivia) whitespaceTrivia] + ? whitespaceTrivia + : default; - if (currentToken.IsKind(SyntaxKind.CloseBraceToken) && currentToken.Parent.IsKind(SyntaxKind.AccessorList)) + using var _ = ArrayBuilder.GetInstance(out var finalAttributes); + foreach (var attributeList in fieldAttributes) { - return true; + // Change any field attributes to be `[field: ...]` attributes. Take the property's trivia and place it + // on the first field attribute we move over. + var converted = ConvertAttributeList(attributeList); + finalAttributes.Add(attributeList == fieldAttributes[0] + ? converted.WithLeadingTrivia(leadingTrivia) + : converted); } - return false; - } - - public override AdjustNewLinesOperation GetAdjustNewLinesOperation(in SyntaxToken previousToken, in SyntaxToken currentToken, in NextGetAdjustNewLinesOperation nextOperation) - { - if (ForceSingleSpace(previousToken, currentToken)) + foreach (var attributeList in property.AttributeLists) { - return null; + // Remove the leading trivia off of the first attribute. We're going to move it before all the new + // field attributes we're adding. + finalAttributes.Add(attributeList == property.AttributeLists[0] + ? attributeList.WithLeadingTrivia(indentation) + : attributeList); } - return base.GetAdjustNewLinesOperation(in previousToken, in currentToken, in nextOperation); + return property + .WithAttributeLists([]) + .WithLeadingTrivia(indentation) + .WithAttributeLists(List(finalAttributes)); } - public override AdjustSpacesOperation GetAdjustSpacesOperation(in SyntaxToken previousToken, in SyntaxToken currentToken, in NextGetAdjustSpacesOperation nextOperation) - { - if (ForceSingleSpace(previousToken, currentToken)) - { - return new AdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces); - } + static AttributeListSyntax ConvertAttributeList(AttributeListSyntax attributeList) + => attributeList.WithTarget(AttributeTargetSpecifier(Identifier(SyntaxFacts.GetText(SyntaxKind.FieldKeyword)), ColonToken.WithTrailingTrivia(Space))); - return base.GetAdjustSpacesOperation(in previousToken, in currentToken, in nextOperation); + static AccessorListSyntax ConvertToAccessorList( + PropertyDeclarationSyntax propertyDeclaration, + bool isTrivialGetAccessor, + bool isTrivialSetAccessor) + { + // If we don't have an accessor list at all, convert the property's expr body to a `get => ...` accessor. + var accessorList = propertyDeclaration.AccessorList ?? AccessorList(SingletonList( + AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) + .WithExpressionBody(propertyDeclaration.ExpressionBody) + .WithSemicolonToken(SemicolonToken))); + + // Now that we have an accessor list, convert the getter/setter to `get;`/`set;` form if requested. + return accessorList.WithAccessors(List(accessorList.Accessors.Select( + accessor => + { + var convert = + (isTrivialGetAccessor && accessor.Kind() is SyntaxKind.GetAccessorDeclaration) || + (isTrivialSetAccessor && IsSetOrInitAccessor(accessor)); + + if (convert) + { + if (accessor.ExpressionBody != null) + return accessor.WithExpressionBody(null).WithKeyword(accessor.Keyword.WithoutTrailingTrivia()); + + if (accessor.Body != null) + return accessor.WithBody(null).WithSemicolonToken(SemicolonToken.WithTrailingTrivia(accessor.Body.CloseBraceToken.TrailingTrivia)); + } + + return accessor; + }))); } } - private static async Task GetFieldInitializerAsync(IFieldSymbol fieldSymbol, CancellationToken cancellationToken) + protected override ImmutableArray GetFormattingRules( + Document document, + SyntaxNode propertyDeclaration) { - var variableDeclarator = (VariableDeclaratorSyntax)await fieldSymbol.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken).ConfigureAwait(false); - return variableDeclarator.Initializer?.Value; + // If the final property is only simple `get;set;` accessors, then reformat the property to be on a single line. + if (propertyDeclaration is PropertyDeclarationSyntax { AccessorList.Accessors: var accessors } && + accessors.All(a => a is { ExpressionBody: null, Body: null })) + { + return [new SingleLinePropertyFormattingRule(), .. Formatter.GetDefaultFormattingRules(document)]; + } + + return default; } private static bool NeedsSetter(Compilation compilation, PropertyDeclarationSyntax propertyDeclaration, bool isWrittenOutsideOfConstructor) { - if (propertyDeclaration.AccessorList?.Accessors.Any(SyntaxKind.SetAccessorDeclaration) == true) + // Don't need to add if we already have a setter. + if (propertyDeclaration.AccessorList != null && + propertyDeclaration.AccessorList.Accessors.Any(IsSetOrInitAccessor)) { - // Already has a setter. return false; } + // If the language doesn't have readonly properties, then we'll need a setter here. if (!SupportsReadOnlyProperties(compilation)) - { - // If the language doesn't have readonly properties, then we'll need a - // setter here. return true; - } // If we're written outside a constructor we need a setter. return isWrittenOutsideOfConstructor; } - - private static bool SupportsReadOnlyProperties(Compilation compilation) - => compilation.LanguageVersion() >= LanguageVersion.CSharp6; - - private static AccessorListSyntax UpdateAccessorList(AccessorListSyntax accessorList) - { - if (accessorList == null) - { - var getter = AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) - .WithSemicolonToken(SemicolonToken); - return AccessorList([getter]); - } - - return accessorList.WithAccessors([.. GetAccessors(accessorList.Accessors)]); - } - - private static IEnumerable GetAccessors(SyntaxList accessors) - { - foreach (var accessor in accessors) - { - yield return accessor.WithBody(null) - .WithExpressionBody(null) - .WithSemicolonToken(SemicolonToken); - } - } } diff --git a/src/Features/CSharp/Portable/UseAutoProperty/SingleLinePropertyFormattingRule.cs b/src/Features/CSharp/Portable/UseAutoProperty/SingleLinePropertyFormattingRule.cs new file mode 100644 index 0000000000000..889d73f575ec3 --- /dev/null +++ b/src/Features/CSharp/Portable/UseAutoProperty/SingleLinePropertyFormattingRule.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Formatting.Rules; + +namespace Microsoft.CodeAnalysis.CSharp.UseAutoProperty; + +internal sealed partial class CSharpUseAutoPropertyCodeFixProvider +{ + private sealed class SingleLinePropertyFormattingRule : AbstractFormattingRule + { + private static bool ForceSingleSpace(SyntaxToken previousToken, SyntaxToken currentToken) + { + if (currentToken.IsKind(SyntaxKind.OpenBraceToken) && currentToken.Parent.IsKind(SyntaxKind.AccessorList)) + return true; + + if (previousToken.IsKind(SyntaxKind.OpenBraceToken) && previousToken.Parent.IsKind(SyntaxKind.AccessorList)) + return true; + + if (currentToken.IsKind(SyntaxKind.CloseBraceToken) && currentToken.Parent.IsKind(SyntaxKind.AccessorList)) + return true; + + if (previousToken.IsKind(SyntaxKind.SemicolonToken) && currentToken.Parent is AccessorDeclarationSyntax) + return true; + + return false; + } + + public override AdjustNewLinesOperation? GetAdjustNewLinesOperation(in SyntaxToken previousToken, in SyntaxToken currentToken, in NextGetAdjustNewLinesOperation nextOperation) + { + if (ForceSingleSpace(previousToken, currentToken)) + return null; + + return base.GetAdjustNewLinesOperation(in previousToken, in currentToken, in nextOperation); + } + + public override AdjustSpacesOperation? GetAdjustSpacesOperation(in SyntaxToken previousToken, in SyntaxToken currentToken, in NextGetAdjustSpacesOperation nextOperation) + { + if (ForceSingleSpace(previousToken, currentToken)) + return new AdjustSpacesOperation(1, AdjustSpacesOption.ForceSpaces); + + return base.GetAdjustSpacesOperation(in previousToken, in currentToken, in nextOperation); + } + } +} diff --git a/src/Features/CSharp/Portable/UseAutoProperty/UseAutoPropertyRewriter.cs b/src/Features/CSharp/Portable/UseAutoProperty/UseAutoPropertyRewriter.cs new file mode 100644 index 0000000000000..672bf3cb19c38 --- /dev/null +++ b/src/Features/CSharp/Portable/UseAutoProperty/UseAutoPropertyRewriter.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.CSharp.UseAutoProperty; + +using static SyntaxFactory; + +internal sealed partial class CSharpUseAutoPropertyCodeFixProvider +{ + private sealed class UseAutoPropertyRewriter( + IdentifierNameSyntax propertyIdentifierName, + ISet identifierNames) : CSharpSyntaxRewriter + { + private readonly IdentifierNameSyntax _propertyIdentifierName = propertyIdentifierName; + private readonly ISet _identifierNames = identifierNames; + + public override SyntaxNode? VisitMemberAccessExpression(MemberAccessExpressionSyntax node) + { + if (node.Name is IdentifierNameSyntax identifierName && + _identifierNames.Contains(identifierName)) + { + if (node.Expression.IsKind(SyntaxKind.ThisExpression)) + { + // `this.fieldName` gets rewritten to `field`. + return FieldExpression().WithTriviaFrom(node); + } + else + { + // `obj.fieldName` gets rewritten to `obj.PropName` + return node.WithName(_propertyIdentifierName.WithTriviaFrom(identifierName)); + } + } + + return base.VisitMemberAccessExpression(node); + } + + public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node) + { + if (_identifierNames.Contains(node)) + { + if (node.Parent is AssignmentExpressionSyntax + { + Parent: InitializerExpressionSyntax { RawKind: (int)SyntaxKind.ObjectInitializerExpression } + } assignment && assignment.Left == node) + { + // `new X { fieldName = ... }` gets rewritten to `new X { propName = ... }` + return _propertyIdentifierName.WithTriviaFrom(node); + } + + // Any other naked reference to fieldName within the property gets updated to `field`. + return FieldExpression().WithTriviaFrom(node); + } + + return base.VisitIdentifierName(node); + } + } +} diff --git a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs index f69678a6b1b9c..56b6366f8a0c5 100644 --- a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs @@ -28,19 +28,15 @@ namespace Microsoft.CodeAnalysis.CSharp.UseExpressionBody; [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.UseExpressionBody), Shared] [ExtensionOrder(Before = PredefinedCodeRefactoringProviderNames.ExtractClass)] -internal class UseExpressionBodyCodeRefactoringProvider : SyntaxEditorBasedCodeRefactoringProvider +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class UseExpressionBodyCodeRefactoringProvider() : SyntaxEditorBasedCodeRefactoringProvider { private static readonly ImmutableArray _helpers = UseExpressionBodyHelper.Helpers; private static readonly BidirectionalMap<(UseExpressionBodyHelper helper, bool useExpressionBody), string> s_equivalenceKeyMap = CreateEquivalanceKeyMap(UseExpressionBodyHelper.Helpers); - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public UseExpressionBodyCodeRefactoringProvider() - { - } - private static BidirectionalMap<(UseExpressionBodyHelper helper, bool useExpressionBody), string> CreateEquivalanceKeyMap( ImmutableArray helpers) { @@ -127,9 +123,9 @@ private static bool TryComputeRefactoring( context.RegisterRefactoring( CodeAction.Create( helper.UseExpressionBodyTitle.ToString(), - c => UpdateDocumentAsync( + cancellationToken => UpdateDocumentAsync( document, root, declaration, helper, - useExpressionBody: true, cancellationToken: c), + useExpressionBody: true, cancellationToken), s_equivalenceKeyMap[(helper, useExpressionBody: true)]), declaration.Span); succeeded = true; @@ -140,9 +136,9 @@ private static bool TryComputeRefactoring( context.RegisterRefactoring( CodeAction.Create( helper.UseBlockBodyTitle.ToString(), - c => UpdateDocumentAsync( + cancellationToken => UpdateDocumentAsync( document, root, declaration, helper, - useExpressionBody: false, cancellationToken: c), + useExpressionBody: false, cancellationToken), s_equivalenceKeyMap[(helper, useExpressionBody: false)]), declaration.Span); succeeded = true; @@ -192,7 +188,6 @@ protected override async Task FixAllAsync( Document document, ImmutableArray fixAllSpans, SyntaxEditor editor, - CodeActionOptionsProvider optionsProvider, string? equivalenceKey, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs index 124e0daf8ad2e..4b4f7d5970f22 100644 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs @@ -22,14 +22,10 @@ namespace Microsoft.CodeAnalysis.CSharp.UseExpressionBodyForLambda; [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.UseExpressionBodyForLambda), Shared] -internal sealed class UseExpressionBodyForLambdaCodeRefactoringProvider : CodeRefactoringProvider +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class UseExpressionBodyForLambdaCodeRefactoringProvider() : CodeRefactoringProvider { - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public UseExpressionBodyForLambdaCodeRefactoringProvider() - { - } - public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf index 7f0533d300048..7c277d113addf 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf @@ -422,16 +422,6 @@ Uspořádat direktivy using - - Generate explicit conversion operator in '{0}' - Generovat explicitní operátor převodu v {0} - - - - Generate implicit conversion operator in '{0}' - Generovat implicitní operátor převodu v {0} - - record záznam diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf index 1e7b07b7e8b6f..43abdee07e7c8 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf @@ -422,16 +422,6 @@ Using-Direktiven organisieren - - Generate explicit conversion operator in '{0}' - Expliziten Konversionsoperator in '{0}' generieren - - - - Generate implicit conversion operator in '{0}' - Impliziten Konversionsoperator in '{0}' generieren - - record Datensatz diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf index 83a293824024e..fb1506e889134 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf @@ -422,16 +422,6 @@ Organizar instrucciones Using - - Generate explicit conversion operator in '{0}' - Generar operador de conversión explícito en '{0}' - - - - Generate implicit conversion operator in '{0}' - Generar operador de conversión implícito en '{0}' - - record registro diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf index 6e703336084c1..c3660c23351bb 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf @@ -422,16 +422,6 @@ Organiser les instructions Using - - Generate explicit conversion operator in '{0}' - Générer l’opérateur de conversion explicite dans « {0} » - - - - Generate implicit conversion operator in '{0}' - Générer l’opérateur de conversion implicite dans « {0} » - - record enregistrement diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf index fff92a6b43f6f..d781f9904657c 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf @@ -422,16 +422,6 @@ Organizza using - - Generate explicit conversion operator in '{0}' - Genera l'operatore di conversione esplicito in '{0}' - - - - Generate implicit conversion operator in '{0}' - Genera l'operatore di conversione implicito in '{0}' - - record record diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf index b757ebe7f5e27..261bbf1413967 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf @@ -422,16 +422,6 @@ using の整理 - - Generate explicit conversion operator in '{0}' - 明示的な変換演算子を '{0}' に生成します - - - - Generate implicit conversion operator in '{0}' - 暗黙的な変換演算子を '{0}' に生成します - - record レコード diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf index 474c98f6aff17..5bc2e5b7bcf2e 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf @@ -422,16 +422,6 @@ Using 구성 - - Generate explicit conversion operator in '{0}' - '{0}'에서 명시적 변환 연산자 생성 - - - - Generate implicit conversion operator in '{0}' - '{0}'에서 암시적 변환 연산자 생성 - - record 레코드 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf index 2e48e00f969d1..af1a6a9a74558 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf @@ -422,16 +422,6 @@ Organizuj użycia - - Generate explicit conversion operator in '{0}' - Generuj operator jawnej konwersji w elemencie „{0}” - - - - Generate implicit conversion operator in '{0}' - Generuj operator niejawnej konwersji w elemencie „{0}” - - record rekord diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf index e9132a814721f..8a38cb15bb1ec 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf @@ -422,16 +422,6 @@ Organizar Usos - - Generate explicit conversion operator in '{0}' - Gerar um operador de conversão explícita em '{0}' - - - - Generate implicit conversion operator in '{0}' - Gerar um operador de conversão implícita em '{0}' - - record registro diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf index 4aba44a091853..fba75ab606895 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf @@ -422,16 +422,6 @@ Упорядочение Using - - Generate explicit conversion operator in '{0}' - Создать явный оператор преобразования в "{0}" - - - - Generate implicit conversion operator in '{0}' - Создать неявный оператор преобразования в "{0}" - - record запись diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf index 4d452af524791..ee5a5cf4b1dcb 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf @@ -422,16 +422,6 @@ Kullanımları Düzenle - - Generate explicit conversion operator in '{0}' - '{0}' içinde açık dönüşüm işleci oluştur - - - - Generate implicit conversion operator in '{0}' - '{0}' içinde örtük dönüşüm işleci oluştur - - record kayıt diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf index e2ef3d0802186..241b9c403b1b2 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf @@ -422,16 +422,6 @@ 组织 Using - - Generate explicit conversion operator in '{0}' - 在“{0}”中生成显示转换运算符 - - - - Generate implicit conversion operator in '{0}' - 在“{0}”中生成隐式转换运算符 - - record 记录 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf index 312afb20a8fb6..645b87cd0be55 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf @@ -422,16 +422,6 @@ 組合管理 Using - - Generate explicit conversion operator in '{0}' - 在 '{0}' 中產生明確轉換運算子 - - - - Generate implicit conversion operator in '{0}' - 在 '{0}' 中產生隱含轉換運算子 - - record 記錄 diff --git a/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs b/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs index 09c709fb680cb..0d2493062550d 100644 --- a/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs +++ b/src/Features/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs @@ -460,7 +460,7 @@ void Method() var diagnostics = await diagnosticService.GetDiagnosticsForSpanAsync(document, span, CancellationToken.None); Assert.Equal(2, diagnostics.Where(d => d.Id == "CS0219").Count()); - var allFixes = (await fixService.GetFixesAsync(document, span, CodeActionOptions.DefaultProvider, CancellationToken.None)) + var allFixes = (await fixService.GetFixesAsync(document, span, CancellationToken.None)) .SelectMany(fixCollection => fixCollection.Fixes); var cs0219Fixes = allFixes.Where(fix => fix.PrimaryDiagnostic.Id == "CS0219").ToArray(); diff --git a/src/Features/CSharpTest/EditAndContinue/ActiveStatementTests.cs b/src/Features/CSharpTest/EditAndContinue/ActiveStatementTests.cs index 34ac43666a296..ca9091ad4a272 100644 --- a/src/Features/CSharpTest/EditAndContinue/ActiveStatementTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/ActiveStatementTests.cs @@ -3126,7 +3126,6 @@ public C() {} var active = GetActiveStatements(src1, src2); edits.VerifySemanticDiagnostics(active, - Diagnostic(RudeEditKind.Move, "int c", GetResource("field")), Diagnostic(RudeEditKind.DeleteActiveStatement, "class C", GetResource("field", "C.a")), Diagnostic(RudeEditKind.Delete, "class C", GetResource("field", "a"))); } @@ -3633,6 +3632,100 @@ static void Main(string[] args) Diagnostic(RudeEditKind.UpdateAroundActiveStatement, "lock (G(a => a))", CSharpFeaturesResources.lock_statement)); } + [Fact] + public void Lock_Update_Type() + { + var src1 = """ + class C + { + static void F() + { + var a = new object(); + var b = new C(); + var c = ""; + + lock (a) + { + lock (b) + { + lock (c) + { + System.Console.Write(); + } + } + } + } + } + """; + + var src2 = """ + class C + { + static void F() + { + var a = new object(); + var b = new object(); // type changed + var c = ""; + + lock (a) + { + lock (b) + { + lock (c) + { + System.Console.Write(); + } + } + } + } + } + """; + + var edits = GetTopEdits(src1, src2); + var active = GetActiveStatements(src1, src2); + + edits.VerifySemanticDiagnostics(active, + Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "lock (b)", CSharpFeaturesResources.lock_statement, "C", "object")); + } + + [Fact] + public void Lock_Update_Type_SemanticError() + { + var src1 = """ + class C + { + static void F() + { + var a = new object(); + + lock (a) + { + System.Console.Write(); + } + } + } + """; + + var src2 = """ + class C + { + static void F() + { + lock (a) + { + System.Console.Write(); + } + } + } + """; + + var edits = GetTopEdits(src1, src2); + var active = GetActiveStatements(src1, src2); + + edits.VerifySemanticDiagnostics(active, + Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "lock (a)", CSharpFeaturesResources.lock_statement, "object", "?")); + } + #endregion #region Fixed Statement @@ -3680,6 +3773,49 @@ static void Main(string[] args) edits.VerifySemanticDiagnostics(active); } + [Fact] + public void FixedBody_Update_TypeChange() + { + var src1 = """ + class C + { + static unsafe void F() + { + var x = new int[1]; + var y = new int[1]; + var z = new int[1,1]; + fixed (int* p = x, q = y, r = z) + { + System.Console.WriteLine(); + } + } + } + """; + + var src2 = """ + class C + { + static unsafe void F() + { + var x = new int[1]; + var y = new int[1,1]; + var z = new int[1]; + fixed (int* p = x, q = y, r = z) + { + System.Console.WriteLine(); + } + } + } + """; + + var edits = GetTopEdits(src1, src2); + var active = GetActiveStatements(src1, src2); + + edits.VerifySemanticDiagnostics(active, + Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "fixed (int* p = x, q = y, r = z)", CSharpFeaturesResources.fixed_statement, "int[]", "int[*,*]"), + Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "fixed (int* p = x, q = y, r = z)", CSharpFeaturesResources.fixed_statement, "int[*,*]", "int[]")); + } + [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/755742")] public void Fixed_Insert_Leaf() { @@ -5198,7 +5334,7 @@ struct Buffer4 } [Fact] - public void ForEach_Update_Nullable() + public void ForEach_Update_Nullable_Struct() { var src1 = @" class C @@ -5229,6 +5365,42 @@ static void F() var edits = GetTopEdits(src1, src2); var active = GetActiveStatements(src1, src2); + edits.VerifySemanticDiagnostics(active, + Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "foreach (var s in arr)", CSharpFeaturesResources.foreach_statement, "int?[]", "int[]")); + } + + [Fact] + public void ForEach_Update_Nullable_Class() + { + var src1 = @" +class C +{ + static void F() + { + var arr = new object?[] { 0 }; + foreach (var s in arr) + { + Console.WriteLine(1); + } + } +} +"; + var src2 = @" +class C +{ + static void F() + { + var arr = new object[] { 0 }; + foreach (var s in arr) + { + Console.WriteLine(1); + } + } +} +"; + var edits = GetTopEdits(src1, src2); + var active = GetActiveStatements(src1, src2); + edits.VerifySemanticDiagnostics(active); } @@ -5778,6 +5950,54 @@ static void Main(string[] args) Diagnostic(RudeEditKind.InsertAroundActiveStatement, "using (c)", CSharpFeaturesResources.using_statement)); } + [Fact] + public void UsingStatement_Expression_Update_Leaf_TypeChange() + { + var src1 = """ + using System; + + class C + { + static void F() + { + var x = new D1(); + using (x) + { + System.Console.Write(); + } + } + } + + class D1 : IDisposable { public void Dispose() { } } + class D2 : IDisposable { public void Dispose() { } } + """; + + var src2 = """ + using System; + + class C + { + static void F() + { + var x = new D2(); + using (x) + { + System.Console.Write(); + } + } + } + + class D1 : IDisposable { public void Dispose() { } } + class D2 : IDisposable { public void Dispose() { } } + """; + + var edits = GetTopEdits(src1, src2); + var active = GetActiveStatements(src1, src2); + + edits.VerifySemanticDiagnostics(active, + Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "using (x)", CSharpFeaturesResources.using_statement, "D1", "D2")); + } + [Fact] public void UsingStatement_Declaration_Update_Leaf() { diff --git a/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs b/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs index c69d310fb220a..5f2f298878bf1 100644 --- a/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs @@ -316,15 +316,15 @@ public static void Main() var oldStatementSyntax = oldSyntaxRoot.FindNode(oldStatementTextSpan); var baseActiveStatements = new ActiveStatementsMap( - ImmutableDictionary.CreateRange(new[] - { + ImmutableDictionary.CreateRange( + [ KeyValuePairUtil.Create(newDocument.FilePath, ImmutableArray.Create( new ActiveStatement( new ActiveStatementId(0), ActiveStatementFlags.LeafFrame, new SourceFileSpan(newDocument.FilePath, oldStatementSpan), instructionId: default))) - }), + ]), ActiveStatementsMap.Empty.InstructionMap); var result = await AnalyzeDocumentAsync(oldProject, newDocument, baseActiveStatements); @@ -765,7 +765,7 @@ public async Task AnalyzeDocumentAsync_InternalError(bool outOfMemory) // here so that any trailing punctuation is removed from the translated template string. : $"ENC0080: {string.Format(FeaturesResources.Modifying_source_file_0_requires_restarting_the_application_due_to_internal_error_1, filePath, "System.NullReferenceException: NullRef!\n")}".Split('\n').First(); - AssertEx.Equal(new[] { expectedDiagnostic }, result.RudeEdits.Select(d => d.ToDiagnostic(newSyntaxTree)) + AssertEx.Equal([expectedDiagnostic], result.RudeEdits.Select(d => d.ToDiagnostic(newSyntaxTree)) .Select(d => $"{d.Id}: {d.GetMessage().Split(new[] { Environment.NewLine }, StringSplitOptions.None).First()}")); } diff --git a/src/Features/CSharpTest/EditAndContinue/LineEditTests.cs b/src/Features/CSharpTest/EditAndContinue/LineEditTests.cs index e844f7b8631ad..2cb7654e06f2c 100644 --- a/src/Features/CSharpTest/EditAndContinue/LineEditTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/LineEditTests.cs @@ -69,12 +69,12 @@ public void Method_Reorder1() var src1 = @" class C { - static void Goo() + static void G() { Console.ReadLine(1); } - static void Bar() + static void F() { Console.ReadLine(2); } @@ -83,76 +83,83 @@ static void Bar() var src2 = @" class C { - static void Bar() + static void F() { Console.ReadLine(2); } - static void Goo() + static void G() { Console.ReadLine(1); } }"; var edits = GetTopEdits(src1, src2); + + // Consider: we could detect that the body of the method hasn't changed and avoid creating an update. edits.VerifyLineEdits( new[] { new SourceLineUpdate(4, 9), new SourceLineUpdate(7, 7), new SourceLineUpdate(9, 4) - }); + }, + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F"))]); } [Fact] public void Method_Reorder2() { var src1 = @" -class Program +class C { static void Main() { - Goo(); - Bar(); + F(); + G(); } - static int Goo() + static int G() { return 1; } - static int Bar() + static int F() { return 2; } }"; var src2 = @" -class Program +class C { - static int Goo() + static int F() { return 1; } static void Main() { - Goo(); - Bar(); + F(); + G(); } - static int Bar() + static int G() { return 2; } }"; var edits = GetTopEdits(src1, src2); + + // Consider: we could detect that the body of the method hasn't changed and create line edits instead of an update. edits.VerifyLineEdits( new[] { new SourceLineUpdate(4, 9), - new SourceLineUpdate(8, 8), - new SourceLineUpdate(10, 4), - new SourceLineUpdate(13, 13), - }); + }, + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.G")) + ]); } [Fact] @@ -758,13 +765,19 @@ public C(int a) } }"; var edits = GetTopEdits(src1, src2); + + // Consider: we could detect that the body of the method hasn't changed and avoid creating an update. edits.VerifyLineEdits( new[] { new SourceLineUpdate(3, 7), new SourceLineUpdate(6, 6), new SourceLineUpdate(7, 3) - }); + }, + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").Constructors.Single(c => c.Parameters is [{ Type.SpecialType: SpecialType.System_Boolean }]), preserveLocalVariables: true) + ]); } [Fact] @@ -1357,13 +1370,13 @@ class C var src2 = @" class C { - static int Bar = 2; - static int Goo = 1; + static int Bar = 1; + static int Goo = 2; }"; var edits = GetTopEdits(src1, src2); edits.VerifyLineEdits( Array.Empty(), - diagnostics: [Diagnostic(RudeEditKind.Move, "static int Bar = 2", FeaturesResources.field)]); + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").StaticConstructors.Single(), preserveLocalVariables: true)]); } [Fact] diff --git a/src/Features/CSharpTest/EditAndContinue/SyntaxUtilitiesTests.cs b/src/Features/CSharpTest/EditAndContinue/SyntaxUtilitiesTests.cs index 8fce613da6968..6834fd3bdde4d 100644 --- a/src/Features/CSharpTest/EditAndContinue/SyntaxUtilitiesTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/SyntaxUtilitiesTests.cs @@ -255,11 +255,11 @@ IAsyncEnumerable f() var f = m2.DescendantNodes().OfType().Single(m => m.Identifier.ValueText == "f"); AssertEx.Empty(SyntaxUtilities.GetSuspensionPoints(x.Initializer)); - AssertEx.Equal(new[] { "yield return 1;" }, SyntaxUtilities.GetSuspensionPoints(m1.Body).Select(n => n.ToString())); + AssertEx.Equal(["yield return 1;"], SyntaxUtilities.GetSuspensionPoints(m1.Body).Select(n => n.ToString())); AssertEx.Empty(SyntaxUtilities.GetSuspensionPoints(m2.Body)); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "yield return 1;", "await Task.FromResult(1)", "await foreach (var x in F()) { }", @@ -267,6 +267,6 @@ IAsyncEnumerable f() "x1 = F1()", "x2 = F2()", "x3 = F3()", - }, SyntaxUtilities.GetSuspensionPoints(f.Body).Select(n => n.ToString())); + ], SyntaxUtilities.GetSuspensionPoints(f.Body).Select(n => n.ToString())); } } diff --git a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 7cf962f9814f8..960cd5c325a9d 100644 --- a/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/Features/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.UnitTests; +using Microsoft.CodeAnalysis.Differencing; using Microsoft.CodeAnalysis.EditAndContinue; using Microsoft.CodeAnalysis.EditAndContinue.UnitTests; using Microsoft.CodeAnalysis.Emit; @@ -3018,7 +3019,7 @@ record struct C(int X) var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoStruct, "_y = 0", FeaturesResources.field, CSharpFeaturesResources.record_struct)); + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "_y = 0", FeaturesResources.field, CSharpFeaturesResources.record_struct)); } [Fact] @@ -3037,7 +3038,7 @@ record struct C(int X) var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoStruct, "public int Y", GetResource("auto-property"), GetResource("record struct"))); + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "public int Y", GetResource("auto-property"), GetResource("record struct"))); } [Fact] @@ -3376,6 +3377,27 @@ public void Record_Field_Insert_WithInitializer() capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType); } + [Fact] + public void Record_EventField_Insert_WithInitializer() + { + var src1 = "record C(int X) { }"; + var src2 = "record C(int X) { event System.Action E = null; }"; + var syntaxMap = GetSyntaxMap(src1, src2); + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.PrintMembers")), + SemanticEdit(SemanticEditKind.Update, c => c.GetSpecializedEqualsOverload("C")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.GetHashCode")), + SemanticEdit(SemanticEditKind.Update, c => c.GetCopyConstructor("C")), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.E")), + SemanticEdit(SemanticEditKind.Update, c => c.GetPrimaryConstructor("C"), preserveLocalVariables: true) + ], + capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType | EditAndContinueCapabilities.AddMethodToExistingType); + } + [Fact] public void Record_Field_Insert_WithExistingInitializer() { @@ -3856,7 +3878,7 @@ public void Record_Property_Delete_ReplacingCustomWithSynthesized_TypeLayoutChan var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.InsertIntoStruct, "int P", GetResource("auto-property"), GetResource("record struct"))], + [Diagnostic(RudeEditKind.InsertOrMoveStructMember, "int P", GetResource("auto-property"), GetResource("record struct"))], capabilities: EditAndContinueCapabilities.AddInstanceFieldToExistingType | EditAndContinueCapabilities.AddMethodToExistingType); } @@ -8390,17 +8412,161 @@ class C } [Fact] - public void MethodReorder1() + public void Method_Reorder() + { + var src1 = """ + class C + { + + void F() {} + void G() {} + void H() {} + } + """; + + var src2 = """ + class C + { + void H() {} + void F() {} + void G() {} + + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemantics([SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.H"))]); + } + + [Theory] + [CombinatorialData] + public void Method_Reorder_Interface(bool isStatic) + { + var (modifier, body) = isStatic ? ("static", ";") : ("", " {}"); + + var src1 = $$""" + interface I + { + {{modifier}} void F(){{body}} + {{modifier}} void G(){{body}} + {{modifier}} void H(){{body}} + } + """; + + var src2 = $$""" + interface I + { + {{modifier}} void H(){{body}} + {{modifier}} void F(){{body}} + {{modifier}} void G(){{body}} + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemantics([SemanticEdit(SemanticEditKind.Update, c => c.GetMember("I.H"))]); + } + + [Theory] + [InlineData("static extern ")] // static method must be extern in COM interface + [InlineData("")] + public void Method_Reorder_Interface_ComImport(string modifier) + { + var src1 = $$""" + using System.Runtime.InteropServices; + [ComImport] + [Guid("DBE8A85B-7883-4657-83FD-1FA27A9561EB")] + interface I + { + {{modifier}}void F(); + {{modifier}}void G(); + {{modifier}}void H(); + } + """; + + var src2 = $$""" + using System.Runtime.InteropServices; + [ComImport] + [Guid("DBE8A85B-7883-4657-83FD-1FA27A9561EB")] + interface I + { + {{modifier}}void H(); + {{modifier}}void F(); + {{modifier}}void G(); + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemanticDiagnostics( + Diagnostic(RudeEditKind.InsertOrMoveComInterfaceMember, modifier + "void H()", GetResource("method"))); + } + + [Fact] + public void Method_Insert_Interface_ComImport() + { + var src1 = $$""" + using System.Runtime.InteropServices; + [ComImport] + [Guid("DBE8A85B-7883-4657-83FD-1FA27A9561EB")] + interface I + { + } + """; + + var src2 = $$""" + using System.Runtime.InteropServices; + [ComImport] + [Guid("DBE8A85B-7883-4657-83FD-1FA27A9561EB")] + interface I + { + void F(); + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemanticDiagnostics( + Diagnostic(RudeEditKind.InsertVirtual, "void F()", GetResource("method")), + Diagnostic(RudeEditKind.InsertOrMoveComInterfaceMember, "void F()", GetResource("method"))); + } + + [Fact] + public void Method_Insert_Interface_ComImport_Static() { - var src1 = "class C { void f(int a, int b) { a = b; } void g() { } }"; - var src2 = "class C { void g() { } void f(int a, int b) { a = b; } }"; + var src1 = $$""" + [System.Runtime.InteropServices.ComImport] + [Guid("DBE8A85B-7883-4657-83FD-1FA27A9561EB")] + interface I + { + } + """; + + var src2 = $$""" + [System.Runtime.InteropServices.ComImport] + [Guid("DBE8A85B-7883-4657-83FD-1FA27A9561EB")] + interface I + { + extern static void F(); + } + """; var edits = GetTopEdits(src1, src2); - edits.VerifyEdits("Reorder [void g() { }]@42 -> @10"); + + edits.VerifySemanticDiagnostics( + Diagnostic(RudeEditKind.InsertExtern, "extern static void F()", GetResource("method")), + Diagnostic(RudeEditKind.InsertOrMoveComInterfaceMember, "extern static void F()", GetResource("method"))); } [Fact] - public void MethodInsertDelete1() + public void Method_InsertDelete() { var src1 = "class C { class D { } void f(int a, int b) { a = b; } }"; var src2 = "class C { class D { void f(int a, int b) { a = b; } } }"; @@ -8485,7 +8651,7 @@ void M(int a, int b, int c) } [Fact] - public void Method_Update_Parameter_Partial() + public void Method_Update_Parameter_Insert_Partial() { var src1 = @" class C @@ -10046,7 +10212,7 @@ public void Method_Partial_DeleteInsert_ImplementationPart() DocumentResults(), DocumentResults(), DocumentResults( - semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F").PartialImplementationPart, partialType: "C")]), + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F").PartialImplementationPart, partialType: "C")]), ]); } @@ -10063,9 +10229,9 @@ public void Method_Partial_Swap_ImplementationAndDefinitionParts() [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], [ DocumentResults( - semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F").PartialImplementationPart, partialType: "C")]), + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F").PartialImplementationPart, partialType: "C")]), DocumentResults( - semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F").PartialImplementationPart, partialType: "C")]), + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.F").PartialImplementationPart, partialType: "C")]), ]); } @@ -10936,7 +11102,7 @@ public void Constructor_Parameter_Update_Type_Record_TypeLayout() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.InsertIntoStruct, "int x", GetResource("auto-property"), GetResource("record struct"))], + [Diagnostic(RudeEditKind.InsertOrMoveStructMember, "int x", GetResource("auto-property"), GetResource("record struct"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); } @@ -11431,7 +11597,7 @@ public void Constructor_Parameter_Insert_Primary_Captured_Struct() edits.VerifySemanticDiagnostics( [ Diagnostic(RudeEditKind.CapturingPrimaryConstructorParameter, "b", GetResource("struct"), "b"), - Diagnostic(RudeEditKind.InsertIntoStruct, "int b", GetResource("parameter"), GetResource("struct")) + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "int b", GetResource("parameter"), GetResource("struct")) ], capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); } @@ -11481,7 +11647,7 @@ record C(int X, int Y) { } var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "int Y", GetResource("auto-property"), GetResource("record"))); + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "int Y", GetResource("auto-property"), GetResource("record"))); } [Fact] @@ -11500,7 +11666,7 @@ record struct C(int x, int y) var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoStruct, "int y", GetResource("auto-property"), GetResource("record struct"))); + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "int y", GetResource("auto-property"), GetResource("record struct"))); } [Fact] @@ -11729,7 +11895,7 @@ class C(int x, int y) edits.VerifySemanticDiagnostics( [ Diagnostic(RudeEditKind.CapturingPrimaryConstructorParameter, "y", GetResource("class with explicit or sequential layout"), "y"), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "int y", GetResource("parameter"), GetResource("class")) + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "int y", GetResource("parameter"), GetResource("class")) ]); } @@ -11761,7 +11927,7 @@ class C(int x, int y) edits.VerifySemanticDiagnostics( [ Diagnostic(RudeEditKind.CapturingPrimaryConstructorParameter, "y", GetResource("class with explicit or sequential layout"), "y"), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "int y", GetResource("parameter"), GetResource("class")) + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "int y", GetResource("parameter"), GetResource("class")) ]); } @@ -11791,7 +11957,7 @@ public void Constructor_Parameter_Reorder_Primary_NotLifted_Record_Struct() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.InsertIntoStruct, "byte y", GetResource("auto-property"), GetResource("record struct"))], + [Diagnostic(RudeEditKind.InsertOrMoveStructMember, "byte y", GetResource("auto-property"), GetResource("record struct"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); } @@ -11803,7 +11969,7 @@ public void Constructor_Parameter_Reorder_Primary_Lifted_Struct() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.InsertIntoStruct, "byte y", GetResource("parameter"), GetResource("struct"))], + [Diagnostic(RudeEditKind.InsertOrMoveStructMember, "byte y", GetResource("parameter"), GetResource("struct"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); } @@ -11843,11 +12009,8 @@ public void Constructor_Parameter_Reorder_Primary_Lifted_Record() SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.x")), SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_x")), SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.set_x")), - // TODO: y should also be updated (to update sequence points to the new location) - // https://github.com/dotnet/roslyn/issues/69894 - // SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.y")), - // SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_y")), - // SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.set_y")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_y")), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.set_y")), ], capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); @@ -12704,7 +12867,7 @@ public void Constructor_Instance_Insert_Struct_Primary_Record() edits.VerifySemanticDiagnostics( [ - Diagnostic(RudeEditKind.InsertIntoStruct, "int X", GetResource("auto-property"), GetResource("record struct")) + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "int X", GetResource("auto-property"), GetResource("record struct")) ], capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); } @@ -14445,7 +14608,7 @@ public void MemberInitializer_Update_Field() } [Fact] - public void MemberInitializer_Update_Field_Event() + public void MemberInitializer_Update_EventField() { var src1 = "class C { event System.Action a = F(0); static System.Action F(int a) => null; }"; var src2 = "class C { event System.Action a = F(1); static System.Action F(int a) => null; }"; @@ -16485,7 +16648,7 @@ public void Field_Const_Update() } [Fact] - public void Field_Event_VariableDeclarator_Update() + public void EventField_VariableDeclarator_Update() { var src1 = "class C { event Action a; }"; var src2 = "class C { event Action a = () => { }; }"; @@ -16504,16 +16667,211 @@ public void Field_Event_VariableDeclarator_Update() [Fact] public void Field_Reorder() { - var src1 = "class C { int a = 0; int b = 1; int c = 2; }"; - var src2 = "class C { int c = 2; int a = 0; int b = 1; }"; + var src1 = """ + class C + { + + int a = 0; + int b = 1; + int c; + } + """; + + var src2 = """ + class C + { + int c; + int a = 0; + int b = 1; + + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemantics(); + } + + [Fact] + public void Field_Reorder_WithInitializer() + { + var src1 = """ + class C + { + + int a = 0; + int b = 1; + int c = 2; + } + """; + + var src2 = """ + class C + { + int c = 2; + int a = 0; + int b = 1; + + } + """; var edits = GetTopEdits(src1, src2); - edits.VerifyEdits( - "Reorder [int c = 2;]@32 -> @10"); + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemantics([SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)]); + } + + [Theory] + [CombinatorialData] + public void Field_Reorder_WithInitializer_RemoveOrAdd(bool remove) + { + var src1 = $$""" + class C + { + + int a = 0; + int b = 1; + int c{{(remove ? " = 2" : "")}}; + } + """; + + var src2 = $$""" + class C + { + int c{{(remove ? "" : " = 2")}}; + int a = 0; + int b = 1; + + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder, EditKind.Update); + + edits.VerifySemantics([SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)]); + } + + [Fact] + public void Field_Reorder_Modifiers_Update() + { + var src1 = """ + class C + { + + int a = 0; + int b = 1; + static int c; + } + """; + + var src2 = """ + class C + { + int c; + int a = 0; + int b = 1; + + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder, EditKind.Update); + + edits.VerifySemanticDiagnostics( + Diagnostic(RudeEditKind.ModifiersUpdate, "int c", GetResource("field"))); + } + + [Fact] + public void Field_Reorder_Attribute_Update() + { + var attributeDecl = """ + class A : System.Attribute {} + """; + + var src1 = attributeDecl + """ + class C + { + + int a = 0; + int b = 1; + int c; + } + """; + + var src2 = attributeDecl + """ + class C + { + [A]int c; + int a = 0; + int b = 1; + + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder, EditKind.Update); + + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.c"))], + capabilities: EditAndContinueCapabilities.ChangeCustomAttributes); + } + + [Theory] + [InlineData("", "struct", RudeEditKind.InsertOrMoveStructMember)] + [InlineData("", "record struct", RudeEditKind.InsertOrMoveStructMember)] + [InlineData("[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]", "class", RudeEditKind.InsertOrMoveTypeWithLayoutMember)] + [InlineData("[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]", "record class", RudeEditKind.InsertOrMoveTypeWithLayoutMember)] + internal void Field_Reorder_TypeLayout(string attribute, string keyword, RudeEditKind rudeEditKind) + { + var src1 = attribute + keyword + " C { int a = 0; int b = 1; int c = 2; }"; + var src2 = attribute + keyword + " C { int c = 2; int a = 0; int b = 1; }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Move, "int c = 2", FeaturesResources.field)); + Diagnostic(rudeEditKind, "int c = 2", GetResource("field"), GetResource(keyword))); + } + + [Fact] + public void Field_Reorder_Reloadable() + { + var src1 = ReloadableAttributeSrc + """ + [CreateNewOnMetadataUpdate] + struct C + { + + int a = 0; + int b = 1; + int c; + } + """; + + var src2 = ReloadableAttributeSrc + """ + [CreateNewOnMetadataUpdate] + struct C + { + int c; + int a = 0; + int b = 1; + + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Replace, c => c.GetMember("C"))], + capabilities: EditAndContinueCapabilities.NewTypeDefinition); } [Fact] @@ -16564,10 +16922,10 @@ struct S var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoStruct, "b", FeaturesResources.field, CSharpFeaturesResources.struct_), - Diagnostic(RudeEditKind.InsertIntoStruct, "c", FeaturesResources.field, CSharpFeaturesResources.struct_), - Diagnostic(RudeEditKind.InsertIntoStruct, "f = 1", FeaturesResources.field, CSharpFeaturesResources.struct_), - Diagnostic(RudeEditKind.InsertIntoStruct, "d", CSharpFeaturesResources.event_field, CSharpFeaturesResources.struct_)); + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "b", GetResource("field"), GetResource("struct")), + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "c", GetResource("field"), GetResource("struct")), + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "f = 1", GetResource("field"), GetResource("struct")), + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "d", GetResource("event field"), GetResource("struct"))); } [Fact] @@ -16640,9 +16998,9 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "b", FeaturesResources.field, FeaturesResources.class_), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "c", FeaturesResources.field, FeaturesResources.class_), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "d", FeaturesResources.field, FeaturesResources.class_)); + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "b", GetResource("field"), GetResource("class")), + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "c", GetResource("field"), GetResource("class")), + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "d", GetResource("field"), GetResource("class"))); } [Fact] @@ -16673,9 +17031,9 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "b", FeaturesResources.field, FeaturesResources.class_), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "c", FeaturesResources.field, FeaturesResources.class_), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "d", FeaturesResources.field, FeaturesResources.class_)); + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "b", GetResource("field"), GetResource("class")), + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "c", GetResource("field"), GetResource("class")), + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "d", GetResource("field"), GetResource("class"))); } [Fact] @@ -17127,7 +17485,6 @@ public void Field_Type_Update_ReorderRemoveAdd() "Delete [H]@20"); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Move, "G", FeaturesResources.field), Diagnostic(RudeEditKind.TypeUpdate, "string G, F", FeaturesResources.field), Diagnostic(RudeEditKind.TypeUpdate, "string G, F", FeaturesResources.field), Diagnostic(RudeEditKind.TypeUpdate, "double V, U", FeaturesResources.field), @@ -17675,53 +18032,153 @@ public void PropertyAccessorDelete2() } [Fact] - public void Property_Reorder1() + public void Property_Reorder_Auto() { - var src1 = "class C { int P { get { return 1; } } int Q { get { return 1; } } }"; - var src2 = "class C { int Q { get { return 1; } } int P { get { return 1; } } }"; - - var edits = GetTopEdits(src1, src2); + var src1 = """ + class C + { - edits.VerifyEdits( - "Reorder [int Q { get { return 1; } }]@38 -> @10"); + int P { get; } = 0; + int Q { get; } = 1; + int R { get; } + } + """; - // TODO: we can allow the move since the property doesn't have a backing field - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Move, "int Q", FeaturesResources.property_)); + var src2 = """ + class C + { + int R { get; } + int P { get; } = 0; + int Q { get; } = 1; + + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemantics(); } [Fact] - public void Property_Reorder_Auto_Class() + public void Property_Reorder_Auto_WithInitializer() { - var src1 = "class C { int P { get; set; } int Q { get; set; } }"; - var src2 = "class C { int Q { get; set; } int P { get; set; } }"; + var src1 = """ + class C + { + + int P { get; } = 0; + int Q { get; } = 1; + int R { get; } = 2; + } + """; + + var src2 = """ + class C + { + int R { get; } = 2; + int P { get; } = 0; + int Q { get; } = 1; + + } + """; var edits = GetTopEdits(src1, src2); - edits.VerifyEdits( - "Reorder [int Q { get; set; }]@30 -> @10"); + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemantics([SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)]); + } + + [Theory] + [InlineData("", "struct")] + [InlineData("", "record struct")] + [InlineData("[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]", "class")] + [InlineData("[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]", "record class")] + internal void Property_Reorder_TypeLayout(string attribute, string keyword) + { + var src1 = attribute + keyword + """ + C + { + + int P => 0; + int Q => 1; + int R => 2; + } + """; + + var src2 = attribute + keyword + """ + C + { + int R => 2; + int P => 0; + int Q => 1; + + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemantics(); + } + + [Theory] + [InlineData("", "struct", RudeEditKind.InsertOrMoveStructMember)] + [InlineData("", "record struct", RudeEditKind.InsertOrMoveStructMember)] + [InlineData("[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]", "class", RudeEditKind.InsertOrMoveTypeWithLayoutMember)] + [InlineData("[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]", "record class", RudeEditKind.InsertOrMoveTypeWithLayoutMember)] + internal void Property_Reorder_Auto_TypeLayout(string attribute, string keyword, RudeEditKind rudeEditKind) + { + var src1 = attribute + keyword + " C { int P { get; } int Q { get; } int R { get; } }"; + var src2 = attribute + keyword + " C { int R { get; } int P { get; } int Q { get; } }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Move, "int Q", FeaturesResources.auto_property)); + Diagnostic(rudeEditKind, "int R", GetResource("auto-property"), GetResource(keyword))); } [Fact] - public void Property_Reorder_Auto_Struct() + public void Property_Reorder_Auto_Reloadable() { - var src1 = "struct C { int P { get; set; } byte Q { get; set; } }"; - var src2 = "struct C { byte Q { get; set; } int P { get; set; } }"; + var src1 = ReloadableAttributeSrc + """ + [CreateNewOnMetadataUpdate] + struct C + { + + int P { get; } = 0; + int Q { get; } = 1; + int R { get; } + } + """; + + var src2 = ReloadableAttributeSrc + """ + [CreateNewOnMetadataUpdate] + struct C + { + int R { get; } + int P { get; } = 0; + int Q { get; } = 1; + + } + """; var edits = GetTopEdits(src1, src2); - edits.VerifyEdits( - "Reorder [byte Q { get; set; }]@31 -> @11"); + edits.VerifyEdits(EditKind.Reorder); - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Move, "byte Q", FeaturesResources.auto_property)); + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Replace, c => c.GetMember("C"))], + capabilities: EditAndContinueCapabilities.NewTypeDefinition); } [Fact] - public void PropertyAccessorReorder_GetSet() + public void PropertyAccessor_Reorder_GetSet() { var src1 = "class C { int P { get { return 1; } set { } } }"; var src2 = "class C { int P { set { } get { return 1; } } }"; @@ -17735,7 +18192,7 @@ public void PropertyAccessorReorder_GetSet() } [Fact] - public void PropertyAccessorReorder_GetInit() + public void PropertyAccessor_Reorder_GetInit() { var src1 = "class C { int P { get { return 1; } init { } } }"; var src2 = "class C { int P { init { } get { return 1; } } }"; @@ -17824,7 +18281,7 @@ public void Property_Update_Type_TypeLayout() var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.InsertIntoStruct, "long P", GetResource("auto-property"), GetResource("struct"))], + [Diagnostic(RudeEditKind.InsertOrMoveStructMember, "long P", GetResource("auto-property"), GetResource("struct"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); } @@ -17987,8 +18444,44 @@ class C Diagnostic(RudeEditKind.InsertExtern, "private static extern int P3", FeaturesResources.property_)); } + [Theory] + [InlineData("", "struct", RudeEditKind.InsertOrMoveStructMember)] + [InlineData("[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]", "class", RudeEditKind.InsertOrMoveTypeWithLayoutMember)] + internal void Property_Insert_TypeLayout(string attribute, string type, RudeEditKind rudeEditKind) + { + var src1 = attribute + type + """ + S + { + public int a; + + public S(int z) { a = z; } + } + """; + var src2 = attribute + type + """ + S + { + public int a; + int c { get; set; } + int e { get { return 0; } set { } } + int g { get; } = 1; + int i { get; set; } = 1; + int k => 1; + int l { get => 1; set {} } + int m { get => 1; set => k; } + public S(int z) { a = z; } + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemanticDiagnostics( + Diagnostic(rudeEditKind, "int c", GetResource("auto-property"), GetResource(type)), + Diagnostic(rudeEditKind, "int g", GetResource("auto-property"), GetResource(type)), + Diagnostic(rudeEditKind, "int i", GetResource("auto-property"), GetResource(type))); + } + [Fact] - public void Property_Insert_IntoStruct() + public void Property_Insert_IntoStruct_Static() { var src1 = @" struct S @@ -18002,13 +18495,13 @@ struct S struct S { public int a; - private static int c { get; set; } - private static int e { get { return 0; } set { } } - private static int g { get; } = 1; - private static int i { get; set; } = 1; - private static int k => 1; - private static int l { get => 1; set {} } - private static int m { get => 1; set => k; } + static int c { get; set; } + static int e { get { return 0; } set { } } + static int g { get; } = 1; + static int i { get; set; } = 1; + static int k => 1; + static int l { get => 1; set {} } + static int m { get => 1; set => k; } public S(int z) { a = z; } } "; @@ -18016,56 +18509,9 @@ struct S var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoStruct, "private static int c", GetResource("auto-property"), GetResource("struct")), - Diagnostic(RudeEditKind.InsertIntoStruct, "private static int g", GetResource("auto-property"), GetResource("struct")), - Diagnostic(RudeEditKind.InsertIntoStruct, "private static int i", GetResource("auto-property"), GetResource("struct"))); - } - - [Fact] - public void Property_Insert_IntoLayoutClass_Sequential() - { - var src1 = @" -using System.Runtime.InteropServices; - -[StructLayoutAttribute(LayoutKind.Sequential)] -class C -{ - private int a; -} -"; - var src2 = @" -using System.Runtime.InteropServices; - -[StructLayoutAttribute(LayoutKind.Sequential)] -class C -{ - private int a; - private int b { get; set; } - private static int c { get; set; } - private int d { get { return 0; } set { } } - private static int e { get { return 0; } set { } } - private int f { get; } = 1; - private static int g { get; } = 1; - private int h { get; set; } = 1; - private static int i { get; set; } = 1; - private int j => 1; - private static int k => 1; - private int l { get => 1; set { } } - private static int m { get => 1; set { } } - private int n { get { return 1; } set => a; } - private static int o { get { return 1; } set => a; } -} -"; - - var edits = GetTopEdits(src1, src2); - - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "private int b", GetResource("auto-property"), GetResource("class")), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "private static int c", GetResource("auto-property"), GetResource("class")), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "private int f", GetResource("auto-property"), GetResource("class")), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "private static int g", GetResource("auto-property"), GetResource("class")), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "private int h", GetResource("auto-property"), GetResource("class")), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "private static int i", GetResource("auto-property"), GetResource("class"))); + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "static int c", GetResource("auto-property"), GetResource("struct")), + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "static int g", GetResource("auto-property"), GetResource("struct")), + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "static int i", GetResource("auto-property"), GetResource("struct"))); } [Fact] @@ -18783,6 +19229,316 @@ class C(int A, int B) capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); } + [Fact] + public void Property_Partial_DeleteInsert_DefinitionPart() + { + var srcA1 = "partial class C { partial int P { get; } }"; + var srcB1 = "partial class C { partial int P => 1; }"; + var srcC1 = "partial class C { }"; + + var srcA2 = "partial class C { }"; + var srcB2 = "partial class C { partial int P => 1; }"; + var srcC2 = "partial class C { partial int P { get; } }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2), GetTopEdits(srcC1, srcC2)], + [ + DocumentResults(), + DocumentResults(), + DocumentResults( + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P").PartialImplementationPart, partialType: "C")]), + ]); + } + + [Fact] + public void Property_Partial_DeleteInsert_ImplementationPart() + { + var srcA1 = "partial class C { partial int P { get; } }"; + var srcB1 = "partial class C { partial int P => 1; }"; + var srcC1 = "partial class C { }"; + + var srcA2 = "partial class C { partial int P { get; } }"; + var srcB2 = "partial class C { }"; + var srcC2 = "partial class C { partial int P => 1; }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2), GetTopEdits(srcC1, srcC2)], + [ + DocumentResults(), + DocumentResults(), + DocumentResults( + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P").PartialImplementationPart, partialType: "C")]), + ]); + } + + [Fact] + public void Property_Partial_Swap_ImplementationAndDefinitionParts() + { + var srcA1 = "partial class C { partial int P { get; } }"; + var srcB1 = "partial class C { partial int P => 1; }"; + + var srcA2 = "partial class C { partial int P => 1; }"; + var srcB2 = "partial class C { partial int P { get; } }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults( + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P").PartialImplementationPart, partialType: "C")]), + DocumentResults(), + ]); + } + + [Fact] + public void Property_Partial_DeleteBoth() + { + var srcA1 = "partial class C { partial int P { get; } }"; + var srcB1 = "partial class C { partial int P => 1; }"; + + var srcA2 = "partial class C { }"; + var srcB2 = "partial class C { }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults( + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.P").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C") + ]), + DocumentResults( + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.P").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C") + ]), + ]); + } + + [Fact] + public void Property_Partial_DeleteInsertBoth() + { + var srcA1 = "partial class C { partial int P { get; } }"; + var srcB1 = "partial class C { partial int P => 1; }"; + var srcC1 = "partial class C { }"; + var srcD1 = "partial class C { }"; + + var srcA2 = "partial class C { }"; + var srcB2 = "partial class C { }"; + var srcC2 = "partial class C { partial int P { get; } }"; + var srcD2 = "partial class C { partial int P => 1; }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2), GetTopEdits(srcC1, srcC2), GetTopEdits(srcD1, srcD2)], + [ + DocumentResults(), + DocumentResults(), + DocumentResults( + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P").PartialImplementationPart, partialType: "C")]), + DocumentResults( + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P").PartialImplementationPart, partialType: "C")]) + ]); + } + + [Fact] + public void Property_Partial_Insert() + { + var srcA1 = "partial class C { }"; + var srcB1 = "partial class C { }"; + + var srcA2 = "partial class C { partial int P { get; } }"; + var srcB2 = "partial class C { partial int P => 1; }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults(), + DocumentResults( + semanticEdits: [SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.P").PartialImplementationPart)]), + ], + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + } + + [Fact] + public void Property_Partial_Insert_Reloadable() + { + var srcA1 = ReloadableAttributeSrc + "[CreateNewOnMetadataUpdate]partial class C { }"; + var srcB1 = "partial class C { }"; + + var srcA2 = ReloadableAttributeSrc + "[CreateNewOnMetadataUpdate]partial class C { partial int P { get; } }"; + var srcB2 = "partial class C { partial int P { get => 1; } }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults( + semanticEdits: [SemanticEdit(SemanticEditKind.Replace, c => c.GetMember("C"), partialType: "C")]), + DocumentResults( + semanticEdits: [SemanticEdit(SemanticEditKind.Replace, c => c.GetMember("C"), partialType: "C")]), + ], + capabilities: EditAndContinueCapabilities.NewTypeDefinition); + } + + [Fact] + public void Property_Partial_Update_Attribute_Definition() + { + var attribute = """ + public class A : System.Attribute { public A(int x) {} } + """; + + var srcA1 = attribute + + "partial class C { [A(1)]partial int P { get; } }"; + var srcB1 = "partial class C { partial int P => 1; }"; + + var srcA2 = attribute + + "partial class C { [A(2)]partial int P { get; } }"; + var srcB2 = "partial class C { partial int P => 1; }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults( + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.P").PartialImplementationPart, partialType: "C")]), + DocumentResults(), + ], + capabilities: EditAndContinueCapabilities.ChangeCustomAttributes); + } + + [Fact] + public void Property_Partial_Update_Attribute_Implementation() + { + var attribute = """ + public class A : System.Attribute { public A(int x) {} } + """; + + var srcA1 = attribute + + "partial class C { partial int P { get; } }"; + var srcB1 = "partial class C { [A(1)]partial int P => 1; }"; + + var srcA2 = attribute + + "partial class C { partial int P { get; } }"; + var srcB2 = "partial class C { [A(2)]partial int P => 1; }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults(), + DocumentResults( + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.P").PartialImplementationPart, partialType: "C"), + + // Updating the accessor is superfluous. + // It is added since we see an update to an expression bodied property. We don't distinguish between update to the body and update to an attribute. + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P").PartialImplementationPart, partialType: "C") + ]), + ], + capabilities: EditAndContinueCapabilities.ChangeCustomAttributes); + } + + [Fact] + public void Property_Partial_Update_Attribute_DefinitionAndImplementation() + { + var attribute = """ + public class A : System.Attribute { public A(int x) {} } + """; + + var srcA1 = attribute + + "partial class C { [A(1)]partial int P { get; } }"; + var srcB1 = "partial class C { [A(1)]partial int P => 1; }"; + + var srcA2 = attribute + + "partial class C { [A(2)]partial int P { get; } }"; + var srcB2 = "partial class C { [A(2)]partial int P => 1; }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults( + semanticEdits: [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.P").PartialImplementationPart, partialType: "C")]), + DocumentResults( + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P").PartialImplementationPart, partialType: "C"), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.P").PartialImplementationPart, partialType: "C") + ]), + ], + capabilities: EditAndContinueCapabilities.ChangeCustomAttributes); + } + + [Fact] + public void Property_Partial_DeleteInsert_DefinitionWithAttributeChange() + { + var attribute = """ + public class A : System.Attribute {} + """; + + var srcA1 = attribute + + "partial class C { [A]partial int P { get; } }"; + var srcB1 = "partial class C { partial int P => 1; }"; + + var srcA2 = attribute + + "partial class C { }"; + var srcB2 = "partial class C { partial int P => 1; partial int P { get; } }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults(), + + DocumentResults( + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.get_P").PartialImplementationPart, partialType: "C"), + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.P").PartialImplementationPart, partialType: "C") + ]), + ], + capabilities: EditAndContinueCapabilities.ChangeCustomAttributes); + } + + [Fact] + public void Property_Partial_Parameter_TypeChange() + { + var srcA1 = "partial class C { partial int P { get; } }"; + var srcB1 = "partial class C { partial int P => 1; }"; + + var srcA2 = "partial class C { partial long P { get; } }"; + var srcB2 = "partial class C { partial long P => 1; }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults( + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.P").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.get_P").PartialImplementationPart, partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.P").PartialImplementationPart, partialType: "C"), + ]), + DocumentResults( + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_P").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.P").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.get_P").PartialImplementationPart, partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.P").PartialImplementationPart, partialType: "C"), + ]), + ], + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults( + diagnostics: [Diagnostic(RudeEditKind.ChangingSignatureNotSupportedByRuntime, "partial long P", GetResource("property"))]), + DocumentResults( + diagnostics: [Diagnostic(RudeEditKind.ChangingSignatureNotSupportedByRuntime, "partial long P", GetResource("property"))]), + ], + capabilities: EditAndContinueCapabilities.Baseline); + } + #endregion #region Indexers @@ -19337,7 +20093,7 @@ public void Indexer_Update_Type_Stackalloc_WithExpressionBody() } [Fact] - public void Indexer_Parameter_Update_Type() + public void Indexer_Parameter_TypeChange() { var src1 = "class C { int this[byte a] { get => 1; set { } } }"; var src2 = "class C { int this[long a] { get => 1; set { } } }"; @@ -19356,6 +20112,52 @@ public void Indexer_Parameter_Update_Type() capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } + [Fact] + public void Indexer_Partial_Parameter_TypeChange() + { + var srcA1 = "partial class C { partial int this[long x] { get; set; } }"; + var srcB1 = "partial class C { partial int this[long x] { get => 1; set { } } }"; + + var srcA2 = "partial class C { partial int this[byte x] { get; set; } }"; + var srcB2 = "partial class C { partial int this[byte x] { get => 1; set { } } }"; + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults( + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.this[]").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_Item").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_Item").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.this[]").PartialImplementationPart, partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.get_Item").PartialImplementationPart, partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.set_Item").PartialImplementationPart, partialType: "C"), + ]), + DocumentResults( + semanticEdits: + [ + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.this[]").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_Item").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_Item").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.this[]").PartialImplementationPart, partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.get_Item").PartialImplementationPart, partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.set_Item").PartialImplementationPart, partialType: "C"), + ]), + ], + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + EditAndContinueValidation.VerifySemantics( + [GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2)], + [ + DocumentResults( + diagnostics: [Diagnostic(RudeEditKind.ChangingSignatureNotSupportedByRuntime, "byte x", GetResource("indexer"))]), + DocumentResults( + diagnostics: [Diagnostic(RudeEditKind.ChangingSignatureNotSupportedByRuntime, "byte x", GetResource("indexer"))]), + ], + capabilities: EditAndContinueCapabilities.Baseline); + } + [Fact] public void Indexer_Parameter_Rename() { @@ -19420,6 +20222,46 @@ public void Indexer_Parameter_Insert() capabilities: EditAndContinueCapabilities.AddMethodToExistingType); } + [Fact] + public void Indexer_Parameter_Insert_Partial() + { + var src1 = """ + class C + { + partial int this[int a] { get; set; } + partial int this[int a] { get => 1; set { } } + } + """; + + var src2 = """ + class C + { + partial int this[int a, int/*1*/b, int c] { get; set; } + partial int this[int a, int/*2*/b, int c] { get => 1; set { } } + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifySemantics( + [ + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.this[]").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.get_Item").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Delete, c => c.GetMember("C.set_Item").PartialImplementationPart, deletedSymbolContainerProvider: c => c.GetMember("C"), partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.this[]").PartialImplementationPart, partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.get_Item").PartialImplementationPart, partialType: "C"), + SemanticEdit(SemanticEditKind.Insert, c => c.GetMember("C.set_Item").PartialImplementationPart, partialType: "C"), + ], + capabilities: EditAndContinueCapabilities.AddMethodToExistingType); + + edits.VerifySemanticDiagnostics( + [ + Diagnostic(RudeEditKind.ChangingSignatureNotSupportedByRuntime, "int/*1*/b", GetResource("indexer")), + Diagnostic(RudeEditKind.ChangingSignatureNotSupportedByRuntime, "int/*2*/b", GetResource("indexer")) + ], + capabilities: EditAndContinueCapabilities.Baseline); + } + [Fact] public void Indexer_Parameter_Delete() { @@ -19963,7 +20805,7 @@ public void Event_Insert() } [Fact] - public void Event_Delete_CustomAccessors() + public void Event_Delete() { var src1 = "class C { event int E { remove { } add { } } }"; var src2 = "class C { }"; @@ -19980,7 +20822,7 @@ public void Event_Delete_CustomAccessors() } [Fact] - public void Event_Delete_SynthesizedAccessors() + public void EventField_Delete() { var src1 = "class C { event System.Action E; }"; var src2 = "class C { }"; @@ -19993,7 +20835,7 @@ public void Event_Delete_SynthesizedAccessors() } [Fact] - public void Event_Insert_TypeLayout_CustomAccessors() + public void Event_Insert_TypeLayout() { var src1 = @" using System; @@ -20021,7 +20863,7 @@ private event Action c { add { } remove { } } } [Fact] - public void Event_Insert_TypeLayout_SynthesizedAccessors() + public void EventField_Insert_TypeLayout() { var src1 = @" using System; @@ -20046,7 +20888,7 @@ class C var edits = GetTopEdits(src1, src2); edits.VerifySemanticDiagnostics( - [Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "c", GetResource("event field"), GetResource("class"))], + [Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "c", GetResource("event field"), GetResource("class"))], capabilities: EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType); } @@ -20178,7 +21020,7 @@ public readonly event Action E } [Fact] - public void Event_Attribute_Add_SynthesizedAccessors() + public void EventField_Attribute_Add() { var src1 = @" class C @@ -20268,7 +21110,7 @@ event Action F { add {} [System.Obsolete]remove {} } } [Fact] - public void Field_Event_Attribute_Delete() + public void EventField_Attribute_Delete() { var src1 = @" class C @@ -20392,7 +21234,7 @@ public void Event_Update_Type_Stackalloc() } [Fact] - public void Event_Rename_CustomAcccessors() + public void Event_Rename() { var src1 = "class C { event System.Action E { remove { } add { } } }"; var src2 = "class C { event System.Action F { remove { } add { } } }"; @@ -20416,7 +21258,7 @@ public void Event_Rename_CustomAcccessors() } [Fact] - public void Event_Rename_SynthesizedAccessors() + public void EventField_Rename() { var src1 = "class C { event System.Action E; }"; var src2 = "class C { event System.Action F; }"; @@ -20429,7 +21271,7 @@ public void Event_Rename_SynthesizedAccessors() } [Fact] - public void Event_Update_Type_CustomAcccessors() + public void Event_Update_Type() { var src1 = "class C { event System.Action E { remove { } add { } } }"; var src2 = "class C { event System.Action E { remove { } add { } } }"; @@ -20452,7 +21294,7 @@ public void Event_Update_Type_CustomAcccessors() } [Fact] - public void Event_Update_Type_SynthesizedAcccessors_RuntimeTypeChanged() + public void EventField_Update_Type_RuntimeTypeChanged() { var src1 = "class C { event System.Action E; }"; var src2 = "class C { event System.Action E; }"; @@ -20468,7 +21310,7 @@ public void Event_Update_Type_SynthesizedAcccessors_RuntimeTypeChanged() [InlineData("string", "string?")] [InlineData("object", "dynamic")] [InlineData("(int a, int b)", "(int a, int c)")] - public void Event_Update_Type_SynthesizedAcccessors_RuntimeTypeUnchanged(string oldType, string newType) + public void EventField_Update_Type_RuntimeTypeUnchanged(string oldType, string newType) { var src1 = "class C { event System.Action<" + oldType + "> F, G; }"; var src2 = "class C { event System.Action<" + newType + "> F, G; }"; @@ -20481,22 +21323,142 @@ public void Event_Update_Type_SynthesizedAcccessors_RuntimeTypeUnchanged(string } [Fact] - public void Event_Reorder_SynthesizedAccessors() + public void EventField_Reorder() { - var src1 = "class C { int a = 0; int b = 1; event System.Action c = 2; }"; - var src2 = "class C { event System.Action c = 2; int a = 0; int b = 1; }"; + var src1 = """ + using System; + class C + { + + event Action a = null; + event Action b = null; + event Action c; + } + """; + + var src2 = """ + using System; + class C + { + event Action c; + event Action a = null; + event Action b = null; + + } + """; var edits = GetTopEdits(src1, src2); - edits.VerifyEdits( - "Reorder [event System.Action c = 2;]@32 -> @10"); + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemantics(); + } + + [Fact] + public void EventField_Reorder_WithInitializer() + { + var src1 = """ + using System; + class C + { + + event Action a = null; + event Action b = null; + event Action c = null; + } + """; + + var src2 = """ + using System; + class C + { + event Action c = null; + event Action a = null; + event Action b = null; + + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemantics([SemanticEdit(SemanticEditKind.Update, c => c.GetParameterlessConstructor("C"), preserveLocalVariables: true)]); + } + + [Theory] + [InlineData("", "struct", RudeEditKind.InsertOrMoveStructMember)] + [InlineData("", "record struct", RudeEditKind.InsertOrMoveStructMember)] + [InlineData("[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]", "class", RudeEditKind.InsertOrMoveTypeWithLayoutMember)] + [InlineData("[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]", "record class", RudeEditKind.InsertOrMoveTypeWithLayoutMember)] + internal void EventField_Reorder_TypeLayout(string attribute, string keyword, RudeEditKind rudeEditKind) + { + var src1 = $$""" + using System; + {{attribute}}{{keyword}} C + { + + event Action a; + event Action b; + event Action c; + } + """; + + var src2 = $$""" + using System; + {{attribute}}{{keyword}} C + { + event Action c; + event Action a; + event Action b; + + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Move, "event System.Action c = 2", CSharpFeaturesResources.event_field)); + Diagnostic(rudeEditKind, "event Action c", GetResource("event field"), GetResource(keyword))); } [Fact] - public void Event_Partial_InsertDelete_SynthesizedAccessors() + public void EventField_Reorder_Reloadable() + { + var src1 = "using System;" + ReloadableAttributeSrc + """ + [CreateNewOnMetadataUpdate] + class C + { + + event Action a = null; + event Action b = null; + event Action c; + } + """; + + var src2 = "using System;" + ReloadableAttributeSrc + """ + [CreateNewOnMetadataUpdate] + class C + { + event Action c; + event Action a = null; + event Action b = null; + + } + """; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits(EditKind.Reorder); + + edits.VerifySemantics( + [SemanticEdit(SemanticEditKind.Replace, c => c.GetMember("C"))], + capabilities: EditAndContinueCapabilities.NewTypeDefinition); + } + + [Fact] + public void EventField_Partial_InsertDelete() { var srcA1 = "partial class C { static void F() {} }"; var srcB1 = "partial class C { event System.Action E = F; }"; @@ -20741,10 +21703,8 @@ public void Parameter_Reorder_UpdateBody() "Reorder [int b]@31 -> @24"); edits.VerifySemantics( - [ - SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M")) - ], - capabilities: EditAndContinueCapabilities.UpdateParameters); + [SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C.M"))], + capabilities: EditAndContinueCapabilities.UpdateParameters); edits.VerifySemanticDiagnostics( [Diagnostic(RudeEditKind.RenamingNotSupportedByRuntime, "int b", FeaturesResources.parameter)], diff --git a/src/Features/CSharpTest/EncapsulateField/EncapsulateFieldTests.cs b/src/Features/CSharpTest/EncapsulateField/EncapsulateFieldTests.cs index 2c23b1a52476f..9c8b82ad9cfcb 100644 --- a/src/Features/CSharpTest/EncapsulateField/EncapsulateFieldTests.cs +++ b/src/Features/CSharpTest/EncapsulateField/EncapsulateFieldTests.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.Diagnostics.CodeAnalysis; using System.Globalization; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; @@ -20,13 +19,13 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.EncapsulateField; [Trait(Traits.Feature, Traits.Features.EncapsulateField)] -public class EncapsulateFieldTests : AbstractCSharpCodeActionTest_NoEditor +public sealed class EncapsulateFieldTests : AbstractCSharpCodeActionTest_NoEditor { protected override CodeRefactoringProvider CreateCodeRefactoringProvider(TestWorkspace workspace, TestParameters parameters) => new EncapsulateFieldRefactoringProvider(); private OptionsCollection AllOptionsOff - => new OptionsCollection(GetLanguage()) + => new(GetLanguage()) { { CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.NeverWithSilentEnforcement }, { CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.NeverWithSilentEnforcement }, @@ -34,12 +33,12 @@ private OptionsCollection AllOptionsOff internal Task TestAllOptionsOffAsync( TestHost host, - string initialMarkup, - string expectedMarkup, - ParseOptions parseOptions = null, - CompilationOptions compilationOptions = null, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string initialMarkup, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string expectedMarkup, + ParseOptions? parseOptions = null, + CompilationOptions? compilationOptions = null, int index = 0, - OptionsCollection options = null) + OptionsCollection? options = null) { options ??= new OptionsCollection(GetLanguage()); options.AddRange(AllOptionsOff); @@ -1649,4 +1648,29 @@ void M() """; await TestAllOptionsOffAsync(host, text, expected, index: 1); } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/75210")] + public async Task PrimaryConstructor(TestHost host, bool andUseProperty) + { + await TestAllOptionsOffAsync(host, """ + public class C(object o) + { + public readonly int [|A|] = 1; + } + """, """ + public class C(object o) + { + private readonly int a = 1; + + public int A + { + get + { + return a; + } + } + } + """, + index: andUseProperty ? 0 : 1); + } } diff --git a/src/Features/CSharpTest/ExtractClass/ExtractClassTests.cs b/src/Features/CSharpTest/ExtractClass/ExtractClassTests.cs index c9acb30cfcb20..447e92479f21a 100644 --- a/src/Features/CSharpTest/ExtractClass/ExtractClassTests.cs +++ b/src/Features/CSharpTest/ExtractClass/ExtractClassTests.cs @@ -2904,32 +2904,69 @@ public void M() [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/63315")] public async Task TestMethodInsideNamespace_NoException() { - var code = """ - namespace N - { - class C + await new Test() + { + TestCode = """ + namespace N { - } + class C + { + } - public void $$N + public void $$N + { + } + } + """, + FixedState = + { + Sources = { + """ + namespace N + { + class C : MyBase + { + } + """, + """ + namespace N + { + internal class MyBase + { + } + + public void N + { + } + } + } + """, + }, + ExpectedDiagnostics = + { + // /0/Test0.cs(5,6): error CS1513: } expected + DiagnosticResult.CompilerError("CS1513").WithSpan(5, 6, 5, 6), + // /0/Test1.cs(5,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + DiagnosticResult.CompilerError("CS1519").WithSpan("/0/Test1.cs", 5, 5, 5, 6).WithArguments("}"), + // /0/Test1.cs(7,17): error CS0547: 'MyBase.N': property or indexer cannot have void type + DiagnosticResult.CompilerError("CS0547").WithSpan("/0/Test1.cs", 7, 17, 7, 18).WithArguments("N.MyBase.N"), + // /0/Test1.cs(7,17): error CS0548: 'MyBase.N': property or indexer must have at least one accessor + DiagnosticResult.CompilerError("CS0548").WithSpan("/0/Test1.cs", 7, 17, 7, 18).WithArguments("N.MyBase.N"), } - } - """; - - await new Test() - { - TestCode = code, - FixedCode = code, + }, ExpectedDiagnostics = { - // /0/Test0.cs(7,17): error CS0116: A namespace cannot directly contain members such as fields, methods or statements - DiagnosticResult.CompilerError("CS0116").WithSpan(7, 17, 7, 18), - // /0/Test0.cs(7,17): error CS0547: '.N': property or indexer cannot have void type - DiagnosticResult.CompilerError("CS0547").WithSpan(7, 17, 7, 18).WithArguments("N..N"), - // /0/Test0.cs(7,17): error CS0548: '.N': property or indexer must have at least one accessor - DiagnosticResult.CompilerError("CS0548").WithSpan(7, 17, 7, 18).WithArguments("N..N"), - } + // /0/Test0.cs(5,5): error CS1519: Invalid token '}' in class, record, struct, or interface member declaration + DiagnosticResult.CompilerError("CS1519").WithSpan(5, 5, 5, 6).WithArguments("}"), + // /0/Test0.cs(7,17): error CS0547: 'C.N': property or indexer cannot have void type + DiagnosticResult.CompilerError("CS0547").WithSpan(7, 17, 7, 18).WithArguments("N.C.N"), + // /0/Test0.cs(7,17): error CS0548: 'C.N': property or indexer must have at least one accessor + DiagnosticResult.CompilerError("CS0548").WithSpan(7, 17, 7, 18).WithArguments("N.C.N"), + // /0/Test0.cs(10,2): error CS1513: } expected + DiagnosticResult.CompilerError("CS1513").WithSpan(10, 2, 10, 2), + }, + FileName = "Test1.cs" }.RunAsync(); } diff --git a/src/Features/CSharpTest/GenerateVariable/GenerateVariableTests.cs b/src/Features/CSharpTest/GenerateVariable/GenerateVariableTests.cs index b97543703fe46..4f4ef61cfb30f 100644 --- a/src/Features/CSharpTest/GenerateVariable/GenerateVariableTests.cs +++ b/src/Features/CSharpTest/GenerateVariable/GenerateVariableTests.cs @@ -92,11 +92,11 @@ void Method() } """, [ - string.Format(FeaturesResources.Generate_field_0, "goo"), - string.Format(FeaturesResources.Generate_read_only_field_0, "goo"), - string.Format(FeaturesResources.Generate_property_0, "goo"), - string.Format(FeaturesResources.Generate_local_0, "goo"), - string.Format(FeaturesResources.Generate_parameter_0, "goo"), + string.Format(CodeFixesResources.Generate_field_0, "goo"), + string.Format(CodeFixesResources.Generate_read_only_field_0, "goo"), + string.Format(CodeFixesResources.Generate_property_0, "goo"), + string.Format(CodeFixesResources.Generate_local_0, "goo"), + string.Format(CodeFixesResources.Generate_parameter_0, "goo"), ]); } @@ -114,8 +114,8 @@ void Method() } """, [ - string.Format(FeaturesResources.Generate_field_0, "_goo"), - string.Format(FeaturesResources.Generate_read_only_field_0, "_goo"), + string.Format(CodeFixesResources.Generate_field_0, "_goo"), + string.Format(CodeFixesResources.Generate_read_only_field_0, "_goo"), ]); } @@ -356,7 +356,7 @@ void Method(int i) } } """, -[string.Format(FeaturesResources.Generate_field_0, "goo"), string.Format(FeaturesResources.Generate_property_0, "goo"), string.Format(FeaturesResources.Generate_local_0, "goo"), string.Format(FeaturesResources.Generate_parameter_0, "goo")]); +[string.Format(CodeFixesResources.Generate_field_0, "goo"), string.Format(CodeFixesResources.Generate_property_0, "goo"), string.Format(CodeFixesResources.Generate_local_0, "goo"), string.Format(CodeFixesResources.Generate_parameter_0, "goo")]); } [Fact] @@ -377,7 +377,7 @@ public override void Method(int i) } } """, -[string.Format(FeaturesResources.Generate_field_0, "goo"), string.Format(FeaturesResources.Generate_property_0, "goo"), string.Format(FeaturesResources.Generate_local_0, "goo"), string.Format(FeaturesResources.Generate_parameter_0, "goo"), string.Format(FeaturesResources.Generate_parameter_0_and_overrides_implementations, "goo")]); +[string.Format(CodeFixesResources.Generate_field_0, "goo"), string.Format(CodeFixesResources.Generate_property_0, "goo"), string.Format(CodeFixesResources.Generate_local_0, "goo"), string.Format(CodeFixesResources.Generate_parameter_0, "goo"), string.Format(CodeFixesResources.Generate_parameter_0_and_overrides_implementations, "goo")]); } [Fact] @@ -554,7 +554,7 @@ void Method(out int i) } } """, -[string.Format(FeaturesResources.Generate_field_0, "goo"), string.Format(FeaturesResources.Generate_local_0, "goo"), string.Format(FeaturesResources.Generate_parameter_0, "goo")]); +[string.Format(CodeFixesResources.Generate_field_0, "goo"), string.Format(CodeFixesResources.Generate_local_0, "goo"), string.Format(CodeFixesResources.Generate_parameter_0, "goo")]); } [Fact] @@ -2431,7 +2431,7 @@ static void Main() } } """, -[string.Format(FeaturesResources.Generate_field_0, "p"), string.Format(FeaturesResources.Generate_property_0, "p"), string.Format(FeaturesResources.Generate_local_0, "p"), string.Format(FeaturesResources.Generate_parameter_0, "p")]); +[string.Format(CodeFixesResources.Generate_field_0, "p"), string.Format(CodeFixesResources.Generate_property_0, "p"), string.Format(CodeFixesResources.Generate_local_0, "p"), string.Format(CodeFixesResources.Generate_parameter_0, "p")]); await TestInRegularAndScriptAsync( """ @@ -5320,7 +5320,7 @@ void Goo() #line hidden } """; - await TestExactActionSetOfferedAsync(code, [string.Format(FeaturesResources.Generate_local_0, "Bar"), string.Format(FeaturesResources.Generate_parameter_0, "Bar")]); + await TestExactActionSetOfferedAsync(code, [string.Format(CodeFixesResources.Generate_local_0, "Bar"), string.Format(CodeFixesResources.Generate_parameter_0, "Bar")]); await TestInRegularAndScriptAsync(code, """ @@ -10551,8 +10551,8 @@ public C() } """, [ - string.Format(FeaturesResources.Generate_property_0, "Field"), - string.Format(FeaturesResources.Generate_field_0, "Field"), + string.Format(CodeFixesResources.Generate_property_0, "Field"), + string.Format(CodeFixesResources.Generate_field_0, "Field"), ]); } @@ -10575,8 +10575,8 @@ void Goo() } """, [ - string.Format(FeaturesResources.Generate_property_0, "Field"), - string.Format(FeaturesResources.Generate_field_0, "Field"), + string.Format(CodeFixesResources.Generate_property_0, "Field"), + string.Format(CodeFixesResources.Generate_field_0, "Field"), ]); } @@ -10598,8 +10598,8 @@ internal MyException(int error, int offset, string message) : base(message) } """, [ - string.Format(FeaturesResources.Generate_local_0, "Error", "MyException"), - string.Format(FeaturesResources.Generate_parameter_0, "Error", "MyException"), + string.Format(CodeFixesResources.Generate_local_0, "Error", "MyException"), + string.Format(CodeFixesResources.Generate_parameter_0, "Error", "MyException"), ]); } diff --git a/src/Features/CSharpTest/Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj b/src/Features/CSharpTest/Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj index 73c7105b1f10e..55688e4abeed1 100644 --- a/src/Features/CSharpTest/Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj +++ b/src/Features/CSharpTest/Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj @@ -31,7 +31,7 @@ - + diff --git a/src/Features/CSharpTest/RelatedDocuments/CSharpRelatedDocumentsTests.cs b/src/Features/CSharpTest/RelatedDocuments/CSharpRelatedDocumentsTests.cs new file mode 100644 index 0000000000000..6ce75c9c77b29 --- /dev/null +++ b/src/Features/CSharpTest/RelatedDocuments/CSharpRelatedDocumentsTests.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.Threading.Tasks; +using Microsoft.CodeAnalysis.Remote.Testing; +using Microsoft.CodeAnalysis.Test.Utilities.RelatedDocuments; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.RelatedDocuments; + +public sealed class CSharpRelatedDocumentsTests : AbstractRelatedDocumentsTests +{ + [Theory, CombinatorialData] + public async Task EmptyDocument(TestHost testHost) + => await TestAsync(""" + + + $$ + + + """, testHost); + + [Theory, CombinatorialData] + public async Task ReferenceToSameDocument(TestHost testHost) + => await TestAsync(""" + + + [||]$$ + class C + { + C c; + } + + + + """, testHost); + + [Theory, CombinatorialData] + public async Task MultipleReferencesToSameDocument(TestHost testHost) + => await TestAsync(""" + + + [||]$$ + class C + { + C c; + C c; + } + + + + """, testHost); + + [Theory, CombinatorialData] + public async Task ReferenceToDifferentDocument(TestHost testHost) + => await TestAsync(""" + + + $$ + class C + { + D d; + } + + [||] + class D + { + } + + + + """, testHost); + + [Theory, CombinatorialData] + public async Task MultipleReferencesToDifferentDocument(TestHost testHost) + => await TestAsync(""" + + + $$ + class C + { + D d; + D d; + } + + [||] + class D + { + } + + + + """, testHost); + + [Theory, CombinatorialData] + public async Task ReferenceWithinGeneric(TestHost testHost) + => await TestAsync(""" + + + d; + } + ]]> + [||] + class D + { + } + + + + """, testHost); + + [Theory, CombinatorialData] + public async Task QualifiedReferenceWithinGeneric(TestHost testHost) + => await TestAsync(""" + + + $$ + class C + { + N.D d; + } + + [||] + namespace N; + + class D + { + } + + + + """, testHost); + + [Theory, CombinatorialData] + public async Task QualifiedReferenceThroughStaticWithinGeneric(TestHost testHost) + => await TestAsync(""" + + + $$ + class C + { + void M() + { + Console.WriteLine(N.D.I); + } + } + + [||] + namespace N; + + class D + { + public static int I; + } + + + + """, testHost); + + [Theory, CombinatorialData] + public async Task ReferenceToPartialType(TestHost testHost) + => await TestAsync(""" + + + $$ + class C + { + D d; + } + + [||] + partial class D + { + } + + [||] + partial class D + { + } + + + + """, testHost); + + [Theory, CombinatorialData] + public async Task NoReferenceToNamespace(TestHost testHost) + => await TestAsync(""" + + + $$ + using N; + + class C + { + } + + + namespace N; + + partial class D + { + } + + + + """, testHost); + + [Theory, CombinatorialData] + public async Task ReferenceAcrossProjects(TestHost testHost) + => await TestAsync(""" + + + [||] + namespace N; + + public class D + { + } + + + + Assembly1 + $$ + using N; + + class C + { + D d; + } + + + + """, testHost); +} diff --git a/src/Features/CSharpTest/ReplaceMethodWithProperty/ReplaceMethodWithPropertyTests.cs b/src/Features/CSharpTest/ReplaceMethodWithProperty/ReplaceMethodWithPropertyTests.cs index 0bfadd0cc7e59..fa021ef3e571b 100644 --- a/src/Features/CSharpTest/ReplaceMethodWithProperty/ReplaceMethodWithPropertyTests.cs +++ b/src/Features/CSharpTest/ReplaceMethodWithProperty/ReplaceMethodWithPropertyTests.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeActions.ReplaceMethodWithProperty; [Trait(Traits.Feature, Traits.Features.CodeActionsReplaceMethodWithProperty)] -public class ReplaceMethodWithPropertyTests : AbstractCSharpCodeActionTest_NoEditor +public sealed class ReplaceMethodWithPropertyTests : AbstractCSharpCodeActionTest_NoEditor { protected override CodeRefactoringProvider CreateCodeRefactoringProvider(TestWorkspace workspace, TestParameters parameters) => new ReplaceMethodWithPropertyCodeRefactoringProvider(); @@ -3021,4 +3021,46 @@ int Goo } """); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/61161")] + public async Task TestEndOfLineTrivia1() + { + await TestInRegularAndScriptAsync( + """ + class C + { + public int [||]Test1() { return 1; } + public void Test2() { } + } + """, + """ + class C + { + public int Test1 => 1; + public void Test2() { } + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/61161")] + public async Task TestEndOfLineTrivia2() + { + await TestInRegularAndScriptAsync( + """ + class C + { + public int [||]Test1() { return 1; } + + public void Test2() { } + } + """, + """ + class C + { + public int Test1 => 1; + + public void Test2() { } + } + """); + } } diff --git a/src/Features/CSharpTest/ReplacePropertyWithMethods/ReplacePropertyWithMethodsTests.cs b/src/Features/CSharpTest/ReplacePropertyWithMethods/ReplacePropertyWithMethodsTests.cs index fb9bdd58cfd6c..efeb6a9e832d6 100644 --- a/src/Features/CSharpTest/ReplacePropertyWithMethods/ReplacePropertyWithMethodsTests.cs +++ b/src/Features/CSharpTest/ReplacePropertyWithMethods/ReplacePropertyWithMethodsTests.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeActions.ReplacePropertyWithMethods; [Trait(Traits.Feature, Traits.Features.CodeActionsReplacePropertyWithMethods)] -public class ReplacePropertyWithMethodsTests : AbstractCSharpCodeActionTest_NoEditor +public sealed class ReplacePropertyWithMethodsTests : AbstractCSharpCodeActionTest_NoEditor { private OptionsCollection PreferExpressionBodiedMethods => new(GetLanguage()) { { CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenPossibleWithSuggestionEnforcement } }; @@ -2490,4 +2490,29 @@ private static void SetSomeValue(int value) } """); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75135")] + public async Task TestMatchInPropertyPattern() + { + await TestInRegularAndScriptAsync(""" + class C + { + public int [||]Property { get { return 0; } } + public bool M() + { + return this is { Property: 1 }; + } + } + """, """ + class C + { + public int GetProperty() + { return 0; } + public bool M() + { + return this is { {|Conflict:Property|}: 1 }; + } + } + """); + } } diff --git a/src/Features/CSharpTest/SemanticSearch/CSharpSemanticSearchServiceTests.cs b/src/Features/CSharpTest/SemanticSearch/CSharpSemanticSearchServiceTests.cs index c841e11de33b6..20eb7b1fecda7 100644 --- a/src/Features/CSharpTest/SemanticSearch/CSharpSemanticSearchServiceTests.cs +++ b/src/Features/CSharpTest/SemanticSearch/CSharpSemanticSearchServiceTests.cs @@ -80,7 +80,7 @@ static IEnumerable Find(Compilation compilation) var result = await service.ExecuteQueryAsync(solution, query, s_referenceAssembliesDir, observer, options, traceSource, CancellationToken.None); Assert.Null(result.ErrorMessage); - AssertEx.Equal(new[] { "namespace N" }, results.Select(Inspect)); + AssertEx.Equal(["namespace N"], results.Select(Inspect)); } [ConditionalFact(typeof(CoreClrOnly))] diff --git a/src/Features/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs b/src/Features/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs index 0c5aaddff2311..e507f937454dc 100644 --- a/src/Features/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs +++ b/src/Features/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs @@ -7304,39 +7304,63 @@ await TestMissingInRegularAndScriptAsync( """, new TestParameters(options: featureOptions)); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75162")] + public async Task TestEditorBrowsable1() + { + await TestMissingInRegularAndScriptAsync(""" + using System.ComponentModel; + + [EditorBrowsable(EditorBrowsableState.Never)] + class Base + { + public static void Method() { } + } + + class Derived : Base { } + + class Test + { + void M() + { + [|Derived|].Method(); + } + } + """); + } + private async Task TestWithPredefinedTypeOptionsAsync(string code, string expected, int index = 0) => await TestInRegularAndScript1Async(code, expected, index, new TestParameters(options: PreferIntrinsicTypeEverywhere)); private OptionsCollection PreferIntrinsicTypeEverywhere - => new OptionsCollection(GetLanguage()) + => new(GetLanguage()) { { CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, true, NotificationOption2.Error }, { CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, this.onWithError }, }; private OptionsCollection PreferIntrinsicTypeInDeclaration - => new OptionsCollection(GetLanguage()) + => new(GetLanguage()) { { CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, true, NotificationOption2.Error }, { CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, this.offWithSilent }, }; private OptionsCollection PreferIntrinsicTypeInMemberAccess - => new OptionsCollection(GetLanguage()) + => new(GetLanguage()) { { CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, true, NotificationOption2.Error }, { CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, this.offWithSilent }, }; private OptionsCollection PreferImplicitTypeEverywhere - => new OptionsCollection(GetLanguage()) + => new(GetLanguage()) { { CSharpCodeStyleOptions.VarElsewhere, onWithInfo }, { CSharpCodeStyleOptions.VarWhenTypeIsApparent, onWithInfo }, { CSharpCodeStyleOptions.VarForBuiltInTypes, onWithInfo }, }; - private readonly CodeStyleOption2 offWithSilent = new CodeStyleOption2(false, NotificationOption2.Silent); - private readonly CodeStyleOption2 onWithInfo = new CodeStyleOption2(true, NotificationOption2.Suggestion); - private readonly CodeStyleOption2 onWithError = new CodeStyleOption2(true, NotificationOption2.Error); + private readonly CodeStyleOption2 offWithSilent = new(false, NotificationOption2.Silent); + private readonly CodeStyleOption2 onWithInfo = new(true, NotificationOption2.Suggestion); + private readonly CodeStyleOption2 onWithError = new(true, NotificationOption2.Error); } diff --git a/src/Features/CSharpTest/Snippets/AbstractCSharpAutoPropertySnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/AbstractCSharpAutoPropertySnippetProviderTests.cs new file mode 100644 index 0000000000000..8dbe4ef2d7abb --- /dev/null +++ b/src/Features/CSharpTest/Snippets/AbstractCSharpAutoPropertySnippetProviderTests.cs @@ -0,0 +1,167 @@ +// 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.Tasks; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; + +[Trait(Traits.Feature, Traits.Features.Snippets)] +public abstract class AbstractCSharpAutoPropertySnippetProviderTests : AbstractCSharpSnippetProviderTests +{ + protected abstract string DefaultPropertyBlockText { get; } + + [Fact] + public async Task NoSnippetInBlockNamespaceTest() + { + await VerifySnippetIsAbsentAsync(""" + namespace Namespace + { + $$ + } + """); + } + + [Fact] + public async Task NoSnippetInFileScopedNamespaceTest() + { + await VerifySnippetIsAbsentAsync(""" + namespace Namespace + + $$ + """); + } + + [Fact] + public async Task NoSnippetInTopLevelContextTest() + { + await VerifySnippetIsAbsentAsync(""" + System.Console.WriteLine(); + $$ + """); + } + + [Fact] + public async Task InsertSnippetInClassTest() + { + await VerifyDefaultPropertyAsync(""" + class MyClass + { + $$ + } + """); + } + + [Fact] + public async Task InsertSnippetInRecordTest() + { + await VerifyDefaultPropertyAsync(""" + record MyRecord + { + $$ + } + """); + } + + [Fact] + public async Task InsertSnippetInStructTest() + { + await VerifyDefaultPropertyAsync(""" + struct MyStruct + { + $$ + } + """); + } + + [Fact] + public abstract Task InsertSnippetInReadonlyStructTest(); + + [Fact] + public abstract Task InsertSnippetInReadonlyStructTest_ReadonlyModifierInOtherPartialDeclaration(); + + [Fact] + public abstract Task InsertSnippetInReadonlyStructTest_ReadonlyModifierInOtherPartialDeclaration_MissingPartialModifier(); + + // This case might produce non-default results for different snippets (e.g. no `set` accessor in 'propg' snippet), + // so it is tested separately for all of them + [Fact] + public abstract Task InsertSnippetInInterfaceTest(); + + [Fact] + public async Task InsertSnippetNamingTest() + { + await VerifyDefaultPropertyAsync(""" + class MyClass + { + public int MyProperty { get; set; } + $$ + } + """, "MyProperty1"); + } + + [Fact] + public async Task NoSnippetInEnumTest() + { + await VerifySnippetIsAbsentAsync(""" + enum MyEnum + { + $$ + } + """); + } + + [Fact] + public async Task NoSnippetInMethodTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public void Method() + { + $$ + } + } + """); + } + + [Fact] + public async Task NoSnippetInConstructorTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public Program() + { + $$ + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertSnippetAfterAccessibilityModifierTest(string modifier) + { + await VerifyPropertyAsync($$""" + class Program + { + {{modifier}} $$ + } + """, $$"""{|0:int|} {|1:MyProperty|} {{DefaultPropertyBlockText}}"""); + } + + protected async Task VerifyPropertyAsync([StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string markup, string propertyMarkup) + { + TestFileMarkupParser.GetPosition(markup, out var code, out var position); + var expectedCode = code.Insert(position, propertyMarkup + "$$"); + await VerifySnippetAsync(markup, expectedCode); + } + + protected Task VerifyDefaultPropertyAsync([StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string markup, string propertyName = "MyProperty") + => VerifyPropertyAsync(markup, $$"""public {|0:int|} {|1:{{propertyName}}|} {{DefaultPropertyBlockText}}"""); +} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpConditionalBlockSnippetCompletionProviderTests.cs b/src/Features/CSharpTest/Snippets/AbstractCSharpConditionalBlockSnippetProviderTests.cs similarity index 54% rename from src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpConditionalBlockSnippetCompletionProviderTests.cs rename to src/Features/CSharpTest/Snippets/AbstractCSharpConditionalBlockSnippetProviderTests.cs index 7831a0e46ece3..1e17af2b5fce3 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/AbstractCSharpConditionalBlockSnippetCompletionProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/AbstractCSharpConditionalBlockSnippetProviderTests.cs @@ -7,15 +7,15 @@ using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; -[Trait(Traits.Feature, Traits.Features.Completion)] -public abstract class AbstractCSharpConditionalBlockSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests +[Trait(Traits.Feature, Traits.Features.Snippets)] +public abstract class AbstractCSharpConditionalBlockSnippetProviderTests : AbstractCSharpSnippetProviderTests { - [WpfFact] + [Fact] public async Task InsertSnippetInMethodTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class Program { public void Method() @@ -23,81 +23,58 @@ public void Method() $$ } } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" class Program { public void Method() { - {{ItemToCommit}} (true) + {{SnippetIdentifier}} ({|0:true|}) { $$ } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertSnippetInGlobalContextTest() { - var markupBeforeCommit = """ - Ins$$ - """; - - var expectedCodeAfterCommit = $$""" - {{ItemToCommit}} (true) + await VerifySnippetAsync(""" + $$ + """, $$""" + {{SnippetIdentifier}} ({|0:true|}) { $$ } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task NoSnippetInBlockNamespaceTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" namespace Namespace { $$ - class Program - { - public async Task MethodAsync() - { - } - } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task NoSnippetInFileScopedNamespaceTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" namespace Namespace; - $$ - class Program - { - public async Task MethodAsync() - { - } - } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + $$ + """); } - [WpfFact] + [Fact] public async Task InsertSnippetInConstructorTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class Program { public Program() @@ -106,29 +83,25 @@ public Program() $$ } } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" class Program { public Program() { var x = 5; - {{ItemToCommit}} (true) + {{SnippetIdentifier}} ({|0:true|}) { $$ } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertSnippetInLocalFunctionTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class Program { public void Method() @@ -140,9 +113,7 @@ void LocalMethod() } } } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" class Program { public void Method() @@ -150,86 +121,82 @@ public void Method() var x = 5; void LocalMethod() { - {{ItemToCommit}} (true) + {{SnippetIdentifier}} ({|0:true|}) { $$ } } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertSnippetInAnonymousFunctionTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" public delegate void Print(int value); static void Main(string[] args) { - Print print = delegate(int val) { + Print print = delegate(int val) + { $$ }; } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" public delegate void Print(int value); static void Main(string[] args) { - Print print = delegate(int val) { - {{ItemToCommit}} (true) + Print print = delegate(int val) + { + {{SnippetIdentifier}} ({|0:true|}) { $$ } }; } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertSnippetInParenthesizedLambdaExpressionTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" + using System; + Func testForEquality = (x, y) => { $$ return x == y; }; - """; + """, $$""" + using System; - var expectedCodeAfterCommit = $$""" Func testForEquality = (x, y) => { - {{ItemToCommit}} (true) + {{SnippetIdentifier}} ({|0:true|}) { $$ } return x == y; }; - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task NoSnippetInSwitchExpression() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { public void Method() { - var operation = 2; - + var operation = 2; + var result = operation switch { $$ @@ -240,31 +207,29 @@ public void Method() }; } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task NoSnippetInSingleLambdaExpression() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" + using System; + class Program { public void Method() { - Func f = x => $$; + Func f = x => $$; } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task NoSnippetInStringTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { public void Method() @@ -272,71 +237,60 @@ public void Method() var str = "$$"; } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] - public async Task NoSnippetInObjectInitializerTest() + [Fact] + public async Task NoSnippetInConstructorArgumentsTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { public void Method() { - var str = new Test($$); + var test = new Test($$); } } class Test { - private string val; - public Test(string val) { - this.val = val; } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task NoSnippetInParameterListTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { public void Method(int x, $$) { } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task NoSnippetInRecordDeclarationTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" public record Person { $$ - public string FirstName { get; init; } = default!; - public string LastName { get; init; } = default!; + public string FirstName { get; init; } + public string LastName { get; init; } }; - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task NoSnippetInVariableDeclarationTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { public void Method() @@ -344,73 +298,13 @@ public void Method() var x = $$ } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task InsertSnippetWithInvocationBeforeAndAfterCursorTest() - { - var markupBeforeCommit = """ - class Program - { - public void Method() - { - Wr$$Blah - } - } - """; - - var expectedCodeAfterCommit = $$""" - class Program - { - public void Method() - { - {{ItemToCommit}} (true) - { - $$ - } - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] - public async Task InsertSnippetWithInvocationUnderscoreBeforeAndAfterCursorTest() - { - var markupBeforeCommit = """ - class Program - { - public void Method() - { - _Wr$$Blah_ - } - } - """; - - var expectedCodeAfterCommit = $$""" - class Program - { - public void Method() - { - {{ItemToCommit}} (true) - { - $$ - } - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] + [Fact] public async Task InsertInlineSnippetForCorrectTypeTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class Program { void M(bool arg) @@ -418,28 +312,24 @@ void M(bool arg) arg.$$ } } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" class Program { void M(bool arg) { - {{ItemToCommit}} (arg) + {{SnippetIdentifier}} (arg) { $$ } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task NoInlineSnippetForIncorrectTypeTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { void M(int arg) @@ -447,15 +337,13 @@ void M(int arg) arg.$$ } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task NoInlineSnippetWhenNotDirectlyExpressionStatementTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { void M(bool arg) @@ -463,18 +351,16 @@ void M(bool arg) System.Console.WriteLine(arg.$$); } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfTheory] + [Theory] [InlineData("// comment")] [InlineData("/* comment */")] [InlineData("#region test")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest1(string trivia) { - var markupBeforeCommit = $$""" + await VerifySnippetAsync($$""" class Program { void M(bool arg) @@ -483,32 +369,28 @@ void M(bool arg) arg.$$ } } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" class Program { void M(bool arg) { {{trivia}} - {{ItemToCommit}} (arg) + {{SnippetIdentifier}} (arg) { $$ } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] + [Theory] [InlineData("#if true")] [InlineData("#pragma warning disable CS0108")] [InlineData("#nullable enable")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest2(string trivia) { - var markupBeforeCommit = $$""" + await VerifySnippetAsync($$""" class Program { void M(bool arg) @@ -517,76 +399,62 @@ void M(bool arg) arg.$$ } } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" class Program { void M(bool arg) { {{trivia}} - {{ItemToCommit}} (arg) + {{SnippetIdentifier}} (arg) { $$ } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] + [Theory] [InlineData("// comment")] [InlineData("/* comment */")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest1(string trivia) { - var markupBeforeCommit = $$""" - {{trivia}} + await VerifySnippetAsync($""" + {trivia} true.$$ - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" {{trivia}} - {{ItemToCommit}} (true) + {{SnippetIdentifier}} (true) { $$ } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] + [Theory] [InlineData("#region test")] [InlineData("#if true")] [InlineData("#pragma warning disable CS0108")] [InlineData("#nullable enable")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest2(string trivia) { - var markupBeforeCommit = $$""" - {{trivia}} + await VerifySnippetAsync($""" + {trivia} true.$$ - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" {{trivia}} - {{ItemToCommit}} (true) + {{SnippetIdentifier}} (true) { $$ } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] public async Task InsertInlineSnippetWhenDottingBeforeContextualKeywordTest1() { - var markupBeforeCommit = """ - using System.Collections.Generic; - + await VerifySnippetAsync(""" class C { void M(bool flag) @@ -595,70 +463,56 @@ void M(bool flag) var a = 0; } } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; - + """, $$""" class C { void M(bool flag) { - {{ItemToCommit}} (flag) + {{SnippetIdentifier}} (flag) { $$ } var a = 0; } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] public async Task InsertInlineSnippetWhenDottingBeforeContextualKeywordTest2() { - var markupBeforeCommit = """ - using System.Collections.Generic; - + await VerifySnippetAsync(""" class C { - void M(bool flag, Task t) + async void M(bool flag, Task t) { flag.$$ await t; } } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; - + """, $$""" class C { - void M(bool flag, Task t) + async void M(bool flag, Task t) { - {{ItemToCommit}} (flag) + {{SnippetIdentifier}} (flag) { $$ } await t; } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] [InlineData("Task")] [InlineData("Task")] [InlineData("System.Threading.Tasks.Task")] public async Task InsertInlineSnippetWhenDottingBeforeNameSyntaxTest(string nameSyntax) { - var markupBeforeCommit = $$""" - using System.Collections.Generic; + await VerifySnippetAsync($$""" + using System.Threading.Tasks; class C { @@ -668,24 +522,124 @@ void M(bool flag) {{nameSyntax}} t = null; } } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; + """, $$""" + using System.Threading.Tasks; class C { void M(bool flag) { - {{ItemToCommit}} (flag) + {{SnippetIdentifier}} (flag) { $$ } {{nameSyntax}} t = null; } } - """; + """); + } + + [Fact] + public async Task InsertInlineSnippetWhenDottingBeforeMemberAccessExpressionOnTheNextLineTest() + { + await VerifySnippetAsync(""" + using System; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + class C + { + void M(bool flag) + { + flag.$$ + Console.WriteLine(); + } + } + """, $$""" + using System; + + class C + { + void M(bool flag) + { + {{SnippetIdentifier}} (flag) + { + $$ + } + Console.WriteLine(); + } + } + """); + } + + [Fact] + public async Task NoInlineSnippetWhenDottingBeforeMemberAccessExpressionOnTheSameLineTest() + { + await VerifySnippetIsAbsentAsync(""" + class C + { + void M(bool flag) + { + flag.$$ToString(); + } + } + """); + } + + [Fact] + public async Task NoInlineSnippetWhenDottingBeforeContextualKeywordOnTheSameLineTest() + { + await VerifySnippetIsAbsentAsync(""" + class C + { + void M(bool flag) + { + flag.$$var a = 0; + } + } + """); + } + + [Fact] + public async Task NoInlineSnippetForTypeItselfTest() + { + await VerifySnippetIsAbsentAsync(""" + class C + { + void M() + { + bool.$$ + } + } + """); + } + + [Fact] + public async Task NoInlineSnippetForTypeItselfTest_Parenthesized() + { + await VerifySnippetIsAbsentAsync(""" + class C + { + void M() + { + (bool).$$ + } + } + """); + } + + [Fact] + public async Task NoInlineSnippetForTypeItselfTest_BeforeContextualKeyword() + { + await VerifySnippetIsAbsentAsync(""" + using System.Threading.Tasks; + + class C + { + async void M() + { + bool.$$ + await Task.Delay(10); + } + } + """); } } diff --git a/src/Features/CSharpTest/Snippets/AbstractCSharpSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/AbstractCSharpSnippetProviderTests.cs new file mode 100644 index 0000000000000..ac9ebbccf4424 --- /dev/null +++ b/src/Features/CSharpTest/Snippets/AbstractCSharpSnippetProviderTests.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Test.Utilities.Snippets; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; + +public abstract class AbstractCSharpSnippetProviderTests : AbstractSnippetProviderTests +{ + protected sealed override string LanguageName => LanguageNames.CSharp; +} diff --git a/src/Features/CSharpTest/Snippets/CSharpClassSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpClassSnippetProviderTests.cs new file mode 100644 index 0000000000000..605189a8b6fea --- /dev/null +++ b/src/Features/CSharpTest/Snippets/CSharpClassSnippetProviderTests.cs @@ -0,0 +1,419 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; + +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpClassSnippetProviderTests : AbstractCSharpSnippetProviderTests +{ + protected override string SnippetIdentifier => "class"; + + [Fact] + public async Task InsertClassSnippetInBlockNamespaceTest() + { + await VerifySnippetAsync(""" + namespace Namespace + { + $$ + } + """, """ + namespace Namespace + { + class {|0:MyClass|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertClassSnippetInFileScopedNamespaceTest() + { + await VerifySnippetAsync(""" + namespace Namespace; + + $$ + """, """ + namespace Namespace; + + class {|0:MyClass|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertClassSnippetTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + class {|0:MyClass|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertClassTopLevelSnippetTest() + { + await VerifySnippetAsync(""" + System.Console.WriteLine(); + $$ + """, """ + System.Console.WriteLine(); + class {|0:MyClass|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertClassSnippetInClassTest() + { + await VerifySnippetAsync(""" + class MyClass + { + $$ + } + """, """ + class MyClass + { + class {|0:MyClass1|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertClassSnippetInRecordTest() + { + await VerifySnippetAsync(""" + record MyRecord + { + $$ + } + """, """ + record MyRecord + { + class {|0:MyClass|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertClassSnippetInStructTest() + { + await VerifySnippetAsync(""" + struct MyStruct + { + $$ + } + """, """ + struct MyStruct + { + class {|0:MyClass|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertClassSnippetInInterfaceTest() + { + await VerifySnippetAsync(""" + interface MyInterface + { + $$ + } + """, """ + interface MyInterface + { + class {|0:MyClass|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertClassSnippetWithModifiersTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + public class {|0:MyClass|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Fact] + public async Task NoClassSnippetInEnumTest() + { + await VerifySnippetIsAbsentAsync(""" + enum MyEnum + { + $$ + } + """); + } + + [Fact] + public async Task NoClassSnippetInMethodTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public void Method() + { + $$ + } + } + """); + } + + [Fact] + public async Task NoClassSnippetInConstructorTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public Program() + { + $$ + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertClassSnippetAfterAccessibilityModifier(string modifier) + { + await VerifySnippetAsync($""" + {modifier} $$ + """, $$""" + {{modifier}} class {|0:MyClass|} + { + $$ + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertClassSnippetAfterAccessibilityModifier_RequireAccessibilityModifiers(string modifier) + { + await VerifySnippetAsync($""" + {modifier} $$ + """, $$""" + {{modifier}} class {|0:MyClass|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Theory] + [InlineData("abstract")] + [InlineData("sealed")] + [InlineData("static")] + [InlineData("unsafe")] + public async Task InsertClassSnippetAfterValidModifiersTest(string modifier) + { + await VerifySnippetAsync($""" + {modifier} $$ + """, $$""" + {{modifier}} class {|0:MyClass|} + { + $$ + } + """); + } + + [Theory] + [InlineData("ref")] + [InlineData("readonly")] + public async Task NoClassSnippetAfterInvalidModifiersTest(string modifier) + { + await VerifySnippetIsAbsentAsync($""" + {modifier} $$ + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task NoAdditionalAccessibilityModifiersIfAfterPartialKeywordTest(string modifier) + { + await VerifySnippetAsync($""" + {modifier} partial $$ + """, $$""" + {{modifier}} partial class {|0:MyClass|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] + public async Task EnsureCorrectModifierOrderAfterPartialKeywordTest() + { + await VerifySnippetAsync(""" + partial $$ + """, """ + public partial class {|0:MyClass|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] + public async Task EnsureCorrectModifierOrderAfterPartialKeywordTest_InvalidPreferredModifiersList() + { + await VerifySnippetAsync(""" + partial $$ + """, """ + public partial class {|0:MyClass|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + + csharp_preferred_modifier_order = invalid! + """); + } + + [Fact] + public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBeforeAllOthers() + { + await VerifySnippetAsync(""" + sealed unsafe $$ + """, """ + public sealed unsafe class {|0:MyClass|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + + csharp_preferred_modifier_order = public,sealed,unsafe + """); + } + + [Fact] + public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBeforeAllOthers_NotAllModifiersInTheList() + { + await VerifySnippetAsync(""" + sealed unsafe $$ + """, """ + public sealed unsafe class {|0:MyClass|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + + csharp_preferred_modifier_order = public,sealed + """); + } + + [Fact] + public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBetweenOthers() + { + await VerifySnippetAsync(""" + sealed unsafe $$ + """, """ + sealed public unsafe class {|0:MyClass|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + + csharp_preferred_modifier_order = sealed,public,unsafe + """); + } + + [Fact] + public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierAfterAllOthers() + { + await VerifySnippetAsync(""" + sealed unsafe $$ + """, """ + sealed unsafe public class {|0:MyClass|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + + csharp_preferred_modifier_order = sealed,unsafe,public + """); + } +} diff --git a/src/Features/CSharpTest/Snippets/CSharpConsoleSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpConsoleSnippetProviderTests.cs new file mode 100644 index 0000000000000..a62d6aa39cfef --- /dev/null +++ b/src/Features/CSharpTest/Snippets/CSharpConsoleSnippetProviderTests.cs @@ -0,0 +1,414 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; + +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpConsoleSnippetProviderTests : AbstractCSharpSnippetProviderTests +{ + protected override string SnippetIdentifier => "cw"; + + [Fact] + public async Task InsertConsoleSnippetInMethodTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + $$ + } + } + """, """ + using System; + + class Program + { + public void Method() + { + Console.WriteLine($$); + } + } + """); + } + + [Fact] + public async Task InsertNormalConsoleSnippetInAsyncContextTest() + { + await VerifySnippetAsync(""" + using System.Threading.Tasks; + + class Program + { + public async Task MethodAsync() + { + $$ + } + } + """, """ + using System; + using System.Threading.Tasks; + + class Program + { + public async Task MethodAsync() + { + Console.WriteLine($$); + } + } + """); + } + + [Fact] + public async Task InsertConsoleSnippetInGlobalContextTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + using System; + + Console.WriteLine($$); + """); + } + + [Fact] + public async Task NoConsoleSnippetInBlockNamespaceTest() + { + await VerifySnippetIsAbsentAsync(""" + namespace Namespace + { + $$ + } + """); + } + + [Fact] + public async Task NoConsoleSnippetInFileScopedNamespaceTest() + { + await VerifySnippetIsAbsentAsync(""" + namespace Namespace; + + $$ + """); + } + + [Fact] + public async Task InsertConsoleSnippetInConstructorTest() + { + await VerifySnippetAsync(""" + class Program + { + public Program() + { + var x = 5; + $$ + } + } + """, """ + using System; + + class Program + { + public Program() + { + var x = 5; + Console.WriteLine($$); + } + } + """); + } + + [Fact] + public async Task InsertConsoleSnippetInLocalFunctionTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + var x = 5; + void LocalMethod() + { + $$ + } + } + } + """, """ + using System; + + class Program + { + public void Method() + { + var x = 5; + void LocalMethod() + { + Console.WriteLine($$); + } + } + } + """); + } + + [Fact] + public async Task InsertConsoleSnippetInAnonymousFunctionTest() + { + await VerifySnippetAsync(""" + public delegate void Print(int value); + + static void Main(string[] args) + { + Print print = delegate(int val) + { + $$ + }; + + } + """, """ + using System; + + public delegate void Print(int value); + + static void Main(string[] args) + { + Print print = delegate(int val) + { + Console.WriteLine($$); + }; + + } + """); + } + + [Fact] + public async Task InsertConsoleSnippetInParenthesizedLambdaExpressionTest() + { + await VerifySnippetAsync(""" + using System; + + Func testForEquality = (x, y) => + { + $$ + return x == y; + }; + """, """ + using System; + + Func testForEquality = (x, y) => + { + Console.WriteLine($$); + return x == y; + }; + """); + } + + [Fact] + public async Task NoConsoleSnippetInSwitchExpressionTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public void Method() + { + var operation = 2; + + var result = operation switch + { + $$ + 1 => "Case 1", + 2 => "Case 2", + 3 => "Case 3", + 4 => "Case 4", + }; + } + } + """); + } + + [Fact] + public async Task NoConsoleSnippetInStringTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public void Method() + { + var str = "$$"; + } + } + """); + } + + [Fact] + public async Task NoConsoleSnippetInConstructorArgumentsTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public void Method() + { + var test = new Test($$); + } + } + + class Test + { + public Test(string val) + { + } + } + """); + } + + [Fact] + public async Task NoConsoleSnippetInParameterListTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public void Method(int x, $$) + { + } + } + """); + } + + [Fact] + public async Task NoConsoleSnippetInRecordDeclarationTest() + { + await VerifySnippetIsAbsentAsync(""" + public record Person + { + $$ + public string FirstName { get; init; } + public string LastName { get; init; } + }; + """); + } + + [Fact] + public async Task NoConsoleSnippetInVariableDeclarationTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public void Method() + { + var x = $$ + } + } + """); + } + + /// + /// We want to fix this case and insert the fully qualified namespace + /// in a future fix. + /// + [Fact] + public async Task InsertConsoleSnippetWithPropertyNamedConsoleTest() + { + await VerifySnippetAsync(""" + class Program + { + public int Console { get; set; } + + public void Method() + { + $$ + } + } + """, """ + using System; + + class Program + { + public int Console { get; set; } + + public void Method() + { + Console.WriteLine($$); + } + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72266")] + public async Task InsertConsoleSnippetInVoidReturningLambdaTest1() + { + await VerifySnippetAsync(""" + using System; + + M(() => $$); + + void M(Action a) + { + } + """, """ + using System; + + M(() => Console.WriteLine($$)); + + void M(Action a) + { + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72266")] + public async Task InsertConsoleSnippetInVoidReturningLambdaTest2() + { + await VerifySnippetAsync(""" + using System; + + Action action = () => $$ + """, """ + using System; + + Action action = () => Console.WriteLine($$) + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72266")] + public async Task InsertConsoleSnippetInVoidReturningLambdaTest_TypeInference() + { + await VerifySnippetAsync(""" + using System; + + var action = () => $$ + """, """ + using System; + + var action = () => Console.WriteLine($$) + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72266")] + public async Task NoConsoleSnippetInNonVoidReturningLambdaTest1() + { + await VerifySnippetIsAbsentAsync(""" + using System; + + M(() => $$); + + void M(Func f) + { + } + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72266")] + public async Task NoConsoleSnippetInNonVoidReturningLambdaTest2() + { + await VerifySnippetIsAbsentAsync(""" + using System; + + Func f = () => $$ + """); + } +} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpConstructorSnippetCompletionProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpConstructorSnippetProviderTests.cs similarity index 57% rename from src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpConstructorSnippetCompletionProviderTests.cs rename to src/Features/CSharpTest/Snippets/CSharpConstructorSnippetProviderTests.cs index ba82dd751d67d..e5cc0a8775b09 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpConstructorSnippetCompletionProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/CSharpConstructorSnippetProviderTests.cs @@ -7,65 +7,52 @@ using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; -[Trait(Traits.Feature, Traits.Features.Completion)] -public class CSharpConstructorSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpConstructorSnippetProviderTests : AbstractCSharpSnippetProviderTests { - protected override string ItemToCommit => "ctor"; + protected override string SnippetIdentifier => "ctor"; - [WpfFact] + [Fact] public async Task ConstructorSnippetMissingInNamespace() { - var markupBeforeCommit = - """ + await VerifySnippetIsAbsentAsync(""" namespace Namespace { $$ } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task ConstructorSnippetMissingInFileScopedNamespace() { - var markupBeforeCommit = - """ + await VerifySnippetIsAbsentAsync(""" namespace Namespace; $$ - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task ConstructorSnippetMissingInTopLevelContext() { - var markupBeforeCommit = - """ + await VerifySnippetIsAbsentAsync(""" System.Console.WriteLine(); $$ - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task InsertConstructorSnippetInClassTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class MyClass { $$ } - """; - - var expectedCodeAfterCommit = - """ + """, """ class MyClass { public MyClass() @@ -73,23 +60,18 @@ public MyClass() $$ } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertConstructorSnippetInAbstractClassTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" abstract class MyClass { $$ } - """; - - var expectedCodeAfterCommit = - """ + """, """ abstract class MyClass { protected MyClass() @@ -97,15 +79,13 @@ protected MyClass() $$ } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertConstructorSnippetInAbstractClassTest_AbstractModifierInOtherPartialDeclaration() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" partial class MyClass { $$ @@ -114,10 +94,7 @@ partial class MyClass abstract partial class MyClass { } - """; - - var expectedCodeAfterCommit = - """ + """, """ partial class MyClass { protected MyClass() @@ -129,15 +106,13 @@ protected MyClass() abstract partial class MyClass { } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertConstructorSnippetInNestedAbstractClassTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class MyClass { abstract class NestedClass @@ -145,10 +120,7 @@ abstract class NestedClass $$ } } - """; - - var expectedCodeAfterCommit = - """ + """, """ class MyClass { abstract class NestedClass @@ -159,23 +131,18 @@ protected NestedClass() } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertConstructorSnippetInStructTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" struct MyStruct { $$ } - """; - - var expectedCodeAfterCommit = - """ + """, """ struct MyStruct { public MyStruct() @@ -183,23 +150,18 @@ public MyStruct() $$ } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertConstructorSnippetInRecordTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" record MyRecord { $$ } - """; - - var expectedCodeAfterCommit = - """ + """, """ record MyRecord { public MyRecord() @@ -207,29 +169,24 @@ public MyRecord() $$ } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task ConstructorSnippetMissingInInterface() { - var markupBeforeCommit = - """ + await VerifySnippetIsAbsentAsync(""" interface MyInterface { $$ } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task InsertConstructorSnippetInNestedClassTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class MyClass { class MyClass1 @@ -237,10 +194,7 @@ class MyClass1 $$ } } - """; - - var expectedCodeAfterCommit = - """ + """, """ class MyClass { class MyClass1 @@ -251,28 +205,20 @@ public MyClass1() } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("internal")] - [InlineData("private protected")] - [InlineData("protected internal")] + [Theory] [InlineData("static")] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] public async Task InsertConstructorSnippetAfterValidModifiersTest(string modifiers) { - var markupBeforeCommit = $$""" + await VerifySnippetAsync($$""" class MyClass { {{modifiers}} $$ } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" class MyClass { {{modifiers}} MyClass() @@ -280,12 +226,10 @@ class MyClass $$ } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] + [Theory] [InlineData("abstract")] [InlineData("sealed")] [InlineData("virtual")] @@ -295,47 +239,36 @@ class MyClass [InlineData("file")] public async Task ConstructorSnippetMissingAfterInvalidModifierTest(string modifier) { - var markupBeforeCommit = $$""" + await VerifySnippetIsAbsentAsync($$""" class MyClass { {{modifier}} $$ } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfTheory] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("internal")] - [InlineData("private protected")] - [InlineData("protected internal")] + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] public async Task ConstructorSnippetMissingAfterBothAccessibilityModifierAndStaticKeywordTest(string accessibilityModifier) { - var markupBeforeCommit = $$""" + await VerifySnippetIsAbsentAsync($$""" class MyClass { {{accessibilityModifier}} static $$ } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task InsertConstructorSnippetAfterAccessibilityModifierBeforeOtherMemberTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class C { private $$ readonly int Value = 3; } - """; - - var expectedCodeAfterCommit = """ + """, """ class C { private C() @@ -344,23 +277,19 @@ private C() } readonly int Value = 3; } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertConstructorSnippetBetweenAccessibilityModifiersBeforeOtherMemberTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class C { protected $$ internal int Value = 3; } - """; - - var expectedCodeAfterCommit = """ + """, """ class C { protected C() @@ -369,23 +298,19 @@ protected C() } internal int Value = 3; } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertConstructorSnippetAfterAccessibilityModifierBeforeOtherStaticMemberTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class C { internal $$ static int Value = 3; } - """; - - var expectedCodeAfterCommit = """ + """, """ class C { internal C() @@ -394,15 +319,13 @@ internal C() } static int Value = 3; } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/68176")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/68176")] public async Task InsertCorrectConstructorSnippetInNestedTypeTest_CtorBeforeNestedType() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class Outer { $$ @@ -410,9 +333,7 @@ class Inner { } } - """; - - var expectedCodeAfterCommit = """ + """, """ class Outer { public Outer() @@ -423,15 +344,13 @@ class Inner { } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/68176")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/68176")] public async Task InsertCorrectConstructorSnippetInNestedTypeTest_CtorAfterNestedType() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class Outer { class Inner @@ -439,9 +358,7 @@ class Inner } $$ } - """; - - var expectedCodeAfterCommit = """ + """, """ class Outer { class Inner @@ -452,8 +369,6 @@ public Outer() $$ } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpDoSnippetCompletionProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpDoSnippetProviderTests.cs similarity index 51% rename from src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpDoSnippetCompletionProviderTests.cs rename to src/Features/CSharpTest/Snippets/CSharpDoSnippetProviderTests.cs index e1ae704c239b1..2a183f2d66730 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpDoSnippetCompletionProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/CSharpDoSnippetProviderTests.cs @@ -7,17 +7,17 @@ using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; -[Trait(Traits.Feature, Traits.Features.Completion)] -public class CSharpDoSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpDoSnippetProviderTests : AbstractCSharpSnippetProviderTests { - protected override string ItemToCommit => "do"; + protected override string SnippetIdentifier => "do"; - [WpfFact] - public async Task InsertSnippetInMethodTest() + [Fact] + public async Task InsertDoSnippetInMethodTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class Program { public void Method() @@ -25,9 +25,7 @@ public void Method() $$ } } - """; - - var expectedCodeAfterCommit = """ + """, """ class Program { public void Method() @@ -36,72 +34,51 @@ public void Method() { $$ } - while (true); + while ({|0:true|}); } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] - public async Task InsertSnippetInGlobalContextTest() + [Fact] + public async Task InsertDoSnippetInGlobalContextTest() { - var markupBeforeCommit = """ - Ins$$ - """; - - var expectedCodeAfterCommit = """ + await VerifySnippetAsync(""" + $$ + """, """ do { $$ } - while (true); - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + while ({|0:true|}); + """); } - [WpfFact] - public async Task NoSnippetInBlockNamespaceTest() + [Fact] + public async Task NoDoSnippetInBlockNamespaceTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" namespace Namespace { $$ - class Program - { - public async Task MethodAsync() - { - } - } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] - public async Task NoSnippetInFileScopedNamespaceTest() + [Fact] + public async Task NoDoSnippetInFileScopedNamespaceTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" namespace Namespace; - $$ - class Program - { - public async Task MethodAsync() - { - } - } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + $$ + """); } - [WpfFact] - public async Task InsertSnippetInConstructorTest() + [Fact] + public async Task InsertDoSnippetInConstructorTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class Program { public Program() @@ -110,9 +87,7 @@ public Program() $$ } } - """; - - var expectedCodeAfterCommit = """ + """, """ class Program { public Program() @@ -122,18 +97,16 @@ public Program() { $$ } - while (true); + while ({|0:true|}); } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] - public async Task InsertSnippetInLocalFunctionTest() + [Fact] + public async Task InsertDoSnippetInLocalFunctionTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class Program { public void Method() @@ -145,9 +118,7 @@ void LocalMethod() } } } - """; - - var expectedCodeAfterCommit = """ + """, """ class Program { public void Method() @@ -159,79 +130,75 @@ void LocalMethod() { $$ } - while (true); + while ({|0:true|}); } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] - public async Task InsertSnippetInAnonymousFunctionTest() + [Fact] + public async Task InsertDoSnippetInAnonymousFunctionTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" public delegate void Print(int value); static void Main(string[] args) { - Print print = delegate(int val) { + Print print = delegate(int val) + { $$ }; } - """; - - var expectedCodeAfterCommit = """ + """, """ public delegate void Print(int value); static void Main(string[] args) { - Print print = delegate(int val) { + Print print = delegate(int val) + { do { $$ } - while (true); + while ({|0:true|}); }; } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] - public async Task InsertSnippetInParenthesizedLambdaExpressionTest() + [Fact] + public async Task InsertDoSnippetInParenthesizedLambdaExpressionTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" + using System; + Func testForEquality = (x, y) => { $$ return x == y; }; - """; + """, """ + using System; - var expectedCodeAfterCommit = """ Func testForEquality = (x, y) => { do { $$ } - while (true); + while ({|0:true|}); return x == y; }; - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] - public async Task NoSnippetInSwitchExpression() + [Fact] + public async Task NoDoSnippetInSwitchExpression() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { public void Method() @@ -248,15 +215,15 @@ public void Method() }; } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] - public async Task NoSnippetInSingleLambdaExpression() + [Fact] + public async Task NoDoSnippetInSingleLambdaExpression() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" + using System; + class Program { public void Method() @@ -264,15 +231,13 @@ public void Method() Func f = x => $$; } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] - public async Task NoSnippetInStringTest() + [Fact] + public async Task NoDoSnippetInStringTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { public void Method() @@ -280,71 +245,60 @@ public void Method() var str = "$$"; } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] - public async Task NoSnippetInObjectInitializerTest() + [Fact] + public async Task NoDoSnippetInConstructorArgumentsTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { public void Method() { - var str = new Test($$); + var test = new Test($$); } } class Test { - private string val; - public Test(string val) { - this.val = val; } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] - public async Task NoSnippetInParameterListTest() + [Fact] + public async Task NoDoSnippetInParameterListTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { public void Method(int x, $$) { } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] - public async Task NoSnippetInRecordDeclarationTest() + [Fact] + public async Task NoDoSnippetInRecordDeclarationTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" public record Person { $$ - public string FirstName { get; init; } = default!; - public string LastName { get; init; } = default!; + public string FirstName { get; init; } + public string LastName { get; init; } }; - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] - public async Task NoSnippetInVariableDeclarationTest() + [Fact] + public async Task NoDoSnippetInVariableDeclarationTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { public void Method() @@ -352,75 +306,13 @@ public void Method() var x = $$ } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); - } - - [WpfFact] - public async Task InsertSnippetWithInvocationBeforeAndAfterCursorTest() - { - var markupBeforeCommit = """ - class Program - { - public void Method() - { - Wr$$Blah - } - } - """; - - var expectedCodeAfterCommit = """ - class Program - { - public void Method() - { - do - { - $$ - } - while (true); - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); - } - - [WpfFact] - public async Task InsertSnippetWithInvocationUnderscoreBeforeAndAfterCursorTest() - { - var markupBeforeCommit = """ - class Program - { - public void Method() - { - _Wr$$Blah_ - } - } - """; - - var expectedCodeAfterCommit = """ - class Program - { - public void Method() - { - do - { - $$ - } - while (true); - } - } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] - public async Task InsertInlineSnippetForCorrectTypeTest() + [Fact] + public async Task InsertInlineDoSnippetForCorrectTypeTest() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" class Program { void M(bool arg) @@ -428,9 +320,7 @@ void M(bool arg) arg.$$ } } - """; - - var expectedCodeAfterCommit = """ + """, """ class Program { void M(bool arg) @@ -442,15 +332,13 @@ void M(bool arg) while (arg); } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] - public async Task NoInlineSnippetForIncorrectTypeTest() + [Fact] + public async Task NoInlineDoSnippetForIncorrectTypeTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { void M(int arg) @@ -458,15 +346,13 @@ void M(int arg) arg.$$ } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] - public async Task NoInlineSnippetWhenNotDirectlyExpressionStatementTest() + [Fact] + public async Task NoInlineDoSnippetWhenNotDirectlyExpressionStatementTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { void M(bool arg) @@ -474,18 +360,16 @@ void M(bool arg) System.Console.WriteLine(arg.$$); } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfTheory] + [Theory] [InlineData("// comment")] [InlineData("/* comment */")] [InlineData("#region test")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest1(string trivia) { - var markupBeforeCommit = $$""" + await VerifySnippetAsync($$""" class Program { void M(bool arg) @@ -494,9 +378,7 @@ void M(bool arg) arg.$$ } } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" class Program { void M(bool arg) @@ -509,18 +391,16 @@ void M(bool arg) while (arg); } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] + [Theory] [InlineData("#if true")] [InlineData("#pragma warning disable CS0108")] [InlineData("#nullable enable")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest2(string trivia) { - var markupBeforeCommit = $$""" + await VerifySnippetAsync($$""" class Program { void M(bool arg) @@ -529,9 +409,7 @@ void M(bool arg) arg.$$ } } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" class Program { void M(bool arg) @@ -544,46 +422,38 @@ void M(bool arg) while (arg); } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] + [Theory] [InlineData("// comment")] [InlineData("/* comment */")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest1(string trivia) { - var markupBeforeCommit = $$""" - {{trivia}} + await VerifySnippetAsync($""" + {trivia} true.$$ - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" {{trivia}} do { $$ } while (true); - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] + [Theory] [InlineData("#region test")] [InlineData("#if true")] [InlineData("#pragma warning disable CS0108")] [InlineData("#nullable enable")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest2(string trivia) { - var markupBeforeCommit = $$""" - {{trivia}} + await VerifySnippetAsync($""" + {trivia} true.$$ - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" {{trivia}} do @@ -591,17 +461,13 @@ public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatement $$ } while (true); - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] public async Task InsertInlineSnippetWhenDottingBeforeContextualKeywordTest1() { - var markupBeforeCommit = """ - using System.Collections.Generic; - + await VerifySnippetAsync(""" class C { void M(bool flag) @@ -610,11 +476,7 @@ void M(bool flag) var a = 0; } } - """; - - var expectedCodeAfterCommit = """ - using System.Collections.Generic; - + """, """ class C { void M(bool flag) @@ -627,33 +489,25 @@ void M(bool flag) var a = 0; } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] public async Task InsertInlineSnippetWhenDottingBeforeContextualKeywordTest2() { - var markupBeforeCommit = """ - using System.Collections.Generic; - + await VerifySnippetAsync(""" class C { - void M(bool flag, Task t) + async void M(bool flag, Task t) { flag.$$ await t; } } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; - + """, """ class C { - void M(bool flag, Task t) + async void M(bool flag, Task t) { do { @@ -663,19 +517,17 @@ void M(bool flag, Task t) await t; } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] [InlineData("Task")] [InlineData("Task")] [InlineData("System.Threading.Tasks.Task")] public async Task InsertInlineSnippetWhenDottingBeforeNameSyntaxTest(string nameSyntax) { - var markupBeforeCommit = $$""" - using System.Collections.Generic; + await VerifySnippetAsync($$""" + using System.Threading.Tasks; class C { @@ -685,10 +537,8 @@ void M(bool flag) {{nameSyntax}} t = null; } } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; + """, $$""" + using System.Threading.Tasks; class C { @@ -702,8 +552,111 @@ void M(bool flag) {{nameSyntax}} t = null; } } - """; + """); + } + + [Fact] + public async Task InsertInlineDoSnippetWhenDottingBeforeMemberAccessExpressionOnTheNextLineTest() + { + await VerifySnippetAsync(""" + using System; + + class C + { + void M(bool flag) + { + flag.$$ + Console.WriteLine(); + } + } + """, """ + using System; + + class C + { + void M(bool flag) + { + do + { + $$ + } + while (flag); + Console.WriteLine(); + } + } + """); + } - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + [Fact] + public async Task NoInlineDoSnippetWhenDottingBeforeMemberAccessExpressionOnTheSameLineTest() + { + await VerifySnippetIsAbsentAsync(""" + class C + { + void M(bool flag) + { + flag.$$ToString(); + } + } + """); + } + + [Fact] + public async Task NoInlineDoSnippetWhenDottingBeforeContextualKeywordOnTheSameLineTest() + { + await VerifySnippetIsAbsentAsync(""" + class C + { + void M(bool flag) + { + flag.$$var a = 0; + } + } + """); + } + + [Fact] + public async Task NoInlineDoSnippetForTypeItselfTest() + { + await VerifySnippetIsAbsentAsync(""" + class C + { + void M() + { + bool.$$ + } + } + """); + } + + [Fact] + public async Task NoInlineDoSnippetForTypeItselfTest_Parenthesized() + { + await VerifySnippetIsAbsentAsync(""" + class C + { + void M() + { + (bool).$$ + } + } + """); + } + + [Fact] + public async Task NoInlineDoSnippetForTypeItselfTest_BeforeContextualKeyword() + { + await VerifySnippetIsAbsentAsync(""" + using System.Threading.Tasks; + + class C + { + async void M() + { + bool.$$ + await Task.Delay(10); + } + } + """); } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpElseSnippetCompletionProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpElseSnippetProviderTests.cs similarity index 61% rename from src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpElseSnippetCompletionProviderTests.cs rename to src/Features/CSharpTest/Snippets/CSharpElseSnippetProviderTests.cs index 9092a961c772e..6dbd4f8352b6d 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpElseSnippetCompletionProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/CSharpElseSnippetProviderTests.cs @@ -4,21 +4,19 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; -[Trait(Traits.Feature, Traits.Features.Completion)] -public class CSharpElseSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpElseSnippetProviderTests : AbstractCSharpSnippetProviderTests { - protected override string ItemToCommit => "else"; + protected override string SnippetIdentifier => "else"; - [WpfFact] + [Fact] public async Task InsertElseSnippetInMethodTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class Program { public void Method() @@ -29,10 +27,7 @@ public void Method() $$ } } - """; - - var expectedCodeAfterCommit = - """ + """, """ class Program { public void Method() @@ -46,15 +41,13 @@ public void Method() } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task NoElseSnippetInMethodWithoutIfStatementTest() { - var markupBeforeCommit = - """ + await VerifySnippetIsAbsentAsync(""" class Program { public void Method() @@ -62,29 +55,18 @@ public void Method() $$ } } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task InsertElseSnippetGlobalTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" if (true) { } $$ - class Program - { - public async Task MethodAsync() - { - } - } - """; - - var expectedCodeAfterCommit = - """ + """, """ if (true) { } @@ -92,63 +74,39 @@ public async Task MethodAsync() { $$ } - class Program - { - public async Task MethodAsync() - { - } - } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task NoElseSnippetInBlockNamespaceTest() { - var markupBeforeCommit = - """ + await VerifySnippetIsAbsentAsync(""" namespace Namespace { if (true) { } $$ - class Program - { - public async Task MethodAsync() - { - } - } } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task NoElseSnippetInFileScopedNamespaceTest() { - var markupBeforeCommit = - """ + await VerifySnippetIsAbsentAsync(""" namespace Namespace; if (true) { } $$ - class Program - { - public async Task MethodAsync() - { - } - } - """; - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task InsertElseSnippetInConstructorTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class Program { public Program() @@ -159,10 +117,7 @@ public Program() $$ } } - """; - - var expectedCodeAfterCommit = - """ + """, """ class Program { public Program() @@ -176,15 +131,13 @@ public Program() } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertElseSnippetInLocalFunctionTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class Program { public void Method() @@ -200,10 +153,7 @@ void LocalMethod() } } } - """; - - var expectedCodeAfterCommit = - """ + """, """ class Program { public void Method() @@ -222,15 +172,13 @@ void LocalMethod() } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertElseSnippetSingleLineIfWithBlockTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class Program { public void Method() @@ -239,10 +187,7 @@ public void Method() $$ } } - """; - - var expectedCodeAfterCommit = - """ + """, """ class Program { public void Method() @@ -254,16 +199,15 @@ public void Method() } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertElseSnippetSingleLineIfTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" using System; + class Program { public void Method() @@ -272,11 +216,9 @@ public void Method() $$ } } - """; - - var expectedCodeAfterCommit = - """ + """, """ using System; + class Program { public void Method() @@ -288,15 +230,13 @@ public void Method() } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertElseSnippetNestedIfTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class Program { public void Method() @@ -310,10 +250,7 @@ public void Method() $$ } } - """; - - var expectedCodeAfterCommit = - """ + """, """ class Program { public void Method() @@ -330,7 +267,6 @@ public void Method() } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } } diff --git a/src/Features/CSharpTest/Snippets/CSharpEnumSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpEnumSnippetProviderTests.cs new file mode 100644 index 0000000000000..dc880015a72b4 --- /dev/null +++ b/src/Features/CSharpTest/Snippets/CSharpEnumSnippetProviderTests.cs @@ -0,0 +1,262 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; + +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpEnumSnippetProviderTests : AbstractCSharpSnippetProviderTests +{ + protected override string SnippetIdentifier => "enum"; + + [Fact] + public async Task InsertEnumSnippetInBlockNamespaceTest() + { + await VerifySnippetAsync(""" + namespace Namespace + { + $$ + } + """, """ + namespace Namespace + { + enum {|0:MyEnum|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertEnumSnippetInFileScopedNamespaceTest() + { + await VerifySnippetAsync(""" + namespace Namespace; + + $$ + """, """ + namespace Namespace; + + enum {|0:MyEnum|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertEnumSnippetTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + enum {|0:MyEnum|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertEnumTopLevelSnippetTest() + { + await VerifySnippetAsync(""" + System.Console.WriteLine(); + $$ + """, """ + System.Console.WriteLine(); + enum {|0:MyEnum|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertEnumSnippetInClassTest() + { + await VerifySnippetAsync(""" + class MyClass + { + $$ + } + """, """ + class MyClass + { + enum {|0:MyEnum|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertEnumSnippetInRecordTest() + { + await VerifySnippetAsync(""" + record MyRecord + { + $$ + } + """, """ + record MyRecord + { + enum {|0:MyEnum|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertEnumSnippetInStructTest() + { + await VerifySnippetAsync(""" + struct MyStruct + { + $$ + } + """, """ + struct MyStruct + { + enum {|0:MyEnum|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertEnumSnippetInInterfaceTest() + { + await VerifySnippetAsync(""" + interface MyInterface + { + $$ + } + """, """ + interface MyInterface + { + enum {|0:MyEnum|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertEnumSnippetWithModifiersTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + public enum {|0:MyEnum|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Fact] + public async Task NoEnumSnippetInEnumTest() + { + await VerifySnippetIsAbsentAsync(""" + enum MyEnum + { + $$ + } + """); + } + + [Fact] + public async Task NoEnumSnippetInMethodTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public void Method() + { + $$ + } + } + """); + } + + [Fact] + public async Task NoEnumSnippetInConstructorTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public Program() + { + $$ + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertEnumSnippetAfterAccessibilityModifier(string modifier) + { + await VerifySnippetAsync($""" + {modifier} $$ + """, $$""" + {{modifier}} enum {|0:MyEnum|} + { + $$ + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertEnumSnippetAfterAccessibilityModifier_RequireAccessibilityModifiers(string modifier) + { + await VerifySnippetAsync($""" + {modifier} $$ + """, $$""" + {{modifier}} enum {|0:MyEnum|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Theory] + [InlineData("abstract")] + [InlineData("partial")] + [InlineData("sealed")] + [InlineData("static")] + [InlineData("ref")] + [InlineData("readonly")] + [InlineData("unsafe")] + public async Task NoEnumSnippetAfterInvalidModifiersTest(string modifier) + { + await VerifySnippetIsAbsentAsync($""" + {modifier} $$ + """); + } +} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpForEachSnippetCompletionProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpForEachSnippetProviderTests.cs similarity index 50% rename from src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpForEachSnippetCompletionProviderTests.cs rename to src/Features/CSharpTest/Snippets/CSharpForEachSnippetProviderTests.cs index c9cc0eaf2f4c9..2c92199bfcce0 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpForEachSnippetCompletionProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/CSharpForEachSnippetProviderTests.cs @@ -4,101 +4,86 @@ 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.Completion.CompletionProviders.Snippets; +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; -[Trait(Traits.Feature, Traits.Features.Completion)] -public class CSharpForEachSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpForEachSnippetProviderTests : AbstractCSharpSnippetProviderTests { - protected override string ItemToCommit => "foreach"; + protected override string SnippetIdentifier => "foreach"; - [WpfFact] + [Fact] public async Task InsertForEachSnippetInMethodTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class Program { public void Method() { - Ins$$ + $$ } } - """; - - var expectedCodeAfterCommit = - """ + """, """ class Program { public void Method() { - foreach (var item in collection) + foreach (var {|0:item|} in {|1:collection|}) { $$ } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertForEachSnippetInMethodItemUsedTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class Program { public void Method() { var item = 5; - Ins$$ + $$ } } - """; - - var expectedCodeAfterCommit = - """ + """, """ class Program { public void Method() { var item = 5; - foreach (var item1 in collection) + foreach (var {|0:item1|} in {|1:collection|}) { $$ } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertForEachSnippetInGlobalContextTest() { - var markupBeforeCommit = - """ - Ins$$ - """; - - var expectedCodeAfterCommit = - """ - foreach (var item in collection) + await VerifySnippetAsync(""" + $$ + """, """ + foreach (var {|0:item|} in {|1:collection|}) { $$ } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertForEachSnippetInConstructorTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class Program { public Program() @@ -106,30 +91,24 @@ public Program() $$ } } - """; - - var expectedCodeAfterCommit = - """ + """, """ class Program { public Program() { - foreach (var item in collection) + foreach (var {|0:item|} in {|1:collection|}) { $$ } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertForEachSnippetWithCollectionTest() { - var markupBeforeCommit = - """ - using System; + await VerifySnippetAsync(""" using System.Collections.Generic; class Program @@ -140,11 +119,7 @@ public Program() $$ } } - """; - - var expectedCodeAfterCommit = - """ - using System; + """, """ using System.Collections.Generic; class Program @@ -152,21 +127,19 @@ class Program public Program() { var list = new List { 1, 2, 3 }; - foreach (var item in list) + foreach (var {|0:item|} in {|1:list|}) { $$ } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertForEachSnippetInLocalFunctionTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" class Program { public void Method() @@ -178,10 +151,7 @@ void LocalMethod() } } } - """; - - var expectedCodeAfterCommit = - """ + """, """ class Program { public void Method() @@ -189,111 +159,75 @@ public void Method() var x = 5; void LocalMethod() { - foreach (var item in collection) + foreach (var {|0:item|} in {|1:collection|}) { $$ } } } } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task InsertForEachSnippetInAnonymousFunctionTest() { - var markupBeforeCommit = - """ + await VerifySnippetAsync(""" public delegate void Print(int value); + static void Main(string[] args) { - Print print = delegate(int val) { + Print print = delegate(int val) + { $$ }; } - """; - - var expectedCodeAfterCommit = - """ + """, """ public delegate void Print(int value); + static void Main(string[] args) { - Print print = delegate(int val) { - foreach (var item in args) + Print print = delegate(int val) + { + foreach (var {|0:item|} in {|1:args|}) { $$ } }; } - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] - public async Task InsertForEachSnippetInParenthesizedLambdaExpressionRegularTest() + [Fact] + public async Task InsertForEachSnippetInParenthesizedLambdaExpressionTest() { - var markupBeforeCommit = - """ - Func testForEquality = (x, y) => - { - $$ - return x == y; - }; - """; - - var expectedCodeAfterCommit = - """ - Func testForEquality = (x, y) => - { - foreach (var item in args) - { - $$ - } - return x == y; - }; - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit, sourceCodeKind: SourceCodeKind.Regular); - } + await VerifySnippetAsync(""" + using System; - [WpfFact] - public async Task InsertForEachSnippetInParenthesizedLambdaExpressionScriptTest() - { - var markupBeforeCommit = - """ Func testForEquality = (x, y) => { $$ return x == y; }; - """; + """, """ + using System; - var expectedCodeAfterCommit = - """ Func testForEquality = (x, y) => { - foreach (var item in collection) + foreach (var {|0:item|} in {|1:args|}) { $$ } return x == y; }; - """; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit, sourceCodeKind: SourceCodeKind.Script); + """); } - [WpfTheory] - [InlineData("List")] - [InlineData("int[]")] - [InlineData("IEnumerable")] - [InlineData("ArrayList")] - [InlineData("IEnumerable")] + [Theory] + [MemberData(nameof(CommonSnippetTestData.CommonEnumerableTypes), MemberType = typeof(CommonSnippetTestData))] public async Task InsertInlineForEachSnippetForCorrectTypeTest(string collectionType) { - var markupBeforeCommit = $$""" - using System.Collections.Generic; - using System.Collections; - + await VerifySnippetAsync($$""" class C { void M({{collectionType}} enumerable) @@ -301,31 +235,24 @@ void M({{collectionType}} enumerable) enumerable.$$ } } - """; - - var expectedCodeAfterCommit = $$""" - using System.Collections.Generic; - using System.Collections; - + """, $$""" class C { void M({{collectionType}} enumerable) { - foreach (var item in enumerable) + foreach (var {|0:item|} in enumerable) { $$ } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact] + [Fact] public async Task NoInlineForEachSnippetForIncorrectTypeTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" class Program { void M(int arg) @@ -333,15 +260,13 @@ void M(int arg) arg.$$ } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task NoInlineForEachSnippetWhenNotDirectlyExpressionStatementTest() { - var markupBeforeCommit = """ + await VerifySnippetIsAbsentAsync(""" using System; using System.Collections.Generic; @@ -352,18 +277,16 @@ void M(List list) Console.WriteLine(list.$$); } } - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + """); } - [WpfTheory] + [Theory] [InlineData("// comment")] [InlineData("/* comment */")] [InlineData("#region test")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest1(string trivia) { - var markupBeforeCommit = $$""" + await VerifySnippetAsync($$""" class Program { void M(int[] arr) @@ -372,32 +295,28 @@ void M(int[] arr) arr.$$ } } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" class Program { void M(int[] arr) { {{trivia}} - foreach (var item in arr) + foreach (var {|0:item|} in arr) { $$ } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] + [Theory] [InlineData("#if true")] [InlineData("#pragma warning disable CS0108")] [InlineData("#nullable enable")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest2(string trivia) { - var markupBeforeCommit = $$""" + await VerifySnippetAsync($$""" class Program { void M(int[] arr) @@ -406,165 +325,128 @@ void M(int[] arr) arr.$$ } } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" class Program { void M(int[] arr) { {{trivia}} - foreach (var item in arr) + foreach (var {|0:item|} in arr) { $$ } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] + [Theory] [InlineData("// comment")] [InlineData("/* comment */")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest1(string trivia) { - var markupBeforeCommit = $$""" + await VerifySnippetAsync($$""" {{trivia}} (new int[10]).$$ - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" {{trivia}} - foreach (var item in new int[10]) + foreach (var {|0:item|} in new int[10]) { $$ } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] + [Theory] [InlineData("#region test")] [InlineData("#if true")] [InlineData("#pragma warning disable CS0108")] [InlineData("#nullable enable")] public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest2(string trivia) { - var markupBeforeCommit = $$""" + await VerifySnippetAsync($$""" {{trivia}} (new int[10]).$$ - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" {{trivia}} - foreach (var item in new int[10]) + foreach (var {|0:item|} in new int[10]) { $$ } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory] + [Theory] [InlineData("")] [InlineData("async ")] public async Task InsertForEachSnippetAfterSingleAwaitKeywordInMethodBodyTest(string asyncKeyword) { - var markupBeforeCommit = $$""" - - - class C + await VerifySnippetAsync($$""" + class C { {{asyncKeyword}}void M() { await $$ } - } - - - """; - - var expectedCodeAfterCommit = $$""" + } + """, $$""" class C { {{asyncKeyword}}void M() { - await foreach (var item in collection) + await foreach (var {|0:item|} in {|1:collection|}) { $$ } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """, + referenceAssemblies: ReferenceAssemblies.Net.Net70); } - [WpfFact] + [Fact] public async Task InsertForEachSnippetAfterSingleAwaitKeywordInGlobalStatementTest() { - var markupBeforeCommit = """ - - - await $$ - - - """; - - var expectedCodeAfterCommit = """ - await foreach (var item in collection) + await VerifySnippetAsync(""" + await $$ + """, """ + await foreach (var {|0:item|} in {|1:collection|}) { $$ } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """, + referenceAssemblies: ReferenceAssemblies.Net.Net70); } - [WpfFact] + [Fact] public async Task NoForEachStatementAfterAwaitKeywordWhenWontResultInStatementTest() { - var markupBeforeCommit = """ - - - var result = await $$ - - - """; - - await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit); + await VerifySnippetIsAbsentAsync(""" + var result = await $$ + """, + referenceAssemblies: ReferenceAssemblies.Net.Net70); } - [WpfTheory] + [Theory] [InlineData("")] [InlineData("async ")] public async Task PreferAsyncEnumerableVariableInScopeForAwaitForEachTest(string asyncKeyword) { - var markupBeforeCommit = $$""" - - - using System.Collections.Generic; + await VerifySnippetAsync($$""" + using System.Collections.Generic; class C { {{asyncKeyword}}void M() { - IEnumerable<int> enumerable; - IAsyncEnumerable<int> asyncEnumerable; + IEnumerable enumerable; + IAsyncEnumerable asyncEnumerable; await $$ } - } - - - """; - - var expectedCodeAfterCommit = $$""" + } + """, $$""" using System.Collections.Generic; class C @@ -574,60 +456,52 @@ class C IEnumerable enumerable; IAsyncEnumerable asyncEnumerable; - await foreach (var item in asyncEnumerable) + await foreach (var {|0:item|} in {|1:asyncEnumerable|}) { $$ } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """, + referenceAssemblies: ReferenceAssemblies.Net.Net70); } - [WpfTheory] + [Theory] [InlineData("")] [InlineData("async ")] public async Task InsertAwaitForEachSnippetForPostfixAsyncEnumerableTest(string asyncKeyword) { - var markupBeforeCommit = $$""" - - - using System.Collections.Generic; + await VerifySnippetAsync($$""" + using System.Collections.Generic; class C { - {{asyncKeyword}}void M(IAsyncEnumerable<int> asyncEnumerable) + {{asyncKeyword}}void M(IAsyncEnumerable asyncEnumerable) { asyncEnumerable.$$ } - } - - - """; - - var expectedCodeAfterCommit = $$""" + } + """, $$""" using System.Collections.Generic; class C { {{asyncKeyword}}void M(IAsyncEnumerable asyncEnumerable) { - await foreach (var item in asyncEnumerable) + await foreach (var {|0:item|} in asyncEnumerable) { $$ } } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """, + referenceAssemblies: ReferenceAssemblies.Net.Net70); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] public async Task InsertInlineForEachSnippetWhenDottingBeforeContextualKeywordTest1() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" using System.Collections.Generic; class C @@ -638,69 +512,64 @@ void M(IEnumerable ints) var a = 0; } } - """; - - var expectedCodeAfterCommit = """ + """, """ using System.Collections.Generic; class C { void M(IEnumerable ints) { - foreach (var item in ints) + foreach (var {|0:item|} in ints) { $$ } var a = 0; } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] public async Task InsertInlineForEachSnippetWhenDottingBeforeContextualKeywordTest2() { - var markupBeforeCommit = """ + await VerifySnippetAsync(""" + using System.Threading.Tasks; using System.Collections.Generic; class C { - void M(IEnumerable ints, Task t) + async void M(IEnumerable ints, Task t) { ints.$$ await t; } } - """; - - var expectedCodeAfterCommit = """ + """, """ + using System.Threading.Tasks; using System.Collections.Generic; class C { - void M(IEnumerable ints, Task t) + async void M(IEnumerable ints, Task t) { - foreach (var item in ints) + foreach (var {|0:item|} in ints) { $$ } await t; } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """); } - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] [InlineData("Task")] [InlineData("Task")] [InlineData("System.Threading.Tasks.Task")] public async Task InsertInlineForEachSnippetWhenDottingBeforeNameSyntaxTest(string nameSyntax) { - var markupBeforeCommit = $$""" + await VerifySnippetAsync($$""" + using System.Threading.Tasks; using System.Collections.Generic; class C @@ -711,144 +580,351 @@ void M(IEnumerable ints) {{nameSyntax}} t = null; } } - """; - - var expectedCodeAfterCommit = $$""" + """, $$""" + using System.Threading.Tasks; using System.Collections.Generic; class C { void M(IEnumerable ints) { - foreach (var item in ints) + foreach (var {|0:item|} in ints) { $$ } {{nameSyntax}} t = null; } } - """; + """); + } + + [Fact] + public async Task InsertInlineForEachSnippetWhenDottingBeforeMemberAccessExpressionOnTheNextLineTest() + { + await VerifySnippetAsync(""" + using System; + + class C + { + void M(int[] ints) + { + ints.$$ + Console.WriteLine(); + } + } + """, """ + using System; + + class C + { + void M(int[] ints) + { + foreach (var {|0:item|} in ints) + { + $$ + } + Console.WriteLine(); + } + } + """); + } + + [Fact] + public async Task NoInlineForEachSnippetWhenDottingBeforeMemberAccessExpressionOnTheSameLineTest() + { + await VerifySnippetIsAbsentAsync(""" + using System; + + class C + { + void M(int[] ints) + { + ints.$$ToString(); + } + } + """); + } + + [Fact] + public async Task NoInlineForEachSnippetWhenDottingBeforeContextualKeywordOnTheSameLineTest() + { + await VerifySnippetIsAbsentAsync(""" + using System; - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + class C + { + void M(int[] ints) + { + ints.$$var a = 0; + } + } + """); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] public async Task InsertInlineAwaitForEachSnippetWhenDottingBeforeContextualKeywordTest1() { - var markupBeforeCommit = """ - - - using System.Collections.Generic; + await VerifySnippetAsync(""" + using System.Collections.Generic; class C { - void M(IAsyncEnumerable<int> asyncInts) + void M(IAsyncEnumerable asyncInts) { asyncInts.$$ var a = 0; } - } - - - """; - - var expectedCodeAfterCommit = """ + } + """, """ using System.Collections.Generic; class C { void M(IAsyncEnumerable asyncInts) { - await foreach (var item in asyncInts) + await foreach (var {|0:item|} in asyncInts) { $$ } var a = 0; } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """, + referenceAssemblies: ReferenceAssemblies.Net.Net70); } - [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] public async Task InsertInlineAwaitForEachSnippetWhenDottingBeforeContextualKeywordTest2() { - var markupBeforeCommit = """ - - - using System.Collections.Generic; + await VerifySnippetAsync(""" + using System.Threading.Tasks; + using System.Collections.Generic; class C { - void M(IAsyncEnumerable<int> asyncInts, Task t) + async void M(IAsyncEnumerable asyncInts, Task t) { asyncInts.$$ await t; } - } - - - """; - - var expectedCodeAfterCommit = """ + } + """, """ + using System.Threading.Tasks; using System.Collections.Generic; class C { - void M(IAsyncEnumerable asyncInts, Task t) + async void M(IAsyncEnumerable asyncInts, Task t) { - await foreach (var item in asyncInts) + await foreach (var {|0:item|} in asyncInts) { $$ } await t; } } - """; - - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + """, + referenceAssemblies: ReferenceAssemblies.Net.Net70); } - [WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] [InlineData("Task")] [InlineData("Task")] [InlineData("System.Threading.Tasks.Task")] public async Task InsertInlineAwaitForEachSnippetWhenDottingBeforeNameSyntaxTest(string nameSyntax) { - var markupBeforeCommit = $$""" - - - using System.Collections.Generic; + await VerifySnippetAsync($$""" + using System.Threading.Tasks; + using System.Collections.Generic; class C { - void M(IAsyncEnumerable<int> asyncInts) + void M(IAsyncEnumerable asyncInts) { asyncInts.$$ - {{nameSyntax.Replace("<", "<").Replace(">", ">")}} t = null; + {{nameSyntax}} t = null; } - } - - - """; - - var expectedCodeAfterCommit = $$""" + } + """, $$""" + using System.Threading.Tasks; using System.Collections.Generic; class C { void M(IAsyncEnumerable asyncInts) { - await foreach (var item in asyncInts) + await foreach (var {|0:item|} in asyncInts) { $$ } {{nameSyntax}} t = null; } } - """; + """, + referenceAssemblies: ReferenceAssemblies.Net.Net70); + } - await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit); + [Fact] + public async Task InsertInlineAwaitForEachSnippetWhenDottingBeforeMemberAccessExpressionOnTheNextLineTest() + { + await VerifySnippetAsync(""" + using System; + using System.Collections.Generic; + + class C + { + void M(IAsyncEnumerable ints) + { + ints.$$ + Console.WriteLine(); + } + } + """, """ + using System; + using System.Collections.Generic; + + class C + { + void M(IAsyncEnumerable ints) + { + await foreach (var {|0:item|} in ints) + { + $$ + } + Console.WriteLine(); + } + } + """, + referenceAssemblies: ReferenceAssemblies.Net.Net80); + } + + [Fact] + public async Task NoInlineAwaitForEachSnippetWhenDottingBeforeMemberAccessExpressionOnTheSameLineTest() + { + await VerifySnippetIsAbsentAsync(""" + using System.Collections.Generic; + + class C + { + void M(IAsyncEnumerable ints) + { + ints.$$ToString(); + } + } + """, + referenceAssemblies: ReferenceAssemblies.Net.Net80); + } + + [Fact] + public async Task NoInlineAwaitForEachSnippetWhenDottingBeforeContextualKeywordOnTheSameLineTest() + { + await VerifySnippetIsAbsentAsync(""" + using System.Collections.Generic; + + class C + { + void M(IAsyncEnumerable ints) + { + ints.$$var a = 0; + } + } + """, + referenceAssemblies: ReferenceAssemblies.Net.Net80); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.CommonEnumerableTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineForEachSnippetForTypeItselfTest(string collectionType) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M() + { + {{collectionType}}.$$ + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.CommonEnumerableTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineForEachSnippetForTypeItselfTest_Parenthesized(string collectionType) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M() + { + ({{collectionType}}).$$ + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.CommonEnumerableTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineForEachSnippetForTypeItselfTest_BeforeContextualKeyword(string collectionType) + { + await VerifySnippetIsAbsentAsync($$""" + using System.Threading.Tasks; + + class C + { + async void M() + { + {{collectionType}}.$$ + await Task.Delay(10); + } + } + """); + } + + [Theory] + [InlineData("ArrayList")] + [InlineData("IEnumerable")] + [InlineData("MyCollection")] + public async Task InsertInlineForEachSnippetForVariableNamedLikeTypeTest(string typeAndVariableName) + { + await VerifySnippetAsync($$""" + using System.Collections; + using System.Collections.Generic; + + class C + { + void M() + { + {{typeAndVariableName}} {{typeAndVariableName}} = default; + {{typeAndVariableName}}.$$ + } + } + + class MyCollection : IEnumerable + { + public IEnumerator GetEnumerator() => null; + IEnumerator IEnumerable.GetEnumerator() = null; + } + """, $$""" + using System.Collections; + using System.Collections.Generic; + + class C + { + void M() + { + {{typeAndVariableName}} {{typeAndVariableName}} = default; + foreach (var {|0:item|} in {{typeAndVariableName}}) + { + $$ + } + } + } + + class MyCollection : IEnumerable + { + public IEnumerator GetEnumerator() => null; + IEnumerator IEnumerable.GetEnumerator() = null; + } + """); } } diff --git a/src/Features/CSharpTest/Snippets/CSharpForSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpForSnippetProviderTests.cs new file mode 100644 index 0000000000000..2363ffcb65836 --- /dev/null +++ b/src/Features/CSharpTest/Snippets/CSharpForSnippetProviderTests.cs @@ -0,0 +1,1043 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; + +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpForSnippetProviderTests : AbstractCSharpSnippetProviderTests +{ + protected override string SnippetIdentifier => "for"; + + [Fact] + public async Task InsertForSnippetInMethodTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + $$ + } + } + """, """ + class Program + { + public void Method() + { + for (int {|0:i|} = 0; {|0:i|} < {|1:length|}; {|0:i|}++) + { + $$ + } + } + } + """); + } + + [Fact] + public async Task InsertForSnippetInMethodUsedIncrementorTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + int i; + $$ + } + } + """, """ + class Program + { + public void Method() + { + int i; + for (int {|0:j|} = 0; {|0:j|} < {|1:length|}; {|0:j|}++) + { + $$ + } + } + } + """); + } + + [Fact] + public async Task InsertForSnippetInMethodUsedIncrementorsTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + int i, j, k; + $$ + } + } + """, """ + class Program + { + public void Method() + { + int i, j, k; + for (int {|0:i1|} = 0; {|0:i1|} < {|1:length|}; {|0:i1|}++) + { + $$ + } + } + } + """); + } + + [Fact] + public async Task InsertForSnippetInGlobalContextTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + for (int {|0:i|} = 0; {|0:i|} < {|1:length|}; {|0:i|}++) + { + $$ + } + """); + } + + [Fact] + public async Task InsertForSnippetInConstructorTest() + { + await VerifySnippetAsync(""" + class Program + { + public Program() + { + $$ + } + } + """, """ + class Program + { + public Program() + { + for (int {|0:i|} = 0; {|0:i|} < {|1:length|}; {|0:i|}++) + { + $$ + } + } + } + """); + } + + [Fact] + public async Task InsertForSnippetInLocalFunctionTest() + { + // TODO: fix this test when bug with simplifier failing to find correct node is fixed + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + void LocalFunction() + { + $$ + } + } + } + """, """ + class Program + { + public void Method() + { + void LocalFunction() + { + for (global::System.Int32 {|0:i|} = 0; {|0:i|} < {|1:length|}; {|0:i|}++) + { + $$ + } + } + } + } + """); + } + + [Fact] + public async Task InsertForSnippetInAnonymousFunctionTest() + { + // TODO: fix this test when bug with simplifier failing to find correct node is fixed + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + var action = delegate() + { + $$ + }; + } + } + """, """ + class Program + { + public void Method() + { + var action = delegate() + { + for (global::System.Int32 {|0:i|} = 0; {|0:i|} < {|1:length|}; {|0:i|}++) + { + $$ + } + }; + } + } + """); + } + + [Fact] + public async Task InsertForSnippetInParenthesizedLambdaExpressionTest() + { + // TODO: fix this test when bug with simplifier failing to find correct node is fixed + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + var action = () => + { + $$ + }; + } + } + """, """ + class Program + { + public void Method() + { + var action = () => + { + for (global::System.Int32 {|0:i|} = 0; {|0:i|} < {|1:length|}; {|0:i|}++) + { + $$ + } + }; + } + } + """); + } + + [Fact] + public async Task ProduceVarWithSpecificCodeStyleTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + $$ + } + } + """, """ + class Program + { + public void Method() + { + for (var {|0:i|} = 0; {|0:i|} < {|1:length|}; {|0:i|}++) + { + $$ + } + } + } + """, + editorconfig: """ + root = true + + [*] + csharp_style_var_for_built_in_types = true + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInlineForSnippetInMethodTest(string inlineExpressionType) + { + await VerifySnippetAsync($$""" + class Program + { + public void Method({{inlineExpressionType}} l) + { + l.$$ + } + } + """, $$""" + class Program + { + public void Method({{inlineExpressionType}} l) + { + for ({{inlineExpressionType}} {|0:i|} = 0; {|0:i|} < l; {|0:i|}++) + { + $$ + } + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInlineForSnippetInGlobalContextTest(string inlineExpressionType) + { + await VerifySnippetAsync($$""" + {{inlineExpressionType}} l; + l.$$ + """, $$""" + {{inlineExpressionType}} l; + for ({{inlineExpressionType}} {|0:i|} = 0; {|0:i|} < l; {|0:i|}++) + { + $$ + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.NotIntegerTypesWithoutLengthOrCountProperty), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineForSnippetForIncorrectTypeInMethodTest(string inlineExpressionType) + { + await VerifySnippetIsAbsentAsync($$""" + class Program + { + public void Method({{inlineExpressionType}} l) + { + l.$$ + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.NotIntegerTypesWithoutLengthOrCountProperty), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineForSnippetForIncorrectTypeInGlobalContextTest(string inlineExpressionType) + { + await VerifySnippetIsAbsentAsync($$""" + {{inlineExpressionType}} l; + l.$$ + """); + } + + [Fact] + public async Task ProduceVarWithSpecificCodeStyleForInlineSnippetTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method(int l) + { + l.$$ + } + } + """, """ + class Program + { + public void Method(int l) + { + for (var {|0:i|} = 0; {|0:i|} < l; {|0:i|}++) + { + $$ + } + } + } + """, + editorconfig: """ + root = true + + [*] + csharp_style_var_for_built_in_types = true + """); + } + + [Fact] + public async Task NoInlineForSnippetNotDirectlyExpressionStatementTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public void Method(int l) + { + System.Console.WriteLine(l.$$); + } + } + """); + } + + [Theory] + [InlineData("// comment")] + [InlineData("/* comment */")] + [InlineData("#region test")] + public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest1(string trivia) + { + await VerifySnippetAsync($$""" + class Program + { + void M(int len) + { + {{trivia}} + len.$$ + } + } + """, $$""" + class Program + { + void M(int len) + { + {{trivia}} + for (int {|0:i|} = 0; {|0:i|} < len; {|0:i|}++) + { + $$ + } + } + } + """); + } + + [Theory] + [InlineData("#if true")] + [InlineData("#pragma warning disable CS0108")] + [InlineData("#nullable enable")] + public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest2(string trivia) + { + await VerifySnippetAsync($$""" + class Program + { + void M(int len) + { + {{trivia}} + len.$$ + } + } + """, $$""" + class Program + { + void M(int len) + { + {{trivia}} + for (int {|0:i|} = 0; {|0:i|} < len; {|0:i|}++) + { + $$ + } + } + } + """); + } + + [Theory] + [InlineData("// comment")] + [InlineData("/* comment */")] + public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest1(string trivia) + { + await VerifySnippetAsync($$""" + {{trivia}} + 10.$$ + """, $$""" + {{trivia}} + for (int {|0:i|} = 0; {|0:i|} < 10; {|0:i|}++) + { + $$ + } + """); + } + + [Theory] + [InlineData("#region test")] + [InlineData("#if true")] + [InlineData("#pragma warning disable CS0108")] + [InlineData("#nullable enable")] + public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest2(string trivia) + { + await VerifySnippetAsync($$""" + {{trivia}} + 10.$$ + """, $$""" + + {{trivia}} + for (int {|0:i|} = 0; {|0:i|} < 10; {|0:i|}++) + { + $$ + } + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInlineForSnippetWhenDottingBeforeContextualKeywordTest1(string intType) + { + await VerifySnippetAsync($$""" + using System.Collections.Generic; + + class C + { + void M({{intType}} @int) + { + @int.$$ + var a = 0; + } + } + """, $$""" + using System.Collections.Generic; + + class C + { + void M({{intType}} @int) + { + for ({{intType}} {|0:i|} = 0; {|0:i|} < @int; {|0:i|}++) + { + $$ + } + var a = 0; + } + } + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInlineForSnippetWhenDottingBeforeContextualKeywordTest2(string intType) + { + await VerifySnippetAsync($$""" + using System.Collections.Generic; + + class C + { + async void M({{intType}} @int, Task t) + { + @int.$$ + await t; + } + } + """, $$""" + using System.Collections.Generic; + + class C + { + async void M({{intType}} @int, Task t) + { + for ({{intType}} {|0:i|} = 0; {|0:i|} < @int; {|0:i|}++) + { + $$ + } + await t; + } + } + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [InlineData("Task")] + [InlineData("Task")] + [InlineData("System.Threading.Tasks.Task")] + public async Task InsertInlineForSnippetWhenDottingBeforeNameSyntaxTest(string nameSyntax) + { + await VerifySnippetAsync($$""" + using System.Threading.Tasks; + using System.Collections.Generic; + + class C + { + void M(int @int) + { + @int.$$ + {{nameSyntax}} t = null; + } + } + """, $$""" + using System.Threading.Tasks; + using System.Collections.Generic; + + class C + { + void M(int @int) + { + for (int {|0:i|} = 0; {|0:i|} < @int; {|0:i|}++) + { + $$ + } + {{nameSyntax}} t = null; + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInlineForSnippetWhenDottingBeforeMemberAccessExpressionOnTheNextLineTest(string intType) + { + await VerifySnippetAsync($$""" + using System; + + class C + { + void M({{intType}} @int) + { + @int.$$ + Console.WriteLine(); + } + } + """, $$""" + using System; + + class C + { + void M({{intType}} @int) + { + for ({{intType}} {|0:i|} = 0; {|0:i|} < @int; {|0:i|}++) + { + $$ + } + Console.WriteLine(); + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineForSnippetWhenDottingBeforeMemberAccessExpressionOnTheSameLineTest(string intType) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M({{intType}} @int) + { + @int.$$ToString(); + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineForSnippetWhenDottingBeforeContextualKeywordOnTheSameLineTest(string intType) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M({{intType}} @int) + { + @int.$$var a = 0; + } + } + """); + } + + [Theory] + [InlineData("int[]", "Length")] + [InlineData("Span", "Length")] + [InlineData("ReadOnlySpan", "Length")] + [InlineData("ImmutableArray", "Length")] + [InlineData("List", "Count")] + [InlineData("HashSet", "Count")] + [InlineData("Dictionary", "Count")] + [InlineData("ImmutableList", "Count")] + public async Task InsertInlineForSnippetForCommonTypesWithLengthOrCountPropertyTest(string type, string propertyName) + { + await VerifySnippetAsync($$""" + using System; + using System.Collections.Generic; + using System.Collections.Immutable; + + public class C + { + void M({{type}} type) + { + type.$$ + } + } + """, $$""" + using System; + using System.Collections.Generic; + using System.Collections.Immutable; + + public class C + { + void M({{type}} type) + { + for (int {|0:i|} = 0; {|0:i|} < type.{{propertyName}}; {|0:i|}++) + { + $$ + } + } + } + """, + referenceAssemblies: ReferenceAssemblies.Net.Net80); + } + + [Theory] + [CombinatorialData] + public async Task InsertInlineForSnippetForTypeWithAccessibleLengthOrCountPropertyTest( + [CombinatorialValues("public", "internal", "protected internal")] string propertyAccessibility, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + {{propertyAccessibility}} int {{propertyName}} { get; } + } + """, $$""" + class C + { + void M(MyType type) + { + for (int {|0:i|} = 0; {|0:i|} < type.{{propertyName}}; {|0:i|}++) + { + $$ + } + } + } + + public class MyType + { + {{propertyAccessibility}} int {{propertyName}} { get; } + } + """); + } + + [Theory] + [CombinatorialData] + public async Task InsertInlineForSnippetForTypeWithAccessibleLengthOrCountPropertyGetterTest( + [CombinatorialValues("", "internal", "protected internal")] string getterAccessibility, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public int {{propertyName}} { {{getterAccessibility}} get; } + } + """, $$""" + class C + { + void M(MyType type) + { + for (int {|0:i|} = 0; {|0:i|} < type.{{propertyName}}; {|0:i|}++) + { + $$ + } + } + } + + public class MyType + { + public int {{propertyName}} { {{getterAccessibility}} get; } + } + """); + } + + [Theory] + [CombinatorialData] + public async Task InsertInlineForSnippetForTypesWithLengthOrCountPropertyOfDifferentIntegerTypesTest( + [CombinatorialValues("byte", "sbyte", "short", "ushort", "int", "uint", "long", "ulong", "nint", "nuint")] string integerType, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public {{integerType}} {{propertyName}} { get; } + } + """, $$""" + class C + { + void M(MyType type) + { + for ({{integerType}} {|0:i|} = 0; {|0:i|} < type.{{propertyName}}; {|0:i|}++) + { + $$ + } + } + } + + public class MyType + { + public {{integerType}} {{propertyName}} { get; } + } + """); + } + + [Theory] + [InlineData("Length")] + [InlineData("Count")] + public async Task InsertInlineForSnippetForTypeWithLengthOrCountPropertyInBaseClassTest(string propertyName) + { + await VerifySnippetAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType : MyTypeBase + { + } + + public class MyTypeBase + { + public int {{propertyName}} { get; } + } + """, $$""" + class C + { + void M(MyType type) + { + for (int {|0:i|} = 0; {|0:i|} < type.{{propertyName}}; {|0:i|}++) + { + $$ + } + } + } + + public class MyType : MyTypeBase + { + } + + public class MyTypeBase + { + public int {{propertyName}} { get; } + } + """); + } + + [Theory] + [InlineData("Length")] + [InlineData("Count")] + public async Task NoInlineForSnippetWhenLengthOrCountPropertyHasNoGetterTest(string propertyName) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public int {{propertyName}} { set { } } + } + """); + } + + [Theory] + [CombinatorialData] + public async Task NoInlineForSnippetForInaccessibleLengthPropertyTest( + [CombinatorialValues("private", "protected", "private protected")] string propertyAccessibility, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + {{propertyAccessibility}} int {{propertyName}} { get; } + } + """); + } + + [Theory] + [CombinatorialData] + public async Task NoInlineForSnippetForInaccessibleLengthOrCountPropertyGetterTest( + [CombinatorialValues("private", "protected", "private protected")] string getterAccessibility, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public int {{propertyName}} { {{getterAccessibility}} get; } + } + """); + } + + [Theory] + [CombinatorialData] + public async Task NoInlineForSnippetForLengthPropertyOfIncorrectTypeTest( + [CombinatorialValues("object", "string", "System.DateTime", "System.Action")] string notIntegerType, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public {{notIntegerType}} {{propertyName}} { get; } + } + """); + } + + [Fact] + public async Task NoInlineForSnippetForTypeWithBothLengthAndCountPropertyTest() + { + await VerifySnippetIsAbsentAsync(""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public int Length { get; } + public int Count { get; } + } + """); + } + + [Theory] + [InlineData("MyType")] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineForSnippetForTypeItselfTest(string validTypes) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M() + { + {{validTypes}}.$$ + } + } + + class MyType + { + public int Count => 0; + } + """); + } + + [Theory] + [InlineData("MyType")] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineForSnippetForTypeItselfTest_Parenthesized(string validTypes) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M() + { + ({{validTypes}}).$$ + } + } + + class MyType + { + public int Count => 0; + } + """); + } + + [Theory] + [InlineData("MyType")] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineForSnippetForTypeItselfTest_BeforeContextualKeyword(string validTypes) + { + await VerifySnippetIsAbsentAsync($$""" + using System.Threading.Tasks; + + class C + { + async void M() + { + {{validTypes}}.$$ + await Task.Delay(10); + } + } + + class MyType + { + public int Count => 0; + } + """); + } + + [Fact] + public async Task InsertInlineForSnippetForVariableNamedLikeTypeTest() + { + await VerifySnippetAsync(""" + class C + { + void M() + { + MyType MyType = default; + MyType.$$ + } + } + + class MyType + { + public int Length => 0; + } + """, """ + class C + { + void M() + { + MyType MyType = default; + for (int {|0:i|} = 0; {|0:i|} < MyType.Length; {|0:i|}++) + { + $$ + } + } + } + + class MyType + { + public int Length => 0; + } + """); + } +} diff --git a/src/Features/CSharpTest/Snippets/CSharpIfSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpIfSnippetProviderTests.cs new file mode 100644 index 0000000000000..038ab754902f9 --- /dev/null +++ b/src/Features/CSharpTest/Snippets/CSharpIfSnippetProviderTests.cs @@ -0,0 +1,10 @@ +// 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.CSharp.UnitTests.Snippets; + +public sealed class CSharpIfSnippetProviderTests : AbstractCSharpConditionalBlockSnippetProviderTests +{ + protected override string SnippetIdentifier => "if"; +} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpSimSnippetCompletionProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpIntMainSnippetProviderTests.cs similarity index 57% rename from src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpSimSnippetCompletionProviderTests.cs rename to src/Features/CSharpTest/Snippets/CSharpIntMainSnippetProviderTests.cs index 7854b75169561..55b046b1ae38e 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpSimSnippetCompletionProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/CSharpIntMainSnippetProviderTests.cs @@ -4,46 +4,46 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; -public class CSharpSimSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpIntMainSnippetProviderTests : AbstractCSharpSnippetProviderTests { - protected override string ItemToCommit => "sim"; + protected override string SnippetIdentifier => "sim"; - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task TestMissingInNamespace() + [Fact] + public async Task TestMissingInBlockNamespace() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" namespace Test { $$ } - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingInFileScopedNamespace() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" namespace Test; $$ - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingInTopLevelContext() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" System.Console.WriteLine(); $$ - """, ItemToCommit); + """); } - [WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)] + [Theory] [InlineData("class")] [InlineData("struct")] [InlineData("interface")] @@ -52,12 +52,12 @@ await VerifyItemIsAbsentAsync(""" [InlineData("record struct")] public async Task TestInsertSnippetInType(string type) { - await VerifyCustomCommitProviderAsync($$""" + await VerifySnippetAsync($$""" {{type}} Program { $$ } - """, ItemToCommit, $$""" + """, $$""" {{type}} Program { static int Main(string[] args) @@ -69,21 +69,21 @@ static int Main(string[] args) """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingInEnum() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" enum MyEnum { $$ } - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingInMethod() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" class Program { void M() @@ -91,13 +91,13 @@ void M() $$ } } - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingInConstructor() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" class Program { public Program() @@ -105,23 +105,19 @@ public Program() $$ } } - """, ItemToCommit); + """); } - [WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] public async Task TestInsertSnippetAfterAccessibilityModifier(string modifier) { - await VerifyCustomCommitProviderAsync($$""" + await VerifySnippetAsync($$""" class Program { {{modifier}} $$ } - """, ItemToCommit, $$""" + """, $$""" class Program { {{modifier}} static int Main(string[] args) @@ -133,7 +129,7 @@ class Program """); } - [WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)] + [Theory] [InlineData("static")] [InlineData("virtual")] [InlineData("abstract")] @@ -141,37 +137,37 @@ class Program [InlineData("file")] public async Task TestMissingAfterIncorrectModifiers(string modifier) { - await VerifyItemIsAbsentAsync($$""" + await VerifySnippetIsAbsentAsync($$""" class Program { {{modifier}} $$ } - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingIfAnotherMemberWithNameMainExists() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" class Program { public int Main => 0; $$ } - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingIfTopLevelStatementsArePresent() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" System.Console.WriteLine(); class Program { $$ } - """, ItemToCommit); + """); } } diff --git a/src/Features/CSharpTest/Snippets/CSharpInterfaceSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpInterfaceSnippetProviderTests.cs new file mode 100644 index 0000000000000..d7f11f78611cc --- /dev/null +++ b/src/Features/CSharpTest/Snippets/CSharpInterfaceSnippetProviderTests.cs @@ -0,0 +1,314 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; + +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpInterfaceSnippetProviderTests : AbstractCSharpSnippetProviderTests +{ + protected override string SnippetIdentifier => "interface"; + + [Fact] + public async Task InsertInterfaceSnippetInBlockNamespaceTest() + { + await VerifySnippetAsync(""" + namespace Namespace + { + $$ + } + """, """ + namespace Namespace + { + interface {|0:MyInterface|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertInterfaceSnippetInFileScopedNamespaceTest() + { + await VerifySnippetAsync(""" + namespace Namespace; + + $$ + """, """ + namespace Namespace; + + interface {|0:MyInterface|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertInterfaceSnippetTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + interface {|0:MyInterface|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertInterfaceTopLevelSnippetTest() + { + await VerifySnippetAsync(""" + System.Console.WriteLine(); + $$ + """, """ + System.Console.WriteLine(); + interface {|0:MyInterface|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertInterfaceSnippetInClassTest() + { + await VerifySnippetAsync(""" + class MyClass + { + $$ + } + """, """ + class MyClass + { + interface {|0:MyInterface|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertInterfaceSnippetInRecordTest() + { + await VerifySnippetAsync(""" + record MyRecord + { + $$ + } + """, """ + record MyRecord + { + interface {|0:MyInterface|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertInterfaceSnippetInStructTest() + { + await VerifySnippetAsync(""" + struct MyStruct + { + $$ + } + """, """ + struct MyStruct + { + interface {|0:MyInterface|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertInterfaceSnippetInInterfaceTest() + { + await VerifySnippetAsync(""" + interface MyInterface + { + $$ + } + """, """ + interface MyInterface + { + interface {|0:MyInterface1|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertInterfaceSnippetWithModifiersTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + public interface {|0:MyInterface|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Fact] + public async Task NoInterfaceSnippetInEnumTest() + { + await VerifySnippetIsAbsentAsync(""" + enum MyEnum + { + $$ + } + """); + } + + [Fact] + public async Task NoInterfaceSnippetInMethodTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public void Method() + { + $$ + } + } + """); + } + + [Fact] + public async Task NoInterfaceSnippetInConstructorTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public Program() + { + $$ + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInterfaceSnippetAfterAccessibilityModifier(string modifier) + { + await VerifySnippetAsync($""" + {modifier} $$ + """, $$""" + {{modifier}} interface {|0:MyInterface|} + { + $$ + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInterfaceSnippetAfterAccessibilityModifier_RequireAccessibilityModifiers(string modifier) + { + await VerifySnippetAsync($""" + {modifier} $$ + """, $$""" + {{modifier}} interface {|0:MyInterface|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Theory] + [InlineData("unsafe")] + public async Task InsertInterfaceSnippetAfterValidModifiersTest(string modifier) + { + await VerifySnippetAsync($""" + {modifier} $$ + """, $$""" + {{modifier}} interface {|0:MyInterface|} + { + $$ + } + """); + } + + [Theory] + [InlineData("abstract")] + [InlineData("sealed")] + [InlineData("static")] + [InlineData("ref")] + [InlineData("readonly")] + public async Task NoInterfaceSnippetAfterInvalidModifiersTest(string modifier) + { + await VerifySnippetIsAbsentAsync($""" + {modifier} $$ + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task NoAdditionalAccessibilityModifiersIfAfterPartialKeywordTest(string modifier) + { + await VerifySnippetAsync($""" + {modifier} partial $$ + """, $$""" + {{modifier}} partial interface {|0:MyInterface|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] + public async Task EnsureCorrectModifierOrderAfterPartialKeywordTest() + { + await VerifySnippetAsync(""" + partial $$ + """, """ + public partial interface {|0:MyInterface|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } +} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpLockSnippetCompletionProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpLockSnippetProviderTests.cs similarity index 72% rename from src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpLockSnippetCompletionProviderTests.cs rename to src/Features/CSharpTest/Snippets/CSharpLockSnippetProviderTests.cs index e98f868689a89..41e9169b6b948 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpLockSnippetCompletionProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/CSharpLockSnippetProviderTests.cs @@ -4,20 +4,19 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; -[Trait(Traits.Feature, Traits.Features.Completion)] -public class CSharpLockSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpLockSnippetProviderTests : AbstractCSharpSnippetProviderTests { - protected override string ItemToCommit => "lock"; + protected override string SnippetIdentifier => "lock"; - [WpfFact] + [Fact] public async Task InsertLockSnippetInMethodTest() { - await VerifyCustomCommitProviderAsync(""" + await VerifySnippetAsync(""" class Program { public void Method() @@ -25,12 +24,12 @@ public void Method() $$ } } - """, ItemToCommit, """ + """, """ class Program { public void Method() { - lock (this) + lock ({|0:this|}) { $$ } @@ -39,43 +38,43 @@ public void Method() """); } - [WpfFact] + [Fact] public async Task InsertLockSnippetInGlobalContextTest() { - await VerifyCustomCommitProviderAsync(""" + await VerifySnippetAsync(""" $$ - """, ItemToCommit, """ - lock (this) + """, """ + lock ({|0:this|}) { $$ } """); } - [WpfFact] + [Fact] public async Task NoLockSnippetInBlockNamespaceTest() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" namespace Namespace { $$ } - """, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task NoLockSnippetInFileScopedNamespaceTest() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" namespace Namespace; $$ - """, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task InsertLockSnippetInConstructorTest() { - await VerifyCustomCommitProviderAsync(""" + await VerifySnippetAsync(""" class Program { public Program() @@ -83,12 +82,12 @@ public Program() $$ } } - """, ItemToCommit, """ + """, """ class Program { public Program() { - lock (this) + lock ({|0:this|}) { $$ } @@ -97,21 +96,21 @@ public Program() """); } - [WpfFact] + [Fact] public async Task NoLockSnippetInTypeBodyTest() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" class Program { $$ } - """, ItemToCommit); + """); } - [WpfFact] + [Fact] public async Task InsertLockSnippetInLocalFunctionTest() { - await VerifyCustomCommitProviderAsync(""" + await VerifySnippetAsync(""" class Program { public void Method() @@ -122,14 +121,14 @@ void LocalFunction() } } } - """, ItemToCommit, """ + """, """ class Program { public void Method() { void LocalFunction() { - lock (this) + lock ({|0:this|}) { $$ } @@ -139,10 +138,10 @@ void LocalFunction() """); } - [WpfFact] + [Fact] public async Task InsertLockSnippetInAnonymousFunctionTest() { - await VerifyCustomCommitProviderAsync(""" + await VerifySnippetAsync(""" class Program { public void Method() @@ -153,14 +152,14 @@ public void Method() }; } } - """, ItemToCommit, """ + """, """ class Program { public void Method() { var action = delegate() { - lock (this) + lock ({|0:this|}) { $$ } @@ -170,10 +169,10 @@ public void Method() """); } - [WpfFact] + [Fact] public async Task InsertLockSnippetInParenthesizedLambdaExpressionTest() { - await VerifyCustomCommitProviderAsync(""" + await VerifySnippetAsync(""" class Program { public void Method() @@ -184,14 +183,14 @@ public void Method() }; } } - """, ItemToCommit, """ + """, """ class Program { public void Method() { var action = () => { - lock (this) + lock ({|0:this|}) { $$ } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropSnippetCompletionProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpPropSnippetProviderTests.cs similarity index 63% rename from src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropSnippetCompletionProviderTests.cs rename to src/Features/CSharpTest/Snippets/CSharpPropSnippetProviderTests.cs index 67596503fcc10..903f9d6a2b942 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropSnippetCompletionProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/CSharpPropSnippetProviderTests.cs @@ -4,16 +4,15 @@ using System.Threading.Tasks; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; -public class CSharpPropSnippetCompletionProviderTests : AbstractCSharpAutoPropertyCompletionProviderTests +public sealed class CSharpPropSnippetProviderTests : AbstractCSharpAutoPropertySnippetProviderTests { - protected override string ItemToCommit => "prop"; + protected override string SnippetIdentifier => "prop"; - protected override string GetDefaultPropertyBlockText() - => "{ get; set; }"; + protected override string DefaultPropertyBlockText => "{ get; set; }"; - public override async Task InsertSnippetInReadonlyStruct() + public override async Task InsertSnippetInReadonlyStructTest() { // Ensure we don't generate redundant `set` accessor when executed in readonly struct await VerifyPropertyAsync(""" @@ -21,10 +20,10 @@ readonly struct MyStruct { $$ } - """, "public int MyProperty { get; }"); + """, "public {|0:int|} {|1:MyProperty|} { get; }"); } - public override async Task InsertSnippetInReadonlyStruct_ReadonlyModifierInOtherPartialDeclaration() + public override async Task InsertSnippetInReadonlyStructTest_ReadonlyModifierInOtherPartialDeclaration() { // Ensure we don't generate redundant `set` accessor when executed in readonly struct await VerifyPropertyAsync(""" @@ -36,10 +35,10 @@ partial struct MyStruct readonly partial struct MyStruct { } - """, "public int MyProperty { get; }"); + """, "public {|0:int|} {|1:MyProperty|} { get; }"); } - public override async Task InsertSnippetInReadonlyStruct_ReadonlyModifierInOtherPartialDeclaration_MissingPartialModifier() + public override async Task InsertSnippetInReadonlyStructTest_ReadonlyModifierInOtherPartialDeclaration_MissingPartialModifier() { // Even though there is no `partial` modifier on the first declaration // compiler still treats the whole type as partial since it is more likely that @@ -54,10 +53,10 @@ struct MyStruct readonly partial struct MyStruct { } - """, "public int MyProperty { get; }"); + """, "public {|0:int|} {|1:MyProperty|} { get; }"); } - public override async Task InsertSnippetInInterface() + public override async Task InsertSnippetInInterfaceTest() { await VerifyDefaultPropertyAsync(""" interface MyInterface diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropgSnippetCompletionProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpPropgSnippetProviderTests.cs similarity index 62% rename from src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropgSnippetCompletionProviderTests.cs rename to src/Features/CSharpTest/Snippets/CSharpPropgSnippetProviderTests.cs index 0e6802bd9df30..d4413d32e9bc5 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropgSnippetCompletionProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/CSharpPropgSnippetProviderTests.cs @@ -4,16 +4,15 @@ using System.Threading.Tasks; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; -public class CSharpPropgSnippetCompletionProviderTests : AbstractCSharpAutoPropertyCompletionProviderTests +public sealed class CSharpPropgSnippetProviderTests : AbstractCSharpAutoPropertySnippetProviderTests { - protected override string ItemToCommit => "propg"; + protected override string SnippetIdentifier => "propg"; - protected override string GetDefaultPropertyBlockText() - => "{ get; private set; }"; + protected override string DefaultPropertyBlockText => "{ get; private set; }"; - public override async Task InsertSnippetInReadonlyStruct() + public override async Task InsertSnippetInReadonlyStructTest() { // Ensure we don't generate redundant `set` accessor when executed in readonly struct await VerifyPropertyAsync(""" @@ -21,10 +20,10 @@ readonly struct MyStruct { $$ } - """, "public int MyProperty { get; }"); + """, "public {|0:int|} {|1:MyProperty|} { get; }"); } - public override async Task InsertSnippetInReadonlyStruct_ReadonlyModifierInOtherPartialDeclaration() + public override async Task InsertSnippetInReadonlyStructTest_ReadonlyModifierInOtherPartialDeclaration() { // Ensure we don't generate redundant `set` accessor when executed in readonly struct await VerifyPropertyAsync(""" @@ -36,10 +35,10 @@ partial struct MyStruct readonly partial struct MyStruct { } - """, "public int MyProperty { get; }"); + """, "public {|0:int|} {|1:MyProperty|} { get; }"); } - public override async Task InsertSnippetInReadonlyStruct_ReadonlyModifierInOtherPartialDeclaration_MissingPartialModifier() + public override async Task InsertSnippetInReadonlyStructTest_ReadonlyModifierInOtherPartialDeclaration_MissingPartialModifier() { // Even though there is no `partial` modifier on the first declaration // compiler still treats the whole type as partial since it is more likely that @@ -54,10 +53,10 @@ struct MyStruct readonly partial struct MyStruct { } - """, "public int MyProperty { get; }"); + """, "public {|0:int|} {|1:MyProperty|} { get; }"); } - public override async Task InsertSnippetInInterface() + public override async Task InsertSnippetInInterfaceTest() { // Ensure we don't generate redundant `set` accessor when executed in interface await VerifyPropertyAsync(""" @@ -65,6 +64,6 @@ interface MyInterface { $$ } - """, "public int MyProperty { get; }"); + """, "public {|0:int|} {|1:MyProperty|} { get; }"); } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropiSnippetCompletionProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpPropiSnippetProviderTests.cs similarity index 59% rename from src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropiSnippetCompletionProviderTests.cs rename to src/Features/CSharpTest/Snippets/CSharpPropiSnippetProviderTests.cs index 5a2d0250db204..880dcf3a70927 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpPropiSnippetCompletionProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/CSharpPropiSnippetProviderTests.cs @@ -4,16 +4,15 @@ using System.Threading.Tasks; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; -public class CSharpPropiSnippetCompletionProviderTests : AbstractCSharpAutoPropertyCompletionProviderTests +public sealed class CSharpPropiSnippetProviderTests : AbstractCSharpAutoPropertySnippetProviderTests { - protected override string ItemToCommit => "propi"; + protected override string SnippetIdentifier => "propi"; - protected override string GetDefaultPropertyBlockText() - => "{ get; init; }"; + protected override string DefaultPropertyBlockText => "{ get; init; }"; - public override async Task InsertSnippetInReadonlyStruct() + public override async Task InsertSnippetInReadonlyStructTest() { await VerifyDefaultPropertyAsync(""" readonly struct MyStruct @@ -23,7 +22,7 @@ readonly struct MyStruct """); } - public override async Task InsertSnippetInReadonlyStruct_ReadonlyModifierInOtherPartialDeclaration() + public override async Task InsertSnippetInReadonlyStructTest_ReadonlyModifierInOtherPartialDeclaration() { await VerifyDefaultPropertyAsync(""" partial struct MyStruct @@ -37,7 +36,7 @@ readonly partial struct MyStruct """); } - public override async Task InsertSnippetInReadonlyStruct_ReadonlyModifierInOtherPartialDeclaration_MissingPartialModifier() + public override async Task InsertSnippetInReadonlyStructTest_ReadonlyModifierInOtherPartialDeclaration_MissingPartialModifier() { await VerifyDefaultPropertyAsync(""" struct MyStruct @@ -51,7 +50,7 @@ readonly partial struct MyStruct """); } - public override async Task InsertSnippetInInterface() + public override async Task InsertSnippetInInterfaceTest() { await VerifyDefaultPropertyAsync(""" interface MyInterface diff --git a/src/Features/CSharpTest/Snippets/CSharpReversedForSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpReversedForSnippetProviderTests.cs new file mode 100644 index 0000000000000..c29a2e87b6e79 --- /dev/null +++ b/src/Features/CSharpTest/Snippets/CSharpReversedForSnippetProviderTests.cs @@ -0,0 +1,1045 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; + +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpReversedForSnippetProviderTests : AbstractCSharpSnippetProviderTests +{ + protected override string SnippetIdentifier => "forr"; + + [Fact] + public async Task InsertReversedForSnippetInMethodTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + $$ + } + } + """, """ + class Program + { + public void Method() + { + for (int {|0:i|} = {|1:length|} - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + """); + } + + [Fact] + public async Task InsertReversedForSnippetInMethodUsedIncrementorTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + int i; + $$ + } + } + """, """ + class Program + { + public void Method() + { + int i; + for (int {|0:j|} = {|1:length|} - 1; {|0:j|} >= 0; {|0:j|}--) + { + $$ + } + } + } + """); + } + + [Fact] + public async Task InsertReversedForSnippetInMethodUsedIncrementorsTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + int i, j, k; + $$ + } + } + """, """ + class Program + { + public void Method() + { + int i, j, k; + for (int {|0:i1|} = {|1:length|} - 1; {|0:i1|} >= 0; {|0:i1|}--) + { + $$ + } + } + } + """); + } + + [Fact] + public async Task InsertReversedForSnippetInGlobalContextTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + for (int {|0:i|} = {|1:length|} - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + """); + } + + [Fact] + public async Task InsertReversedForSnippetInConstructorTest() + { + await VerifySnippetAsync(""" + class Program + { + public Program() + { + $$ + } + } + """, """ + class Program + { + public Program() + { + for (int {|0:i|} = {|1:length|} - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + """); + } + + [Fact] + public async Task InsertReversedForSnippetInLocalFunctionTest() + { + // TODO: fix this test when bug with simplifier failing to find correct node is fixed + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + void LocalFunction() + { + $$ + } + } + } + """, """ + class Program + { + public void Method() + { + void LocalFunction() + { + for (global::System.Int32 {|0:i|} = {|1:(length)|} - (1); {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + } + """); + } + + [Fact] + public async Task InsertReversedForSnippetInAnonymousFunctionTest() + { + // TODO: fix this test when bug with simplifier failing to find correct node is fixed + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + var action = delegate() + { + $$ + }; + } + } + """, """ + class Program + { + public void Method() + { + var action = delegate() + { + for (global::System.Int32 {|0:i|} = {|1:(length)|} - (1); {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + }; + } + } + """); + } + + [Fact] + public async Task InsertReversedForSnippetInParenthesizedLambdaExpressionTest() + { + // TODO: fix this test when bug with simplifier failing to find correct node is fixed + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + var action = () => + { + $$ + }; + } + } + """, """ + class Program + { + public void Method() + { + var action = () => + { + for (global::System.Int32 {|0:i|} = {|1:(length)|} - (1); {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + }; + } + } + """); + } + + [Fact] + public async Task TryToProduceVarWithSpecificCodeStyleTest() + { + // In non-inline reversed for snippet type of expression `length - 1` is unknown, + // so it cannot be simplified to `var`. Therefore having explicit `int` type here is expected + await VerifySnippetAsync(""" + class Program + { + public void Method() + { + $$ + } + } + """, """ + class Program + { + public void Method() + { + for (int {|0:i|} = {|1:length|} - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + """, + editorconfig: """ + root = true + + [*] + csharp_style_var_for_built_in_types = true + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInlineReversedForSnippetInMethodTest(string inlineExpressionType) + { + await VerifySnippetAsync($$""" + class Program + { + public void Method({{inlineExpressionType}} l) + { + l.$$ + } + } + """, $$""" + class Program + { + public void Method({{inlineExpressionType}} l) + { + for ({{inlineExpressionType}} {|0:i|} = l - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInlineReversedForSnippetInGlobalContextTest(string inlineExpressionType) + { + await VerifySnippetAsync($$""" + {{inlineExpressionType}} l; + l.$$ + """, $$""" + {{inlineExpressionType}} l; + for ({{inlineExpressionType}} {|0:i|} = l - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.NotIntegerTypesWithoutLengthOrCountProperty), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineReversedForSnippetForIncorrectTypeInMethodTest(string inlineExpressionType) + { + await VerifySnippetIsAbsentAsync($$""" + class Program + { + public void Method({{inlineExpressionType}} l) + { + l.$$ + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.NotIntegerTypesWithoutLengthOrCountProperty), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineReversedForSnippetForIncorrectTypeInGlobalContextTest(string inlineExpressionType) + { + await VerifySnippetIsAbsentAsync($$""" + {{inlineExpressionType}} l; + l.$$ + """); + } + + [Fact] + public async Task ProduceVarWithSpecificCodeStyleForInlineSnippetTest() + { + await VerifySnippetAsync(""" + class Program + { + public void Method(int l) + { + l.$$ + } + } + """, """ + class Program + { + public void Method(int l) + { + for (var {|0:i|} = l - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + """, + editorconfig: """ + root = true + + [*] + csharp_style_var_for_built_in_types = true + """); + } + + [Fact] + public async Task NoInlineReversedForSnippetNotDirectlyExpressionStatementTest() + { + await VerifySnippetIsAbsentAsync(""" + class Program + { + public void Method(int l) + { + System.Console.WriteLine(l.$$); + } + } + """); + } + + [Theory] + [InlineData("// comment")] + [InlineData("/* comment */")] + [InlineData("#region test")] + public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest1(string trivia) + { + await VerifySnippetAsync($$""" + class Program + { + void M(int len) + { + {{trivia}} + len.$$ + } + } + """, $$""" + class Program + { + void M(int len) + { + {{trivia}} + for (int {|0:i|} = len - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + """); + } + + [Theory] + [InlineData("#if true")] + [InlineData("#pragma warning disable CS0108")] + [InlineData("#nullable enable")] + public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInMethodTest2(string trivia) + { + await VerifySnippetAsync($$""" + class Program + { + void M(int len) + { + {{trivia}} + len.$$ + } + } + """, $$""" + class Program + { + void M(int len) + { + {{trivia}} + for (int {|0:i|} = len - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + """); + } + + [Theory] + [InlineData("// comment")] + [InlineData("/* comment */")] + public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest1(string trivia) + { + await VerifySnippetAsync($$""" + {{trivia}} + 10.$$ + """, $$""" + {{trivia}} + for (int {|0:i|} = 10 - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + """); + } + + [Theory] + [InlineData("#region test")] + [InlineData("#if true")] + [InlineData("#pragma warning disable CS0108")] + [InlineData("#nullable enable")] + public async Task CorrectlyDealWithLeadingTriviaInInlineSnippetInGlobalStatementTest2(string trivia) + { + await VerifySnippetAsync($$""" + {{trivia}} + 10.$$ + """, $$""" + + {{trivia}} + for (int {|0:i|} = 10 - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInlineReversedForSnippetWhenDottingBeforeContextualKeywordTest1(string intType) + { + await VerifySnippetAsync($$""" + using System.Collections.Generic; + + class C + { + void M({{intType}} @int) + { + @int.$$ + var a = 0; + } + } + """, $$""" + using System.Collections.Generic; + + class C + { + void M({{intType}} @int) + { + for ({{intType}} {|0:i|} = @int - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + var a = 0; + } + } + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInlineReversedForSnippetWhenDottingBeforeContextualKeywordTest2(string intType) + { + await VerifySnippetAsync($$""" + using System.Collections.Generic; + + class C + { + async void M({{intType}} @int, Task t) + { + @int.$$ + await t; + } + } + """, $$""" + using System.Collections.Generic; + + class C + { + async void M({{intType}} @int, Task t) + { + for ({{intType}} {|0:i|} = @int - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + await t; + } + } + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69598")] + [InlineData("Task")] + [InlineData("Task")] + [InlineData("System.Threading.Tasks.Task")] + public async Task InsertInlineReversedForSnippetWhenDottingBeforeNameSyntaxTest(string nameSyntax) + { + await VerifySnippetAsync($$""" + using System.Threading.Tasks; + using System.Collections.Generic; + + class C + { + void M(int @int) + { + @int.$$ + {{nameSyntax}} t = null; + } + } + """, $$""" + using System.Threading.Tasks; + using System.Collections.Generic; + + class C + { + void M(int @int) + { + for (int {|0:i|} = @int - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + {{nameSyntax}} t = null; + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertInlineReversedForSnippetWhenDottingBeforeMemberAccessExpressionOnTheNextLineTest(string intType) + { + await VerifySnippetAsync($$""" + using System; + + class C + { + void M({{intType}} @int) + { + @int.$$ + Console.WriteLine(); + } + } + """, $$""" + using System; + + class C + { + void M({{intType}} @int) + { + for ({{intType}} {|0:i|} = @int - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + Console.WriteLine(); + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineReversedForSnippetWhenDottingBeforeMemberAccessExpressionOnTheSameLineTest(string intType) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M({{intType}} @int) + { + @int.$$ToString(); + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineReversedForSnippetWhenDottingBeforeContextualKeywordOnTheSameLineTest(string intType) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M({{intType}} @int) + { + @int.$$var a = 0; + } + } + """); + } + + [Theory] + [InlineData("int[]", "Length")] + [InlineData("Span", "Length")] + [InlineData("ReadOnlySpan", "Length")] + [InlineData("ImmutableArray", "Length")] + [InlineData("List", "Count")] + [InlineData("HashSet", "Count")] + [InlineData("Dictionary", "Count")] + [InlineData("ImmutableList", "Count")] + public async Task InsertInlineReversedForSnippetForCommonTypesWithLengthOrCountPropertyTest(string type, string propertyName) + { + await VerifySnippetAsync($$""" + using System; + using System.Collections.Generic; + using System.Collections.Immutable; + + public class C + { + void M({{type}} type) + { + type.$$ + } + } + """, $$""" + using System; + using System.Collections.Generic; + using System.Collections.Immutable; + + public class C + { + void M({{type}} type) + { + for (int {|0:i|} = type.{{propertyName}} - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + """, + referenceAssemblies: ReferenceAssemblies.Net.Net80); + } + + [Theory] + [CombinatorialData] + public async Task InsertInlineReversedForSnippetForTypeWithAccessibleLengthOrCountPropertyTest( + [CombinatorialValues("public", "internal", "protected internal")] string propertyAccessibility, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + {{propertyAccessibility}} int {{propertyName}} { get; } + } + """, $$""" + class C + { + void M(MyType type) + { + for (int {|0:i|} = type.{{propertyName}} - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + + public class MyType + { + {{propertyAccessibility}} int {{propertyName}} { get; } + } + """); + } + + [Theory] + [CombinatorialData] + public async Task InsertInlineReversedForSnippetForTypeWithAccessibleLengthOrCountPropertyGetterTest( + [CombinatorialValues("", "internal", "protected internal")] string getterAccessibility, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public int {{propertyName}} { {{getterAccessibility}} get; } + } + """, $$""" + class C + { + void M(MyType type) + { + for (int {|0:i|} = type.{{propertyName}} - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + + public class MyType + { + public int {{propertyName}} { {{getterAccessibility}} get; } + } + """); + } + + [Theory] + [CombinatorialData] + public async Task InsertInlineReversedForSnippetForTypesWithLengthOrCountPropertyOfDifferentIntegerTypesTest( + [CombinatorialValues("byte", "sbyte", "short", "ushort", "int", "uint", "long", "ulong", "nint", "nuint")] string integerType, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public {{integerType}} {{propertyName}} { get; } + } + """, $$""" + class C + { + void M(MyType type) + { + for ({{integerType}} {|0:i|} = type.{{propertyName}} - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + + public class MyType + { + public {{integerType}} {{propertyName}} { get; } + } + """); + } + + [Theory] + [InlineData("Length")] + [InlineData("Count")] + public async Task InsertInlineReversedForSnippetForTypeWithLengthOrCountPropertyInBaseClassTest(string propertyName) + { + await VerifySnippetAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType : MyTypeBase + { + } + + public class MyTypeBase + { + public int {{propertyName}} { get; } + } + """, $$""" + class C + { + void M(MyType type) + { + for (int {|0:i|} = type.{{propertyName}} - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + + public class MyType : MyTypeBase + { + } + + public class MyTypeBase + { + public int {{propertyName}} { get; } + } + """); + } + + [Theory] + [InlineData("Length")] + [InlineData("Count")] + public async Task NoInlineReversedForSnippetWhenLengthOrCountPropertyHasNoGetterTest(string propertyName) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public int {{propertyName}} { set { } } + } + """); + } + + [Theory] + [CombinatorialData] + public async Task NoInlineReversedForSnippetForInaccessibleLengthPropertyTest( + [CombinatorialValues("private", "protected", "private protected")] string propertyAccessibility, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + {{propertyAccessibility}} int {{propertyName}} { get; } + } + """); + } + + [Theory] + [CombinatorialData] + public async Task NoInlineReversedForSnippetForInaccessibleLengthOrCountPropertyGetterTest( + [CombinatorialValues("private", "protected", "private protected")] string getterAccessibility, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public int {{propertyName}} { {{getterAccessibility}} get; } + } + """); + } + + [Theory] + [CombinatorialData] + public async Task NoInlineReversedForSnippetForLengthPropertyOfIncorrectTypeTest( + [CombinatorialValues("object", "string", "System.DateTime", "System.Action")] string notIntegerType, + [CombinatorialValues("Length", "Count")] string propertyName) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public {{notIntegerType}} {{propertyName}} { get; } + } + """); + } + + [Fact] + public async Task NoInlineReversedForSnippetForTypeWithBothLengthAndCountPropertyTest() + { + await VerifySnippetIsAbsentAsync(""" + class C + { + void M(MyType type) + { + type.$$ + } + } + + public class MyType + { + public int Length { get; } + public int Count { get; } + } + """); + } + + [Theory] + [InlineData("MyType")] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineReversedForSnippetForTypeItselfTest(string validTypes) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M() + { + {{validTypes}}.$$ + } + } + + class MyType + { + public int Count => 0; + } + """); + } + + [Theory] + [InlineData("MyType")] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineReversedForSnippetForTypeItselfTest_Parenthesized(string validTypes) + { + await VerifySnippetIsAbsentAsync($$""" + class C + { + void M() + { + ({{validTypes}}).$$ + } + } + + class MyType + { + public int Count => 0; + } + """); + } + + [Theory] + [InlineData("MyType")] + [MemberData(nameof(CommonSnippetTestData.IntegerTypes), MemberType = typeof(CommonSnippetTestData))] + public async Task NoInlineReversedForSnippetForTypeItselfTest_BeforeContextualKeyword(string validTypes) + { + await VerifySnippetIsAbsentAsync($$""" + using System.Threading.Tasks; + + class C + { + async void M() + { + {{validTypes}}.$$ + await Task.Delay(10); + } + } + + class MyType + { + public int Count => 0; + } + """); + } + + [Fact] + public async Task InsertInlineReversedForSnippetForVariableNamedLikeTypeTest() + { + await VerifySnippetAsync(""" + class C + { + void M() + { + MyType MyType = default; + MyType.$$ + } + } + + class MyType + { + public int Length => 0; + } + """, """ + class C + { + void M() + { + MyType MyType = default; + for (int {|0:i|} = MyType.Length - 1; {|0:i|} >= 0; {|0:i|}--) + { + $$ + } + } + } + + class MyType + { + public int Length => 0; + } + """); + } +} diff --git a/src/Features/CSharpTest/Snippets/CSharpStructSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpStructSnippetProviderTests.cs new file mode 100644 index 0000000000000..39200d76aeefc --- /dev/null +++ b/src/Features/CSharpTest/Snippets/CSharpStructSnippetProviderTests.cs @@ -0,0 +1,419 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; + +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpStructSnippetProviderTests : AbstractCSharpSnippetProviderTests +{ + protected override string SnippetIdentifier => "struct"; + + [Fact] + public async Task InsertStructSnippetInBlockNamespaceTest() + { + await VerifySnippetAsync(""" + namespace Namespace + { + $$ + } + """, """ + namespace Namespace + { + struct {|0:MyStruct|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertStructSnippetInFileScopedNamespaceTest() + { + await VerifySnippetAsync(""" + namespace Namespace; + + $$ + """, """ + namespace Namespace; + + struct {|0:MyStruct|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertStructSnippetTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + struct {|0:MyStruct|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertStructTopLevelSnippetTest() + { + await VerifySnippetAsync(""" + System.Console.WriteLine(); + $$ + """, """ + System.Console.WriteLine(); + struct {|0:MyStruct|} + { + $$ + } + """); + } + + [Fact] + public async Task InsertStructSnippetInClassTest() + { + await VerifySnippetAsync(""" + class MyClass + { + $$ + } + """, """ + class MyClass + { + struct {|0:MyStruct|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertStructSnippetInRecordTest() + { + await VerifySnippetAsync(""" + record MyRecord + { + $$ + } + """, """ + record MyRecord + { + struct {|0:MyStruct|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertStructSnippetInStructTest() + { + await VerifySnippetAsync(""" + struct MyStruct + { + $$ + } + """, """ + struct MyStruct + { + struct {|0:MyStruct1|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertStructSnippetInInterfaceTest() + { + await VerifySnippetAsync(""" + interface MyInterface + { + $$ + } + """, """ + interface MyInterface + { + struct {|0:MyStruct|} + { + $$ + } + } + """); + } + + [Fact] + public async Task InsertStructSnippetWithModifiersTest() + { + await VerifySnippetAsync(""" + $$ + """, """ + public struct {|0:MyStruct|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Fact] + public async Task NoStructSnippetInEnumTest() + { + await VerifySnippetIsAbsentAsync(""" + enum MyEnum + { + $$ + } + """); + } + + [Fact] + public async Task NoStructSnippetInMethodTest() + { + await VerifySnippetIsAbsentAsync(""" + struct Program + { + public void Method() + { + $$ + } + } + """); + } + + [Fact] + public async Task NoStructSnippetInConstructorTest() + { + await VerifySnippetIsAbsentAsync(""" + struct Program + { + public Program() + { + $$ + } + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertStructSnippetAfterAccessibilityModifier(string modifier) + { + await VerifySnippetAsync($""" + {modifier} $$ + """, $$""" + {{modifier}} struct {|0:MyStruct|} + { + $$ + } + """); + } + + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task InsertStructSnippetAfterAccessibilityModifier_RequireAccessibilityModifiers(string modifier) + { + await VerifySnippetAsync($""" + {modifier} $$ + """, $$""" + {{modifier}} struct {|0:MyStruct|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Theory] + [InlineData("ref")] + [InlineData("readonly")] + [InlineData("unsafe")] + public async Task InsertStructSnippetAfterValidModifiersTest(string modifier) + { + await VerifySnippetAsync($""" + {modifier} $$ + """, $$""" + {{modifier}} struct {|0:MyStruct|} + { + $$ + } + """); + } + + [Theory] + [InlineData("abstract")] + [InlineData("sealed")] + [InlineData("static")] + public async Task NoStructSnippetAfterInvalidModifiersTest(string modifier) + { + await VerifySnippetIsAbsentAsync($""" + {modifier} $$ + """); + } + + [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] + public async Task NoAdditionalAccessibilityModifiersIfAfterPartialKeywordTest(string modifier) + { + await VerifySnippetAsync($""" + {modifier} partial $$ + """, $$""" + {{modifier}} partial struct {|0:MyStruct|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] + public async Task EnsureCorrectModifierOrderAfterPartialKeywordTest() + { + await VerifySnippetAsync(""" + partial $$ + """, """ + public partial struct {|0:MyStruct|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + """); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69600")] + public async Task EnsureCorrectModifierOrderAfterPartialKeywordTest_InvalidPreferredModifiersList() + { + await VerifySnippetAsync(""" + partial $$ + """, """ + public partial struct {|0:MyStruct|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + + csharp_preferred_modifier_order = invalid! + """); + } + + [Fact] + public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBeforeAllOthers() + { + await VerifySnippetAsync(""" + readonly ref $$ + """, """ + public readonly ref struct {|0:MyStruct|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + + csharp_preferred_modifier_order = public,readonly,ref + """); + } + + [Fact] + public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBeforeAllOthers_NotAllModifiersInTheList() + { + await VerifySnippetAsync(""" + readonly ref $$ + """, """ + public readonly ref struct {|0:MyStruct|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + + csharp_preferred_modifier_order = public,readonly + """); + } + + [Fact] + public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierBetweenOthers() + { + await VerifySnippetAsync(""" + readonly ref $$ + """, """ + readonly public ref struct {|0:MyStruct|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + + csharp_preferred_modifier_order = readonly,public,ref + """); + } + + [Fact] + public async Task EnsureCorrectModifierOrderFromOptionsTest_PublicModifierAfterAllOthers() + { + await VerifySnippetAsync(""" + readonly ref $$ + """, """ + readonly ref public struct {|0:MyStruct|} + { + $$ + } + """, + editorconfig: """ + root = true + + [*] + dotnet_style_require_accessibility_modifiers = always + + csharp_preferred_modifier_order = readonly,ref,public + """); + } +} diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpSvmSnippetCompletionProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpVoidMainSnippetProviderTests.cs similarity index 57% rename from src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpSvmSnippetCompletionProviderTests.cs rename to src/Features/CSharpTest/Snippets/CSharpVoidMainSnippetProviderTests.cs index 2c87172c08f06..1303b298e4f97 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/Snippets/CSharpSvmSnippetCompletionProviderTests.cs +++ b/src/Features/CSharpTest/Snippets/CSharpVoidMainSnippetProviderTests.cs @@ -4,46 +4,46 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; using Xunit; -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets; +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; -public class CSharpSvmSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests +[Trait(Traits.Feature, Traits.Features.Snippets)] +public sealed class CSharpVoidMainSnippetProviderTests : AbstractCSharpSnippetProviderTests { - protected override string ItemToCommit => "svm"; + protected override string SnippetIdentifier => "svm"; - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] - public async Task TestMissingInNamespace() + [Fact] + public async Task TestMissingInBlockNamespace() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" namespace Test { $$ } - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingInFileScopedNamespace() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" namespace Test; $$ - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingInTopLevelContext() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" System.Console.WriteLine(); $$ - """, ItemToCommit); + """); } - [WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)] + [Theory] [InlineData("class")] [InlineData("struct")] [InlineData("interface")] @@ -52,12 +52,12 @@ await VerifyItemIsAbsentAsync(""" [InlineData("record struct")] public async Task TestInsertSnippetInType(string type) { - await VerifyCustomCommitProviderAsync($$""" + await VerifySnippetAsync($$""" {{type}} Program { $$ } - """, ItemToCommit, $$""" + """, $$""" {{type}} Program { static void Main(string[] args) @@ -68,21 +68,21 @@ static void Main(string[] args) """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingInEnum() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" enum MyEnum { $$ } - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingInMethod() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" class Program { void M() @@ -90,13 +90,13 @@ void M() $$ } } - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingInConstructor() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" class Program { public Program() @@ -104,23 +104,19 @@ public Program() $$ } } - """, ItemToCommit); + """); } - [WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)] - [InlineData("public")] - [InlineData("private")] - [InlineData("protected")] - [InlineData("private protected")] - [InlineData("protected internal")] + [Theory] + [MemberData(nameof(CommonSnippetTestData.AllAccessibilityModifiers), MemberType = typeof(CommonSnippetTestData))] public async Task TestInsertSnippetAfterAccessibilityModifier(string modifier) { - await VerifyCustomCommitProviderAsync($$""" + await VerifySnippetAsync($$""" class Program { {{modifier}} $$ } - """, ItemToCommit, $$""" + """, $$""" class Program { {{modifier}} static void Main(string[] args) @@ -131,7 +127,7 @@ class Program """); } - [WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)] + [Theory] [InlineData("static")] [InlineData("virtual")] [InlineData("abstract")] @@ -139,37 +135,37 @@ class Program [InlineData("file")] public async Task TestMissingAfterIncorrectModifiers(string modifier) { - await VerifyItemIsAbsentAsync($$""" + await VerifySnippetIsAbsentAsync($$""" class Program { {{modifier}} $$ } - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingIfAnotherMemberWithNameMainExists() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" class Program { public int Main => 0; $$ } - """, ItemToCommit); + """); } - [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [Fact] public async Task TestMissingIfTopLevelStatementsArePresent() { - await VerifyItemIsAbsentAsync(""" + await VerifySnippetIsAbsentAsync(""" System.Console.WriteLine(); class Program { $$ } - """, ItemToCommit); + """); } } diff --git a/src/Features/CSharpTest/Snippets/CSharpWhileSnippetProviderTests.cs b/src/Features/CSharpTest/Snippets/CSharpWhileSnippetProviderTests.cs new file mode 100644 index 0000000000000..7d175ed42f969 --- /dev/null +++ b/src/Features/CSharpTest/Snippets/CSharpWhileSnippetProviderTests.cs @@ -0,0 +1,10 @@ +// 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.CSharp.UnitTests.Snippets; + +public sealed class CSharpWhileSnippetProviderTests : AbstractCSharpConditionalBlockSnippetProviderTests +{ + protected override string SnippetIdentifier => "while"; +} diff --git a/src/Features/CSharpTest/Snippets/CommonSnippetTestData.cs b/src/Features/CSharpTest/Snippets/CommonSnippetTestData.cs new file mode 100644 index 0000000000000..9cbd0e10a127a --- /dev/null +++ b/src/Features/CSharpTest/Snippets/CommonSnippetTestData.cs @@ -0,0 +1,51 @@ +// 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 Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Snippets; + +public static class CommonSnippetTestData +{ + public static TheoryData IntegerTypes => new() + { + "byte", + "sbyte", + "short", + "ushort", + "int", + "uint", + "long", + "ulong", + "nint", + "nuint", + }; + + public static TheoryData NotIntegerTypesWithoutLengthOrCountProperty => new() + { + "object", + "System.DateTime", + "System.Action", + }; + + public static TheoryData AllAccessibilityModifiers => new() + { + "public", + "private", + "protected", + "internal", + "private protected", + "protected internal", + }; + + public static TheoryData CommonEnumerableTypes => new() + { + "string", + "System.Collections.Generic.List", + "int[]", + "System.Collections.Generic.IEnumerable", + "System.Collections.ArrayList", + "System.Collections.IEnumerable", + }; +} diff --git a/src/Features/CSharpTest/Testing/CSharpTestMethodFinderTests.cs b/src/Features/CSharpTest/Testing/CSharpTestMethodFinderTests.cs index e6dd93f8af36b..a868be0be5d08 100644 --- a/src/Features/CSharpTest/Testing/CSharpTestMethodFinderTests.cs +++ b/src/Features/CSharpTest/Testing/CSharpTestMethodFinderTests.cs @@ -549,7 +549,7 @@ public class TestMethodAttribute : Attribute { } private static async Task TestAsync(string code, string testAttributeDefinitionsCode, params string[] expectedTestNames) { - var workspace = TestWorkspace.CreateCSharp(new[] { code, testAttributeDefinitionsCode }); + var workspace = TestWorkspace.CreateCSharp([code, testAttributeDefinitionsCode]); var testDocument = workspace.Documents.First(); var span = testDocument.CursorPosition != null ? new TextSpan(testDocument.CursorPosition.Value, 0) : testDocument.SelectedSpans.Single(); @@ -563,7 +563,7 @@ private static async Task TestAsync(string code, string testAttributeDefinitions private static async Task TestMatchAsync(string code, string testAttributeDefinitionsCode, params string[] expectedTestNames) { - var workspace = TestWorkspace.CreateCSharp(new[] { code, testAttributeDefinitionsCode }); + var workspace = TestWorkspace.CreateCSharp([code, testAttributeDefinitionsCode]); var testDocument = workspace.Documents.First(); var span = testDocument.CursorPosition != null ? new TextSpan(testDocument.CursorPosition.Value, 0) : testDocument.SelectedSpans.Single(); diff --git a/src/Features/CSharpTest/UseExpressionBodyForLambda/UseExpressionBodyForLambdasRefactoringTests.cs b/src/Features/CSharpTest/UseExpressionBodyForLambda/UseExpressionBodyForLambdasRefactoringTests.cs index ebe2273829beb..fed4ea0b006aa 100644 --- a/src/Features/CSharpTest/UseExpressionBodyForLambda/UseExpressionBodyForLambdasRefactoringTests.cs +++ b/src/Features/CSharpTest/UseExpressionBodyForLambda/UseExpressionBodyForLambdasRefactoringTests.cs @@ -11,12 +11,13 @@ using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseExpressionBody; [Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] -public class UseExpressionBodyForLambdasRefactoringTests : AbstractCSharpCodeActionTest_NoEditor +public sealed class UseExpressionBodyForLambdasRefactoringTests : AbstractCSharpCodeActionTest_NoEditor { protected override CodeRefactoringProvider CreateCodeRefactoringProvider(TestWorkspace workspace, TestParameters parameters) => new UseExpressionBodyForLambdaCodeRefactoringProvider(); @@ -208,4 +209,20 @@ void Goo() } """, parameters: new TestParameters(options: UseExpressionBody)); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74137")] + public async Task TestNotWithPreprocessorDirectives() + { + await TestMissingAsync( + """ + app.UseSwaggerUI(c [||]=> + { + #if DEBUG + c.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1"); + #else + c.SwaggerEndpoint("/api/swagger/v1/swagger.json", "API V1"); + #endif + }); + """, parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + } } diff --git a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParameterResult.cs b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParameterResult.cs index f9264b5986113..349181b4146c2 100644 --- a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParameterResult.cs +++ b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParameterResult.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.AddConstructorParametersFromMembers; -internal partial class AddConstructorParametersFromMembersCodeRefactoringProvider +internal sealed partial class AddConstructorParametersFromMembersCodeRefactoringProvider { private readonly struct AddConstructorParameterResult( ImmutableArray requiredParameterActions, diff --git a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs index d10d4e82f76f6..c51e3806dcc8d 100644 --- a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs +++ b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.AddConstructorParametersFromMembers; -internal partial class AddConstructorParametersFromMembersCodeRefactoringProvider +internal sealed partial class AddConstructorParametersFromMembersCodeRefactoringProvider { private sealed class AddConstructorParametersCodeAction( Document document, diff --git a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.ConstructorCandidate.cs b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.ConstructorCandidate.cs index 080c0e3fd8c23..3a6d2fa46f82e 100644 --- a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.ConstructorCandidate.cs +++ b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.ConstructorCandidate.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.AddConstructorParametersFromMembers; -internal partial class AddConstructorParametersFromMembersCodeRefactoringProvider +internal sealed partial class AddConstructorParametersFromMembersCodeRefactoringProvider { private readonly struct ConstructorCandidate(IMethodSymbol constructor, ImmutableArray missingMembers, ImmutableArray missingParameters) { diff --git a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.State.cs b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.State.cs index 9eb44f2e1aae8..508f9808a7f25 100644 --- a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.State.cs +++ b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.State.cs @@ -15,9 +15,9 @@ namespace Microsoft.CodeAnalysis.AddConstructorParametersFromMembers; -internal partial class AddConstructorParametersFromMembersCodeRefactoringProvider +internal sealed partial class AddConstructorParametersFromMembersCodeRefactoringProvider { - private class State + private sealed class State { public ImmutableArray ConstructorCandidates { get; private set; } diff --git a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs index 4de2c54743918..d4927fd483caf 100644 --- a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs @@ -26,7 +26,7 @@ namespace Microsoft.CodeAnalysis.AddConstructorParametersFromMembers; [ExtensionOrder(After = PredefinedCodeRefactoringProviderNames.GenerateConstructorFromMembers, Before = PredefinedCodeRefactoringProviderNames.GenerateOverrides)] [IntentProvider(WellKnownIntents.AddConstructorParameter, LanguageNames.CSharp)] -internal partial class AddConstructorParametersFromMembersCodeRefactoringProvider : AbstractGenerateFromMembersCodeRefactoringProvider, IIntentProvider +internal sealed partial class AddConstructorParametersFromMembersCodeRefactoringProvider : AbstractGenerateFromMembersCodeRefactoringProvider, IIntentProvider { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs index e6839321d88fc..ba770d65ba71c 100644 --- a/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs @@ -125,12 +125,11 @@ private async Task ApplyAsync(Document document, TTypeDeclarationSynta { attributeArgument = generator.InterpolatedStringExpression( generator.CreateInterpolatedStringStartToken(isVerbatim: false), - new SyntaxNode[] - { + [ generator.InterpolatedStringText(generator.InterpolatedStringTextToken("{{", "{{")), generator.Interpolation(generator.NameOfExpression(generator.IdentifierName(DebuggerDisplayMethodName))), generator.InterpolatedStringText(generator.InterpolatedStringTextToken("(),nq}}", "(),nq}}")), - }, + ], generator.CreateInterpolatedStringEndToken()); } else diff --git a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs index 8d47511a3bf60..3027288b8bbb8 100644 --- a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs @@ -187,7 +187,6 @@ protected sealed override async Task FixAllAsync( Document document, ImmutableArray fixAllSpans, SyntaxEditor editor, - CodeActionOptionsProvider optionsProvider, string? equivalenceKey, CancellationToken cancellationToken) { diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index e1022a0b6262a..a4e6a7b315b60 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -57,9 +57,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var addImportService = document.GetRequiredLanguageService(); var services = document.Project.Solution.Services; - - var codeActionOptions = context.Options.GetOptions(document.Project.Services); - var searchOptions = codeActionOptions.SearchOptions; + var searchOptions = await document.GetSymbolSearchOptionsAsync(cancellationToken).ConfigureAwait(false); var symbolSearchService = _symbolSearchService ?? services.GetRequiredService(); diff --git a/src/Features/Core/Portable/AddImport/CodeActions/InstallWithPackageManagerCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/InstallWithPackageManagerCodeAction.cs index 1556893fb5bec..25984050cfc0b 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/InstallWithPackageManagerCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/InstallWithPackageManagerCodeAction.cs @@ -31,7 +31,7 @@ protected override Task> ComputeOperationsAs new InstallWithPackageManagerCodeActionOperation(_installerService, _packageName))); } - private class InstallWithPackageManagerCodeActionOperation( + private sealed class InstallWithPackageManagerCodeActionOperation( IPackageInstallerService installerService, string packageName) : CodeActionOperation { diff --git a/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs index 03332599440dc..c1cee271e6915 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.AddImport; internal abstract partial class AbstractAddImportFeatureService { - private class MetadataSymbolReferenceCodeAction : SymbolReferenceCodeAction + private sealed class MetadataSymbolReferenceCodeAction : SymbolReferenceCodeAction { /// /// This code action only works by adding a reference to a metadata dll. As such, it requires a non diff --git a/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs index d001735f17c77..30318b4a371b2 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs @@ -18,7 +18,7 @@ internal abstract partial class AbstractAddImportFeatureService - private class ProjectSymbolReferenceCodeAction : SymbolReferenceCodeAction + private sealed class ProjectSymbolReferenceCodeAction : SymbolReferenceCodeAction { /// /// This code action may or may not add a project reference. If it does, it requires a non document change diff --git a/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs b/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs index f8b44b74dd6e0..36b9e16ef649a 100644 --- a/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs +++ b/src/Features/Core/Portable/AddImport/References/AssemblyReference.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.AddImport; internal abstract partial class AbstractAddImportFeatureService { - private partial class AssemblyReference( + private sealed partial class AssemblyReference( AbstractAddImportFeatureService provider, SearchResult searchResult, ReferenceAssemblyWithTypeResult referenceAssemblyWithType) : Reference(provider, searchResult) diff --git a/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs b/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs index 85489d2dd52c5..fd7ea5e5b8a51 100644 --- a/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs +++ b/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.AddImport; internal abstract partial class AbstractAddImportFeatureService { - private partial class MetadataSymbolReference( + private sealed partial class MetadataSymbolReference( AbstractAddImportFeatureService provider, SymbolResult symbolResult, ProjectId referenceProjectId, diff --git a/src/Features/Core/Portable/AddImport/References/PackageReference.cs b/src/Features/Core/Portable/AddImport/References/PackageReference.cs index 3e49e117a256d..cf4d197ada0bc 100644 --- a/src/Features/Core/Portable/AddImport/References/PackageReference.cs +++ b/src/Features/Core/Portable/AddImport/References/PackageReference.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.AddImport; internal abstract partial class AbstractAddImportFeatureService { - private partial class PackageReference( + private sealed partial class PackageReference( AbstractAddImportFeatureService provider, SearchResult searchResult, string source, diff --git a/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs b/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs index 28ebd21bafee5..d3244b60ba256 100644 --- a/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs +++ b/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs @@ -24,7 +24,7 @@ internal abstract partial class AbstractAddImportFeatureService - private partial class ProjectSymbolReference( + private sealed partial class ProjectSymbolReference( AbstractAddImportFeatureService provider, SymbolResult symbolResult, Project project) : SymbolReference(provider, symbolResult) diff --git a/src/Features/Core/Portable/AddImport/SearchScopes/AllSymbolsProjectSearchScope.cs b/src/Features/Core/Portable/AddImport/SearchScopes/AllSymbolsProjectSearchScope.cs index 7248a18c3153d..e9ca8dc3ee3b9 100644 --- a/src/Features/Core/Portable/AddImport/SearchScopes/AllSymbolsProjectSearchScope.cs +++ b/src/Features/Core/Portable/AddImport/SearchScopes/AllSymbolsProjectSearchScope.cs @@ -16,7 +16,7 @@ internal abstract partial class AbstractAddImportFeatureService - private class AllSymbolsProjectSearchScope( + private sealed class AllSymbolsProjectSearchScope( AbstractAddImportFeatureService provider, Project project, bool exact) : ProjectSearchScope(provider, project, exact) diff --git a/src/Features/Core/Portable/AddImport/SearchScopes/MetadataSymbolsSearchScope.cs b/src/Features/Core/Portable/AddImport/SearchScopes/MetadataSymbolsSearchScope.cs index e0663ad885a0d..9ffc253c1c595 100644 --- a/src/Features/Core/Portable/AddImport/SearchScopes/MetadataSymbolsSearchScope.cs +++ b/src/Features/Core/Portable/AddImport/SearchScopes/MetadataSymbolsSearchScope.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.AddImport; internal abstract partial class AbstractAddImportFeatureService { - private class MetadataSymbolsSearchScope( + private sealed class MetadataSymbolsSearchScope( AbstractAddImportFeatureService provider, Project assemblyProject, IAssemblySymbol assembly, diff --git a/src/Features/Core/Portable/AddImport/SearchScopes/SourceSymbolsProjectSearchScope.cs b/src/Features/Core/Portable/AddImport/SearchScopes/SourceSymbolsProjectSearchScope.cs index 456f38ab8eaea..e07eb96de9244 100644 --- a/src/Features/Core/Portable/AddImport/SearchScopes/SourceSymbolsProjectSearchScope.cs +++ b/src/Features/Core/Portable/AddImport/SearchScopes/SourceSymbolsProjectSearchScope.cs @@ -19,7 +19,7 @@ internal abstract partial class AbstractAddImportFeatureService - private class SourceSymbolsProjectSearchScope( + private sealed class SourceSymbolsProjectSearchScope( AbstractAddImportFeatureService provider, ConcurrentDictionary> projectToAssembly, Project project, bool ignoreCase) : ProjectSearchScope(provider, project, ignoreCase) diff --git a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs index 9755b7d2d1790..b9880b8c5d876 100644 --- a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs +++ b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder.cs @@ -24,7 +24,7 @@ namespace Microsoft.CodeAnalysis.AddImport; internal abstract partial class AbstractAddImportFeatureService { - private partial class SymbolReferenceFinder + private sealed partial class SymbolReferenceFinder { private const string AttributeSuffix = nameof(Attribute); @@ -571,7 +571,7 @@ private async Task> GetReferencesForExtensionMet return GetNamespaceSymbolReferences(searchScope, namespaceSymbols); } - protected bool ExpressionBinds( + private bool ExpressionBinds( TSimpleNameSyntax nameNode, bool checkForExtensionMethods, CancellationToken cancellationToken) { // See if the name binds to something other then the error type. If it does, there's nothing further we need to do. diff --git a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs index e44f84af36d3a..79f101ba69054 100644 --- a/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs +++ b/src/Features/Core/Portable/AddImport/SymbolReferenceFinder_PackageAssemblySearch.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.AddImport; internal abstract partial class AbstractAddImportFeatureService { - private partial class SymbolReferenceFinder + private sealed partial class SymbolReferenceFinder { internal async Task FindNugetOrReferenceAssemblyReferencesAsync( ConcurrentQueue allReferences, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/AddMissingReference/AbstractAddMissingReferenceCodeFixProvider.cs b/src/Features/Core/Portable/AddMissingReference/AbstractAddMissingReferenceCodeFixProvider.cs index 549182e4ffa03..f94b609e766f3 100644 --- a/src/Features/Core/Portable/AddMissingReference/AbstractAddMissingReferenceCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddMissingReference/AbstractAddMissingReferenceCodeFixProvider.cs @@ -20,16 +20,6 @@ namespace Microsoft.CodeAnalysis.AddMissingReference; internal abstract partial class AbstractAddMissingReferenceCodeFixProvider : AbstractAddPackageCodeFixProvider { - /// - /// Values for these parameters can be provided (during testing) for mocking purposes. - /// - protected AbstractAddMissingReferenceCodeFixProvider( - IPackageInstallerService? packageInstallerService = null, - ISymbolSearchService? symbolSearchService = null) - : base(packageInstallerService, symbolSearchService) - { - } - protected override bool IncludePrerelease => false; public override FixAllProvider? GetFixAllProvider() diff --git a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs index c6dd016be4013..2cdf37758dd8d 100644 --- a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; @@ -18,25 +16,14 @@ namespace Microsoft.CodeAnalysis.AddPackage; +/// +/// Values for parameters can be provided (during testing) for mocking purposes. +/// internal abstract partial class AbstractAddPackageCodeFixProvider : CodeFixProvider { - private readonly IPackageInstallerService _packageInstallerService; - private readonly ISymbolSearchService _symbolSearchService; - - /// - /// Values for these parameters can be provided (during testing) for mocking purposes. - /// - protected AbstractAddPackageCodeFixProvider( - IPackageInstallerService packageInstallerService, - ISymbolSearchService symbolSearchService) - { - _packageInstallerService = packageInstallerService; - _symbolSearchService = symbolSearchService; - } - protected abstract bool IncludePrerelease { get; } - public abstract override FixAllProvider GetFixAllProvider(); + public abstract override FixAllProvider? GetFixAllProvider(); protected async Task> GetAddPackagesCodeActionsAsync( CodeFixContext context, ISet assemblyNames) @@ -46,31 +33,35 @@ protected async Task> GetAddPackagesCodeActionsAsync( var workspaceServices = document.Project.Solution.Services; - var symbolSearchService = _symbolSearchService ?? workspaceServices.GetService(); - var installerService = _packageInstallerService ?? workspaceServices.GetService(); + if (workspaceServices.GetService() is not { } symbolSearchService || + workspaceServices.GetService() is not { } installerService || + !installerService.IsEnabled(document.Project.Id)) + { + return []; + } + + var options = await document.GetSymbolSearchOptionsAsync(cancellationToken).ConfigureAwait(false); + if (!options.SearchNuGetPackages) + { + return []; + } var codeActions = ArrayBuilder.GetInstance(); - if (symbolSearchService != null && - installerService != null && - context.Options.GetOptions(document.Project.Services).SearchOptions.SearchNuGetPackages && - installerService.IsEnabled(document.Project.Id)) + var packageSources = PackageSourceHelper.GetPackageSources(installerService.TryGetPackageSources()); + + foreach (var (name, source) in packageSources) { - var packageSources = PackageSourceHelper.GetPackageSources(installerService.TryGetPackageSources()); + cancellationToken.ThrowIfCancellationRequested(); + + var sortedPackages = await FindMatchingPackagesAsync( + name, symbolSearchService, + assemblyNames, cancellationToken).ConfigureAwait(false); - foreach (var (name, source) in packageSources) + foreach (var package in sortedPackages) { - cancellationToken.ThrowIfCancellationRequested(); - - var sortedPackages = await FindMatchingPackagesAsync( - name, symbolSearchService, - assemblyNames, cancellationToken).ConfigureAwait(false); - - foreach (var package in sortedPackages) - { - codeActions.Add(new InstallPackageParentCodeAction( - installerService, source, - package.PackageName, IncludePrerelease, document)); - } + codeActions.Add(new InstallPackageParentCodeAction( + installerService, source, + package.PackageName, IncludePrerelease, document)); } } diff --git a/src/Features/Core/Portable/AddPackage/AbstractAddSpecificPackageCodeFixProvider.cs b/src/Features/Core/Portable/AddPackage/AbstractAddSpecificPackageCodeFixProvider.cs index f3bc83dce9071..ddebcbe127d78 100644 --- a/src/Features/Core/Portable/AddPackage/AbstractAddSpecificPackageCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddPackage/AbstractAddSpecificPackageCodeFixProvider.cs @@ -17,10 +17,7 @@ internal abstract partial class AbstractAddSpecificPackageCodeFixProvider : Abst /// /// Values for these parameters can be provided (during testing) for mocking purposes. /// - protected AbstractAddSpecificPackageCodeFixProvider( - IPackageInstallerService packageInstallerService = null, - ISymbolSearchService symbolSearchService = null) - : base(packageInstallerService, symbolSearchService) + protected AbstractAddSpecificPackageCodeFixProvider() { } diff --git a/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs b/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs index b42717f4769bf..5d46e6058545c 100644 --- a/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs +++ b/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.AddPackage; /// navigate through, and we don't want our child items confusingly being added to the /// top level light-bulb where it's not clear what effect they would have if invoked. /// -internal class InstallPackageParentCodeAction( +internal sealed class InstallPackageParentCodeAction( IPackageInstallerService installerService, string source, string packageName, diff --git a/src/Features/Core/Portable/AddPackage/InstallWithPackageManagerCodeAction.cs b/src/Features/Core/Portable/AddPackage/InstallWithPackageManagerCodeAction.cs index a60e4bcabe987..3e2e26bc7c043 100644 --- a/src/Features/Core/Portable/AddPackage/InstallWithPackageManagerCodeAction.cs +++ b/src/Features/Core/Portable/AddPackage/InstallWithPackageManagerCodeAction.cs @@ -28,7 +28,7 @@ protected override Task> ComputeOperationsAs new InstallWithPackageManagerCodeActionOperation(this))); } - private class InstallWithPackageManagerCodeActionOperation( + private sealed class InstallWithPackageManagerCodeActionOperation( InstallWithPackageManagerCodeAction codeAction) : CodeActionOperation { private readonly InstallWithPackageManagerCodeAction _codeAction = codeAction; diff --git a/src/Features/Core/Portable/BraceCompletion/ExportBraceCompletionServiceAttribute.cs b/src/Features/Core/Portable/BraceCompletion/ExportBraceCompletionServiceAttribute.cs index cc81d078452f9..ac3103a43eb40 100644 --- a/src/Features/Core/Portable/BraceCompletion/ExportBraceCompletionServiceAttribute.cs +++ b/src/Features/Core/Portable/BraceCompletion/ExportBraceCompletionServiceAttribute.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.BraceCompletion; [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] -internal class ExportBraceCompletionServiceAttribute(string language) : ExportAttribute(typeof(IBraceCompletionService)) +internal sealed class ExportBraceCompletionServiceAttribute(string language) : ExportAttribute(typeof(IBraceCompletionService)) { public string Language { get; } = language ?? throw new ArgumentNullException(nameof(language)); } diff --git a/src/Features/Core/Portable/BraceMatching/BraceMatchingService.cs b/src/Features/Core/Portable/BraceMatching/BraceMatchingService.cs index 89f7cdcc321ee..7fd6768603f65 100644 --- a/src/Features/Core/Portable/BraceMatching/BraceMatchingService.cs +++ b/src/Features/Core/Portable/BraceMatching/BraceMatchingService.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.BraceMatching; [Export(typeof(IBraceMatchingService)), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal class BraceMatchingService( +internal sealed class BraceMatchingService( [ImportMany] IEnumerable> braceMatchers) : IBraceMatchingService { private readonly ImmutableArray> _braceMatchers = braceMatchers.ToImmutableArray(); diff --git a/src/Features/Core/Portable/BraceMatching/ExportEmbeddedLanguageBraceMatcherAttribute.cs b/src/Features/Core/Portable/BraceMatching/ExportEmbeddedLanguageBraceMatcherAttribute.cs index 1a9a1fa50a4e3..ba1c901983032 100644 --- a/src/Features/Core/Portable/BraceMatching/ExportEmbeddedLanguageBraceMatcherAttribute.cs +++ b/src/Features/Core/Portable/BraceMatching/ExportEmbeddedLanguageBraceMatcherAttribute.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.BraceMatching; /// /// Use this attribute to export a . /// -internal class ExportEmbeddedLanguageBraceMatcherAttribute( +internal sealed class ExportEmbeddedLanguageBraceMatcherAttribute( string name, string[] languages, bool supportsUnannotatedAPIs, params string[] identifiers) : ExportEmbeddedLanguageFeatureServiceAttribute(typeof(IEmbeddedLanguageBraceMatcher), name, languages, supportsUnannotatedAPIs, identifiers) { public ExportEmbeddedLanguageBraceMatcherAttribute( diff --git a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureCodeRefactoringProvider.cs b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureCodeRefactoringProvider.cs index 33df06ae11ee0..ea2efa8abce62 100644 --- a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureCodeRefactoringProvider.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.ChangeSignature; [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.ChangeSignature), Shared] -internal class ChangeSignatureCodeRefactoringProvider : CodeRefactoringProvider +internal sealed class ChangeSignatureCodeRefactoringProvider : CodeRefactoringProvider { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] diff --git a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs index dede202ce5e56..e596ee072d155 100644 --- a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs +++ b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs @@ -382,7 +382,7 @@ private static async Task> FindChangeSignatureR var root = await doc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (root is null) { - throw new NotSupportedException(WorkspacesResources.Document_does_not_support_syntax_trees); + throw new NotSupportedException(WorkspaceExtensionsResources.Document_does_not_support_syntax_trees); } var nodes = nodesToUpdate[docId]; diff --git a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs index e4e149fe93e49..9d9371497fa00 100644 --- a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs +++ b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.ChangeSignature; -internal class ChangeSignatureCodeAction(AbstractChangeSignatureService changeSignatureService, ChangeSignatureAnalysisSucceededContext context) : CodeActionWithOptions +internal sealed class ChangeSignatureCodeAction(AbstractChangeSignatureService changeSignatureService, ChangeSignatureAnalysisSucceededContext context) : CodeActionWithOptions { private readonly AbstractChangeSignatureService _changeSignatureService = changeSignatureService; private readonly ChangeSignatureAnalysisSucceededContext _context = context; diff --git a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.cs b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.cs index 7a2eb58160c84..6232b66e14c85 100644 --- a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.cs +++ b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureTelemetryLogger.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.ChangeSignature; -internal class ChangeSignatureLogger +internal sealed class ChangeSignatureLogger { private const string Maximum = nameof(Maximum); private const string Minimum = nameof(Minimum); diff --git a/src/Features/Core/Portable/CodeFixes/CodeFixCollection.cs b/src/Features/Core/Portable/CodeFixes/CodeFixCollection.cs index f7b987bdfa94d..606674ac7c07e 100644 --- a/src/Features/Core/Portable/CodeFixes/CodeFixCollection.cs +++ b/src/Features/Core/Portable/CodeFixes/CodeFixCollection.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes; /// Represents a collection of es supplied by a given fix provider /// (such as or ). /// -internal class CodeFixCollection( +internal sealed class CodeFixCollection( object provider, TextSpan span, ImmutableArray fixes, diff --git a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs index 50f7f1eec0767..c618db13e848f 100644 --- a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes; -internal partial class FixMultipleCodeAction( +internal sealed partial class FixMultipleCodeAction( IFixAllState fixAllState, string title, string computingFixWaitDialogMessage) : AbstractFixAllCodeFixCodeAction(fixAllState, showPreviewChangesDialog: false) diff --git a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/IFixMultipleOccurrencesService.cs b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/IFixMultipleOccurrencesService.cs index 20fba9729c20a..68baeb8d06f0d 100644 --- a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/IFixMultipleOccurrencesService.cs +++ b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/IFixMultipleOccurrencesService.cs @@ -23,7 +23,6 @@ Solution GetFix( Workspace workspace, CodeFixProvider fixProvider, FixAllProvider fixAllProvider, - CodeActionOptionsProvider optionsProvider, string equivalenceKey, string waitDialogTitle, string waitDialogMessage, @@ -39,7 +38,6 @@ Solution GetFix( Workspace workspace, CodeFixProvider fixProvider, FixAllProvider fixAllProvider, - CodeActionOptionsProvider optionsProvider, string equivalenceKey, string waitDialogTitle, string waitDialogMessage, diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractSuppressionCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractSuppressionCodeAction.cs index 0b587c53739c0..e100dde757739 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractSuppressionCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.AbstractSuppressionCodeAction.cs @@ -6,18 +6,16 @@ namespace Microsoft.CodeAnalysis.CodeFixes.Suppression; -internal partial class AbstractSuppressionCodeFixProvider +internal abstract partial class AbstractSuppressionCodeFixProvider { internal abstract class AbstractSuppressionCodeAction : NestedSuppressionCodeAction { - private readonly AbstractSuppressionCodeFixProvider _fixer; - protected AbstractSuppressionCodeAction(AbstractSuppressionCodeFixProvider fixer, string title) : base(title) { - _fixer = fixer; + Fixer = fixer; } - protected AbstractSuppressionCodeFixProvider Fixer => _fixer; + protected AbstractSuppressionCodeFixProvider Fixer { get; } } } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs index 4c5dcd72e5d3f..74ad683824a18 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageCodeAction.cs @@ -20,7 +20,6 @@ internal sealed class GlobalSuppressMessageCodeAction( Project project, Diagnostic diagnostic, AbstractSuppressionCodeFixProvider fixer) : AbstractGlobalSuppressMessageCodeAction(fixer, project) { - private readonly ISymbol _targetSymbol = targetSymbol; private readonly INamedTypeSymbol _suppressMessageAttribute = suppressMessageAttribute; private readonly Diagnostic _diagnostic = diagnostic; @@ -33,12 +32,12 @@ protected override async Task GetChangedSuppressionDocumentAsync(Cance var options = await suppressionsDoc.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); suppressionsRoot = Fixer.AddGlobalSuppressMessageAttribute( - suppressionsRoot, _targetSymbol, _suppressMessageAttribute, _diagnostic, services, options, addImportsService, cancellationToken); + suppressionsRoot, TargetSymbol_TestOnly, _suppressMessageAttribute, _diagnostic, services, options, addImportsService, cancellationToken); return suppressionsDoc.WithSyntaxRoot(suppressionsRoot); } protected override string DiagnosticIdForEquivalenceKey => _diagnostic.Id; - internal ISymbol TargetSymbol_TestOnly => _targetSymbol; + internal ISymbol TargetSymbol_TestOnly { get; } = targetSymbol; } } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.IPragmaBasedCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.IPragmaBasedCodeAction.cs index 151e4c20645d2..ef72378420df2 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.IPragmaBasedCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.IPragmaBasedCodeAction.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes.Suppression; -internal partial class AbstractSuppressionCodeFixProvider +internal abstract partial class AbstractSuppressionCodeFixProvider { /// /// Suppression code action based on pragma add/remove/edit. diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.LocalSuppressMessageCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.LocalSuppressMessageCodeAction.cs index b54fd2b163f23..4639ed56525fe 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.LocalSuppressMessageCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.LocalSuppressMessageCodeAction.cs @@ -22,21 +22,20 @@ internal sealed class LocalSuppressMessageCodeAction( private readonly AbstractSuppressionCodeFixProvider _fixer = fixer; private readonly ISymbol _targetSymbol = targetSymbol; private readonly INamedTypeSymbol _suppressMessageAttribute = suppressMessageAttribute; - private readonly SyntaxNode _targetNode = targetNode; private readonly Document _document = document; private readonly Diagnostic _diagnostic = diagnostic; protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) { var newTargetNode = _fixer.AddLocalSuppressMessageAttribute( - _targetNode, _targetSymbol, _suppressMessageAttribute, _diagnostic); + TargetNode_TestOnly, _targetSymbol, _suppressMessageAttribute, _diagnostic); var root = await _document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var newRoot = root.ReplaceNode(_targetNode, newTargetNode); + var newRoot = root.ReplaceNode(TargetNode_TestOnly, newTargetNode); return _document.WithSyntaxRoot(newRoot); } protected override string DiagnosticIdForEquivalenceKey => _diagnostic.Id; - internal SyntaxNode TargetNode_TestOnly => _targetNode; + internal SyntaxNode TargetNode_TestOnly { get; } = targetNode; } } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaBatchFixHelpers.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaBatchFixHelpers.cs index dd7aab504f8e2..457c663b0e422 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaBatchFixHelpers.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaBatchFixHelpers.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes.Suppression; -internal partial class AbstractSuppressionCodeFixProvider +internal abstract partial class AbstractSuppressionCodeFixProvider { /// /// Helper methods for pragma suppression add/remove batch fixers. diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs index e0c7a073532e0..915b463b4dec2 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.PragmaHelpers.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes.Suppression; -internal partial class AbstractSuppressionCodeFixProvider +internal abstract partial class AbstractSuppressionCodeFixProvider { /// /// Helper methods for pragma based suppression code actions. diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs index 8c519f3b4459a..1e873e75fac13 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.RemoveSuppressionCodeAction_Pragma.cs @@ -22,7 +22,7 @@ internal abstract partial class RemoveSuppressionCodeAction /// /// Code action to edit/remove/add the pragma directives for removing diagnostic suppression. /// - private class PragmaRemoveAction : RemoveSuppressionCodeAction, IPragmaBasedCodeAction + private sealed class PragmaRemoveAction : RemoveSuppressionCodeAction, IPragmaBasedCodeAction { private readonly Document _document; private readonly SyntaxFormattingOptions _options; @@ -210,7 +210,7 @@ private async Task IsDiagnosticSuppressedBeforeLeadingPragmaAsync(int inde length: 1); var locationToCheck = Location.Create(tree, spanToCheck); var dummyDiagnosticWithLocationToCheck = Diagnostic.Create(_diagnostic.Descriptor, locationToCheck); - var effectiveDiagnostic = CompilationWithAnalyzers.GetEffectiveDiagnostics(new[] { dummyDiagnosticWithLocationToCheck }, model.Compilation).FirstOrDefault(); + var effectiveDiagnostic = CompilationWithAnalyzers.GetEffectiveDiagnostics([dummyDiagnosticWithLocationToCheck], model.Compilation).FirstOrDefault(); return effectiveDiagnostic == null || effectiveDiagnostic.IsSuppressed; } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs index 7afb14e30a060..5cc449b6d569c 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs @@ -253,7 +253,7 @@ private async Task> GetSuppressionsAsync( return result.ToImmutableAndFree(); } - internal class SuppressionTargetInfo + internal sealed class SuppressionTargetInfo { public ISymbol TargetSymbol { get; set; } public SyntaxToken StartToken { get; set; } diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/ExportConfigurationFixProviderAttribute.cs b/src/Features/Core/Portable/CodeFixes/Suppression/ExportConfigurationFixProviderAttribute.cs index f48ab5e57cf7d..ea31ad2864db4 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/ExportConfigurationFixProviderAttribute.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/ExportConfigurationFixProviderAttribute.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes; /// [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] -internal class ExportConfigurationFixProviderAttribute : ExportAttribute +internal sealed class ExportConfigurationFixProviderAttribute : ExportAttribute { /// /// The name of the . diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/WrapperCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Suppression/WrapperCodeFixProvider.cs index 027e2a48e2782..c6265f76b4724 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/WrapperCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/WrapperCodeFixProvider.cs @@ -14,26 +14,25 @@ namespace Microsoft.CodeAnalysis.CodeFixes.Suppression; internal sealed class WrapperCodeFixProvider(IConfigurationFixProvider suppressionFixProvider, IEnumerable diagnosticIds) : CodeFixProvider { private readonly ImmutableArray _originalDiagnosticIds = diagnosticIds.Distinct().ToImmutableArray(); - private readonly IConfigurationFixProvider _suppressionFixProvider = suppressionFixProvider; - public IConfigurationFixProvider SuppressionFixProvider => _suppressionFixProvider; + public IConfigurationFixProvider SuppressionFixProvider { get; } = suppressionFixProvider; public override ImmutableArray FixableDiagnosticIds => _originalDiagnosticIds; public override async Task RegisterCodeFixesAsync(CodeFixContext context) { - var diagnostics = context.Diagnostics.Where(_suppressionFixProvider.IsFixableDiagnostic); + var diagnostics = context.Diagnostics.Where(SuppressionFixProvider.IsFixableDiagnostic); var documentDiagnostics = diagnostics.Where(d => d.Location.IsInSource).ToImmutableArray(); if (!documentDiagnostics.IsEmpty) { - var suppressionFixes = await _suppressionFixProvider.GetFixesAsync(context.Document, context.Span, documentDiagnostics, context.CancellationToken).ConfigureAwait(false); + var suppressionFixes = await SuppressionFixProvider.GetFixesAsync(context.Document, context.Span, documentDiagnostics, context.CancellationToken).ConfigureAwait(false); RegisterSuppressionFixes(context, suppressionFixes); } var projectDiagnostics = diagnostics.Where(d => !d.Location.IsInSource).ToImmutableArray(); if (!projectDiagnostics.IsEmpty) { - var suppressionFixes = await _suppressionFixProvider.GetFixesAsync(context.Document.Project, projectDiagnostics, context.CancellationToken).ConfigureAwait(false); + var suppressionFixes = await SuppressionFixProvider.GetFixesAsync(context.Document.Project, projectDiagnostics, context.CancellationToken).ConfigureAwait(false); RegisterSuppressionFixes(context, suppressionFixes); } } @@ -50,5 +49,5 @@ private static void RegisterSuppressionFixes(CodeFixContext context, ImmutableAr } public override FixAllProvider GetFixAllProvider() - => _suppressionFixProvider.GetFixAllProvider(); + => SuppressionFixProvider.GetFixAllProvider(); } diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoring.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoring.cs index a35daaab4d96b..bbc6c52bd38c2 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoring.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoring.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings; /// /// Represents a set of transformations that can be applied to a piece of code. /// -internal class CodeRefactoring +internal sealed class CodeRefactoring { public CodeRefactoringProvider Provider { get; } @@ -28,18 +28,14 @@ internal class CodeRefactoring public FixAllProviderInfo? FixAllProviderInfo { get; } - public CodeActionOptionsProvider CodeActionOptionsProvider { get; } - public CodeRefactoring( CodeRefactoringProvider provider, ImmutableArray<(CodeAction, TextSpan?)> actions, - FixAllProviderInfo? fixAllProviderInfo, - CodeActionOptionsProvider codeActionOptionsProvider) + FixAllProviderInfo? fixAllProviderInfo) { Provider = provider; CodeActions = actions.NullToEmpty(); FixAllProviderInfo = fixAllProviderInfo; - CodeActionOptionsProvider = codeActionOptionsProvider; if (CodeActions.IsEmpty) { diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs index bed4bf0716d5e..7955a0e2c53ac 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs @@ -90,7 +90,6 @@ static ProjectCodeRefactoringProvider.ExtensionInfo GetExtensionInfo(ExportCodeR public async Task HasRefactoringsAsync( TextDocument document, TextSpan state, - CodeActionOptionsProvider options, CancellationToken cancellationToken) { // A token for controlling the inner work we do calling out to each provider. Once we have a single provider @@ -104,7 +103,7 @@ public async Task HasRefactoringsAsync( source: this.GetProviders(document), produceItems: static async (provider, callback, args, cancellationToken) => { - var (@this, document, state, options, linkedTokenSource) = args; + var (@this, document, state, linkedTokenSource) = args; // Do no work if either the outer request canceled, or another provider already found a refactoring. if (cancellationToken.IsCancellationRequested || linkedTokenSource.Token.IsCancellationRequested) @@ -115,7 +114,7 @@ public async Task HasRefactoringsAsync( // We want to pass linkedTokenSource.Token here so that we can cancel the inner operation once the // outer ProducerConsumer sees a single refactoring returned by any provider. var refactoring = await @this.GetRefactoringFromProviderAsync( - document, state, provider, options, linkedTokenSource.Token).ConfigureAwait(false); + document, state, provider, linkedTokenSource.Token).ConfigureAwait(false); // If we have a refactoring, send a single VoidResult value to the consumer so it can cancel the // other concurrent operations, and can return 'true' to the caller to indicate that there are @@ -142,7 +141,7 @@ public async Task HasRefactoringsAsync( return false; }, - args: (this, document, state, options, linkedTokenSource), + args: (this, document, state, linkedTokenSource), // intentionally using the outer token here. The linked token is only used to cancel the inner operations. cancellationToken).ConfigureAwait(false); } @@ -151,7 +150,6 @@ public async Task> GetRefactoringsAsync( TextDocument document, TextSpan state, CodeActionRequestPriority? priority, - CodeActionOptionsProvider options, CancellationToken cancellationToken) { using (TelemetryLogging.LogBlockTimeAggregated(FunctionId.CodeRefactoring_Summary, $"Pri{priority.GetPriorityInt()}")) @@ -165,7 +163,7 @@ public async Task> GetRefactoringsAsync( source: orderedProviders, produceItems: static async (provider, callback, args, cancellationToken) => { - var (@this, document, state, options) = args; + var (@this, document, state) = args; // Run all providers in parallel to get the set of refactorings for this document. // Log an individual telemetry event for slow code refactoring computations to @@ -186,12 +184,12 @@ public async Task> GetRefactoringsAsync( using (TelemetryLogging.LogBlockTime(FunctionId.CodeRefactoring_Delay, logMessage, CodeRefactoringTelemetryDelay)) { var refactoring = await @this.GetRefactoringFromProviderAsync( - document, state, provider, options, cancellationToken).ConfigureAwait(false); + document, state, provider, cancellationToken).ConfigureAwait(false); if (refactoring != null) callback((provider, refactoring)); } }, - args: (@this: this, document, state, options), + args: (@this: this, document, state), cancellationToken).ConfigureAwait(false); // Order the refactorings by the order of the providers. @@ -208,7 +206,6 @@ public async Task> GetRefactoringsAsync( TextDocument textDocument, TextSpan state, CodeRefactoringProvider provider, - CodeActionOptionsProvider options, CancellationToken cancellationToken) { RefactoringToMetadataMap.TryGetValue(provider, out var providerMetadata); @@ -237,7 +234,6 @@ public async Task> GetRefactoringsAsync( actions.Add((action, applicableToSpan)); } }, - options, cancellationToken); var task = provider.ComputeRefactoringsAsync(context) ?? Task.CompletedTask; @@ -250,11 +246,11 @@ public async Task> GetRefactoringsAsync( var fixAllProviderInfo = extensionManager.PerformFunction( provider, () => ImmutableInterlocked.GetOrAdd(ref _fixAllProviderMap, provider, FixAllProviderInfo.Create), defaultValue: null); - return new CodeRefactoring(provider, actions.ToImmutable(), fixAllProviderInfo, options); + return new CodeRefactoring(provider, actions.ToImmutable(), fixAllProviderInfo); }, defaultValue: null, cancellationToken); } - private class ProjectCodeRefactoringProvider + private sealed class ProjectCodeRefactoringProvider : AbstractProjectExtensionProvider { protected override ImmutableArray GetLanguages(ExportCodeRefactoringProviderAttribute exportAttribute) diff --git a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs index 65f019826fb69..b0a1c05e8405b 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.ExtractMethod; [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.ExtractMethod), Shared] -internal class ExtractMethodCodeRefactoringProvider : CodeRefactoringProvider +internal sealed class ExtractMethodCodeRefactoringProvider : CodeRefactoringProvider { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] diff --git a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs index 832ae4c4bb765..73c0e093b368d 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ICodeRefactoringService.cs @@ -12,13 +12,13 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings; internal interface ICodeRefactoringService { - Task HasRefactoringsAsync(TextDocument document, TextSpan textSpan, CodeActionOptionsProvider options, CancellationToken cancellationToken); + Task HasRefactoringsAsync(TextDocument document, TextSpan textSpan, CancellationToken cancellationToken); - Task> GetRefactoringsAsync(TextDocument document, TextSpan textSpan, CodeActionRequestPriority? priority, CodeActionOptionsProvider options, CancellationToken cancellationToken); + Task> GetRefactoringsAsync(TextDocument document, TextSpan textSpan, CodeActionRequestPriority? priority, CancellationToken cancellationToken); } internal static class ICodeRefactoringServiceExtensions { - public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, TextDocument document, TextSpan state, CodeActionOptionsProvider options, CancellationToken cancellationToken) - => service.GetRefactoringsAsync(document, state, priority: null, options, cancellationToken); + public static Task> GetRefactoringsAsync(this ICodeRefactoringService service, TextDocument document, TextSpan state, CancellationToken cancellationToken) + => service.GetRefactoringsAsync(document, state, priority: null, cancellationToken); } diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs index ed50eee129f6c..29f4b9c7a8fe5 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeEditor.cs @@ -76,13 +76,12 @@ private async Task RemoveUnnecessaryImportsAsync( Solution solution, DocumentId sourceDocumentId, DocumentId documentWithMovedTypeId) { var documentWithMovedType = solution.GetRequiredDocument(documentWithMovedTypeId); - var documentWithMovedTypeFormattingOptions = await documentWithMovedType.GetSyntaxFormattingOptionsAsync(CancellationToken).ConfigureAwait(false); var syntaxFacts = documentWithMovedType.GetRequiredLanguageService(); var removeUnnecessaryImports = documentWithMovedType.GetRequiredLanguageService(); // Remove all unnecessary imports from the new document we've created. - documentWithMovedType = await removeUnnecessaryImports.RemoveUnnecessaryImportsAsync(documentWithMovedType, documentWithMovedTypeFormattingOptions, CancellationToken).ConfigureAwait(false); + documentWithMovedType = await removeUnnecessaryImports.RemoveUnnecessaryImportsAsync(documentWithMovedType, CancellationToken).ConfigureAwait(false); solution = solution.WithDocumentSyntaxRoot( documentWithMovedTypeId, await documentWithMovedType.GetRequiredSyntaxRootAsync(CancellationToken).ConfigureAwait(false)); @@ -95,11 +94,9 @@ private async Task RemoveUnnecessaryImportsAsync( // Now remove any unnecessary imports from the original doc that moved to the new doc. var sourceDocument = solution.GetRequiredDocument(sourceDocumentId); - var sourceDocumentFormattingOptions = await sourceDocument.GetSyntaxFormattingOptionsAsync(CancellationToken).ConfigureAwait(false); sourceDocument = await removeUnnecessaryImports.RemoveUnnecessaryImportsAsync( sourceDocument, n => movedImports.Contains(i => syntaxFacts.AreEquivalent(i, n)), - sourceDocumentFormattingOptions, CancellationToken).ConfigureAwait(false); return solution.WithDocumentSyntaxRoot( diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs index e7ee173d5ecab..827090fedda6a 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.MoveTypeNamespaceScopeEditor.cs @@ -20,7 +20,7 @@ internal abstract partial class AbstractMoveTypeService - private class MoveTypeNamespaceScopeEditor(TService service, State state, string fileName, CancellationToken cancellationToken) : Editor(service, state, fileName, cancellationToken) + private sealed class MoveTypeNamespaceScopeEditor(TService service, State state, string fileName, CancellationToken cancellationToken) : Editor(service, state, fileName, cancellationToken) { public override async Task GetModifiedSolutionAsync() { diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameFileEditor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameFileEditor.cs index ca50d8147f37f..129164ffabd3c 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameFileEditor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameFileEditor.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType; internal abstract partial class AbstractMoveTypeService { - private class RenameFileEditor(TService service, State state, string fileName, CancellationToken cancellationToken) : Editor(service, state, fileName, cancellationToken) + private sealed class RenameFileEditor(TService service, State state, string fileName, CancellationToken cancellationToken) : Editor(service, state, fileName, cancellationToken) { public override Task> GetOperationsAsync() => Task.FromResult(RenameFileToMatchTypeName()); diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs index fdb34911480dc..bd302522bd3e1 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/AbstractMoveTypeService.RenameTypeEditor.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType; internal abstract partial class AbstractMoveTypeService { - private class RenameTypeEditor(TService service, State state, string fileName, CancellationToken cancellationToken) : Editor(service, state, fileName, cancellationToken) + private sealed class RenameTypeEditor(TService service, State state, string fileName, CancellationToken cancellationToken) : Editor(service, state, fileName, cancellationToken) { /// diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs index acf73a0697624..c692cee67481f 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.MoveType; [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.MoveTypeToFile), Shared] -internal class MoveTypeCodeRefactoringProvider : CodeRefactoringProvider +internal sealed class MoveTypeCodeRefactoringProvider : CodeRefactoringProvider { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] diff --git a/src/Features/Core/Portable/CodeRefactorings/ServicesLayerCodeActionHelpersService.cs b/src/Features/Core/Portable/CodeRefactorings/ServicesLayerCodeActionHelpersService.cs index 869e3e468557a..d881ce4234945 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ServicesLayerCodeActionHelpersService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ServicesLayerCodeActionHelpersService.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings; [ExportWorkspaceServiceFactory(typeof(ICodeRefactoringHelpersService), ServiceLayer.Default), Shared] -internal class ServicesLayerCodeActionHelpersService : IWorkspaceServiceFactory +internal sealed class ServicesLayerCodeActionHelpersService : IWorkspaceServiceFactory { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -23,7 +23,7 @@ public ServicesLayerCodeActionHelpersService() public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) => new CodeActionHelpersService(); - private class CodeActionHelpersService : ICodeRefactoringHelpersService + private sealed class CodeActionHelpersService : ICodeRefactoringHelpersService { public bool ActiveInlineRenameSession => false; } diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs index cdc645c34fe07..43ee85d7434cc 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs @@ -798,7 +798,6 @@ async static Task RemoveUnnecessaryImportsWorkerAsync( return await removeImportService.RemoveUnnecessaryImportsAsync( doc, import => importsToRemove.Any(importToRemove => syntaxFacts.AreEquivalent(importToRemove, import)), - formattingOptions, token).ConfigureAwait(false); } } @@ -850,7 +849,7 @@ private static async Task MergeDiffAsync(Solution oldSolution, Solutio return mergeResult.MergedSolution; } - private class SyntaxNodeSpanStartComparer : IComparer + private sealed class SyntaxNodeSpanStartComparer : IComparer { private SyntaxNodeSpanStartComparer() { diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.MoveFileCodeAction.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.MoveFileCodeAction.cs index bed1fb9e5d44f..0fe3627c92a64 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.MoveFileCodeAction.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.MoveFileCodeAction.cs @@ -121,7 +121,7 @@ private static ImmutableArray> FindCandidateFolders( return builder.ToImmutableAndFree(); } - private class FolderInfo + private sealed class FolderInfo { private readonly Dictionary _childFolders; diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/SyncNamespaceDocumentsNotInSolutionException.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/SyncNamespaceDocumentsNotInSolutionException.cs index 0179fe923c91e..7198bc1934f33 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/SyncNamespaceDocumentsNotInSolutionException.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/SyncNamespaceDocumentsNotInSolutionException.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.SyncNamespace; -internal class SyncNamespaceDocumentsNotInSolutionException(ImmutableArray documentIds) : Exception +internal sealed class SyncNamespaceDocumentsNotInSolutionException(ImmutableArray documentIds) : Exception { private readonly ImmutableArray _documentIds = documentIds; diff --git a/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs b/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs index 178d6758b87e3..c289508ca54d5 100644 --- a/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs +++ b/src/Features/Core/Portable/Completion/CompletionService_GetCompletions.cs @@ -340,7 +340,7 @@ await extensionManager.PerformActionAsync( return context; } - private class DisplayNameToItemsMap(CompletionService service) : IEnumerable, IDisposable + private sealed class DisplayNameToItemsMap(CompletionService service) : IEnumerable, IDisposable { // We might need to handle large amount of items with import completion enabled, // so use a dedicated pool to minimize array allocations. Set the size of pool to a small diff --git a/src/Features/Core/Portable/Completion/MatchResult.cs b/src/Features/Core/Portable/Completion/MatchResult.cs index a4278adba9e0c..c358a7e8d6833 100644 --- a/src/Features/Core/Portable/Completion/MatchResult.cs +++ b/src/Features/Core/Portable/Completion/MatchResult.cs @@ -46,7 +46,7 @@ internal readonly struct MatchResult( public static IComparer SortingComparer { get; } = new Comparer(); - private class Comparer : IComparer + private sealed class Comparer : IComparer { // This comparison is used for sorting items in the completion list for the original sorting. diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs index 730aff1b8f646..b3864d7dcf94e 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs @@ -73,7 +73,7 @@ private async Task> RecommendKeywordsAsync( public sealed override Task GetTextChangeAsync(Document document, CompletionItem item, char? ch, CancellationToken cancellationToken) => Task.FromResult((TextChange?)new TextChange(item.Span, item.DisplayText)); - private class Comparer : IEqualityComparer + private sealed class Comparer : IEqualityComparer { public bool Equals(CompletionItem? x, CompletionItem? y) => x?.DisplayText == y?.DisplayText; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractOverrideCompletionProvider.ItemGetter.cs b/src/Features/Core/Portable/Completion/Providers/AbstractOverrideCompletionProvider.ItemGetter.cs index 9e07d92fef95c..08405522e430d 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractOverrideCompletionProvider.ItemGetter.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractOverrideCompletionProvider.ItemGetter.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Completion.Providers; internal abstract partial class AbstractOverrideCompletionProvider { - private partial class ItemGetter + private sealed partial class ItemGetter { private readonly CancellationToken _cancellationToken; private readonly int _position; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs index ddf3d0b4c1397..fbbdb17690df8 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs @@ -61,7 +61,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) protected override async Task GenerateMemberAsync(ISymbol member, INamedTypeSymbol containingType, Document document, CompletionItem item, CancellationToken cancellationToken) { - var syntaxFactory = document.GetLanguageService(); + var syntaxFactory = document.GetRequiredLanguageService(); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var method = (IMethodSymbol)member; diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs index c42bd319da702..9a7e27a3f107c 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractSymbolCompletionProvider.cs @@ -108,11 +108,23 @@ private ImmutableArray CreateItems( // We might get symbol w/o name but CanBeReferencedByName is still set to true, // need to filter them out. // https://github.com/dotnet/roslyn/issues/47690 - var symbolGroups = from symbol in symbols - let texts = GetDisplayAndSuffixAndInsertionText(symbol.Symbol, contextLookup(symbol)) - where !string.IsNullOrWhiteSpace(texts.displayText) - group symbol by texts into g - select g; + // + // Use SymbolReferenceEquivalenceComparer.Instance as the value comparer as we + // don't want symbols with just the same name to necessarily match + // (as the default comparer on SymbolAndSelectionInfo does) + var symbolGroups = new MultiDictionary<(string displayText, string suffix, string insertionText), SymbolAndSelectionInfo>( + capacity: symbols.Length, + comparer: EqualityComparer<(string, string, string)>.Default, + valueComparer: SymbolReferenceEquivalenceComparer.Instance); + + foreach (var symbol in symbols) + { + var texts = GetDisplayAndSuffixAndInsertionText(symbol.Symbol, contextLookup(symbol)); + if (!string.IsNullOrWhiteSpace(texts.displayText)) + { + symbolGroups.Add(texts, symbol); + } + } using var _ = ArrayBuilder.GetInstance(out var itemListBuilder); var typeConvertibilityCache = new Dictionary(SymbolEqualityComparer.Default); @@ -120,8 +132,12 @@ group symbol by texts into g foreach (var symbolGroup in symbolGroups) { var includeItemInTargetTypedCompletion = false; - var arbitraryFirstContext = contextLookup(symbolGroup.First()); - var symbolList = symbolGroup.ToImmutableArray(); + using var symbolListBuilder = TemporaryArray.Empty; + foreach (var symbol in symbolGroup.Value) + symbolListBuilder.Add(symbol); + + var symbolList = symbolListBuilder.ToImmutableAndClear(); + var arbitraryFirstContext = contextLookup(symbolList[0]); if (completionContext.CompletionOptions.TargetTypedCompletionFilter) { @@ -151,6 +167,20 @@ group symbol by texts into g return itemListBuilder.ToImmutableAndClear(); } + /// + /// Alternative comparer to SymbolAndSelectionInfo's default which considers both the full symbol and preselect. + /// + private sealed class SymbolReferenceEquivalenceComparer : IEqualityComparer + { + public static readonly SymbolReferenceEquivalenceComparer Instance = new(); + + public bool Equals(SymbolAndSelectionInfo x, SymbolAndSelectionInfo y) + => x.Symbol == y.Symbol && x.Preselect == y.Preselect; + + public int GetHashCode(SymbolAndSelectionInfo symbol) + => Hash.Combine(symbol.Symbol.GetHashCode(), symbol.Preselect ? 1 : 0); + } + protected static bool TryFindFirstSymbolMatchesTargetTypes( Func contextLookup, ImmutableArray symbolList, diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionCacheServiceFactory.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionCacheServiceFactory.cs index 3d31cab69e03c..e91c21220a3bb 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionCacheServiceFactory.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractImportCompletionCacheServiceFactory.cs @@ -63,7 +63,7 @@ private void OnCacheFlushRequested(object? sender, EventArgs e) _projectItemsCache.Clear(); } - private class ImportCompletionCacheService( + private sealed class ImportCompletionCacheService( ConcurrentDictionary peCache, ConcurrentDictionary projectCache, AsyncBatchingWorkQueue workQueue) : IImportCompletionCacheService diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs index e60fa043f7a19..803c4601f7231 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/AbstractTypeImportCompletionProvider.cs @@ -159,7 +159,7 @@ static bool ShouldAddItem( } } - private class TelemetryCounter + private sealed class TelemetryCounter { private readonly SharedStopwatch _elapsedTime; diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs index 3fc61edaab320..441b5eabe42cb 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.Completion.Providers; internal static partial class ExtensionMethodImportCompletionHelper { - private class SymbolComputer + private sealed class SymbolComputer { private readonly int _position; private readonly Document _originatingDocument; diff --git a/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs index 0d4d46a80215a..652a2c1bf1535 100644 --- a/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/MemberInsertingCompletionItem.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Completion.Providers; -internal class MemberInsertionCompletionItem +internal sealed class MemberInsertionCompletionItem { public static CompletionItem Create( string displayText, diff --git a/src/Features/Core/Portable/Completion/Providers/Snippets/AbstractSnippetCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/Snippets/AbstractSnippetCompletionProvider.cs index 2262c164dfb1b..ecc4b1fedba12 100644 --- a/src/Features/Core/Portable/Completion/Providers/Snippets/AbstractSnippetCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/Snippets/AbstractSnippetCompletionProvider.cs @@ -32,11 +32,11 @@ public override async Task GetChangeAsync(Document document, C Logger.Log(FunctionId.Completion_SemanticSnippets, $"Name: {snippetIdentifier}", LogLevel.Information); // This retrieves the generated Snippet - var snippet = await snippetProvider.GetSnippetAsync(strippedDocument, position, cancellationToken).ConfigureAwait(false); + var snippetChange = await snippetProvider.GetSnippetChangeAsync(strippedDocument, position, cancellationToken).ConfigureAwait(false); var strippedText = await strippedDocument.GetValueTextAsync(cancellationToken).ConfigureAwait(false); // This introduces the text changes of the snippet into the document with the completion invoking text - var allChangesText = strippedText.WithChanges(snippet.TextChanges); + var allChangesText = strippedText.WithChanges(snippetChange.TextChanges); // This retrieves ALL text changes from the original document which includes the TextChanges from the snippet // as well as the clean up. @@ -46,7 +46,7 @@ public override async Task GetChangeAsync(Document document, C var change = Utilities.Collapse(allChangesText, allTextChanges.AsImmutable()); // Converts the snippet to an LSP formatted snippet string. - var lspSnippet = await RoslynLSPSnippetConverter.GenerateLSPSnippetAsync(allChangesDocument, snippet.CursorPosition, snippet.Placeholders, change, item.Span.Start, cancellationToken).ConfigureAwait(false); + var lspSnippet = await RoslynLSPSnippetConverter.GenerateLSPSnippetAsync(allChangesDocument, snippetChange.FinalCaretPosition, snippetChange.Placeholders, change, item.Span.Start, cancellationToken).ConfigureAwait(false); // If the TextChanges retrieved starts after the trigger point of the CompletionItem, // then we need to move the bounds backwards and encapsulate the trigger point and adjust the changed text. @@ -60,7 +60,7 @@ public override async Task GetChangeAsync(Document document, C var props = ImmutableDictionary.Empty .Add(SnippetCompletionItem.LSPSnippetKey, lspSnippet); - return CompletionChange.Create(change, allTextChanges.AsImmutable(), properties: props, snippet.CursorPosition, includesCommitCharacter: true); + return CompletionChange.Create(change, allTextChanges.AsImmutable(), properties: props, snippetChange.FinalCaretPosition, includesCommitCharacter: true); } public override async Task ProvideCompletionsAsync(CompletionContext context) @@ -82,7 +82,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var syntaxContext = await context.GetSyntaxContextWithExistingSpeculativeModelAsync(document, cancellationToken).ConfigureAwait(false); var snippetContext = new SnippetContext(syntaxContext); - var snippets = await service.GetSnippetsAsync(snippetContext, cancellationToken).ConfigureAwait(false); + var snippets = service.GetSnippets(snippetContext, cancellationToken); foreach (var snippetData in snippets) { diff --git a/src/Features/Core/Portable/Completion/Providers/Snippets/SnippetCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/Snippets/SnippetCompletionItem.cs index e150a004aed91..f8da6b9a4831c 100644 --- a/src/Features/Core/Portable/Completion/Providers/Snippets/SnippetCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/Snippets/SnippetCompletionItem.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.Completion.Providers.Snippets; -internal class SnippetCompletionItem +internal sealed class SnippetCompletionItem { public static string LSPSnippetKey = "LSPSnippet"; public static string SnippetIdentifierKey = "SnippetIdentifier"; diff --git a/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs index 6500eba0a36e8..ae12d898f9126 100644 --- a/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs @@ -391,6 +391,7 @@ private static IMethodSymbol CreateClassConstructor( }); var assignmentStatements = generator.CreateAssignmentStatements( + generator.SyntaxGeneratorInternal, semanticModel, parameters, parameterToPropMap, ImmutableDictionary.Empty, addNullChecks: false, preferThrowExpression: false); diff --git a/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs index 22bfe93345261..2b215f791388a 100644 --- a/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs @@ -180,7 +180,6 @@ protected sealed override async Task FixAllAsync( Document document, ImmutableArray fixAllSpans, SyntaxEditor editor, - CodeActionOptionsProvider optionsProvider, string? equivalenceKey, CancellationToken cancellationToken) { diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs index 651f39a9f512c..5b370bfafccf6 100644 --- a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs @@ -938,6 +938,7 @@ private static IMethodSymbol CreateConstructor( }); var assignmentStatements = generator.CreateAssignmentStatements( + generator.SyntaxGeneratorInternal, semanticModel, parameters, parameterToPropMap, ImmutableDictionary.Empty, addNullChecks: false, preferThrowExpression: false); diff --git a/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.cs b/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.cs index 13f2f65139617..0bdd083ad9584 100644 --- a/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.cs +++ b/src/Features/Core/Portable/Copilot/ICopilotCodeAnalysisService.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.Threading; using System.Threading.Tasks; @@ -72,8 +73,8 @@ internal interface ICopilotCodeAnalysisService : ILanguageService Task GetOnTheFlyDocsAsync(string symbolSignature, ImmutableArray declarationCode, string language, CancellationToken cancellationToken); /// - /// Determines if there are any exclusions in the workspace. + /// Determines if the given is excluded in the workspace. /// - Task IsAnyExclusionAsync(CancellationToken cancellationToken); + Task IsFileExcludedAsync(string filePath, CancellationToken cancellationToken); } diff --git a/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.NameAndArity.cs b/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.NameAndArity.cs index 2ef9e72dc358a..c893ef0494379 100644 --- a/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.NameAndArity.cs +++ b/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.NameAndArity.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Debugging; -internal partial class AbstractBreakpointResolver +internal abstract partial class AbstractBreakpointResolver { protected struct NameAndArity(string name, int arity) { diff --git a/src/Features/Core/Portable/Debugging/DebugInformationReaderProvider.cs b/src/Features/Core/Portable/Debugging/DebugInformationReaderProvider.cs index 380169eff4f5a..a54db62a8890d 100644 --- a/src/Features/Core/Portable/Debugging/DebugInformationReaderProvider.cs +++ b/src/Features/Core/Portable/Debugging/DebugInformationReaderProvider.cs @@ -92,7 +92,7 @@ public override void Dispose() var symReader = Interlocked.Exchange(ref _symReader, null); if (symReader != null && Marshal.IsComObject(symReader)) { -#if NETCOREAPP +#if NET Debug.Assert(OperatingSystem.IsWindows()); #endif Marshal.ReleaseComObject(symReader); diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs index 5907c6c6ed020..b0bb42a5324db 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticArguments.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics; /// helper type to package diagnostic arguments to pass around between remote hosts /// [DataContract] -internal class DiagnosticArguments +internal sealed class DiagnosticArguments { /// /// Flag indicating if suppressed diagnostics should be returned. diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticProviderMetadata.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticProviderMetadata.cs index 15d57c3ed94c6..8ff833bd77638 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticProviderMetadata.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticProviderMetadata.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics; -internal class DiagnosticProviderMetadata(IDictionary data) : ILanguageMetadata +internal sealed class DiagnosticProviderMetadata(IDictionary data) : ILanguageMetadata { public string Name { get; } = (string)data.GetValueOrDefault("Name"); public string Language { get; } = (string)data.GetValueOrDefault("Language"); diff --git a/src/Features/Core/Portable/Diagnostics/LanguageServer/LspBuildOnlyDiagnosticsAttribute.cs b/src/Features/Core/Portable/Diagnostics/LanguageServer/LspBuildOnlyDiagnosticsAttribute.cs index 4f0960c49617b..4b7dcdacaf211 100644 --- a/src/Features/Core/Portable/Diagnostics/LanguageServer/LspBuildOnlyDiagnosticsAttribute.cs +++ b/src/Features/Core/Portable/Diagnostics/LanguageServer/LspBuildOnlyDiagnosticsAttribute.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer; /// [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] -internal class LspBuildOnlyDiagnosticsAttribute(string languageName, params string[] buildOnlyDiagnostics) : ExportAttribute(typeof(ILspBuildOnlyDiagnostics)), ILspBuildOnlyDiagnosticsMetadata +internal sealed class LspBuildOnlyDiagnosticsAttribute(string languageName, params string[] buildOnlyDiagnostics) : ExportAttribute(typeof(ILspBuildOnlyDiagnostics)), ILspBuildOnlyDiagnosticsMetadata { public string LanguageName { get; } = languageName; public string[] BuildOnlyDiagnostics { get; } = buildOnlyDiagnostics; diff --git a/src/Features/Core/Portable/DocumentHighlighting/ExportEmbeddedLanguageDocumentHighlighterAttribute.cs b/src/Features/Core/Portable/DocumentHighlighting/ExportEmbeddedLanguageDocumentHighlighterAttribute.cs index df279130d13e2..721bf0600b6c0 100644 --- a/src/Features/Core/Portable/DocumentHighlighting/ExportEmbeddedLanguageDocumentHighlighterAttribute.cs +++ b/src/Features/Core/Portable/DocumentHighlighting/ExportEmbeddedLanguageDocumentHighlighterAttribute.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.DocumentHighlighting; /// /// Use this attribute to export a . /// -internal class ExportEmbeddedLanguageDocumentHighlighterAttribute( +internal sealed class ExportEmbeddedLanguageDocumentHighlighterAttribute( string name, string[] languages, bool supportsUnannotatedAPIs, params string[] identifiers) : ExportEmbeddedLanguageFeatureServiceAttribute(typeof(IEmbeddedLanguageDocumentHighlighter), name, languages, supportsUnannotatedAPIs, identifiers) { public ExportEmbeddedLanguageDocumentHighlighterAttribute( diff --git a/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentFormattingService.cs b/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentFormattingService.cs index 026b3bc4f7a68..a8d81cb41ebcb 100644 --- a/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentFormattingService.cs +++ b/src/Features/Core/Portable/DocumentationComments/AbstractDocumentationCommentFormattingService.cs @@ -25,7 +25,7 @@ private enum DocumentationCommentListType Table, } - private class FormatterState + private sealed class FormatterState { private bool _anyNonWhitespaceSinceLastPara; private bool _pendingParagraphBreak; diff --git a/src/Features/Core/Portable/DocumentationComments/DocumentationCommentSnippet.cs b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentSnippet.cs index 9d27a3927db17..89e88c6c201c1 100644 --- a/src/Features/Core/Portable/DocumentationComments/DocumentationCommentSnippet.cs +++ b/src/Features/Core/Portable/DocumentationComments/DocumentationCommentSnippet.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.DocumentationComments; -internal class DocumentationCommentSnippet +internal sealed class DocumentationCommentSnippet { /// /// The span in the original text that should be replaced with the documentation comment. diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 769cf5bc507d0..b5242a5245b4b 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -426,9 +426,12 @@ internal abstract void ReportOtherRudeEditsAroundActiveStatement( IReadOnlyDictionary forwardMap, SyntaxNode oldActiveStatement, DeclarationBody oldBody, + SemanticModel oldModel, SyntaxNode newActiveStatement, DeclarationBody newBody, - bool isNonLeaf); + SemanticModel newModel, + bool isNonLeaf, + CancellationToken cancellationToken); internal abstract void ReportInsertedMemberSymbolRudeEdits(ArrayBuilder diagnostics, ISymbol newSymbol, SyntaxNode newNode, bool insertingIntoExistingContainingType); internal abstract void ReportStateMachineSuspensionPointRudeEdits(DiagnosticContext diagnosticContext, SyntaxNode oldNode, SyntaxNode newNode); @@ -1185,8 +1188,9 @@ private void AnalyzeChangedMemberBody( TextSpan newSpan; if (hasMatching) { - Debug.Assert(newStatementSyntax != null); - Debug.Assert(newBody != null); + Contract.ThrowIfNull(newStatementSyntax); + Contract.ThrowIfNull(newBody); + Contract.ThrowIfNull(oldModel); // The matching node doesn't produce sequence points. // E.g. "const" keyword is inserted into a local variable declaration with an initializer. @@ -1204,9 +1208,12 @@ private void AnalyzeChangedMemberBody( enclosingBodyMap.Reverse, oldStatementSyntax, oldBody, + oldModel, newStatementSyntax, newBody, - isNonLeaf); + newModel, + isNonLeaf, + cancellationToken); } else if (enclosingBodyMap.Forward.IsEmpty()) { @@ -1775,6 +1782,15 @@ protected void AddAroundActiveStatementRudeDiagnostic(ArrayBuilder diagnostics, SyntaxNode newNode, ITypeSymbol oldType, ITypeSymbol newType) + { + diagnostics.Add(new RudeEditDiagnostic( + RudeEditKind.TypeUpdateAroundActiveStatement, + GetDiagnosticSpan(newNode, EditKind.Update), + newNode, + [GetDisplayName(newNode, EditKind.Update), oldType.ToDisplayString(), newType.ToDisplayString()])); + } + protected void AddRudeUpdateAroundActiveStatement(ArrayBuilder diagnostics, SyntaxNode newNode) { diagnostics.Add(new RudeEditDiagnostic( @@ -1805,13 +1821,17 @@ protected void AddRudeDeleteAroundActiveStatement(ArrayBuilder( ArrayBuilder diagnostics, IReadOnlyDictionary reverseMap, - Func nodeSelector, SyntaxNode oldActiveStatement, SyntaxNode oldEncompassingAncestor, + SemanticModel oldModel, SyntaxNode newActiveStatement, SyntaxNode newEncompassingAncestor, + SemanticModel newModel, + Func nodeSelector, + Func> getTypedNodes, Func areEquivalent, - Func? areSimilar) + Func? areSimilar, + CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode { var newNodes = GetAncestors(newEncompassingAncestor, newActiveStatement, nodeSelector); @@ -1825,12 +1845,12 @@ protected void ReportUnmatchedStatements( int matchCount; if (oldNodes != null) { - matchCount = MatchNodes(oldNodes, newNodes, diagnostics: null, reverseMap, comparer: areEquivalent); + matchCount = MatchNodes(oldNodes, oldModel, newNodes, newModel, diagnostics, reverseMap, getTypedNodes, comparer: areEquivalent, exactMatch: true, cancellationToken); // Do another pass over the nodes to improve error messages. if (areSimilar != null && matchCount < Math.Min(oldNodes.Count, newNodes.Count)) { - matchCount += MatchNodes(oldNodes, newNodes, diagnostics, reverseMap: null, comparer: areSimilar); + matchCount += MatchNodes(oldNodes, oldModel, newNodes, newModel, diagnostics, reverseMap: null, getTypedNodes, comparer: areSimilar, exactMatch: false, cancellationToken); } } else @@ -1871,10 +1891,15 @@ private void ReportRudeEditsAndInserts(List? oldNodes, List( List oldNodes, + SemanticModel oldModel, List newNodes, - ArrayBuilder? diagnostics, + SemanticModel newModel, + ArrayBuilder diagnostics, IReadOnlyDictionary? reverseMap, - Func comparer) + Func> getTypedNodes, + Func comparer, + bool exactMatch, + CancellationToken cancellationToken) where TSyntaxNode : SyntaxNode { var matchCount = 0; @@ -1918,15 +1943,44 @@ private int MatchNodes( if (i >= 0) { - // we have an update or an exact match: - oldNodes[i] = null; - newNodes[newIndex] = null; - matchCount++; + // An update or an exact match. - if (diagnostics != null) + oldNode = oldNodes[i]; + Contract.ThrowIfNull(oldNode); + + // If the nodes don't match exactly report rude edit right away, + // otherwise check if the types of temp variable the node generates (if any) changed. + + if (!exactMatch) { AddRudeUpdateAroundActiveStatement(diagnostics, newNode); } + else + { + var oldTypedNodes = getTypedNodes((TSyntaxNode)oldNode); + var newTypedNodes = getTypedNodes((TSyntaxNode)newNode); + + // nodes are syntactically equivallent, so they should yield the same amount of types: + Contract.ThrowIfFalse(oldTypedNodes.Count == newTypedNodes.Count); + + for (var t = 0; t < oldTypedNodes.Count; t++) + { + var oldType = oldModel.GetTypeInfo(oldTypedNodes[t], cancellationToken).Type; + var newType = newModel.GetTypeInfo(newTypedNodes[t], cancellationToken).Type; + + Contract.ThrowIfNull(oldType); + Contract.ThrowIfNull(newType); + + if (!TypesEquivalent(oldType, newType, exact: false)) + { + AddRudeTypeUpdateAroundActiveStatement(diagnostics, newNode, oldType, newType); + } + } + } + + oldNodes[i] = null; + newNodes[newIndex] = null; + matchCount++; } } @@ -2302,10 +2356,10 @@ public int GetHashCode(IAssemblySymbol? obj) // They only affect custom attributes or metadata flags emitted on the members - all runtimes are expected to accept // these updates in metadata deltas, even if they do not have any observable effect. private static readonly SymbolEquivalenceComparer s_runtimeSymbolEqualityComparer = new( - AssemblyEqualityComparer.Instance, distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true); + AssemblyEqualityComparer.Instance, distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); private static readonly SymbolEquivalenceComparer s_exactSymbolEqualityComparer = new( - AssemblyEqualityComparer.Instance, distinguishRefFromOut: true, tupleNamesMustMatch: true, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: false); + AssemblyEqualityComparer.Instance, distinguishRefFromOut: true, tupleNamesMustMatch: true, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: false, arrayAndReadOnlySpanCompareEqually: false); protected static bool SymbolsEquivalent(ISymbol oldSymbol, ISymbol newSymbol) => s_exactSymbolEqualityComparer.Equals(oldSymbol, newSymbol); @@ -2673,9 +2727,9 @@ newSymbol is IPropertySymbol newProperty && break; } - // If a partial method definition is deleted (and not moved to another partial type declaration, which is handled above) + // If a partial method/property/indexer definition is deleted (and not moved to another partial type declaration, which is handled above) // so must be the implementation. An edit will be issued for the implementation change. - if (newSymbol is IMethodSymbol { IsPartialDefinition: true }) + if (newSymbol?.IsPartialDefinition() == true) { continue; } @@ -2823,7 +2877,7 @@ newSymbol is IPropertySymbol newProperty && // If a partial method definition is inserted (and not moved to another partial type declaration, which is handled above) // so must be the implementation. An edit will be issued for the implementation change. - if (newSymbol is IMethodSymbol { IsPartialDefinition: true }) + if (newSymbol.IsPartialDefinition()) { continue; } @@ -2948,9 +3002,17 @@ newSymbol is IPropertySymbol newProperty && break; case EditKind.Reorder: + Contract.ThrowIfNull(oldModel); + Contract.ThrowIfNull(newModel); Contract.ThrowIfNull(oldSymbol); Contract.ThrowIfNull(newSymbol); + // Reordering fields in a type in source doesn't actually result in + // a metadata update that would reoder them in the runtime type representation. + // The runtime does not allow us to communicate such change in the delta. + // If we allowed reodering fields of a type with sequential/explicit layout + // it might be confusing because after the change the order of the fields + // in the runtime type may not match the source anymore. ReportTypeLayoutUpdateRudeEdits(diagnosticContext, oldSymbol, cancellationToken); if (oldSymbol is IParameterSymbol && @@ -2958,9 +3020,12 @@ newSymbol is IPropertySymbol newProperty && !capabilities.Grant(EditAndContinueCapabilities.UpdateParameters)) { diagnosticContext.Report(RudeEditKind.RenamingNotSupportedByRuntime, cancellationToken); + continue; } - continue; + // The member may also be updated (modifiers, attributes, body, etc.). Continue processing as an update. + editKind = SemanticEditKind.Update; + break; default: throw ExceptionUtilities.UnexpectedValue(edit.Kind); @@ -3185,8 +3250,7 @@ IFieldSymbol or // The partial type needs to be specified in the following cases: // 1) partial method is updated (in case both implementation and definition are updated) // 2) partial type is updated - // https://github.com/dotnet/roslyn/issues/73772: do we also need to check IPropertySymbol.PartialDefinitionPart here? - var partialType = editKind == SemanticEditKind.Update && symbol is IMethodSymbol { PartialDefinitionPart: not null } + var partialType = editKind == SemanticEditKind.Update && symbol.IsPartialImplementation() ? symbolCache.GetKey(symbol.ContainingType, cancellationToken) : IsPartialTypeEdit(oldSymbol, newSymbol, oldTree, newTree) ? symbolKey @@ -3355,8 +3419,7 @@ bool PreprocessSymbolEdit(ref ISymbol? oldSymbol, ref ISymbol? newSymbol) var result = symbolKey.Resolve(compilation, ignoreAssemblyKey: true, cancellationToken).Symbol; // If we were looking for a definition and an implementation is returned the definition does not exist. - // https://github.com/dotnet/roslyn/issues/73772: Does PartialDefinitionPart also need to be checked here? - return symbol is IMethodSymbol { PartialDefinitionPart: not null } && result is IMethodSymbol { IsPartialDefinition: true } ? null : result; + return symbol.IsPartialImplementation() && result?.IsPartialDefinition() == true ? null : result; } var symbol = newSymbol ?? oldSymbol; @@ -3627,9 +3690,7 @@ void AddUpdate(ISymbol? symbol) if (symbol is null) return; - Debug.Assert(symbol is not IMethodSymbol { IsPartialDefinition: true }); - - semanticEdits.Add(SemanticEditInfo.CreateUpdate(SymbolKey.Create(symbol, cancellationToken), syntaxMaps: default, partialType: null)); + semanticEdits.Add(SemanticEditInfo.CreateUpdate(symbol, syntaxMaps: default, cancellationToken)); } } @@ -3668,11 +3729,7 @@ void AddDelete(ISymbol? symbol) if (symbol is null) return; - // https://github.com/dotnet/roslyn/issues/73772 - Debug.Assert(symbol is not IMethodSymbol { IsPartialDefinition: true }); - - var partialType = symbol is IMethodSymbol { PartialDefinitionPart: not null } ? SymbolKey.Create(symbol.ContainingType, cancellationToken) : (SymbolKey?)null; - semanticEdits.Add(SemanticEditInfo.CreateDelete(SymbolKey.Create(symbol, cancellationToken), deletedSymbolContainer, partialType)); + semanticEdits.Add(SemanticEditInfo.CreateDelete(symbol, deletedSymbolContainer, cancellationToken)); } } @@ -3686,9 +3743,7 @@ private static void AddInsertEditsForMemberAndAccessors(ArrayBuilder item.Key, - static item => new RuntimeRudeEdit(item.Value.ToDiagnostic(item.Key.SyntaxTree).ToString())); + static item => new RuntimeRudeEdit(item.Value.ToDiagnostic(item.Key.SyntaxTree).ToString(), (int)item.Value.Kind)); runtimeRudeEdits = node => rudeEdits.TryGetValue(node, out var message) ? message : null; return; @@ -6635,7 +6699,10 @@ public bool IsPrimaryConstructorParameterMatchingSymbol(ISymbol symbol, Cancella /// private static bool SymbolPresenceAffectsSynthesizedRecordMembers(ISymbol symbol) => symbol is { IsStatic: false, ContainingType.IsRecord: true } and - (IPropertySymbol { GetMethod.IsImplicitlyDeclared: false, SetMethod: null or { IsImplicitlyDeclared: false } } or IFieldSymbol); + (IPropertySymbol { GetMethod.IsImplicitlyDeclared: false, SetMethod: null or { IsImplicitlyDeclared: false } } or + IFieldSymbol or + // event field: + IEventSymbol { AddMethod.IsImplicitlyDeclared: true }); /// /// True if a syntactic delete edit of an in diff --git a/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs b/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs index a2087fccd5557..71169e100204b 100644 --- a/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs +++ b/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs @@ -276,7 +276,7 @@ public bool ContainsDocument(DocumentId documentId) filePath: document.FilePath, isGenerated: document.State.Attributes.IsGenerated) .WithDesignTimeOnly(document.State.Attributes.DesignTimeOnly) - .WithDocumentServiceProvider(document.State.Services)); + .WithDocumentServiceProvider(document.State.DocumentServiceProvider)); } var matchingSourceText = maybeMatchingSourceText.Value; diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index 2f6cbb396eadd..f528fb3a0fc29 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -111,6 +111,8 @@ internal DebuggingSession( IEnumerable> initialDocumentStates, bool reportDiagnostics) { + EditAndContinueService.Log.Write($"Debugging session started: #{id}"); + _compilationOutputsProvider = compilationOutputsProvider; SourceTextProvider = sourceTextProvider; _reportTelemetry = ReportTelemetry; @@ -198,6 +200,8 @@ public void EndSession(out DebuggingSessionTelemetry.Data telemetryData) _reportTelemetry(telemetryData); Dispose(); + + EditAndContinueService.Log.Write($"Debugging session ended: #{Id}"); } public void BreakStateOrCapabilitiesChanged(bool? inBreakState) @@ -205,6 +209,8 @@ public void BreakStateOrCapabilitiesChanged(bool? inBreakState) internal void RestartEditSession(ImmutableDictionary>? nonRemappableRegions, bool? inBreakState) { + EditAndContinueService.Log.Write($"Edit session restarted (break state: {inBreakState?.ToString() ?? "null"})"); + ThrowIfDisposed(); EndEditSession(); @@ -270,7 +276,7 @@ private bool AddModulePreparedForUpdate(Guid mvid) catch (Exception e) { var descriptor = EditAndContinueDiagnosticDescriptors.GetDescriptor(EditAndContinueErrorCode.ErrorReadingFile); - return (Mvid: Guid.Empty, Error: Diagnostic.Create(descriptor, Location.None, new[] { outputs.AssemblyDisplayPath, e.Message })); + return (Mvid: Guid.Empty, Error: Diagnostic.Create(descriptor, Location.None, [outputs.AssemblyDisplayPath, e.Message])); } } @@ -412,7 +418,7 @@ private static unsafe bool TryCreateInitialBaseline( EditAndContinueService.Log.Write("Failed to create baseline for '{0}': {1}", projectId, e.Message); var descriptor = EditAndContinueDiagnosticDescriptors.GetDescriptor(EditAndContinueErrorCode.ErrorReadingFile); - diagnostics = [Diagnostic.Create(descriptor, Location.None, new[] { fileBeingRead, e.Message })]; + diagnostics = [Diagnostic.Create(descriptor, Location.None, [fileBeingRead, e.Message])]; } finally { @@ -535,13 +541,25 @@ public async ValueTask EmitSolutionUpdateAsync( solutionUpdate.NonRemappableRegions)); } + using var _ = ArrayBuilder.GetInstance(out var rudeEditDiagnostics); + foreach (var (projectId, projectRudeEdits) in solutionUpdate.DocumentsWithRudeEdits.GroupBy(static e => e.DocumentId.ProjectId)) + { + foreach (var (documentId, rudeEdits) in projectRudeEdits) + { + var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + rudeEditDiagnostics.Add(new(projectId, rudeEdits.SelectAsArray(static (rudeEdit, tree) => rudeEdit.ToDiagnostic(tree), tree))); + } + } + // Note that we may return empty deltas if all updates have been deferred. // The debugger will still call commit or discard on the update batch. return new EmitSolutionUpdateResults() { + Solution = solution, ModuleUpdates = solutionUpdate.ModuleUpdates, Diagnostics = solutionUpdate.Diagnostics, - RudeEdits = solutionUpdate.DocumentsWithRudeEdits, + RudeEdits = rudeEditDiagnostics.ToImmutable(), SyntaxError = solutionUpdate.SyntaxError, }; } diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs index 0a4f36236f738..c4f134f6bbc50 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs @@ -91,8 +91,8 @@ void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, Di AddRudeEdit(RudeEditKind.InsertExtern, nameof(FeaturesResources.Adding_an_extern_0_requires_restarting_the_application)); AddRudeEdit(RudeEditKind.InsertDllImport, nameof(FeaturesResources.Adding_an_imported_method_requires_restarting_the_application)); AddRudeEdit(RudeEditKind.InsertOperator, nameof(FeaturesResources.Adding_a_user_defined_0_requires_restarting_the_application)); - AddRudeEdit(RudeEditKind.InsertIntoStruct, nameof(FeaturesResources.Adding_0_into_a_1_requires_restarting_the_application)); - AddRudeEdit(RudeEditKind.InsertIntoClassWithLayout, nameof(FeaturesResources.Adding_0_into_a_class_with_explicit_or_sequential_layout_requires_restarting_the_application)); + AddRudeEdit(RudeEditKind.InsertOrMoveStructMember, nameof(FeaturesResources.Adding_or_moving_0_of_1_requires_restarting_the_application)); + AddRudeEdit(RudeEditKind.InsertOrMoveTypeWithLayoutMember, nameof(FeaturesResources.Adding_or_moving_0_of_1_with_explicit_or_sequential_layout_requires_restarting_the_application)); AddRudeEdit(RudeEditKind.Move, nameof(FeaturesResources.Moving_0_requires_restarting_the_application)); AddRudeEdit(RudeEditKind.Delete, nameof(FeaturesResources.Deleting_0_requires_restarting_the_application)); AddRudeEdit(RudeEditKind.GenericMethodUpdate, nameof(FeaturesResources.Modifying_a_generic_method_requires_restarting_the_application)); @@ -148,6 +148,8 @@ void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, Di AddRudeEdit(RudeEditKind.ChangingAttribute, nameof(FeaturesResources.Changing_attribute_0_requires_restarting_the_application)); AddRudeEdit(RudeEditKind.ChangingNameOrSignatureOfActiveMember, nameof(FeaturesResources.Changing_name_or_signature_of_0_that_contains_an_active_statement_requires_restarting_the_application)); AddRudeEdit(RudeEditKind.UpdateMightNotHaveAnyEffect, nameof(FeaturesResources.Changing_0_might_not_have_any_effect_until_the_application_is_restarted), DiagnosticSeverity.Warning); + AddRudeEdit(RudeEditKind.TypeUpdateAroundActiveStatement, nameof(FeaturesResources.Updating_a_0_around_an_active_statement_requires_restarting_the_application)); + AddRudeEdit(RudeEditKind.InsertOrMoveComInterfaceMember, nameof(FeaturesResources.Adding_or_moving_0_of_a_COM_interface_requires_restarting_the_application)); // VB specific AddRudeEdit(RudeEditKind.HandlesClauseUpdate, nameof(FeaturesResources.Updating_the_Handles_clause_of_0_requires_restarting_the_application)); diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index 985a173377a30..464434736f223 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -423,7 +423,7 @@ internal static async ValueTask HasChangedOrAddedDocumentsAsync(Project ol return false; } - internal static async Task PopulateChangedAndAddedDocumentsAsync(Project oldProject, Project newProject, ArrayBuilder changedOrAddedDocuments, CancellationToken cancellationToken) + internal static async Task PopulateChangedAndAddedDocumentsAsync(Project oldProject, Project newProject, ArrayBuilder changedOrAddedDocuments, ArrayBuilder diagnostics, CancellationToken cancellationToken) { changedOrAddedDocuments.Clear(); @@ -432,14 +432,12 @@ internal static async Task PopulateChangedAndAddedDocumentsAsync(Project oldProj return; } + var oldSourceGeneratedDocumentStates = await GetSourceGeneratedDocumentStatesAsync(oldProject, diagnostics, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - var oldSourceGeneratedDocumentStates = await oldProject.Solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(oldProject.State, cancellationToken).ConfigureAwait(false); - + var newSourceGeneratedDocumentStates = await GetSourceGeneratedDocumentStatesAsync(newProject, diagnostics, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - var newSourceGeneratedDocumentStates = await newProject.Solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(newProject.State, cancellationToken).ConfigureAwait(false); - foreach (var documentId in newSourceGeneratedDocumentStates.GetChangedStateIds(oldSourceGeneratedDocumentStates, ignoreUnchangedContent: true)) { var newState = newSourceGeneratedDocumentStates.GetRequiredState(documentId); @@ -463,6 +461,23 @@ internal static async Task PopulateChangedAndAddedDocumentsAsync(Project oldProj } } + private static async ValueTask> GetSourceGeneratedDocumentStatesAsync(Project project, ArrayBuilder? diagnostics, CancellationToken cancellationToken) + { + var generatorDiagnostics = await project.Solution.CompilationState.GetSourceGeneratorDiagnosticsAsync(project.State, cancellationToken).ConfigureAwait(false); + + if (generatorDiagnostics is not []) + { + diagnostics?.Add(new ProjectDiagnostics(project.Id, generatorDiagnostics)); + } + + foreach (var generatorDiagnostic in generatorDiagnostics) + { + EditAndContinueService.Log.Write("Source generator failed: {0}", generatorDiagnostic); + } + + return await project.Solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(project.State, cancellationToken).ConfigureAwait(false); + } + /// /// Enumerates s of changed (not added or removed) s (not additional nor analyzer config). /// @@ -496,14 +511,12 @@ internal static async IAsyncEnumerable GetChangedDocumentsAsync(Proj yield break; } + var oldSourceGeneratedDocumentStates = await GetSourceGeneratedDocumentStatesAsync(oldProject, diagnostics: null, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - var oldSourceGeneratedDocumentStates = await oldProject.Solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(oldProject.State, cancellationToken).ConfigureAwait(false); - + var newSourceGeneratedDocumentStates = await GetSourceGeneratedDocumentStatesAsync(newProject, diagnostics: null, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); - var newSourceGeneratedDocumentStates = await newProject.Solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(newProject.State, cancellationToken).ConfigureAwait(false); - foreach (var documentId in newSourceGeneratedDocumentStates.GetChangedStateIds(oldSourceGeneratedDocumentStates, ignoreUnchangedContent: true)) { yield return documentId; @@ -530,7 +543,7 @@ internal static async IAsyncEnumerable GetChangedDocumentsAsync(Proj case CommittedSolution.DocumentState.OutOfSync: var descriptor = EditAndContinueDiagnosticDescriptors.GetDescriptor((oldDocumentState == CommittedSolution.DocumentState.Indeterminate) ? EditAndContinueErrorCode.UnableToReadSourceFileOrPdb : EditAndContinueErrorCode.DocumentIsOutOfSyncWithDebuggee); - documentDiagnostics.Add(Diagnostic.Create(descriptor, Location.Create(newDocument.FilePath!, textSpan: default, lineSpan: default), new[] { newDocument.FilePath })); + documentDiagnostics.Add(Diagnostic.Create(descriptor, Location.Create(newDocument.FilePath!, textSpan: default, lineSpan: default), [newDocument.FilePath])); break; case CommittedSolution.DocumentState.MatchesBuildOutput: @@ -830,7 +843,7 @@ public async ValueTask EmitSolutionUpdateAsync(Solution solution continue; } - await PopulateChangedAndAddedDocumentsAsync(oldProject, newProject, changedOrAddedDocuments, cancellationToken).ConfigureAwait(false); + await PopulateChangedAndAddedDocumentsAsync(oldProject, newProject, changedOrAddedDocuments, diagnostics, cancellationToken).ConfigureAwait(false); if (changedOrAddedDocuments.IsEmpty) { continue; diff --git a/src/Features/Core/Portable/EditAndContinue/EmitSolutionUpdateResults.cs b/src/Features/Core/Portable/EditAndContinue/EmitSolutionUpdateResults.cs index c56529f240735..7ca941eea35b5 100644 --- a/src/Features/Core/Portable/EditAndContinue/EmitSolutionUpdateResults.cs +++ b/src/Features/Core/Portable/EditAndContinue/EmitSolutionUpdateResults.cs @@ -32,49 +32,106 @@ internal readonly struct Data public required ImmutableArray Diagnostics { get; init; } [DataMember] - public required ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> RudeEdits { get; init; } + public required ImmutableArray RudeEdits { get; init; } [DataMember] public required DiagnosticData? SyntaxError { get; init; } + + internal ImmutableArray GetAllDiagnostics() + { + using var _ = ArrayBuilder.GetInstance(out var builder); + + // Add semantic and lowering diagnostics reported during delta emit: + + foreach (var diagnostic in Diagnostics) + { + builder.Add(diagnostic.ToHotReloadDiagnostic(ModuleUpdates.Status, isRudeEdit: false)); + } + + // Add syntax error: + + if (SyntaxError != null) + { + Debug.Assert(SyntaxError.DataLocation != null); + Debug.Assert(SyntaxError.Message != null); + + var fileSpan = SyntaxError.DataLocation.MappedFileSpan; + + builder.Add(new ManagedHotReloadDiagnostic( + SyntaxError.Id, + SyntaxError.Message, + ManagedHotReloadDiagnosticSeverity.Error, + fileSpan.Path, + fileSpan.Span.ToSourceSpan())); + } + + // Report all rude edits. + + foreach (var data in RudeEdits) + { + builder.Add(data.ToHotReloadDiagnostic(ModuleUpdates.Status, isRudeEdit: true)); + } + + return builder.ToImmutableAndClear(); + } } public static readonly EmitSolutionUpdateResults Empty = new() { + Solution = null, ModuleUpdates = new ModuleUpdates(ModuleUpdateStatus.None, []), Diagnostics = [], RudeEdits = [], SyntaxError = null }; + /// + /// Solution snapshot to resolve diagnostics in. + /// Note that this might be a different snapshot from the one passed to , + /// with source generator files refreshed. + /// + /// Null only for empty results. + /// + public required Solution? Solution { get; init; } + public required ModuleUpdates ModuleUpdates { get; init; } public required ImmutableArray Diagnostics { get; init; } - public required ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> RudeEdits { get; init; } + public required ImmutableArray RudeEdits { get; init; } public required Diagnostic? SyntaxError { get; init; } - public Data Dehydrate(Solution solution) - => new() + public Data Dehydrate() + => Solution == null + ? new() + { + ModuleUpdates = ModuleUpdates, + Diagnostics = [], + RudeEdits = [], + SyntaxError = null + } + : new() { ModuleUpdates = ModuleUpdates, - Diagnostics = Diagnostics.ToDiagnosticData(solution), - RudeEdits = RudeEdits, - SyntaxError = GetSyntaxErrorData(solution) + Diagnostics = Diagnostics.ToDiagnosticData(Solution), + RudeEdits = RudeEdits.ToDiagnosticData(Solution), + SyntaxError = GetSyntaxErrorData() }; - public DiagnosticData? GetSyntaxErrorData(Solution solution) + private DiagnosticData? GetSyntaxErrorData() { if (SyntaxError == null) { return null; } + Debug.Assert(Solution != null); Debug.Assert(SyntaxError.Location.SourceTree != null); - return DiagnosticData.Create(SyntaxError, solution.GetRequiredDocument(SyntaxError.Location.SourceTree)); + return DiagnosticData.Create(SyntaxError, Solution.GetRequiredDocument(SyntaxError.Location.SourceTree)); } private IEnumerable GetProjectsContainingBlockingRudeEdits(Solution solution) => RudeEdits - .Where(static e => e.Diagnostics.Any(static d => d.Kind.IsBlocking())) - .Select(static e => e.DocumentId.ProjectId) + .Where(static e => e.Diagnostics.HasBlockingRudeEdits()) + .Select(static e => e.ProjectId) .Distinct() .OrderBy(static id => id) .Select(solution.GetRequiredProject); @@ -124,7 +181,7 @@ public void GetProjectsToRebuildAndRestart( // We iterate over this set updating the reset set until no new project is added to the reset set. // Once a project is determined to affect a running process, all running processes that // reference this project are added to the reset set. The project is then removed from updated - // project set as it can't contribute any more running projects to the reset set. + // project set as it can't contribute any more running projects to the reset set. // If an updated project does not affect reset set in a given iteration, it stays in the set // because it may affect reset set later on, after another running project is added to it. @@ -192,7 +249,7 @@ bool AddImpactedRunningProjects(ICollection impactedProjects, Project i } } - public async Task> GetAllDiagnosticsAsync(Solution solution, CancellationToken cancellationToken) + public ImmutableArray GetAllDiagnostics() { using var _ = ArrayBuilder.GetInstance(out var diagnostics); @@ -209,84 +266,11 @@ public async Task> GetAllDiagnosticsAsync(Solution so } // add rude edits: - foreach (var (documentId, documentRudeEdits) in RudeEdits) + foreach (var (_, projectEmitDiagnostics) in RudeEdits) { - var document = await solution.GetDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); - Contract.ThrowIfNull(document); - - var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - foreach (var documentRudeEdit in documentRudeEdits) - { - diagnostics.Add(documentRudeEdit.ToDiagnostic(tree)); - } + diagnostics.AddRange(projectEmitDiagnostics); } return diagnostics.ToImmutableAndClear(); } - - internal static async ValueTask> GetAllDiagnosticsAsync( - Solution solution, - ImmutableArray diagnosticData, - ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> rudeEdits, - DiagnosticData? syntaxError, - ModuleUpdateStatus updateStatus, - CancellationToken cancellationToken) - { - using var _ = ArrayBuilder.GetInstance(out var builder); - - // Add semantic and lowering diagnostics reported during delta emit: - - foreach (var data in diagnosticData) - { - builder.Add(data.ToHotReloadDiagnostic(updateStatus)); - } - - // Add syntax error: - - if (syntaxError != null) - { - Debug.Assert(syntaxError.DataLocation != null); - Debug.Assert(syntaxError.Message != null); - - var fileSpan = syntaxError.DataLocation.MappedFileSpan; - - builder.Add(new ManagedHotReloadDiagnostic( - syntaxError.Id, - syntaxError.Message, - ManagedHotReloadDiagnosticSeverity.Error, - fileSpan.Path, - fileSpan.Span.ToSourceSpan())); - } - - // Report all rude edits. - - foreach (var (documentId, diagnostics) in rudeEdits) - { - var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); - var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - - foreach (var diagnostic in diagnostics) - { - var descriptor = EditAndContinueDiagnosticDescriptors.GetDescriptor(diagnostic.Kind); - - var severity = descriptor.DefaultSeverity switch - { - DiagnosticSeverity.Error => ManagedHotReloadDiagnosticSeverity.RestartRequired, - DiagnosticSeverity.Warning => ManagedHotReloadDiagnosticSeverity.Warning, - _ => throw ExceptionUtilities.UnexpectedValue(descriptor.DefaultSeverity) - }; - - var fileSpan = tree.GetMappedLineSpan(diagnostic.Span, cancellationToken); - - builder.Add(new ManagedHotReloadDiagnostic( - descriptor.Id, - string.Format(descriptor.MessageFormat.ToString(CultureInfo.CurrentUICulture), diagnostic.Arguments), - severity, - fileSpan.Path ?? "", - fileSpan.Span.ToSourceSpan())); - } - } - - return builder.ToImmutableAndClear(); - } } diff --git a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs index 0421adfb42391..dfb2d42af2407 100644 --- a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs +++ b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteDebuggingSessionProxy.cs @@ -53,64 +53,43 @@ await client.TryInvokeAsync( Dispose(); } - public async ValueTask<( - ModuleUpdates updates, - ImmutableArray diagnostics, - ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> rudeEdits, - DiagnosticData? syntaxError)> EmitSolutionUpdateAsync( + public async ValueTask EmitSolutionUpdateAsync( Solution solution, ActiveStatementSpanProvider activeStatementSpanProvider, CancellationToken cancellationToken) { - ModuleUpdates moduleUpdates; - ImmutableArray diagnosticData; - ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> rudeEdits; - DiagnosticData? syntaxError; - try { var client = await RemoteHostClient.TryGetClientAsync(services, cancellationToken).ConfigureAwait(false); if (client == null) { - var results = await GetLocalService().EmitSolutionUpdateAsync(sessionId, solution, activeStatementSpanProvider, cancellationToken).ConfigureAwait(false); - moduleUpdates = results.ModuleUpdates; - diagnosticData = results.Diagnostics.ToDiagnosticData(solution); - rudeEdits = results.RudeEdits; - syntaxError = results.GetSyntaxErrorData(solution); + return (await GetLocalService().EmitSolutionUpdateAsync(sessionId, solution, activeStatementSpanProvider, cancellationToken).ConfigureAwait(false)).Dehydrate(); } - else + + var result = await client.TryInvokeAsync( + solution, + (service, solutionInfo, callbackId, cancellationToken) => service.EmitSolutionUpdateAsync(solutionInfo, callbackId, sessionId, cancellationToken), + callbackTarget: new ActiveStatementSpanProviderCallback(activeStatementSpanProvider), + cancellationToken).ConfigureAwait(false); + + return result.HasValue ? result.Value : new EmitSolutionUpdateResults.Data() { - var result = await client.TryInvokeAsync( - solution, - (service, solutionInfo, callbackId, cancellationToken) => service.EmitSolutionUpdateAsync(solutionInfo, callbackId, sessionId, cancellationToken), - callbackTarget: new ActiveStatementSpanProviderCallback(activeStatementSpanProvider), - cancellationToken).ConfigureAwait(false); - - if (result.HasValue) - { - moduleUpdates = result.Value.ModuleUpdates; - diagnosticData = result.Value.Diagnostics; - rudeEdits = result.Value.RudeEdits; - syntaxError = result.Value.SyntaxError; - } - else - { - moduleUpdates = new ModuleUpdates(ModuleUpdateStatus.RestartRequired, []); - diagnosticData = []; - rudeEdits = []; - syntaxError = null; - } - } + ModuleUpdates = new ModuleUpdates(ModuleUpdateStatus.RestartRequired, []), + Diagnostics = [], + RudeEdits = [], + SyntaxError = null, + }; } catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { - diagnosticData = GetInternalErrorDiagnosticData(solution, e); - rudeEdits = []; - moduleUpdates = new ModuleUpdates(ModuleUpdateStatus.RestartRequired, []); - syntaxError = null; + return new EmitSolutionUpdateResults.Data() + { + ModuleUpdates = new ModuleUpdates(ModuleUpdateStatus.RestartRequired, []), + Diagnostics = GetInternalErrorDiagnosticData(solution, e), + RudeEdits = [], + SyntaxError = null, + }; } - - return (moduleUpdates, diagnosticData, rudeEdits, syntaxError); } private static ImmutableArray GetInternalErrorDiagnosticData(Solution solution, Exception e) diff --git a/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnostic.cs b/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnostic.cs index fa44813915315..9b3d43d4488f4 100644 --- a/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnostic.cs +++ b/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnostic.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Text; +using System.Collections.Immutable; namespace Microsoft.CodeAnalysis.EditAndContinue; @@ -52,6 +53,12 @@ internal static DiagnosticSeverity GetSeverity(this RudeEditKind kind) internal static bool IsBlocking(this RudeEditKind kind) => kind.GetSeverity() == DiagnosticSeverity.Error; + internal static bool IsBlockingRudeEdit(this Diagnostic diagnostic) + => diagnostic.Descriptor.DefaultSeverity == DiagnosticSeverity.Error; + + public static bool HasBlockingRudeEdits(this ImmutableArray diagnostics) + => diagnostics.Any(IsBlockingRudeEdit); + public static bool HasBlockingRudeEdits(this IEnumerable diagnostics) => diagnostics.Any(static e => e.Kind.IsBlocking()); } diff --git a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs index b7ebc68e84176..ad21348734f9b 100644 --- a/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs +++ b/src/Features/Core/Portable/EditAndContinue/RudeEditKind.cs @@ -41,8 +41,8 @@ internal enum RudeEditKind : ushort // InsertNonPublicConstructor = 27, // InsertGenericMethod = 28, InsertDllImport = 29, - InsertIntoStruct = 30, - InsertIntoClassWithLayout = 31, + InsertOrMoveStructMember = 30, + InsertOrMoveTypeWithLayoutMember = 31, Move = 32, Delete = 33, // MethodBodyAdd = 34, @@ -143,4 +143,6 @@ internal enum RudeEditKind : ushort ChangingAttribute = 116, ChangingNameOrSignatureOfActiveMember = 117, UpdateMightNotHaveAnyEffect = 118, + TypeUpdateAroundActiveStatement = 119, + InsertOrMoveComInterfaceMember = 120, } diff --git a/src/Features/Core/Portable/EditAndContinue/SemanticEditInfo.cs b/src/Features/Core/Portable/EditAndContinue/SemanticEditInfo.cs index f8b0ee33f870f..ffd746296a3b6 100644 --- a/src/Features/Core/Portable/EditAndContinue/SemanticEditInfo.cs +++ b/src/Features/Core/Portable/EditAndContinue/SemanticEditInfo.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Threading; using Microsoft.CodeAnalysis.Emit; namespace Microsoft.CodeAnalysis.EditAndContinue; @@ -57,15 +58,36 @@ public SemanticEditInfo( public static SemanticEditInfo CreateInsert(SymbolKey symbol, SymbolKey? partialType) => new(SemanticEditKind.Insert, symbol, syntaxMaps: default, partialType, deletedSymbolContainer: null); + public static SemanticEditInfo CreateInsert(ISymbol symbol, CancellationToken cancellationToken) + { + Debug.Assert(!symbol.IsPartialDefinition()); + var partialType = symbol.IsPartialImplementation() ? SymbolKey.Create(symbol.ContainingType, cancellationToken) : (SymbolKey?)null; + return CreateInsert(SymbolKey.Create(symbol, cancellationToken), partialType); + } + public static SemanticEditInfo CreateUpdate(SymbolKey symbol, SyntaxMaps syntaxMaps, SymbolKey? partialType) => new(SemanticEditKind.Update, symbol, syntaxMaps, partialType, deletedSymbolContainer: null); + public static SemanticEditInfo CreateUpdate(ISymbol symbol, SyntaxMaps syntaxMaps, CancellationToken cancellationToken) + { + Debug.Assert(!symbol.IsPartialDefinition()); + var partialType = symbol.IsPartialImplementation() ? SymbolKey.Create(symbol.ContainingType, cancellationToken) : (SymbolKey?)null; + return CreateUpdate(SymbolKey.Create(symbol, cancellationToken), syntaxMaps, partialType); + } + public static SemanticEditInfo CreateReplace(SymbolKey symbol, SymbolKey? partialType) => new(SemanticEditKind.Replace, symbol, syntaxMaps: default, partialType, deletedSymbolContainer: null); public static SemanticEditInfo CreateDelete(SymbolKey symbol, SymbolKey deletedSymbolContainer, SymbolKey? partialType) => new(SemanticEditKind.Delete, symbol, syntaxMaps: default, partialType, deletedSymbolContainer); + public static SemanticEditInfo CreateDelete(ISymbol symbol, SymbolKey containingSymbolKey, CancellationToken cancellationToken) + { + Debug.Assert(!symbol.IsPartialDefinition()); + var partialType = symbol.IsPartialImplementation() ? containingSymbolKey : (SymbolKey?)null; + return CreateDelete(SymbolKey.Create(symbol, cancellationToken), containingSymbolKey, partialType); + } + /// /// or or . /// diff --git a/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs b/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs index 0d2226145bc2a..88e9891d095b6 100644 --- a/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs +++ b/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs @@ -95,18 +95,25 @@ private static bool IsRazorDesignTimeOnlyDocument(string filePath) => filePath.EndsWith(".razor.g.cs", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".cshtml.g.cs", StringComparison.OrdinalIgnoreCase); - public static ManagedHotReloadDiagnostic ToHotReloadDiagnostic(this DiagnosticData data, ModuleUpdateStatus updateStatus) + public static ManagedHotReloadDiagnostic ToHotReloadDiagnostic(this DiagnosticData data, ModuleUpdateStatus updateStatus, bool isRudeEdit) { var fileSpan = data.DataLocation.MappedFileSpan; return new( data.Id, data.Message ?? FeaturesResources.Unknown_error_occurred, - updateStatus == ModuleUpdateStatus.RestartRequired - ? ManagedHotReloadDiagnosticSeverity.RestartRequired - : (data.Severity == DiagnosticSeverity.Error) - ? ManagedHotReloadDiagnosticSeverity.Error - : ManagedHotReloadDiagnosticSeverity.Warning, + isRudeEdit + ? data.DefaultSeverity switch + { + DiagnosticSeverity.Error => ManagedHotReloadDiagnosticSeverity.RestartRequired, + DiagnosticSeverity.Warning => ManagedHotReloadDiagnosticSeverity.Warning, + _ => throw ExceptionUtilities.UnexpectedValue(data.DefaultSeverity) + } + : updateStatus == ModuleUpdateStatus.RestartRequired + ? ManagedHotReloadDiagnosticSeverity.RestartRequired + : (data.Severity == DiagnosticSeverity.Error) + ? ManagedHotReloadDiagnosticSeverity.Error + : ManagedHotReloadDiagnosticSeverity.Warning, fileSpan.Path ?? "", fileSpan.Span.ToSourceSpan()); } @@ -183,9 +190,33 @@ private static bool ParsePrimaryParameterBackingFieldName(string fieldName, [Not => (IMethodSymbol?)constructor.ContainingType.GetMembers(WellKnownMemberNames.DeconstructMethodName).FirstOrDefault( static (symbol, constructor) => symbol is IMethodSymbol method && HasDeconstructorSignature(method, constructor), constructor)?.PartialAsImplementation(); - // https://github.com/dotnet/roslyn/issues/73772: does this helper need to be updated to use IPropertySymbol.PartialImplementationPart? + /// + /// Returns a partial implementation part of a partial member, or the member itself if it's not partial. + /// public static ISymbol PartialAsImplementation(this ISymbol symbol) - => symbol is IMethodSymbol { PartialImplementationPart: { } impl } ? impl : symbol; + => PartialImplementationPart(symbol) ?? symbol; + + public static bool IsPartialDefinition(this ISymbol symbol) + => symbol is IMethodSymbol { IsPartialDefinition: true } or IPropertySymbol { IsPartialDefinition: true }; + + public static bool IsPartialImplementation(this ISymbol symbol) + => symbol is IMethodSymbol { PartialDefinitionPart: not null } or IPropertySymbol { PartialDefinitionPart: not null }; + + public static ISymbol? PartialDefinitionPart(this ISymbol symbol) + => symbol switch + { + IMethodSymbol { PartialDefinitionPart: var def } => def, + IPropertySymbol { PartialDefinitionPart: var def } => def, + _ => null + }; + + public static ISymbol? PartialImplementationPart(this ISymbol symbol) + => symbol switch + { + IMethodSymbol { PartialImplementationPart: var impl } => impl, + IPropertySymbol { PartialImplementationPart: var impl } => impl, + _ => null + }; /// /// Returns true if any member of the type implements an interface member explicitly. diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Classification/ExportEmbeddedLanguageClassifier.cs b/src/Features/Core/Portable/EmbeddedLanguages/Classification/ExportEmbeddedLanguageClassifier.cs index 735645b0a0c51..650a27ca77d0c 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/Classification/ExportEmbeddedLanguageClassifier.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/Classification/ExportEmbeddedLanguageClassifier.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Classification; /// /// Use this attribute to export a . /// -internal class ExportEmbeddedLanguageClassifierAttribute( +internal sealed class ExportEmbeddedLanguageClassifierAttribute( string name, string[] languages, bool supportsUnannotatedAPIs, params string[] identifiers) : ExportEmbeddedLanguageFeatureServiceAttribute(typeof(IEmbeddedLanguageClassifier), name, languages, supportsUnannotatedAPIs, identifiers) { public ExportEmbeddedLanguageClassifierAttribute( diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeItem.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeItem.cs index 57ca43092a55a..c4a5544ac5f1a 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeItem.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateAndTimeItem.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime; -internal partial class DateAndTimeEmbeddedCompletionProvider +internal sealed partial class DateAndTimeEmbeddedCompletionProvider { private readonly struct DateAndTimeItem( string displayText, string inlineDescription, string fullDescription, CompletionChange change, bool isDefault) diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateTimeTree.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateTimeTree.cs index eae16db26deae..533faf39f6d64 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateTimeTree.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/DateTimeTree.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime; /// /// No actual tree for DateAndTime. But we use this to fit into the common pattern of embedded languages. /// -internal class DateTimeTree +internal sealed class DateTimeTree { public static readonly DateTimeTree Instance = new(); diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/EmbeddedCompletionContext.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/EmbeddedCompletionContext.cs index 38a0ab4c4ac88..fe071a5ea2f72 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/EmbeddedCompletionContext.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/EmbeddedCompletionContext.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime; -internal partial class DateAndTimeEmbeddedCompletionProvider +internal sealed partial class DateAndTimeEmbeddedCompletionProvider { private readonly struct EmbeddedCompletionContext { diff --git a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs index a42b7a39d6962..0dfbd9e4db13c 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/DateAndTime/LanguageServices/DateAndTimeEmbeddedLanguage.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.DateAndTime.LanguageServices; -internal class DateAndTimeEmbeddedLanguage : IEmbeddedLanguage +internal sealed class DateAndTimeEmbeddedLanguage : IEmbeddedLanguage { public readonly EmbeddedLanguageInfo Info; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageCommentDetector.cs b/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageCommentDetector.cs index 48e18827cfef8..32c480bf56cc3 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageCommentDetector.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageCommentDetector.cs @@ -43,7 +43,7 @@ public bool TryMatch( identifier = match.Groups["identifier"].Value; var optionGroup = match.Groups["option"]; -#if NETCOREAPP +#if NET options = optionGroup.Captures.Select(c => c.Value); #else options = optionGroup.Captures.OfType().Select(c => c.Value); diff --git a/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageMetadata.cs b/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageMetadata.cs index 79111d92ef969..42c620d4f36b1 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageMetadata.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/EmbeddedLanguageMetadata.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.EmbeddedLanguages; -internal class EmbeddedLanguageMetadata : OrderableMetadata, ILanguagesMetadata +internal sealed class EmbeddedLanguageMetadata : OrderableMetadata, ILanguagesMetadata { /// /// The particular language-IDs this language supports (for example 'regex/regexp/etc.'). diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonClassifier.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonClassifier.cs index 447d66618bc93..61df84bec7a9a 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonClassifier.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonClassifier.cs @@ -113,7 +113,7 @@ private static void AddTriviaClassifications(JsonTrivia trivia, EmbeddedLanguage } } - private class Visitor : IJsonNodeVisitor + private sealed class Visitor : IJsonNodeVisitor { public EmbeddedLanguageClassificationContext Context; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonEmbeddedLanguage.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonEmbeddedLanguage.cs index d146b801ac752..22a26090eba10 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonEmbeddedLanguage.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonEmbeddedLanguage.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; -internal class JsonEmbeddedLanguage : IEmbeddedLanguage +internal sealed class JsonEmbeddedLanguage : IEmbeddedLanguage { // No completion for embedded json currently. public EmbeddedLanguageCompletionProvider? CompletionProvider => null; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/EmbeddedCompletionContext.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/EmbeddedCompletionContext.cs index 8a5d2b415debf..42e215ae2dab0 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/EmbeddedCompletionContext.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/EmbeddedCompletionContext.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; -internal partial class RegexEmbeddedCompletionProvider +internal sealed partial class RegexEmbeddedCompletionProvider { private readonly struct EmbeddedCompletionContext { diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexClassifier.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexClassifier.cs index 6e565476b0a47..7f7f28d1c11bf 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexClassifier.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexClassifier.cs @@ -101,7 +101,7 @@ private static void AddTriviaClassifications(RegexTrivia trivia, EmbeddedLanguag } } - private class Visitor : IRegexNodeVisitor + private sealed class Visitor : IRegexNodeVisitor { public EmbeddedLanguageClassificationContext Context; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexEmbeddedLanguage.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexEmbeddedLanguage.cs index 8abe207bc42ca..857b8244a1258 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexEmbeddedLanguage.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexEmbeddedLanguage.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; -internal class RegexEmbeddedLanguage : IEmbeddedLanguage +internal sealed class RegexEmbeddedLanguage : IEmbeddedLanguage { public readonly EmbeddedLanguageInfo Info; diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexItem.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexItem.cs index a94c33595ef24..7a1c3c469f5cd 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexItem.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/RegexItem.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; -internal partial class RegexEmbeddedCompletionProvider +internal sealed partial class RegexEmbeddedCompletionProvider { private readonly struct RegexItem( string displayText, string inlineDescription, string fullDescription, CompletionChange change) diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexCharClass.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexCharClass.cs index 96d6859e5f10b..8e1974186964a 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexCharClass.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/RegexCharClass.cs @@ -204,11 +204,7 @@ public static bool IsBoundaryWordChar(VirtualChar r) // Fast lookup in our lookup table for ASCII characters. This is purely an optimization, and has the // behavior as if we fell through to the switch below (which was actually used to produce the lookup table). - ReadOnlySpan asciiLookup = new byte[] - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, - 0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07 - }; + ReadOnlySpan asciiLookup = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07]; var chDiv8 = ch >> 3; if ((uint)chDiv8 < (uint)asciiLookup.Length) { diff --git a/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameCompilationUnit.cs b/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameCompilationUnit.cs index d898248b6fd7e..f4cccc973fe87 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameCompilationUnit.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameCompilationUnit.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.EmbeddedLanguages.StackFrame; /// Any leading "at " is considered trivia of , and " in " is put as trivia for the . /// Remaining unparsable text is put as leading trivia on the /// -internal class StackFrameCompilationUnit(StackFrameMethodDeclarationNode methodDeclaration, StackFrameFileInformationNode? fileInformationExpression, StackFrameToken endOfLineToken) : StackFrameNode(StackFrameKind.CompilationUnit) +internal sealed class StackFrameCompilationUnit(StackFrameMethodDeclarationNode methodDeclaration, StackFrameFileInformationNode? fileInformationExpression, StackFrameToken endOfLineToken) : StackFrameNode(StackFrameKind.CompilationUnit) { /// /// Represents the method declaration for a stack frame. Requires at least a member diff --git a/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameTree.cs b/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameTree.cs index 5c18fc66ae027..b103880e4066c 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameTree.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/StackFrame/StackFrameTree.cs @@ -8,6 +8,6 @@ namespace Microsoft.CodeAnalysis.EmbeddedLanguages.StackFrame; -internal class StackFrameTree(VirtualCharSequence text, StackFrameCompilationUnit root) : EmbeddedSyntaxTree(text, root, ImmutableArray.Empty) +internal sealed class StackFrameTree(VirtualCharSequence text, StackFrameCompilationUnit root) : EmbeddedSyntaxTree(text, root, ImmutableArray.Empty) { } diff --git a/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs b/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs index b683bd5d55a9a..64d8bcaba5598 100644 --- a/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs +++ b/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -12,7 +10,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Formatting; @@ -21,6 +18,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Rename; +using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; @@ -28,7 +26,9 @@ namespace Microsoft.CodeAnalysis.EncapsulateField; -internal abstract partial class AbstractEncapsulateFieldService : ILanguageService +internal abstract partial class AbstractEncapsulateFieldService< + TConstructorDeclarationSyntax> : IEncapsulateFieldService + where TConstructorDeclarationSyntax : SyntaxNode { private static readonly CultureInfo EnUSCultureInfo = new("en-US"); private static readonly SymbolRenameOptions s_symbolRenameOptions = new( @@ -39,9 +39,9 @@ internal abstract partial class AbstractEncapsulateFieldService : ILanguageServi protected abstract Task RewriteFieldNameAndAccessibilityAsync(string originalFieldName, bool makePrivate, Document document, SyntaxAnnotation declarationAnnotation, CancellationToken cancellationToken); protected abstract Task> GetFieldsAsync(Document document, TextSpan span, CancellationToken cancellationToken); - protected abstract IEnumerable GetConstructorNodes(INamedTypeSymbol containingType); + protected abstract IEnumerable GetConstructorNodes(INamedTypeSymbol containingType); - public async Task EncapsulateFieldsInSpanAsync(Document document, TextSpan span, bool useDefaultBehavior, CancellationToken cancellationToken) + public async Task EncapsulateFieldsInSpanAsync(Document document, TextSpan span, bool useDefaultBehavior, CancellationToken cancellationToken) { var fields = await GetFieldsAsync(document, span, cancellationToken).ConfigureAwait(false); if (fields.IsDefaultOrEmpty) @@ -60,14 +60,12 @@ public async Task> GetEncapsulateFieldCodeActionsAsyn if (fields.IsDefaultOrEmpty) return []; + // there is only one field if (fields.Length == 1) - { - // there is only one field return EncapsulateOneField(document, fields[0]); - } // there are multiple fields. - using var _ = ArrayBuilder.GetInstance(out var builder); + using var builder = TemporaryArray.Empty; if (span.IsEmpty) { @@ -147,8 +145,8 @@ private async Task EncapsulateFieldsInCurrentProcessAsync(Document doc var currentSolution = document.Project.Solution; foreach (var field in fields) { - document = currentSolution.GetDocument(document.Id); - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + document = currentSolution.GetRequiredDocument(document.Id); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var compilation = semanticModel.Compilation; // We couldn't resolve this field. skip it @@ -165,7 +163,7 @@ private async Task EncapsulateFieldsInCurrentProcessAsync(Document doc return currentSolution; } - private async Task EncapsulateFieldAsync( + private async Task EncapsulateFieldAsync( Document document, IFieldSymbol field, bool updateReferences, @@ -183,9 +181,9 @@ private async Task EncapsulateFieldAsync( var solution = document.Project.Solution; // Resolve the annotated symbol and prepare for rename. - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var compilation = semanticModel.Compilation; - field = field.GetSymbolKey(cancellationToken).Resolve(compilation, cancellationToken: cancellationToken).Symbol as IFieldSymbol; + field = (IFieldSymbol)field.GetSymbolKey(cancellationToken).Resolve(compilation, cancellationToken: cancellationToken).Symbol!; // We couldn't resolve field after annotating its declaration. Bail if (field == null) @@ -193,7 +191,7 @@ private async Task EncapsulateFieldAsync( var solutionNeedingProperty = await UpdateReferencesAsync( updateReferences, solution, document, field, finalFieldName, generatedPropertyName, cancellationToken).ConfigureAwait(false); - document = solutionNeedingProperty.GetDocument(document.Id); + document = solutionNeedingProperty.GetRequiredDocument(document.Id); var markFieldPrivate = field.DeclaredAccessibility != Accessibility.Private; var rewrittenFieldDeclaration = await RewriteFieldNameAndAccessibilityAsync(finalFieldName, markFieldPrivate, document, declarationAnnotation, cancellationToken).ConfigureAwait(false); @@ -202,11 +200,11 @@ private async Task EncapsulateFieldAsync( document = await Formatter.FormatAsync(document.WithSyntaxRoot(rewrittenFieldDeclaration), Formatter.Annotation, formattingOptions, cancellationToken).ConfigureAwait(false); - semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var newRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var newRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var newDeclaration = newRoot.GetAnnotatedNodes(declarationAnnotation).First(); - field = semanticModel.GetDeclaredSymbol(newDeclaration, cancellationToken) as IFieldSymbol; + field = (IFieldSymbol)semanticModel.GetRequiredDeclaredSymbol(newDeclaration, cancellationToken); var generatedProperty = GenerateProperty( generatedPropertyName, @@ -250,10 +248,10 @@ private async Task UpdateReferencesAsync( filter: (docId, span) => IntersectsWithAny(docId, span, constructorLocations), cancellationToken).ConfigureAwait(false); - document = solution.GetDocument(document.Id); - var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + document = solution.GetRequiredDocument(document.Id); + var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - field = field.GetSymbolKey(cancellationToken).Resolve(compilation, cancellationToken: cancellationToken).Symbol as IFieldSymbol; + field = (IFieldSymbol)field.GetSymbolKey(cancellationToken).Resolve(compilation, cancellationToken: cancellationToken).Symbol!; constructorLocations = GetConstructorLocations(solution, field.ContainingType); } @@ -310,7 +308,9 @@ private static bool IntersectsWithAny(DocumentId documentId, TextSpan span, ISet } private ISet<(DocumentId documentId, TextSpan span)> GetConstructorLocations(Solution solution, INamedTypeSymbol containingType) - => GetConstructorNodes(containingType).Select(n => (solution.GetRequiredDocument(n.SyntaxTree).Id, n.Span)).ToSet(); + => GetConstructorNodes(containingType) + .Select(n => (solution.GetRequiredDocument(n.SyntaxTree).Id, n.Span)) + .ToSet(); protected static async Task AddPropertyAsync( Document document, @@ -319,7 +319,7 @@ protected static async Task AddPropertyAsync( IPropertySymbol property, CancellationToken cancellationToken) { - var codeGenerationService = document.GetLanguageService(); + var codeGenerationService = document.GetRequiredLanguageService(); var fieldDeclaration = field.DeclaringSyntaxReferences.First(); @@ -341,13 +341,13 @@ protected static IPropertySymbol GenerateProperty( SyntaxAnnotation annotation, Document document) { - var factory = document.GetLanguageService(); + var factory = document.GetRequiredLanguageService(); var propertySymbol = annotation.AddAnnotationToSymbol(CodeGenerationSymbolFactory.CreatePropertySymbol(containingType: containingSymbol, attributes: [], accessibility: ComputeAccessibility(accessibility, field.Type), modifiers: new DeclarationModifiers(isStatic: field.IsStatic, isReadOnly: field.IsReadOnly, isUnsafe: field.RequiresUnsafeModifier()), - type: field.GetSymbolType(), + type: field.Type, refKind: RefKind.None, explicitInterfaceImplementations: default, name: propertyName, diff --git a/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs index 9705677551493..c973c07f4748c 100644 --- a/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs +++ b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs @@ -10,20 +10,15 @@ namespace Microsoft.CodeAnalysis.EncapsulateField; -[ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, - Name = PredefinedCodeRefactoringProviderNames.EncapsulateField), Shared] -internal sealed class EncapsulateFieldRefactoringProvider : CodeRefactoringProvider +[ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.EncapsulateField), Shared] +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class EncapsulateFieldRefactoringProvider() : CodeRefactoringProvider { - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public EncapsulateFieldRefactoringProvider() - { - } - public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, textSpan, cancellationToken) = context; - var service = document.GetRequiredLanguageService(); + var service = document.GetRequiredLanguageService(); var actions = await service.GetEncapsulateFieldCodeActionsAsync(document, textSpan, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); diff --git a/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldResult.cs b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldResult.cs index ab3e3385cd1c4..0318404ba0175 100644 --- a/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldResult.cs +++ b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldResult.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.EncapsulateField; -internal class EncapsulateFieldResult(string name, Glyph glyph, Func> getSolutionAsync) +internal sealed class EncapsulateFieldResult(string name, Glyph glyph, Func> getSolutionAsync) { public readonly string Name = name; public readonly Glyph Glyph = glyph; diff --git a/src/Features/Core/Portable/EncapsulateField/IEncapsulateFieldService.cs b/src/Features/Core/Portable/EncapsulateField/IEncapsulateFieldService.cs new file mode 100644 index 0000000000000..b58cb1a93dc69 --- /dev/null +++ b/src/Features/Core/Portable/EncapsulateField/IEncapsulateFieldService.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.EncapsulateField; + +internal interface IEncapsulateFieldService : ILanguageService +{ + Task> GetEncapsulateFieldCodeActionsAsync(Document document, TextSpan span, CancellationToken cancellationToken); + + Task EncapsulateFieldsAsync(Document document, ImmutableArray fields, bool updateReferences, CancellationToken cancellationToken); + Task EncapsulateFieldsInSpanAsync(Document document, TextSpan span, bool useDefaultBehavior, CancellationToken cancellationToken); +} diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingHotReloadService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingHotReloadService.cs index e1eba7afd4c8d..d09a0aec08776 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingHotReloadService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/API/UnitTestingHotReloadService.cs @@ -126,7 +126,7 @@ public async Task StartSessionAsync(Solution solution, ImmutableArray ca update.UpdatedMethods, update.UpdatedTypes)); - var diagnostics = await results.GetAllDiagnosticsAsync(solution, cancellationToken).ConfigureAwait(false); + var diagnostics = results.GetAllDiagnostics(); return (updates, diagnostics); } diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/LegacySolutionEvents/UnitTestingLegacySolutionEventsListener.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/LegacySolutionEvents/UnitTestingLegacySolutionEventsListener.cs index c0f1d64a0f1d3..f9086e7dd3cb3 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/LegacySolutionEvents/UnitTestingLegacySolutionEventsListener.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/LegacySolutionEvents/UnitTestingLegacySolutionEventsListener.cs @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.LegacySolutionEvents /// for unit testing. /// [Export(typeof(ILegacySolutionEventsListener)), Shared] -internal class UnitTestingLegacySolutionEventsListener : ILegacySolutionEventsListener +internal sealed class UnitTestingLegacySolutionEventsListener : ILegacySolutionEventsListener { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/ExportUnitTestingIncrementalAnalyzerProviderAttribute.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/ExportUnitTestingIncrementalAnalyzerProviderAttribute.cs index db7888c6378e1..91b2972431612 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/ExportUnitTestingIncrementalAnalyzerProviderAttribute.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/ExportUnitTestingIncrementalAnalyzerProviderAttribute.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] -internal class ExportUnitTestingIncrementalAnalyzerProviderAttribute : ExportAttribute +internal sealed class ExportUnitTestingIncrementalAnalyzerProviderAttribute : ExportAttribute { public string Name { get; } public string[] WorkspaceKinds { get; } diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/IUnitTestingDocumentDifferenceService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/IUnitTestingDocumentDifferenceService.cs index 9eb899374184f..2fa20aad791a1 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/IUnitTestingDocumentDifferenceService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/IUnitTestingDocumentDifferenceService.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; -internal class UnitTestingDocumentDifferenceResult(UnitTestingInvocationReasons changeType, SyntaxNode? changedMember = null) +internal sealed class UnitTestingDocumentDifferenceResult(UnitTestingInvocationReasons changeType, SyntaxNode? changedMember = null) { public UnitTestingInvocationReasons ChangeType { get; } = changeType; public SyntaxNode? ChangedMember { get; } = changedMember; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerProgressReporter.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerProgressReporter.cs index 2ae33c566501e..6d2c70bdc6617 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerProgressReporter.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerProgressReporter.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; -internal partial class UnitTestingSolutionCrawlerRegistrationService : IUnitTestingSolutionCrawlerRegistrationService +internal sealed partial class UnitTestingSolutionCrawlerRegistrationService : IUnitTestingSolutionCrawlerRegistrationService { /// /// Progress reporter @@ -94,7 +94,7 @@ public void Dispose() /// /// reporter that doesn't do anything /// - private class UnitTestingNullReporter : IUnitTestingSolutionCrawlerProgressReporter + private sealed class UnitTestingNullReporter : IUnitTestingSolutionCrawlerProgressReporter { public static readonly UnitTestingNullReporter Instance = new(); diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerRegistrationService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerRegistrationService.cs index 71e37c111d40d..951f5a269cc7d 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerRegistrationService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerRegistrationService.cs @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler { [ExportWorkspaceService(typeof(IUnitTestingSolutionCrawlerRegistrationService), ServiceLayer.Host), Shared] - internal partial class UnitTestingSolutionCrawlerRegistrationService : IUnitTestingSolutionCrawlerRegistrationService + internal sealed partial class UnitTestingSolutionCrawlerRegistrationService : IUnitTestingSolutionCrawlerRegistrationService { private const string Default = "*"; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerService.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerService.cs index 1f92b2d3da666..9ae6f7976df4a 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerService.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingSolutionCrawlerService.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; -internal partial class UnitTestingSolutionCrawlerRegistrationService : IUnitTestingSolutionCrawlerRegistrationService +internal sealed partial class UnitTestingSolutionCrawlerRegistrationService : IUnitTestingSolutionCrawlerRegistrationService { /// /// nested class of since it is tightly coupled with it. @@ -19,7 +19,7 @@ internal partial class UnitTestingSolutionCrawlerRegistrationService : IUnitTest /// more than one . /// [ExportWorkspaceService(typeof(IUnitTestingSolutionCrawlerService), ServiceLayer.Default), Shared] - internal class UnitTestingSolutionCrawlerService : IUnitTestingSolutionCrawlerService + internal sealed class UnitTestingSolutionCrawlerService : IUnitTestingSolutionCrawlerService { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncDocumentWorkItemQueue.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncDocumentWorkItemQueue.cs index c3137abbe6336..fb8a2a9635cee 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncDocumentWorkItemQueue.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncDocumentWorkItemQueue.cs @@ -9,11 +9,11 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; -internal partial class UnitTestingSolutionCrawlerRegistrationService +internal sealed partial class UnitTestingSolutionCrawlerRegistrationService { - internal partial class UnitTestingWorkCoordinator + internal sealed partial class UnitTestingWorkCoordinator { - private class UnitTestingAsyncDocumentWorkItemQueue(UnitTestingSolutionCrawlerProgressReporter progressReporter) : UnitTestingAsyncWorkItemQueue(progressReporter) + private sealed class UnitTestingAsyncDocumentWorkItemQueue(UnitTestingSolutionCrawlerProgressReporter progressReporter) : UnitTestingAsyncWorkItemQueue(progressReporter) { private readonly Dictionary> _documentWorkQueue = []; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncProjectWorkItemQueue.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncProjectWorkItemQueue.cs index 553de0265fcba..ba19a19a75adc 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncProjectWorkItemQueue.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncProjectWorkItemQueue.cs @@ -10,9 +10,9 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; -internal partial class UnitTestingSolutionCrawlerRegistrationService +internal sealed partial class UnitTestingSolutionCrawlerRegistrationService { - internal partial class UnitTestingWorkCoordinator + internal sealed partial class UnitTestingWorkCoordinator { private sealed class UnitTestingAsyncProjectWorkItemQueue(UnitTestingSolutionCrawlerProgressReporter progressReporter) : UnitTestingAsyncWorkItemQueue(progressReporter) { diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncWorkItemQueue.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncWorkItemQueue.cs index 988aeeac606ef..f83c05f0c510e 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncWorkItemQueue.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingAsyncWorkItemQueue.cs @@ -12,9 +12,9 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; -internal partial class UnitTestingSolutionCrawlerRegistrationService +internal sealed partial class UnitTestingSolutionCrawlerRegistrationService { - internal partial class UnitTestingWorkCoordinator + internal sealed partial class UnitTestingWorkCoordinator { private abstract class UnitTestingAsyncWorkItemQueue(UnitTestingSolutionCrawlerProgressReporter progressReporter) : IDisposable where TKey : class diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingIncrementalAnalyzerProcessor.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingIncrementalAnalyzerProcessor.cs index 7b883e0bed9fd..1ac1eab621f3c 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingIncrementalAnalyzerProcessor.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingIncrementalAnalyzerProcessor.cs @@ -20,11 +20,11 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; -internal partial class UnitTestingSolutionCrawlerRegistrationService +internal sealed partial class UnitTestingSolutionCrawlerRegistrationService { - internal partial class UnitTestingWorkCoordinator + internal sealed partial class UnitTestingWorkCoordinator { - private partial class UnitTestingIncrementalAnalyzerProcessor + private sealed partial class UnitTestingIncrementalAnalyzerProcessor { private static readonly Func s_enqueueLogger = EnqueueLogger; @@ -281,7 +281,7 @@ internal void WaitUntilCompletion() } } - private class UnitTestingAnalyzersGetter(IEnumerable> analyzerProviders) + private sealed class UnitTestingAnalyzersGetter(IEnumerable> analyzerProviders) { private readonly List> _analyzerProviders = analyzerProviders.ToList(); private readonly Dictionary<(string workspaceKind, SolutionServices services), ImmutableArray> _analyzerMap = []; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingNormalPriorityProcessor.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingNormalPriorityProcessor.cs index 9c8fb46ddf534..1fe3c323fddc9 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingNormalPriorityProcessor.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingNormalPriorityProcessor.cs @@ -40,9 +40,6 @@ private sealed class UnitTestingNormalPriorityProcessor : AbstractUnitTestingPri // priorities active,visible, opened files and etc private Solution? _lastSolution = null; - // whether this processor is running or not - private Task _running; - public UnitTestingNormalPriorityProcessor( IAsynchronousOperationListener listener, UnitTestingIncrementalAnalyzerProcessor processor, @@ -52,7 +49,7 @@ public UnitTestingNormalPriorityProcessor( CancellationToken shutdownToken) : base(listener, processor, lazyAnalyzers, globalOperationNotificationService, backOffTimeSpan, shutdownToken) { - _running = Task.CompletedTask; + Running = Task.CompletedTask; _workItemQueue = new UnitTestingAsyncDocumentWorkItemQueue(processor._registration.ProgressReporter); _higherPriorityDocumentsNotProcessed = new ConcurrentDictionary(concurrencyLevel: 2, capacity: 20); @@ -98,7 +95,8 @@ private void AddHigherPriorityDocument(DocumentId id) protected override Task WaitAsync(CancellationToken cancellationToken) => _workItemQueue.WaitAsync(cancellationToken); - public Task Running => _running; + /// whether this processor is running or not + public Task Running { get; private set; } public int WorkItemCount => _workItemQueue.WorkItemCount; public bool HasAnyWork => _workItemQueue.HasAnyWork; @@ -113,7 +111,7 @@ protected override async Task ExecuteAsync() try { // mark it as running - _running = source.Task; + Running = source.Task; await WaitForHigherPriorityOperationsAsync().ConfigureAwait(false); diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingSemanticChangeProcessor.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingSemanticChangeProcessor.cs index 931cbd82838b7..3506f75438884 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingSemanticChangeProcessor.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingSemanticChangeProcessor.cs @@ -318,7 +318,7 @@ public Document GetRequiredDocument() => UnitTestingWorkCoordinator.GetRequiredDocument(Project, _documentId, _document); } - private class UnitTestingProjectProcessor : UnitTestingIdleProcessor + private sealed class UnitTestingProjectProcessor : UnitTestingIdleProcessor { private static readonly Func s_enqueueLogger = (t, i) => string.Format("[{0}] {1}", t, i.ToString()); diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingWorkItem.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingWorkItem.cs index b8b14050ad1cd..e081b62d74437 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingWorkItem.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.UnitTestingWorkItem.cs @@ -12,9 +12,9 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; -internal partial class UnitTestingSolutionCrawlerRegistrationService +internal sealed partial class UnitTestingSolutionCrawlerRegistrationService { - internal partial class UnitTestingWorkCoordinator + internal sealed partial class UnitTestingWorkCoordinator { // this is internal only type private readonly struct UnitTestingWorkItem diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.cs index 17094bd99dc8e..973a916c9963e 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/SolutionCrawler/UnitTestingWorkCoordinator.cs @@ -17,12 +17,10 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler; -internal partial class UnitTestingSolutionCrawlerRegistrationService +internal sealed partial class UnitTestingSolutionCrawlerRegistrationService { internal sealed partial class UnitTestingWorkCoordinator : IUnitTestingWorkCoordinator { - private readonly UnitTestingRegistration _registration; - private readonly CountLogAggregator _logAggregator = new(); private readonly IAsynchronousOperationListener _listener; private readonly Microsoft.CodeAnalysis.SolutionCrawler.ISolutionCrawlerOptionsService? _solutionCrawlerOptionsService; @@ -40,10 +38,10 @@ public UnitTestingWorkCoordinator( IEnumerable> analyzerProviders, UnitTestingRegistration registration) { - _registration = registration; + Registration = registration; _listener = listener; - _solutionCrawlerOptionsService = _registration.Services.GetService(); + _solutionCrawlerOptionsService = Registration.Services.GetService(); // event and worker queues _shutdownToken = _shutdownNotificationSource.Token; @@ -56,7 +54,7 @@ public UnitTestingWorkCoordinator( _documentAndProjectWorkerProcessor = new UnitTestingIncrementalAnalyzerProcessor( listener, analyzerProviders, - _registration, + Registration, allFilesWorkerBackOffTimeSpan, entireProjectWorkerBackOffTimeSpan, _shutdownToken); @@ -64,11 +62,11 @@ public UnitTestingWorkCoordinator( var semanticBackOffTimeSpan = UnitTestingSolutionCrawlerTimeSpan.SemanticChangeBackOff; var projectBackOffTimeSpan = UnitTestingSolutionCrawlerTimeSpan.ProjectPropagationBackOff; - _semanticChangeProcessor = new UnitTestingSemanticChangeProcessor(listener, _registration, _documentAndProjectWorkerProcessor, semanticBackOffTimeSpan, projectBackOffTimeSpan, _shutdownToken); + _semanticChangeProcessor = new UnitTestingSemanticChangeProcessor(listener, Registration, _documentAndProjectWorkerProcessor, semanticBackOffTimeSpan, projectBackOffTimeSpan, _shutdownToken); } - public UnitTestingRegistration Registration => _registration; - public int CorrelationId => _registration.CorrelationId; + public UnitTestingRegistration Registration { get; } + public int CorrelationId => Registration.CorrelationId; public void AddAnalyzer(IUnitTestingIncrementalAnalyzer analyzer) { @@ -76,7 +74,7 @@ public void AddAnalyzer(IUnitTestingIncrementalAnalyzer analyzer) _documentAndProjectWorkerProcessor.AddAnalyzer(analyzer); // and ask to re-analyze whole solution for the given analyzer - var scope = new UnitTestingReanalyzeScope(_registration.GetSolutionToAnalyze().Id); + var scope = new UnitTestingReanalyzeScope(Registration.GetSolutionToAnalyze().Id); Reanalyze(analyzer, scope); } @@ -89,7 +87,7 @@ public void Reanalyze(IUnitTestingIncrementalAnalyzer analyzer, UnitTestingReana { // log big reanalysis request from things like fix all, suppress all or option changes // we are not interested in 1 file re-analysis request which can happen from like venus typing - var solution = _registration.GetSolutionToAnalyze(); + var solution = Registration.GetSolutionToAnalyze(); UnitTestingSolutionCrawlerLogger.LogReanalyze( CorrelationId, analyzer, scope.GetDocumentCount(solution), scope.GetLanguagesStringForTelemetry(solution)); } @@ -386,7 +384,7 @@ private async Task EnqueueFullProjectWorkItemAsync(Project project, UnitTestingI private async Task EnqueueWorkItemAsync(IUnitTestingIncrementalAnalyzer analyzer, UnitTestingReanalyzeScope scope) { - var solution = _registration.GetSolutionToAnalyze(); + var solution = Registration.GetSolutionToAnalyze(); var invocationReasons = UnitTestingInvocationReasons.Reanalyze; @@ -491,7 +489,7 @@ internal TestAccessor(UnitTestingWorkCoordinator workCoordinator) internal void WaitUntilCompletion(ImmutableArray workers) { - var solution = _workCoordinator._registration.GetSolutionToAnalyze(); + var solution = _workCoordinator.Registration.GetSolutionToAnalyze(); var list = new List(); foreach (var project in solution.Projects) diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs index 06d674767fdcc..aeb2a32036ddb 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessor.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting; [method: Obsolete(MefConstruction.FactoryMethodMessage, error: true)] -internal class UnitTestingStackTraceServiceAccessor( +internal sealed class UnitTestingStackTraceServiceAccessor( IStackTraceExplorerService stackTraceExplorerService) : IUnitTestingStackTraceServiceAccessor { private readonly IStackTraceExplorerService _stackTraceExplorerService = stackTraceExplorerService; diff --git a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessorFactory.cs b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessorFactory.cs index c8a08a1adf5cf..6552fd22ffd96 100644 --- a/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessorFactory.cs +++ b/src/Features/Core/Portable/ExternalAccess/UnitTesting/UnitTestingStackTraceServiceAccessorFactory.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting; [ExportWorkspaceServiceFactory(typeof(IUnitTestingStackTraceServiceAccessor))] [Shared] -internal class UnitTestingStackTraceServiceAccessorFactory : IWorkspaceServiceFactory +internal sealed class UnitTestingStackTraceServiceAccessorFactory : IWorkspaceServiceFactory { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigableItemWrapper.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigableItemWrapper.cs index 35d8bb57ec320..4aa2ababfbe27 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigableItemWrapper.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigableItemWrapper.cs @@ -12,7 +12,6 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript; internal sealed class VSTypeScriptNavigableItemWrapper(IVSTypeScriptNavigableItem navigableItem) : INavigableItem { private readonly IVSTypeScriptNavigableItem _navigableItem = navigableItem; - private readonly INavigableItem.NavigableDocument _navigableDocument = INavigableItem.NavigableDocument.FromDocument(navigableItem.Document); public Glyph Glyph => _navigableItem.Glyph; @@ -22,7 +21,7 @@ internal sealed class VSTypeScriptNavigableItemWrapper(IVSTypeScriptNavigableIte public bool IsImplicitlyDeclared => _navigableItem.IsImplicitlyDeclared; - public INavigableItem.NavigableDocument Document => _navigableDocument; + public INavigableItem.NavigableDocument Document { get; } = INavigableItem.NavigableDocument.FromDocument(navigableItem.Document); public TextSpan SourceSpan => _navigableItem.SourceSpan; diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigateToSearchService.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigateToSearchService.cs index 64d222b91d20f..0514f706b5a53 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigateToSearchService.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigateToSearchService.cs @@ -91,7 +91,7 @@ async Task ProcessProjectAsync(Project project) private static INavigateToSearchResult Convert(IVSTypeScriptNavigateToSearchResult result) => new WrappedNavigateToSearchResult(result); - private class WrappedNavigateToSearchResult(IVSTypeScriptNavigateToSearchResult result) : INavigateToSearchResult + private sealed class WrappedNavigateToSearchResult(IVSTypeScriptNavigateToSearchResult result) : INavigateToSearchResult { private readonly IVSTypeScriptNavigateToSearchResult _result = result; diff --git a/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs b/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs index 4a8013d7da7ec..323402fe384fd 100644 --- a/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs +++ b/src/Features/Core/Portable/ExternalAccess/Watch/Api/WatchHotReloadService.cs @@ -178,7 +178,7 @@ public async Task GetUpdatesAsync(Solution solution, Func(); var projectsToRebuild = new HashSet(); @@ -206,6 +206,10 @@ public void EndSession() _sessionId = default; } + // access to internal API: + public static Solution WithProjectInfo(Solution solution, ProjectInfo info) + => solution.WithProjectInfo(info); + internal TestAccessor GetTestAccessor() => new(this); diff --git a/src/Features/Core/Portable/ExtractClass/ExtractClassOptions.cs b/src/Features/Core/Portable/ExtractClass/ExtractClassOptions.cs index 23a1c43465498..7af4fb35e2e08 100644 --- a/src/Features/Core/Portable/ExtractClass/ExtractClassOptions.cs +++ b/src/Features/Core/Portable/ExtractClass/ExtractClassOptions.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.ExtractClass; -internal class ExtractClassOptions( +internal sealed class ExtractClassOptions( string fileName, string typeName, bool sameFile, @@ -20,7 +20,7 @@ internal class ExtractClassOptions( public ImmutableArray MemberAnalysisResults { get; } = memberAnalysisResults; } -internal class ExtractClassMemberAnalysisResult( +internal sealed class ExtractClassMemberAnalysisResult( ISymbol member, bool makeAbstract) { diff --git a/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs b/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs index 7ee3ab7a48de2..3204254d824b9 100644 --- a/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.ExtractClass; -internal class ExtractClassWithDialogCodeAction( +internal sealed class ExtractClassWithDialogCodeAction( Document document, TextSpan span, IExtractClassOptionsService service, diff --git a/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeAction.cs b/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeAction.cs index c64eefa52fa33..5f70ff3b00389 100644 --- a/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeAction.cs +++ b/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeAction.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.ExtractInterface; -internal class ExtractInterfaceCodeAction(AbstractExtractInterfaceService extractInterfaceService, ExtractInterfaceTypeAnalysisResult typeAnalysisResult) : CodeActionWithOptions +internal sealed class ExtractInterfaceCodeAction(AbstractExtractInterfaceService extractInterfaceService, ExtractInterfaceTypeAnalysisResult typeAnalysisResult) : CodeActionWithOptions { private readonly ExtractInterfaceTypeAnalysisResult _typeAnalysisResult = typeAnalysisResult; private readonly AbstractExtractInterfaceService _extractInterfaceService = extractInterfaceService; diff --git a/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeRefactoringProvider.cs b/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeRefactoringProvider.cs index 94d92966ba688..b7b3ad772eefb 100644 --- a/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeRefactoringProvider.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.ExtractInterface; [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.ExtractInterface), Shared] -internal class ExtractInterfaceCodeRefactoringProvider : CodeRefactoringProvider +internal sealed class ExtractInterfaceCodeRefactoringProvider : CodeRefactoringProvider { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.Result.cs b/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.Result.cs index ad61a7c9cd4b5..810d71fa21c45 100644 --- a/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.Result.cs +++ b/src/Features/Core/Portable/ExtractMethod/AbstractSyntaxTriviaService.Result.cs @@ -13,12 +13,10 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; internal abstract partial class AbstractSyntaxTriviaService { - private class Result : ITriviaSavedResult + private sealed class Result : ITriviaSavedResult { private static readonly AnnotationResolver s_defaultAnnotationResolver = ResolveAnnotation; private static readonly TriviaResolver s_defaultTriviaResolver = ResolveTrivia; - - private readonly SyntaxNode _root; private readonly int _endOfLineKind; private readonly Dictionary _annotations; @@ -34,14 +32,14 @@ public Result( Contract.ThrowIfNull(annotations); Contract.ThrowIfNull(triviaList); - _root = root; + Root = root; _endOfLineKind = endOfLineKind; _annotations = annotations; _triviaList = triviaList; } - public SyntaxNode Root => _root; + public SyntaxNode Root { get; } public SyntaxNode RestoreTrivia( SyntaxNode root, diff --git a/src/Features/Core/Portable/ExtractMethod/ExtractMethodMatrix.cs b/src/Features/Core/Portable/ExtractMethod/ExtractMethodMatrix.cs index 521d3698fc4cf..4f60e6641870e 100644 --- a/src/Features/Core/Portable/ExtractMethod/ExtractMethodMatrix.cs +++ b/src/Features/Core/Portable/ExtractMethod/ExtractMethodMatrix.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; -internal class ExtractMethodMatrix +internal sealed class ExtractMethodMatrix { private static readonly Dictionary s_matrix; diff --git a/src/Features/Core/Portable/ExtractMethod/InsertionPoint.cs b/src/Features/Core/Portable/ExtractMethod/InsertionPoint.cs index 382d963e69b42..36cea7e39f7de 100644 --- a/src/Features/Core/Portable/ExtractMethod/InsertionPoint.cs +++ b/src/Features/Core/Portable/ExtractMethod/InsertionPoint.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; -internal class InsertionPoint +internal sealed class InsertionPoint { private readonly SyntaxAnnotation _annotation; private readonly Lazy _context; diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs index 7bbf5e53edcca..778340fcfe87c 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.AnalyzerResult.cs @@ -31,7 +31,6 @@ protected sealed class AnalyzerResult( { private readonly IList _typeParametersInDeclaration = typeParametersInDeclaration.ToList(); private readonly IList _typeParametersInConstraintList = typeParametersInConstraintList.ToList(); - private readonly ImmutableArray _variables = variables; private readonly VariableInfo _variableToUseAsReturnValue = variableToUseAsReturnValue; /// @@ -62,7 +61,7 @@ protected sealed class AnalyzerResult( /// public OperationStatus Status { get; } = status; - public ImmutableArray Variables => _variables; + public ImmutableArray Variables { get; } = variables; public ReadOnlyCollection MethodTypeParametersInDeclaration { @@ -109,32 +108,32 @@ public IEnumerable MethodParameters { get { - return _variables.Where(v => v.UseAsParameter); + return Variables.Where(v => v.UseAsParameter); } } public ImmutableArray GetVariablesToSplitOrMoveIntoMethodDefinition(CancellationToken cancellationToken) { - return _variables.WhereAsArray( + return Variables.WhereAsArray( v => v.GetDeclarationBehavior(cancellationToken) is DeclarationBehavior.SplitIn or DeclarationBehavior.MoveIn); } public IEnumerable GetVariablesToMoveIntoMethodDefinition(CancellationToken cancellationToken) - => _variables.Where(v => v.GetDeclarationBehavior(cancellationToken) == DeclarationBehavior.MoveIn); + => Variables.Where(v => v.GetDeclarationBehavior(cancellationToken) == DeclarationBehavior.MoveIn); public IEnumerable GetVariablesToMoveOutToCallSite(CancellationToken cancellationToken) - => _variables.Where(v => v.GetDeclarationBehavior(cancellationToken) == DeclarationBehavior.MoveOut); + => Variables.Where(v => v.GetDeclarationBehavior(cancellationToken) == DeclarationBehavior.MoveOut); public IEnumerable GetVariablesToMoveOutToCallSiteOrDelete(CancellationToken cancellationToken) { - return _variables.Where(v => v.GetDeclarationBehavior(cancellationToken) is DeclarationBehavior.MoveOut or + return Variables.Where(v => v.GetDeclarationBehavior(cancellationToken) is DeclarationBehavior.MoveOut or DeclarationBehavior.Delete); } public IEnumerable GetVariablesToSplitOrMoveOutToCallSite(CancellationToken cancellationToken) { - return _variables.Where(v => v.GetDeclarationBehavior(cancellationToken) is DeclarationBehavior.SplitOut or + return Variables.Where(v => v.GetDeclarationBehavior(cancellationToken) is DeclarationBehavior.SplitOut or DeclarationBehavior.MoveOut); } diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.GeneratedCode.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.GeneratedCode.cs index 8c8e87977ed4d..7e7c440aaea7a 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.GeneratedCode.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.GeneratedCode.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; internal abstract partial class MethodExtractor { - internal class GeneratedCode + internal sealed class GeneratedCode { public GeneratedCode( SemanticDocument document, diff --git a/src/Features/Core/Portable/ExtractMethod/OperationStatus.cs b/src/Features/Core/Portable/ExtractMethod/OperationStatus.cs index ece120dbb1e9c..028fdf2055d99 100644 --- a/src/Features/Core/Portable/ExtractMethod/OperationStatus.cs +++ b/src/Features/Core/Portable/ExtractMethod/OperationStatus.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; -internal partial class OperationStatus +internal sealed partial class OperationStatus { public OperationStatus(bool succeeded, string reason) { diff --git a/src/Features/Core/Portable/ExtractMethod/OperationStatus_Statics.cs b/src/Features/Core/Portable/ExtractMethod/OperationStatus_Statics.cs index 8aff152ff69b7..1938f6d573211 100644 --- a/src/Features/Core/Portable/ExtractMethod/OperationStatus_Statics.cs +++ b/src/Features/Core/Portable/ExtractMethod/OperationStatus_Statics.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; -internal partial class OperationStatus +internal sealed partial class OperationStatus { public static readonly OperationStatus SucceededStatus = new(succeeded: true, reason: null); public static readonly OperationStatus FailedWithUnknownReason = new(succeeded: false, reason: FeaturesResources.Unknown_error_occurred); diff --git a/src/Features/Core/Portable/ExtractMethod/OperationStatus`1.cs b/src/Features/Core/Portable/ExtractMethod/OperationStatus`1.cs index c003f1124a449..f1a621a29d163 100644 --- a/src/Features/Core/Portable/ExtractMethod/OperationStatus`1.cs +++ b/src/Features/Core/Portable/ExtractMethod/OperationStatus`1.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; /// /// operation status paired with data /// -internal class OperationStatus(OperationStatus status, T data) +internal sealed class OperationStatus(OperationStatus status, T data) { public OperationStatus Status { get; } = status; public T Data { get; } = data; diff --git a/src/Features/Core/Portable/ExtractMethod/ParameterStyle.cs b/src/Features/Core/Portable/ExtractMethod/ParameterStyle.cs index cba9900857912..3e68b33d79676 100644 --- a/src/Features/Core/Portable/ExtractMethod/ParameterStyle.cs +++ b/src/Features/Core/Portable/ExtractMethod/ParameterStyle.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; -internal class ParameterStyle +internal sealed class ParameterStyle { public ParameterBehavior ParameterBehavior { get; private set; } public DeclarationBehavior DeclarationBehavior { get; private set; } diff --git a/src/Features/Core/Portable/ExtractMethod/ReturnStyle.cs b/src/Features/Core/Portable/ExtractMethod/ReturnStyle.cs index b0b74031cca98..03e4097d93042 100644 --- a/src/Features/Core/Portable/ExtractMethod/ReturnStyle.cs +++ b/src/Features/Core/Portable/ExtractMethod/ReturnStyle.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; -internal class ReturnStyle +internal sealed class ReturnStyle { public ParameterBehavior ParameterBehavior { get; private set; } public ReturnBehavior ReturnBehavior { get; private set; } diff --git a/src/Features/Core/Portable/ExtractMethod/UniqueNameGenerator.cs b/src/Features/Core/Portable/ExtractMethod/UniqueNameGenerator.cs index 3e6a118860c00..b958ef1103e14 100644 --- a/src/Features/Core/Portable/ExtractMethod/UniqueNameGenerator.cs +++ b/src/Features/Core/Portable/ExtractMethod/UniqueNameGenerator.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; -internal class UniqueNameGenerator +internal sealed class UniqueNameGenerator { private readonly SemanticModel _semanticModel; diff --git a/src/Features/Core/Portable/ExtractMethod/VariableStyle.cs b/src/Features/Core/Portable/ExtractMethod/VariableStyle.cs index 6615b896696e0..636c1a883a6bf 100644 --- a/src/Features/Core/Portable/ExtractMethod/VariableStyle.cs +++ b/src/Features/Core/Portable/ExtractMethod/VariableStyle.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.ExtractMethod; -internal class VariableStyle +internal sealed class VariableStyle { public ParameterStyle ParameterStyle { get; private set; } public ReturnStyle ReturnStyle { get; private set; } diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index f892d1bed8689..0c9edac5be335 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -201,12 +201,6 @@ Generate delegating constructor '{0}({1})' - - Generate constructor '{0}({1})' - - - Generate field assigning constructor '{0}({1})' - Generate Equals and GetHashCode @@ -216,51 +210,12 @@ Generate GetHashCode() - - Generate constructor in '{0}' - - - Generate all - - - Generate enum member '{0}' - - - Generate constant '{0}' - - - Generate read-only property '{0}' - - - Generate property '{0}' - - - Generate read-only field '{0}' - - - Generate field '{0}' - - - Generate local '{0}' - Generate {0} '{1}' in new file Generate nested {0} '{1}' - - Implement all members explicitly - - - Implement interface abstractly - - - Implement interface through '{0}' - - - Implement interface - Introduce field for '{0}' @@ -399,8 +354,8 @@ Changing the declaration scope of a captured variable '{0}' requires restarting the application. - - Adding {0} into a {1} requires restarting the application. + + Adding or moving {0} of {1} requires restarting the application. Adding {0} into an interface requires restarting the application. @@ -408,8 +363,11 @@ Adding {0} into an interface method requires restarting the application. - - Adding {0} into a class with explicit or sequential layout requires restarting the application. + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + Adding or moving {0} of a COM interface requires restarting the application. Updating the modifiers of {0} requires restarting the application. @@ -499,6 +457,9 @@ Updating a {0} around an active statement requires restarting the application. + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + Updating async or iterator modifier around an active statement requires restarting the application. {Locked="async"}{Locked="iterator"} "async" and "iterator" are C#/VB keywords and should not be localized. @@ -553,15 +514,6 @@ Unexpected interface member kind: {0} - - Generate abstract property '{0}' - - - Generate abstract method '{0}' - - - Generate method '{0}' - The symbol does not have an icon. @@ -658,12 +610,6 @@ Do you want to continue? Note: Tab twice to insert the '{0}' snippet. - - Implement interface explicitly with Dispose pattern - - - Implement interface with Dispose pattern - Suppress {0} @@ -688,12 +634,6 @@ Do you want to continue? Containing Type - - TODO: dispose managed state (managed objects) - - - TODO: set large fields to null - Modifying {0} which contains a static variable requires restarting the application. @@ -829,9 +769,6 @@ This version used in: {2} Install version '{0}' - - Generate variable '{0}' - Classes @@ -914,9 +851,6 @@ This version used in: {2} (Unknown) - - Implement abstract class - Use framework type @@ -1252,12 +1186,6 @@ This version used in: {2} Target type matches - - Generate parameter '{0}' - - - Generate parameter '{0}' (and overrides/implementations) - in Source (attribute) @@ -1322,31 +1250,16 @@ This version used in: {2} Value: - - Implement through '{0}' - Implement all interfaces explicitly Implement explicitly - - Base classes contain inaccessible unimplemented members - Add 'DebuggerDisplay' attribute {Locked="DebuggerDisplay"} "DebuggerDisplay" is a BCL class and should not be localized. - - Do not change this code. Put cleanup code in '{0}' method - - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - AM/PM (abbreviated) @@ -1804,9 +1717,6 @@ If the "H" format specifier is used without other custom format specifiers, it's The "HH" custom format specifier (plus any number of additional "H" specifiers) represents the hour as a number from 00 through 23; that is, the hour is represented by a zero-based 24-hour clock that counts the hours since midnight. A single-digit hour is formatted with a leading zero. - - Implement remaining members explicitly - Generate for '{0}' @@ -2627,12 +2537,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Document must be contained in the workspace that created this service - - Generate constructor in '{0}' (with fields) - - - Generate constructor in '{0}' (with properties) - Property reference cannot be updated @@ -3244,7 +3148,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Query - Semantic search is only supported when code analysis runs in a separate process on the latest .NET (see Tools > Options > Text Editor > C# > Advanced). + Semantic search is only supported when code analysis runs in a separate process on the latest .NET (see Tools > Options > Text Editor > C# > Advanced). Semantic search query terminated with exception @@ -3264,10 +3168,10 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Unable to load type '{0}': '{1}' - - Type members - .NET Code Actions + + Symbol search + \ No newline at end of file diff --git a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs index 2ce30295bc78a..421cf9b778d42 100644 --- a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs +++ b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs @@ -50,7 +50,11 @@ await _context.OnReferencesFoundAsync( /// Forwards IFindReferencesProgress calls to an IFindUsagesContext instance. /// private sealed class FindReferencesProgressAdapter( - Solution solution, IFindUsagesContext context, FindReferencesSearchOptions searchOptions, OptionsProvider classificationOptions) + Solution solution, + ISymbol symbol, + IFindUsagesContext context, + FindReferencesSearchOptions searchOptions, + OptionsProvider classificationOptions) : IStreamingFindReferencesProgress { /// @@ -85,11 +89,14 @@ private async ValueTask GetDefinitionItemAsync(SymbolGroup group { if (!_definitionToItem.TryGetValue(group, out var definitionItem)) { + // Ensure that we prioritize the symbol the user is searching for as the primary definition. This + // will ensure it shows up above the rest in the final results. + var isPrimary = group.Symbols.Contains(symbol.OriginalDefinition); definitionItem = await group.ToClassifiedDefinitionItemAsync( classificationOptions, solution, searchOptions, - isPrimary: _definitionToItem.Count == 0, + isPrimary, includeHiddenLocations: false, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindReferences.cs b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindReferences.cs index 4b99445de4f90..cc12aece54e1f 100644 --- a/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindReferences.cs +++ b/src/Features/Core/Portable/FindUsages/AbstractFindUsagesService_FindReferences.cs @@ -161,7 +161,8 @@ private static Task FindReferencesInCurrentProcessAsync( OptionsProvider classificationOptions, CancellationToken cancellationToken) { - var progress = new FindReferencesProgressAdapter(project.Solution, context, searchOptions, classificationOptions); + var progress = new FindReferencesProgressAdapter( + project.Solution, symbol, context, searchOptions, classificationOptions); return SymbolFinder.FindReferencesAsync( symbol, project.Solution, progress, documents: null, searchOptions, cancellationToken); } diff --git a/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs b/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs index 03b8f72c8f8d9..90c740c26d18e 100644 --- a/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs +++ b/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.FindUsages; -internal partial class DefinitionItem +internal abstract partial class DefinitionItem { /// /// Implementation of a that sits on top of a diff --git a/src/Features/Core/Portable/Formatting/ExportNewDocumentFormattingProviderAttribute.cs b/src/Features/Core/Portable/Formatting/ExportNewDocumentFormattingProviderAttribute.cs index 97aca5f7e8b51..62a1bdb2c68ab 100644 --- a/src/Features/Core/Portable/Formatting/ExportNewDocumentFormattingProviderAttribute.cs +++ b/src/Features/Core/Portable/Formatting/ExportNewDocumentFormattingProviderAttribute.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Formatting; [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] -internal class ExportNewDocumentFormattingProviderAttribute(string languageName) : ExportAttribute(typeof(INewDocumentFormattingProvider)) +internal sealed class ExportNewDocumentFormattingProviderAttribute(string languageName) : ExportAttribute(typeof(INewDocumentFormattingProvider)) { public string Language { get; } = languageName; } diff --git a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyService.cs b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyService.cs index 226d4274bac46..aad6340b3f3a5 100644 --- a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyService.cs +++ b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyService.cs @@ -222,7 +222,7 @@ private async Task> ProcessNodeAsync(Document document, var newRoot = await ReplaceNodeAsync(simpleName, containerName, originalSymbol.IsType, cancellationToken).ConfigureAwait(false); var newDocument = document.WithSyntaxRoot(newRoot); var cleanedDocument = await CodeAction.CleanupDocumentAsync( - newDocument, CodeCleanupOptions.GetDefault(document.Project.Services), cancellationToken).ConfigureAwait(false); + newDocument, await document.GetCodeCleanupOptionsAsync(cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false); return await cleanedDocument.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs index c6e64993f5256..ac299b49b2e62 100644 --- a/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.GenerateComparisonOperators; using static CodeGenerationSymbolFactory; [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.GenerateComparisonOperators), Shared] -internal class GenerateComparisonOperatorsCodeRefactoringProvider : CodeRefactoringProvider +internal sealed class GenerateComparisonOperatorsCodeRefactoringProvider : CodeRefactoringProvider { private const string LeftName = "left"; private const string RightName = "right"; diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs index 98d9879c14c61..4f76eca26640a 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs @@ -62,6 +62,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke factory.IdentifierName(symbolName)); factory.AddAssignmentStatements( + factory.SyntaxGeneratorInternal, semanticModel, parameter, fieldAccess, _addNullChecks, useThrowExpressions, nullCheckStatements, assignStatements); diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs index c2ac3f8841bf4..e280a6bfb748a 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs @@ -45,6 +45,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke var preferThrowExpression = await _service.PrefersThrowExpressionAsync(_document, cancellationToken).ConfigureAwait(false); var members = factory.CreateMemberDelegatingConstructor( + factory.SyntaxGeneratorInternal, semanticModel, _state.ContainingType.Name, _state.ContainingType, @@ -87,12 +88,12 @@ public override string Title if (_state.DelegatedConstructor == null) { - return string.Format(FeaturesResources.Generate_constructor_0_1, + return string.Format(CodeFixesResources.Generate_constructor_0_1, _state.ContainingType.Name, parameterString); } else { - return string.Format(FeaturesResources.Generate_field_assigning_constructor_0_1, + return string.Format(CodeFixesResources.Generate_field_assigning_constructor_0_1, _state.ContainingType.Name, parameterString); } } diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs index 3e0dc1d8070c5..e68125b8f8022 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.GenerateConstructorFromMembers; internal abstract partial class AbstractGenerateConstructorFromMembersCodeRefactoringProvider : AbstractGenerateFromMembersCodeRefactoringProvider { - private class GenerateConstructorWithDialogCodeAction( + private sealed class GenerateConstructorWithDialogCodeAction( AbstractGenerateConstructorFromMembersCodeRefactoringProvider service, Document document, TextSpan textSpan, diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.State.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.State.cs index f43137c327287..2ae6aa4ddad96 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.State.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.State.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.GenerateConstructorFromMembers; internal abstract partial class AbstractGenerateConstructorFromMembersCodeRefactoringProvider { - private class State + private sealed class State { public TextSpan TextSpan { get; private set; } public IMethodSymbol? MatchingConstructor { get; private set; } diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs index 663cef174b2a3..ed1f4d9eeee90 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs @@ -24,7 +24,7 @@ namespace Microsoft.CodeAnalysis.GenerateDefaultConstructors; /// [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.GenerateDefaultConstructors), Shared] -internal class GenerateDefaultConstructorsCodeRefactoringProvider : CodeRefactoringProvider +internal sealed class GenerateDefaultConstructorsCodeRefactoringProvider : CodeRefactoringProvider { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/FormatLargeBinaryExpressionRule.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/FormatLargeBinaryExpressionRule.cs index 0ed9f1ac6b8bc..9e36c0a38f817 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/FormatLargeBinaryExpressionRule.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/FormatLargeBinaryExpressionRule.cs @@ -8,13 +8,13 @@ namespace Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers; -internal partial class AbstractGenerateEqualsAndGetHashCodeService +internal abstract partial class AbstractGenerateEqualsAndGetHashCodeService { /// /// Specialized formatter for the "return a == obj.a && b == obj.b && c == obj.c && ... /// code that we spit out. /// - private class FormatLargeBinaryExpressionRule(ISyntaxFactsService syntaxFacts) : AbstractFormattingRule + private sealed class FormatLargeBinaryExpressionRule(ISyntaxFactsService syntaxFacts) : AbstractFormattingRule { private readonly ISyntaxFactsService _syntaxFacts = syntaxFacts; diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs index e21b01c830d2b..c36a45152c412 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs @@ -16,9 +16,9 @@ namespace Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers; -internal partial class GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider +internal sealed partial class GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider { - private partial class GenerateEqualsAndGetHashCodeAction( + private sealed partial class GenerateEqualsAndGetHashCodeAction( Document document, SyntaxNode typeDeclaration, INamedTypeSymbol containingType, diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs index de20348c4545f..dca654d2d1504 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs @@ -31,7 +31,7 @@ namespace Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers; [ExtensionOrder(After = PredefinedCodeRefactoringProviderNames.GenerateConstructorFromMembers, Before = PredefinedCodeRefactoringProviderNames.AddConstructorParametersFromMembers)] [SuppressMessage("RoslynDiagnosticsReliability", "RS0034:Exported parts should have [ImportingConstructor]", Justification = "Used incorrectly by tests")] -internal partial class GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider(IPickMembersService? pickMembersService) : AbstractGenerateFromMembersCodeRefactoringProvider +internal sealed partial class GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider(IPickMembersService? pickMembersService) : AbstractGenerateFromMembersCodeRefactoringProvider { public const string GenerateOperatorsId = nameof(GenerateOperatorsId); public const string ImplementIEquatableId = nameof(ImplementIEquatableId); diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs index a096ad822ea42..9a1146eadc7d7 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers; -internal partial class GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider +internal sealed partial class GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider { private sealed class GenerateEqualsAndGetHashCodeWithDialogCodeAction( GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider service, diff --git a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs index dcf02f3bae548..96c52ac3ca1e7 100644 --- a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.GenerateOverrides; Name = PredefinedCodeRefactoringProviderNames.GenerateOverrides), Shared] [ExtensionOrder(After = PredefinedCodeRefactoringProviderNames.AddConstructorParametersFromMembers)] [SuppressMessage("RoslynDiagnosticsReliability", "RS0034:Exported parts should have [ImportingConstructor]", Justification = "Used incorrectly by tests")] -internal partial class GenerateOverridesCodeRefactoringProvider(IPickMembersService? pickMembersService) : CodeRefactoringProvider +internal sealed partial class GenerateOverridesCodeRefactoringProvider(IPickMembersService? pickMembersService) : CodeRefactoringProvider { private readonly IPickMembersService? _pickMembersService_forTestingPurposes = pickMembersService; diff --git a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs index ab69fc2aa0117..bd8c52909be04 100644 --- a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.GenerateOverrides; -internal partial class GenerateOverridesCodeRefactoringProvider +internal sealed partial class GenerateOverridesCodeRefactoringProvider { private sealed class GenerateOverridesWithDialogCodeAction( GenerateOverridesCodeRefactoringProvider service, diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs index e1cee305dece0..5610d8f7c2374 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs @@ -28,7 +28,7 @@ internal abstract partial class AbstractGenerateTypeService> GetGenerateIntoExistingD if (!isDialog) { // Not generated from the Dialog - containers = GetNamespaceToGenerateInto().Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + containers = GetNamespaceToGenerateInto().Split(['.'], StringSplitOptions.RemoveEmptyEntries); } else if (!_service.IsSimpleName(_state.NameOrMemberAccessExpression)) { // If the usage was with a namespace - containers = GetNamespaceToGenerateIntoForUsageWithNamespace(targetProject, triggeringProject).Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + containers = GetNamespaceToGenerateIntoForUsageWithNamespace(targetProject, triggeringProject).Split(['.'], StringSplitOptions.RemoveEmptyEntries); } else { diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs index f2bc225c4db8a..d167c36a037dd 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.GenerateNamedType.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.GenerateType; internal abstract partial class AbstractGenerateTypeService { - private partial class Editor + private sealed partial class Editor { private async Task GenerateNamedTypeAsync() { @@ -219,6 +219,7 @@ private async Task AddFieldDelegatingConstructorAsync( if (!(parameters.Count == 0 && options is { TypeKind: TypeKind.Struct })) { members.AddRange(factory.CreateMemberDelegatingConstructor( + factory.SyntaxGeneratorInternal, _semanticDocument.SemanticModel, DetermineName(), null, parameters.ToImmutable(), Accessibility.Public, parameterToExistingFieldMap.ToImmutable(), @@ -316,7 +317,7 @@ private TypeKind DetermineTypeKind() : TypeKind.Class; } - protected IList GetAvailableTypeParameters() + private IList GetAvailableTypeParameters() { var availableInnerTypeParameters = _service.GetTypeParameters(_state, _semanticDocument.SemanticModel, _cancellationToken); var availableOuterTypeParameters = !_intoNamespace && _state.TypeToGenerateInOpt != null diff --git a/src/Features/Core/Portable/GenerateType/GenerateTypeDialogOptions.cs b/src/Features/Core/Portable/GenerateType/GenerateTypeDialogOptions.cs index 525b22514cf74..30de33e1b39b4 100644 --- a/src/Features/Core/Portable/GenerateType/GenerateTypeDialogOptions.cs +++ b/src/Features/Core/Portable/GenerateType/GenerateTypeDialogOptions.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.GenerateType; -internal class GenerateTypeDialogOptions( +internal sealed class GenerateTypeDialogOptions( bool isPublicOnlyAccessibility = false, TypeKindOptions typeKindOptions = TypeKindOptions.AllOptions, bool isAttribute = false) diff --git a/src/Features/Core/Portable/GenerateType/GenerateTypeOptionsResult.cs b/src/Features/Core/Portable/GenerateType/GenerateTypeOptionsResult.cs index de6900b422722..4d0e6e78f32f4 100644 --- a/src/Features/Core/Portable/GenerateType/GenerateTypeOptionsResult.cs +++ b/src/Features/Core/Portable/GenerateType/GenerateTypeOptionsResult.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.GenerateType; -internal class GenerateTypeOptionsResult +internal sealed class GenerateTypeOptionsResult { public static readonly GenerateTypeOptionsResult Cancelled = new(isCancelled: true); diff --git a/src/Features/Core/Portable/GenerateType/TypeKindOptions.cs b/src/Features/Core/Portable/GenerateType/TypeKindOptions.cs index 3aa95697c74c6..68a6c52a4688a 100644 --- a/src/Features/Core/Portable/GenerateType/TypeKindOptions.cs +++ b/src/Features/Core/Portable/GenerateType/TypeKindOptions.cs @@ -38,7 +38,7 @@ internal enum TypeKindOptions GenericInCompatibleTypes = Enum | Module } -internal class TypeKindOptionsHelper +internal sealed class TypeKindOptionsHelper { public static bool IsClass(TypeKindOptions option) => (option & TypeKindOptions.Class) != 0 ? true : false; diff --git a/src/Features/Core/Portable/Highlighting/ExportHighlighterAttribute.cs b/src/Features/Core/Portable/Highlighting/ExportHighlighterAttribute.cs index 59ace2db4e0ca..783b812d13c90 100644 --- a/src/Features/Core/Portable/Highlighting/ExportHighlighterAttribute.cs +++ b/src/Features/Core/Portable/Highlighting/ExportHighlighterAttribute.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Highlighting; [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] [ExcludeFromCodeCoverage] -internal class ExportHighlighterAttribute(string language) : ExportAttribute(typeof(IHighlighter)) +internal sealed class ExportHighlighterAttribute(string language) : ExportAttribute(typeof(IHighlighter)) { public string Language { get; } = language ?? throw new ArgumentNullException(nameof(language)); } diff --git a/src/Features/Core/Portable/Highlighting/HighlightingService.cs b/src/Features/Core/Portable/Highlighting/HighlightingService.cs index 157398c197662..13a72aa52d554 100644 --- a/src/Features/Core/Portable/Highlighting/HighlightingService.cs +++ b/src/Features/Core/Portable/Highlighting/HighlightingService.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.Highlighting; [Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal class HighlightingService( +internal sealed class HighlightingService( [ImportMany] IEnumerable> highlighters) : IHighlightingService { private readonly List> _highlighters = highlighters.ToList(); diff --git a/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs b/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs index 3fb4cc930394f..41cc1521afdc6 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs @@ -382,7 +382,7 @@ private async Task AddNullCheckStatementAsync( private TStatementSyntax CreateNullCheckStatement(SemanticModel semanticModel, SyntaxGenerator generator, IParameterSymbol parameter, TSimplifierOptions options) => CreateParameterCheckIfStatement( - (TExpressionSyntax)generator.CreateNullCheckExpression(semanticModel, parameter.Name), + (TExpressionSyntax)generator.CreateNullCheckExpression(generator.SyntaxGeneratorInternal, semanticModel, parameter.Name), (TStatementSyntax)generator.CreateThrowArgumentNullExceptionStatement(semanticModel.Compilation, parameter), options); diff --git a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs index 0d890aadf1f0b..d4c9d3545c465 100644 --- a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs +++ b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs @@ -376,7 +376,7 @@ private static ImmutableDictionary ComputeRenameTable( return renameTable.ToImmutableDictionary(); } - private class LocalVariableDeclarationVisitor : OperationWalker + private sealed class LocalVariableDeclarationVisitor : OperationWalker { private readonly CancellationToken _cancellationToken; private readonly HashSet _allSymbols = []; diff --git a/src/Features/Core/Portable/Intents/IntentProviderAttribute.cs b/src/Features/Core/Portable/Intents/IntentProviderAttribute.cs index a6a48241580a9..9c1d71ea00f24 100644 --- a/src/Features/Core/Portable/Intents/IntentProviderAttribute.cs +++ b/src/Features/Core/Portable/Intents/IntentProviderAttribute.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Features.Intents; [MetadataAttribute] [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -internal class IntentProviderAttribute(string intentName, string languageName) : ExportAttribute(typeof(IIntentProvider)), IIntentProviderMetadata +internal sealed class IntentProviderAttribute(string intentName, string languageName) : ExportAttribute(typeof(IIntentProvider)), IIntentProviderMetadata { public string IntentName { get; } = intentName; public string LanguageName { get; } = languageName; diff --git a/src/Features/Core/Portable/IntroduceParameter/IntroduceParameterDocumentRewriter.cs b/src/Features/Core/Portable/IntroduceParameter/IntroduceParameterDocumentRewriter.cs index 5caa7d6a6efa4..35663b2ee77eb 100644 --- a/src/Features/Core/Portable/IntroduceParameter/IntroduceParameterDocumentRewriter.cs +++ b/src/Features/Core/Portable/IntroduceParameter/IntroduceParameterDocumentRewriter.cs @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.IntroduceParameter; internal abstract partial class AbstractIntroduceParameterCodeRefactoringProvider { - private class IntroduceParameterDocumentRewriter( + private sealed class IntroduceParameterDocumentRewriter( AbstractIntroduceParameterCodeRefactoringProvider service, Document originalDocument, TExpressionSyntax expression, diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs index 6f498ef5690a7..ea04b0bd15308 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.AbstractIntroduceVariableCodeAction.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable; -internal partial class AbstractIntroduceVariableService +internal abstract partial class AbstractIntroduceVariableService { private abstract class AbstractIntroduceVariableCodeAction : CodeAction { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.CodeAction.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.CodeAction.cs index ab8443bec9cff..64caa1c470554 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.CodeAction.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.CodeAction.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable; -internal partial class AbstractIntroduceVariableService +internal abstract partial class AbstractIntroduceVariableService { private sealed class IntroduceVariableCodeAction( TService service, diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs index 258785ef00557..21c8064c39ec8 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs @@ -6,9 +6,9 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable; -internal partial class AbstractIntroduceVariableService +internal abstract partial class AbstractIntroduceVariableService { - private class IntroduceVariableAllOccurrenceCodeAction( + private sealed class IntroduceVariableAllOccurrenceCodeAction( TService service, SemanticDocument document, CodeCleanupOptions options, diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs index 64c84c5b48e17..c98ab3ca237f2 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable; -internal partial class AbstractIntroduceVariableService +internal abstract partial class AbstractIntroduceVariableService { private sealed partial class State(TService service, SemanticDocument document, CodeCleanupOptions options) { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.cs index ab0100671a730..98a8f9c2efd9f 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Attribute.cs @@ -6,9 +6,9 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable; -internal partial class AbstractIntroduceVariableService +internal abstract partial class AbstractIntroduceVariableService { - private partial class State + private sealed partial class State { private bool IsInAttributeContext() { diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs index 143524130cdec..affe4b3bb255e 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Block.cs @@ -10,9 +10,9 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable; -internal partial class AbstractIntroduceVariableService +internal abstract partial class AbstractIntroduceVariableService { - private partial class State + private sealed partial class State { private bool IsInBlockContext( CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs index 1e14f18828a45..d42bc25f47d16 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_ConstructorInitializer.cs @@ -11,9 +11,9 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable; -internal partial class AbstractIntroduceVariableService +internal abstract partial class AbstractIntroduceVariableService { - private partial class State + private sealed partial class State { private bool IsInConstructorInitializerContext( CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs index 1696359eeee62..602cadea361dc 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Field.cs @@ -11,9 +11,9 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable; -internal partial class AbstractIntroduceVariableService +internal abstract partial class AbstractIntroduceVariableService { - private partial class State + private sealed partial class State { private bool IsInFieldContext( CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs index dff13534cfef8..281e88446b152 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Parameter.cs @@ -10,9 +10,9 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable; -internal partial class AbstractIntroduceVariableService +internal abstract partial class AbstractIntroduceVariableService { - private partial class State + private sealed partial class State { private bool IsInParameterContext( CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs index 4abc911f583bd..da5378e493828 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceVariableService.State_Query.cs @@ -10,9 +10,9 @@ namespace Microsoft.CodeAnalysis.IntroduceVariable; -internal partial class AbstractIntroduceVariableService +internal abstract partial class AbstractIntroduceVariableService { - private partial class State + private sealed partial class State { private bool IsInQueryContext( CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs index 17bb2742fc46a..dfb3a8ae3f4bc 100644 --- a/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs +++ b/src/Features/Core/Portable/LanguageServices/AnonymousTypeDisplayService/AbstractStructuralTypeDisplayService.StructuralTypeCollectorVisitor.cs @@ -8,9 +8,9 @@ namespace Microsoft.CodeAnalysis.LanguageService; -internal partial class AbstractStructuralTypeDisplayService +internal abstract partial class AbstractStructuralTypeDisplayService { - private class StructuralTypeCollectorVisitor(Dictionary namedTypes) : SymbolVisitor + private sealed class StructuralTypeCollectorVisitor(Dictionary namedTypes) : SymbolVisitor { private readonly ISet _seenTypes = new HashSet(); private readonly Dictionary _namedTypes = namedTypes; diff --git a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AbstractSymbolDescriptionBuilder.cs b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AbstractSymbolDescriptionBuilder.cs index 69befc8233a38..f55d35d7ec1df 100644 --- a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AbstractSymbolDescriptionBuilder.cs +++ b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AbstractSymbolDescriptionBuilder.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.LanguageService; -internal partial class AbstractSymbolDisplayService +internal abstract partial class AbstractSymbolDisplayService { protected abstract partial class AbstractSymbolDescriptionBuilder { diff --git a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs index 3ce11c84aefa0..ce9f5bfeb1b03 100644 --- a/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs +++ b/src/Features/Core/Portable/LanguageServices/SymbolDisplayService/AbstractSymbolDisplayService.AnonymousTypes.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.LanguageService; -internal partial class AbstractSymbolDisplayService +internal abstract partial class AbstractSymbolDisplayService { protected abstract partial class AbstractSymbolDescriptionBuilder { diff --git a/src/Features/Core/Portable/LegacySolutionEvents/ILegacySolutionEventsAggregationService.cs b/src/Features/Core/Portable/LegacySolutionEvents/ILegacySolutionEventsAggregationService.cs index 3e185eb8e5a53..5fb02a63843a3 100644 --- a/src/Features/Core/Portable/LegacySolutionEvents/ILegacySolutionEventsAggregationService.cs +++ b/src/Features/Core/Portable/LegacySolutionEvents/ILegacySolutionEventsAggregationService.cs @@ -28,7 +28,7 @@ internal interface ILegacySolutionEventsAggregationService : IWorkspaceService [ExportWorkspaceService(typeof(ILegacySolutionEventsAggregationService)), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal class DefaultLegacySolutionEventsAggregationService( +internal sealed class DefaultLegacySolutionEventsAggregationService( [ImportMany] IEnumerable> eventsServices) : ILegacySolutionEventsAggregationService { private readonly ImmutableArray> _eventsServices = eventsServices.ToImmutableArray(); diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService+CompatAbstractMetadataFormattingRule.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService+CompatAbstractMetadataFormattingRule.cs index eda6341df098a..febb15ffd5617 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService+CompatAbstractMetadataFormattingRule.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService+CompatAbstractMetadataFormattingRule.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal partial class AbstractMetadataAsSourceService +internal abstract partial class AbstractMetadataAsSourceService { protected abstract class CompatAbstractMetadataFormattingRule : AbstractMetadataFormattingRule { diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractMetadataFormattingRule.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractMetadataFormattingRule.cs index 363332930eda6..d10c3f8f770c2 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractMetadataFormattingRule.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractMetadataFormattingRule.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal partial class AbstractMetadataAsSourceService +internal abstract partial class AbstractMetadataAsSourceService { protected abstract class AbstractMetadataFormattingRule : AbstractFormattingRule { diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedNamespaceOrTypeSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedNamespaceOrTypeSymbol.cs index 6da2d46cd4869..e45cdc2916e9a 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedNamespaceOrTypeSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedNamespaceOrTypeSymbol.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal partial class AbstractMetadataAsSourceService +internal abstract partial class AbstractMetadataAsSourceService { private abstract class AbstractWrappedNamespaceOrTypeSymbol : AbstractWrappedSymbol, INamespaceOrTypeSymbol { diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedSymbol.cs index 966031dd6c52d..e4882dbc7678b 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.AbstractWrappedSymbol.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal partial class AbstractMetadataAsSourceService +internal abstract partial class AbstractMetadataAsSourceService { private abstract class AbstractWrappedSymbol : ISymbol { diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.DocCommentFormatter.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.DocCommentFormatter.cs index 144fc1e5f1da0..a1e4a27da2da4 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.DocCommentFormatter.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.DocCommentFormatter.cs @@ -13,9 +13,9 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal partial class AbstractMetadataAsSourceService +internal abstract partial class AbstractMetadataAsSourceService { - internal class DocCommentFormatter + internal sealed class DocCommentFormatter { private const int s_indentSize = 2; private const int s_wrapLength = 80; diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedEventSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedEventSymbol.cs index 46beab79876e9..ddb01cd12a000 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedEventSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedEventSymbol.cs @@ -7,9 +7,9 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal partial class AbstractMetadataAsSourceService +internal abstract partial class AbstractMetadataAsSourceService { - private class WrappedEventSymbol(IEventSymbol eventSymbol, bool canImplementImplicitly, IDocumentationCommentFormattingService docCommentFormattingService) : AbstractWrappedSymbol(eventSymbol, canImplementImplicitly, docCommentFormattingService), IEventSymbol + private sealed class WrappedEventSymbol(IEventSymbol eventSymbol, bool canImplementImplicitly, IDocumentationCommentFormattingService docCommentFormattingService) : AbstractWrappedSymbol(eventSymbol, canImplementImplicitly, docCommentFormattingService), IEventSymbol { private readonly IEventSymbol _symbol = eventSymbol; diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedFieldSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedFieldSymbol.cs index ee2266b043e4f..975d8f3841da4 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedFieldSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedFieldSymbol.cs @@ -9,9 +9,9 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal partial class AbstractMetadataAsSourceService +internal abstract partial class AbstractMetadataAsSourceService { - private class WrappedFieldSymbol(IFieldSymbol fieldSymbol, IDocumentationCommentFormattingService docCommentFormattingService) : AbstractWrappedSymbol(fieldSymbol, canImplementImplicitly: false, docCommentFormattingService: docCommentFormattingService), IFieldSymbol + private sealed class WrappedFieldSymbol(IFieldSymbol fieldSymbol, IDocumentationCommentFormattingService docCommentFormattingService) : AbstractWrappedSymbol(fieldSymbol, canImplementImplicitly: false, docCommentFormattingService: docCommentFormattingService), IFieldSymbol { private readonly IFieldSymbol _symbol = fieldSymbol; diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs index 9dc315ba01e2d..e2238705948fc 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs @@ -10,9 +10,9 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal partial class AbstractMetadataAsSourceService +internal abstract partial class AbstractMetadataAsSourceService { - private class WrappedMethodSymbol(IMethodSymbol methodSymbol, bool canImplementImplicitly, IDocumentationCommentFormattingService docCommentFormattingService) : AbstractWrappedSymbol(methodSymbol, canImplementImplicitly, docCommentFormattingService), IMethodSymbol + private sealed class WrappedMethodSymbol(IMethodSymbol methodSymbol, bool canImplementImplicitly, IDocumentationCommentFormattingService docCommentFormattingService) : AbstractWrappedSymbol(methodSymbol, canImplementImplicitly, docCommentFormattingService), IMethodSymbol { private readonly IMethodSymbol _symbol = methodSymbol; diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs index 67e83823b5ae6..2bfe0264c3107 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedNamedTypeSymbol.cs @@ -13,9 +13,9 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal partial class AbstractMetadataAsSourceService +internal abstract partial class AbstractMetadataAsSourceService { - private class WrappedNamedTypeSymbol : AbstractWrappedNamespaceOrTypeSymbol, INamedTypeSymbol + private sealed class WrappedNamedTypeSymbol : AbstractWrappedNamespaceOrTypeSymbol, INamedTypeSymbol { private readonly INamedTypeSymbol _symbol; private readonly ImmutableArray _members; diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedPropertySymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedPropertySymbol.cs index e2cfb6aefba23..27fd29f8b7fd6 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedPropertySymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedPropertySymbol.cs @@ -9,9 +9,9 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal partial class AbstractMetadataAsSourceService +internal abstract partial class AbstractMetadataAsSourceService { - private class WrappedPropertySymbol(IPropertySymbol propertySymbol, bool canImplementImplicitly, IDocumentationCommentFormattingService docCommentFormattingService) : AbstractWrappedSymbol(propertySymbol, canImplementImplicitly, docCommentFormattingService), IPropertySymbol + private sealed class WrappedPropertySymbol(IPropertySymbol propertySymbol, bool canImplementImplicitly, IDocumentationCommentFormattingService docCommentFormattingService) : AbstractWrappedSymbol(propertySymbol, canImplementImplicitly, docCommentFormattingService), IPropertySymbol { private readonly IPropertySymbol _symbol = propertySymbol; diff --git a/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs b/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs index b410e66ecaa13..b01c28896a082 100644 --- a/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs +++ b/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs @@ -6,6 +6,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Composition; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; @@ -29,10 +30,15 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; [ExportMetadataAsSourceFileProvider(ProviderName), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal class DecompilationMetadataAsSourceFileProvider(IImplementationAssemblyLookupService implementationAssemblyLookupService) : IMetadataAsSourceFileProvider +internal sealed class DecompilationMetadataAsSourceFileProvider(IImplementationAssemblyLookupService implementationAssemblyLookupService) : IMetadataAsSourceFileProvider { internal const string ProviderName = "Decompilation"; + /// + /// Guards access to and workspace updates when opening / closing documents. + /// + private readonly object _gate = new(); + /// /// Accessed only in and , both of which /// are called under a lock in . So this is safe as a plain @@ -271,17 +277,8 @@ private async Task RelocateSymbol_NoLockAsync(Solution solution, Metad return await MetadataAsSourceHelpers.GetLocationInGeneratedSourceAsync(symbolId, temporaryDocument, cancellationToken).ConfigureAwait(false); } - private static void AssertIsMainThread(MetadataAsSourceWorkspace workspace) - { - Contract.ThrowIfNull(workspace); - var threadingService = workspace.Services.GetRequiredService().Service; - Contract.ThrowIfFalse(threadingService.IsOnMainThread); - } - public bool ShouldCollapseOnOpen(MetadataAsSourceWorkspace workspace, string filePath, BlockStructureOptions blockStructureOptions) { - AssertIsMainThread(workspace); - if (_generatedFilenameToInformation.TryGetValue(filePath, out var info)) { return info.SignaturesOnly @@ -292,45 +289,46 @@ public bool ShouldCollapseOnOpen(MetadataAsSourceWorkspace workspace, string fil return false; } - public bool TryAddDocumentToWorkspace(MetadataAsSourceWorkspace workspace, string filePath, SourceTextContainer sourceTextContainer) + public bool TryAddDocumentToWorkspace(MetadataAsSourceWorkspace workspace, string filePath, SourceTextContainer sourceTextContainer, [NotNullWhen(true)] out DocumentId? documentId) { - AssertIsMainThread(workspace); - - if (_generatedFilenameToInformation.TryGetValue(filePath, out var fileInfo)) + lock (_gate) { - Contract.ThrowIfTrue(_openedDocumentIds.ContainsKey(fileInfo)); + if (_generatedFilenameToInformation.TryGetValue(filePath, out var fileInfo)) + { + Contract.ThrowIfTrue(_openedDocumentIds.ContainsKey(fileInfo)); - // We do own the file, so let's open it up in our workspace - var (projectInfo, documentId) = fileInfo.GetProjectInfoAndDocumentId(workspace.Services.SolutionServices, loadFileFromDisk: true); + // We do own the file, so let's open it up in our workspace + (var projectInfo, documentId) = fileInfo.GetProjectInfoAndDocumentId(workspace.Services.SolutionServices, loadFileFromDisk: true); - workspace.OnProjectAdded(projectInfo); - workspace.OnDocumentOpened(documentId, sourceTextContainer); + workspace.OnProjectAdded(projectInfo); + workspace.OnDocumentOpened(documentId, sourceTextContainer); - _openedDocumentIds = _openedDocumentIds.Add(fileInfo, documentId); + _openedDocumentIds = _openedDocumentIds.Add(fileInfo, documentId); + return true; + } - return true; + documentId = null; + return false; } - - return false; } public bool TryRemoveDocumentFromWorkspace(MetadataAsSourceWorkspace workspace, string filePath) { - AssertIsMainThread(workspace); - - if (_generatedFilenameToInformation.TryGetValue(filePath, out var fileInfo)) + lock (_gate) { - if (_openedDocumentIds.ContainsKey(fileInfo)) - return RemoveDocumentFromWorkspace(workspace, fileInfo); - } + if (_generatedFilenameToInformation.TryGetValue(filePath, out var fileInfo)) + { + if (_openedDocumentIds.ContainsKey(fileInfo)) + return RemoveDocumentFromWorkspace_NoLock(workspace, fileInfo); + } - return false; + return false; + } } - private bool RemoveDocumentFromWorkspace(MetadataAsSourceWorkspace workspace, MetadataAsSourceGeneratedFileInfo fileInfo) + private bool RemoveDocumentFromWorkspace_NoLock(MetadataAsSourceWorkspace workspace, MetadataAsSourceGeneratedFileInfo fileInfo) { - AssertIsMainThread(workspace); - + // Serial access is guaranteed by the caller. var documentId = _openedDocumentIds.GetValueOrDefault(fileInfo); Contract.ThrowIfNull(documentId); @@ -359,16 +357,19 @@ private bool RemoveDocumentFromWorkspace(MetadataAsSourceWorkspace workspace, Me public void CleanupGeneratedFiles(MetadataAsSourceWorkspace workspace) { - // Clone the list so we don't break our own enumeration - foreach (var generatedFileInfo in _generatedFilenameToInformation.Values.ToList()) + lock (_gate) { - if (_openedDocumentIds.ContainsKey(generatedFileInfo)) - RemoveDocumentFromWorkspace(workspace, generatedFileInfo); - } + // Clone the list so we don't break our own enumeration + foreach (var generatedFileInfo in _generatedFilenameToInformation.Values.ToList()) + { + if (_openedDocumentIds.ContainsKey(generatedFileInfo)) + RemoveDocumentFromWorkspace_NoLock(workspace, generatedFileInfo); + } - _generatedFilenameToInformation.Clear(); - _keyToInformation.Clear(); - Contract.ThrowIfFalse(_openedDocumentIds.IsEmpty); + _generatedFilenameToInformation.Clear(); + _keyToInformation.Clear(); + Contract.ThrowIfFalse(_openedDocumentIds.IsEmpty); + } } private static async Task GetUniqueDocumentKeyAsync(Project project, INamedTypeSymbol topLevelNamedType, bool signaturesOnly, CancellationToken cancellationToken) @@ -389,7 +390,7 @@ private static async Task GetUniqueDocumentKeyAsync(Project p } } - private class UniqueDocumentKey : IEquatable + private sealed class UniqueDocumentKey : IEquatable { private static readonly IEqualityComparer s_symbolIdComparer = SymbolKey.GetComparer(ignoreCase: false, ignoreAssemblyKeys: true); diff --git a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileProvider.cs b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileProvider.cs index efedd6fef1753..c06d750ebcc7b 100644 --- a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileProvider.cs +++ b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileProvider.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Formatting; @@ -36,7 +37,7 @@ internal interface IMetadataAsSourceFileProvider /// Called when the file returned from needs to be added to the workspace, /// to be opened. Will be called on the main thread of the workspace host. /// - bool TryAddDocumentToWorkspace(MetadataAsSourceWorkspace workspace, string filePath, SourceTextContainer sourceTextContainer); + bool TryAddDocumentToWorkspace(MetadataAsSourceWorkspace workspace, string filePath, SourceTextContainer sourceTextContainer, [NotNullWhen(true)] out DocumentId? documentId); /// /// Called when the file is being closed, and so needs to be removed from the workspace. Will be called on the diff --git a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileService.cs b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileService.cs index 4f0986e03ce2f..bf42a4c73fc68 100644 --- a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceFileService.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Formatting; @@ -31,8 +32,16 @@ Task GetGeneratedFileAsync( MetadataAsSourceOptions options, CancellationToken cancellationToken); - bool TryAddDocumentToWorkspace(string filePath, SourceTextContainer buffer); + /// + /// Checks if the given file path is a metadata as source file and adds to the metadata workspace if it is. + /// Callers must ensure this is only called serially. + /// + bool TryAddDocumentToWorkspace(string filePath, SourceTextContainer sourceTextContainer, [NotNullWhen(true)] out DocumentId? documentId); + /// + /// Checks if the given file path is a metadata as source file and removes from the metadata workspace if it is. + /// Callers must ensure this is only called serially. + /// bool TryRemoveDocumentFromWorkspace(string filePath); bool IsNavigableMetadataSymbol(ISymbol symbol); diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFile.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFile.cs index 218114e34cc51..f8f9b6a167482 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFile.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFile.cs @@ -8,21 +8,16 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; internal sealed class MetadataAsSourceFile { - private readonly string _filePath; - private readonly Location _identifierLocation; - private readonly string _documentTitle; - private readonly string _documentTooltip; - internal MetadataAsSourceFile(string filePath, Location identifierLocation, string documentTitle, string documentTooltip) { - _filePath = filePath; - _identifierLocation = identifierLocation; - _documentTitle = documentTitle; - _documentTooltip = documentTooltip; + FilePath = filePath; + IdentifierLocation = identifierLocation; + DocumentTitle = documentTitle; + DocumentTooltip = documentTooltip; } - public string FilePath => _filePath; - public Location IdentifierLocation => _identifierLocation; - public string DocumentTitle => _documentTitle; - public string DocumentTooltip => _documentTooltip; + public string FilePath { get; } + public Location IdentifierLocation { get; } + public string DocumentTitle { get; } + public string DocumentTooltip { get; } } diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileProviderMetadata.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileProviderMetadata.cs index cc1798a13c68e..29e6bf354e095 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileProviderMetadata.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileProviderMetadata.cs @@ -7,6 +7,6 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal class MetadataAsSourceFileProviderMetadata(IDictionary data) : OrderableLanguageMetadata(data) +internal sealed class MetadataAsSourceFileProviderMetadata(IDictionary data) : OrderableLanguageMetadata(data) { } diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs index 3db7aad7bca35..e21821dd8852a 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs @@ -6,12 +6,12 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -163,7 +163,7 @@ private static void AssertIsMainThread(MetadataAsSourceWorkspace workspace) Contract.ThrowIfFalse(threadingService.IsOnMainThread); } - public bool TryAddDocumentToWorkspace(string filePath, SourceTextContainer sourceTextContainer) + public bool TryAddDocumentToWorkspace(string filePath, SourceTextContainer sourceTextContainer, [NotNullWhen(true)] out DocumentId? documentId) { // If we haven't even created a MetadataAsSource workspace yet, then this file definitely cannot be added to // it. This happens when the MiscWorkspace calls in to just see if it can attach this document to the @@ -171,18 +171,19 @@ public bool TryAddDocumentToWorkspace(string filePath, SourceTextContainer sourc var workspace = _workspace; if (workspace != null) { - AssertIsMainThread(workspace); - foreach (var provider in _providers.Value) { if (!provider.IsValueCreated) continue; - if (provider.Value.TryAddDocumentToWorkspace(workspace, filePath, sourceTextContainer)) + if (provider.Value.TryAddDocumentToWorkspace(workspace, filePath, sourceTextContainer, out documentId)) + { return true; + } } } + documentId = null; return false; } @@ -194,8 +195,6 @@ public bool TryRemoveDocumentFromWorkspace(string filePath) var workspace = _workspace; if (workspace != null) { - AssertIsMainThread(workspace); - foreach (var provider in _providers.Value) { if (!provider.IsValueCreated) diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceHelpers.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceHelpers.cs index 620e803854848..3baf7b5df636e 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceHelpers.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceHelpers.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; /// /// Helpers shared by both the text service and the editor service /// -internal class MetadataAsSourceHelpers +internal sealed class MetadataAsSourceHelpers { #if false diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceWorkspace.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceWorkspace.cs index 1ff4b4a34eb5d..75499c432addd 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceWorkspace.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceWorkspace.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal class MetadataAsSourceWorkspace(MetadataAsSourceFileService fileService, HostServices hostServices) : Workspace(hostServices, WorkspaceKind.MetadataAsSource) +internal sealed class MetadataAsSourceWorkspace(MetadataAsSourceFileService fileService, HostServices hostServices) : Workspace(hostServices, WorkspaceKind.MetadataAsSource) { public readonly MetadataAsSourceFileService FileService = fileService; } diff --git a/src/Features/Core/Portable/MetadataAsSource/SymbolMappingServiceFactory.cs b/src/Features/Core/Portable/MetadataAsSource/SymbolMappingServiceFactory.cs index 72e4c358ca5c8..2b7c3cc9e9342 100644 --- a/src/Features/Core/Portable/MetadataAsSource/SymbolMappingServiceFactory.cs +++ b/src/Features/Core/Portable/MetadataAsSource/SymbolMappingServiceFactory.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource { [ExportWorkspaceServiceFactory(typeof(ISymbolMappingService), [WorkspaceKind.MetadataAsSource])] [Shared] - internal class SymbolMappingServiceFactory : IWorkspaceServiceFactory + internal sealed class SymbolMappingServiceFactory : IWorkspaceServiceFactory { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/MetadataAsSource/TelemetryMessage.cs b/src/Features/Core/Portable/MetadataAsSource/TelemetryMessage.cs index 22308b4a97d3b..972208e4c834a 100644 --- a/src/Features/Core/Portable/MetadataAsSource/TelemetryMessage.cs +++ b/src/Features/Core/Portable/MetadataAsSource/TelemetryMessage.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; -internal class TelemetryMessage : IDisposable +internal sealed class TelemetryMessage : IDisposable { private string? _pdbSource; private string? _sourceFileSource; diff --git a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj index 8d5472cddbcf7..c3729dd724429 100644 --- a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj +++ b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj @@ -52,7 +52,7 @@ - + @@ -84,6 +84,8 @@ + + @@ -113,15 +115,10 @@ - - - + @@ -140,14 +137,11 @@ 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/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveTypeToNamespaceCodeAction.cs b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveTypeToNamespaceCodeAction.cs index 9cb514dc1950e..ab96d1c68a88b 100644 --- a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveTypeToNamespaceCodeAction.cs +++ b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.MoveTypeToNamespaceCodeAction.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.MoveToNamespace; internal abstract partial class AbstractMoveToNamespaceCodeAction { - private class MoveTypeToNamespaceCodeAction(IMoveToNamespaceService changeNamespaceService, MoveToNamespaceAnalysisResult analysisResult) + private sealed class MoveTypeToNamespaceCodeAction(IMoveToNamespaceService changeNamespaceService, MoveToNamespaceAnalysisResult analysisResult) : AbstractMoveToNamespaceCodeAction(changeNamespaceService, analysisResult) { public override string Title => FeaturesResources.Move_to_namespace; diff --git a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceAnalysisResult.ContainerType.cs b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceAnalysisResult.ContainerType.cs index a8a88da910951..04eaf2c1ad63f 100644 --- a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceAnalysisResult.ContainerType.cs +++ b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceAnalysisResult.ContainerType.cs @@ -4,7 +4,7 @@ namespace Microsoft.CodeAnalysis.MoveToNamespace; -internal partial class MoveToNamespaceAnalysisResult +internal sealed partial class MoveToNamespaceAnalysisResult { public enum ContainerType { diff --git a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceAnalysisResult.cs b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceAnalysisResult.cs index fd29dd808caf9..60c098d1ae7f4 100644 --- a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceAnalysisResult.cs +++ b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceAnalysisResult.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.MoveToNamespace; -internal partial class MoveToNamespaceAnalysisResult +internal sealed partial class MoveToNamespaceAnalysisResult { public static readonly MoveToNamespaceAnalysisResult Invalid = new(); diff --git a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs index fff1e8a521add..bafa75fa7955c 100644 --- a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs +++ b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.MoveToNamespace; [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.MoveToNamespace), Shared] [ExtensionOrder(After = PredefinedCodeRefactoringProviderNames.SyncNamespace)] [ExtensionOrder(After = PredefinedCodeRefactoringProviderNames.MoveTypeToFile)] -internal class MoveToNamespaceCodeActionProvider : CodeRefactoringProvider +internal sealed class MoveToNamespaceCodeActionProvider : CodeRefactoringProvider { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] diff --git a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceOptionsResult.cs b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceOptionsResult.cs index ac572dc1147dc..3f89dcb6aa408 100644 --- a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceOptionsResult.cs +++ b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceOptionsResult.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.MoveToNamespace; -internal class MoveToNamespaceOptionsResult +internal sealed class MoveToNamespaceOptionsResult { public static readonly MoveToNamespaceOptionsResult Cancelled = new(); diff --git a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceResult.cs b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceResult.cs index eb72434e226e8..c4d82ebeb3502 100644 --- a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceResult.cs +++ b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceResult.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.MoveToNamespace; -internal class MoveToNamespaceResult +internal sealed class MoveToNamespaceResult { public static readonly MoveToNamespaceResult Failed = new(); diff --git a/src/Features/Core/Portable/NavigateTo/INavigateToSearcherHost.cs b/src/Features/Core/Portable/NavigateTo/INavigateToSearcherHost.cs index d4c1265ea9918..5e24d607d0b33 100644 --- a/src/Features/Core/Portable/NavigateTo/INavigateToSearcherHost.cs +++ b/src/Features/Core/Portable/NavigateTo/INavigateToSearcherHost.cs @@ -31,7 +31,7 @@ internal interface IWorkspaceNavigateToSearcherHostService : IWorkspaceService ValueTask IsFullyLoadedAsync(CancellationToken cancellationToken); } -internal class DefaultNavigateToSearchHost( +internal sealed class DefaultNavigateToSearchHost( Solution solution, IAsynchronousOperationListener asyncListener, CancellationToken disposalToken) : INavigateToSearcherHost diff --git a/src/Features/Core/Portable/NavigateTo/NavigateToSearchResultComparer.cs b/src/Features/Core/Portable/NavigateTo/NavigateToSearchResultComparer.cs index 6f6567bf399df..5ce60ac0c39aa 100644 --- a/src/Features/Core/Portable/NavigateTo/NavigateToSearchResultComparer.cs +++ b/src/Features/Core/Portable/NavigateTo/NavigateToSearchResultComparer.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.NavigateTo; /// same symbol, just for different projects just feels like clutter in the UI without real benefit for the user /// (since navigating will just take the user to the same location). /// -internal class NavigateToSearchResultComparer : IEqualityComparer +internal sealed class NavigateToSearchResultComparer : IEqualityComparer { public static readonly IEqualityComparer Instance = new NavigateToSearchResultComparer(); diff --git a/src/Features/Core/Portable/Navigation/DefaultSymbolNavigationServiceFactory.cs b/src/Features/Core/Portable/Navigation/DefaultSymbolNavigationServiceFactory.cs index 52f5c6977cc37..02a2e385d5db3 100644 --- a/src/Features/Core/Portable/Navigation/DefaultSymbolNavigationServiceFactory.cs +++ b/src/Features/Core/Portable/Navigation/DefaultSymbolNavigationServiceFactory.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Navigation; [ExportWorkspaceServiceFactory(typeof(ISymbolNavigationService), ServiceLayer.Default), Shared] -internal class DefaultSymbolNavigationServiceFactory : IWorkspaceServiceFactory +internal sealed class DefaultSymbolNavigationServiceFactory : IWorkspaceServiceFactory { private ISymbolNavigationService _singleton; diff --git a/src/Features/Core/Portable/Navigation/INavigableItem.cs b/src/Features/Core/Portable/Navigation/INavigableItem.cs index c0b1d0eff144a..15ac7bea56479 100644 --- a/src/Features/Core/Portable/Navigation/INavigableItem.cs +++ b/src/Features/Core/Portable/Navigation/INavigableItem.cs @@ -48,7 +48,7 @@ internal interface INavigableItem ImmutableArray ChildItems { get; } - public record NavigableDocument(NavigableProject Project, string Name, string? FilePath, IReadOnlyList Folders, DocumentId Id, bool IsSourceGeneratedDocument, Workspace? Workspace) + public record NavigableDocument(NavigableProject Project, string Name, string? FilePath, IReadOnlyList Folders, DocumentId Id, SourceGeneratedDocumentIdentity? SourceGeneratedDocumentIdentity, Workspace? Workspace) { public static NavigableDocument FromDocument(Document document) => new( @@ -57,7 +57,7 @@ public static NavigableDocument FromDocument(Document document) document.FilePath, document.Folders, document.Id, - IsSourceGeneratedDocument: document is SourceGeneratedDocument, + SourceGeneratedDocumentIdentity: (document as SourceGeneratedDocument)?.Identity, document.Project.Solution.TryGetWorkspace()); /// @@ -66,7 +66,7 @@ public static NavigableDocument FromDocument(Document document) /// navigable item was constructed during a Find Symbols operation on the same solution instance. /// internal ValueTask GetRequiredDocumentAsync(Solution solution, CancellationToken cancellationToken) - => solution.GetRequiredDocumentAsync(Id, includeSourceGenerated: IsSourceGeneratedDocument, cancellationToken); + => solution.GetRequiredDocumentAsync(Id, includeSourceGenerated: SourceGeneratedDocumentIdentity is not null, cancellationToken); /// /// Get the of the within diff --git a/src/Features/Core/Portable/Navigation/INavigableLocation.cs b/src/Features/Core/Portable/Navigation/INavigableLocation.cs index 3733567b375a2..84eee62f5d52c 100644 --- a/src/Features/Core/Portable/Navigation/INavigableLocation.cs +++ b/src/Features/Core/Portable/Navigation/INavigableLocation.cs @@ -20,7 +20,7 @@ internal interface INavigableLocation Task NavigateToAsync(NavigationOptions options, CancellationToken cancellationToken); } -internal class NavigableLocation(Func> callback) : INavigableLocation +internal sealed class NavigableLocation(Func> callback) : INavigableLocation { private readonly Func> _callback = callback; diff --git a/src/Features/Core/Portable/Navigation/NavigableItemFactory.SymbolLocationNavigableItem.cs b/src/Features/Core/Portable/Navigation/NavigableItemFactory.SymbolLocationNavigableItem.cs index 6500b40b0c7ff..3dd6534faa926 100644 --- a/src/Features/Core/Portable/Navigation/NavigableItemFactory.SymbolLocationNavigableItem.cs +++ b/src/Features/Core/Portable/Navigation/NavigableItemFactory.SymbolLocationNavigableItem.cs @@ -13,9 +13,9 @@ namespace Microsoft.CodeAnalysis.Navigation; -internal partial class NavigableItemFactory +internal static partial class NavigableItemFactory { - private class SymbolLocationNavigableItem( + private sealed class SymbolLocationNavigableItem( Solution solution, ISymbol symbol, Location location, diff --git a/src/Features/Core/Portable/Options/EditorConfig/EditorConfigOptionsEnumerator.cs b/src/Features/Core/Portable/Options/EditorConfig/EditorConfigOptionsEnumerator.cs index f560d9a2097e9..9a6cc0a29b86b 100644 --- a/src/Features/Core/Portable/Options/EditorConfig/EditorConfigOptionsEnumerator.cs +++ b/src/Features/Core/Portable/Options/EditorConfig/EditorConfigOptionsEnumerator.cs @@ -8,13 +8,13 @@ using System.Composition; using System.Linq; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices; using Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.ImplementType; +using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.CodeAnalysis.ValidateFormatString; namespace Microsoft.CodeAnalysis.Options; @@ -41,9 +41,15 @@ internal sealed class EditorConfigOptionsEnumerator( yield return ("unsupported", JsonDetectionOptionsStorage.UnsupportedOptions); yield return ("unsupported", FormatStringValidationOptionStorage.UnsupportedOptions); yield return ("unsupported", RegexOptionsStorage.UnsupportedOptions); + yield return ("unsupported", SymbolSearchOptionsStorage.UnsupportedOptions); } - yield return (FeaturesResources.NET_Code_Actions, MemberDisplayOptionsStorage.EditorConfigOptions); + yield return (FeaturesResources.NET_Code_Actions, + [ + .. ImplementTypeOptionsStorage.EditorConfigOptions, + .. MemberDisplayOptionsStorage.EditorConfigOptions, + .. SymbolSearchOptionsStorage.EditorConfigOptions, + ]); yield return (WorkspacesResources.dot_NET_Coding_Conventions, [ diff --git a/src/Features/Core/Portable/Organizing/Organizers/ExportSyntaxNodeOrganizerAttribute.cs b/src/Features/Core/Portable/Organizing/Organizers/ExportSyntaxNodeOrganizerAttribute.cs index 9202f0c05b3b3..36bdec9c11e7a 100644 --- a/src/Features/Core/Portable/Organizing/Organizers/ExportSyntaxNodeOrganizerAttribute.cs +++ b/src/Features/Core/Portable/Organizing/Organizers/ExportSyntaxNodeOrganizerAttribute.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.Organizing.Organizers; [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] -internal class ExportSyntaxNodeOrganizerAttribute(string languageName) : ExportAttribute(typeof(ISyntaxOrganizer)) +internal sealed class ExportSyntaxNodeOrganizerAttribute(string languageName) : ExportAttribute(typeof(ISyntaxOrganizer)) { public string Language { get; } = languageName; } diff --git a/src/Features/Core/Portable/PdbSourceDocument/ImplementationAssemblyLookupService.cs b/src/Features/Core/Portable/PdbSourceDocument/ImplementationAssemblyLookupService.cs index ead8acddab954..143ce4f9222e7 100644 --- a/src/Features/Core/Portable/PdbSourceDocument/ImplementationAssemblyLookupService.cs +++ b/src/Features/Core/Portable/PdbSourceDocument/ImplementationAssemblyLookupService.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.PdbSourceDocument; [Export(typeof(IImplementationAssemblyLookupService)), Shared] -internal class ImplementationAssemblyLookupService : IImplementationAssemblyLookupService +internal sealed class ImplementationAssemblyLookupService : IImplementationAssemblyLookupService { // We need to generate the namespace name in the same format that is used in metadata, which // is SymbolDisplayFormat.QualifiedNameOnlyFormat, which this is a copy of. diff --git a/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs b/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs index 4e51fab6dd942..1d9e89b352cd7 100644 --- a/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs +++ b/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentMetadataAsSourceFileProvider.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection.Metadata.Ecma335; @@ -43,6 +44,11 @@ internal sealed class PdbSourceDocumentMetadataAsSourceFileProvider( private readonly IImplementationAssemblyLookupService _implementationAssemblyLookupService = implementationAssemblyLookupService; private readonly IPdbSourceDocumentLogger? _logger = logger; + /// + /// Lock to guard access to workspace updates when opening / closing documents. + /// + private readonly object _gate = new(); + /// /// Accessed only in and , both of which /// are called under a lock in . So this is safe as a plain @@ -62,7 +68,12 @@ internal sealed class PdbSourceDocumentMetadataAsSourceFileProvider( /// generally run concurrently. However, to be safe, we make this a concurrent dictionary to be safe to that /// potentially happening. /// - private readonly ConcurrentDictionary _fileToDocumentInfoMap = []; + private readonly ConcurrentDictionary _fileToDocumentInfoMap = new(StringComparer.OrdinalIgnoreCase); + + /// + /// Only accessed and mutated in serial calls either from the UI thread or LSP queue. + /// + private readonly HashSet _openedDocumentIds = new(); public async Task GetGeneratedFileAsync( MetadataAsSourceWorkspace metadataWorkspace, @@ -238,15 +249,26 @@ internal sealed class PdbSourceDocumentMetadataAsSourceFileProvider( return null; var symbolId = SymbolKey.Create(symbol, cancellationToken); - var navigateProject = metadataWorkspace.CurrentSolution.GetRequiredProject(projectId); - var documentInfos = CreateDocumentInfos(sourceFileInfos, encoding, navigateProject.Id, sourceWorkspace, sourceProject); + // Get a view of the solution with the document added, but do not actually update the workspace. + // TryAddDocumentToWorkspace is responsible for actually updating the solution with the new document(s). + // We just need a view with the document added so we can find the right location in the generated source. + var pendingSolution = metadataWorkspace.CurrentSolution; + var documentInfos = CreateDocumentInfos(sourceFileInfos, encoding, projectId, sourceWorkspace, sourceProject); if (documentInfos.Length > 0) { - metadataWorkspace.OnDocumentsAdded(documentInfos); - navigateProject = metadataWorkspace.CurrentSolution.GetRequiredProject(projectId); + foreach (var documentInfo in documentInfos) + { + // The document might have already been added by a previous go to definition call. + if (!pendingSolution.ContainsDocument(documentInfo.Id)) + { + pendingSolution = pendingSolution.AddDocument(documentInfo); + } + } } + var navigateProject = pendingSolution.GetRequiredProject(projectId); + // If MetadataAsSourceHelpers.GetLocationInGeneratedSourceAsync can't find the actual document to navigate to, it will fall back // to the document passed in, which we just use the first document for. // TODO: Support results from multiple source files: https://github.com/dotnet/roslyn/issues/55834 @@ -313,20 +335,22 @@ private ImmutableArray CreateDocumentInfos( } // If a document has multiple symbols then we might already know about it - if (_fileToDocumentInfoMap.ContainsKey(info.FilePath)) + if (_fileToDocumentInfoMap.TryGetValue(info.FilePath, out var sourceDocumentInfo)) { + documents.Add(sourceDocumentInfo.DocumentInfo); continue; } var documentId = DocumentId.CreateNewId(projectId); - documents.Add(DocumentInfo.Create( + var documentInfo = DocumentInfo.Create( documentId, name: Path.GetFileName(info.FilePath), loader: info.Loader, filePath: info.FilePath, isGenerated: true) - .WithDesignTimeOnly(true)); + .WithDesignTimeOnly(true); + documents.Add(documentInfo); // If we successfully got something from SourceLink for this project then its nice to wait a bit longer // if the user performs subsequent navigation @@ -336,49 +360,59 @@ private ImmutableArray CreateDocumentInfos( } // In order to open documents in VS we need to understand the link from temp file to document and its encoding etc. - _fileToDocumentInfoMap[info.FilePath] = new(documentId, encoding, info.ChecksumAlgorithm, sourceProject.Id, sourceWorkspace); + _fileToDocumentInfoMap[info.FilePath] = new(documentId, encoding, info.ChecksumAlgorithm, sourceProject.Id, sourceWorkspace, documentInfo); } return documents.ToImmutableAndClear(); } - private static void AssertIsMainThread(MetadataAsSourceWorkspace workspace) - { - Contract.ThrowIfNull(workspace); - var threadingService = workspace.Services.GetRequiredService().Service; - Contract.ThrowIfFalse(threadingService.IsOnMainThread); - } - public bool ShouldCollapseOnOpen(MetadataAsSourceWorkspace workspace, string filePath, BlockStructureOptions blockStructureOptions) { - AssertIsMainThread(workspace); return _fileToDocumentInfoMap.TryGetValue(filePath, out _) && blockStructureOptions.CollapseMetadataImplementationsWhenFirstOpened; } - public bool TryAddDocumentToWorkspace(MetadataAsSourceWorkspace workspace, string filePath, SourceTextContainer sourceTextContainer) + public bool TryAddDocumentToWorkspace(MetadataAsSourceWorkspace workspace, string filePath, SourceTextContainer sourceTextContainer, [NotNullWhen(true)] out DocumentId? documentId) { - AssertIsMainThread(workspace); - - if (_fileToDocumentInfoMap.TryGetValue(filePath, out var info)) + lock (_gate) { - workspace.OnDocumentOpened(info.DocumentId, sourceTextContainer); - return true; - } + if (_fileToDocumentInfoMap.TryGetValue(filePath, out var info)) + { + Contract.ThrowIfTrue(_openedDocumentIds.Contains(info.DocumentId)); + + workspace.OnDocumentAdded(info.DocumentInfo); + workspace.OnDocumentOpened(info.DocumentId, sourceTextContainer); + documentId = info.DocumentId; + _openedDocumentIds.Add(documentId); + return true; + } - return false; + documentId = null; + return false; + } } public bool TryRemoveDocumentFromWorkspace(MetadataAsSourceWorkspace workspace, string filePath) { - AssertIsMainThread(workspace); - - if (_fileToDocumentInfoMap.TryGetValue(filePath, out var info)) + lock (_gate) { - workspace.OnDocumentClosed(info.DocumentId, new WorkspaceFileTextLoader(workspace.Services.SolutionServices, filePath, info.Encoding)); - return true; - } + if (_fileToDocumentInfoMap.TryGetValue(filePath, out var info)) + { + // In LSP, while calls to TryAddDocumentToWorkspace and TryRemoveDocumentFromWorkspace are handled + // serially, it is possible that TryRemoveDocumentFromWorkspace called without TryAddDocumentToWorkspace first. + // This can happen if the document is immediately closed after opening - only feature requests that force us + // to materialize a solution will trigger TryAddDocumentToWorkspace, if none are made it is never called. + // However TryRemoveDocumentFromWorkspace is always called on close. + if (_openedDocumentIds.Contains(info.DocumentId)) + { + workspace.OnDocumentClosed(info.DocumentId, new WorkspaceFileTextLoader(workspace.Services.SolutionServices, filePath, info.Encoding)); + workspace.OnDocumentRemoved(info.DocumentId); + _openedDocumentIds.Remove(info.DocumentId); + return true; + } + } - return false; + return false; + } } public Project? MapDocument(Document document) @@ -416,11 +450,29 @@ public void CleanupGeneratedFiles(MetadataAsSourceWorkspace workspace) // The MetadataAsSourceFileService will clean up the entire temp folder so no need to do anything here _fileToDocumentInfoMap.Clear(); + _openedDocumentIds.Clear(); _sourceLinkEnabledProjects.Clear(); _implementationAssemblyLookupService.Clear(); } + + internal TestAccessor GetTestAccessor() + { + return new TestAccessor(this); + } + + internal readonly struct TestAccessor + { + private readonly PdbSourceDocumentMetadataAsSourceFileProvider _instance; + + internal TestAccessor(PdbSourceDocumentMetadataAsSourceFileProvider instance) + { + _instance = instance; + } + + public ImmutableDictionary Documents => _instance._fileToDocumentInfoMap.ToImmutableDictionary(); + } } internal sealed record SourceDocument(string FilePath, SourceHashAlgorithm ChecksumAlgorithm, ImmutableArray Checksum, byte[]? EmbeddedTextBytes, string? SourceLinkUrl); -internal record struct SourceDocumentInfo(DocumentId DocumentId, Encoding Encoding, SourceHashAlgorithm ChecksumAlgorithm, ProjectId SourceProjectId, Workspace SourceWorkspace); +internal record struct SourceDocumentInfo(DocumentId DocumentId, Encoding Encoding, SourceHashAlgorithm ChecksumAlgorithm, ProjectId SourceProjectId, Workspace SourceWorkspace, DocumentInfo DocumentInfo); diff --git a/src/Features/Core/Portable/PdbSourceDocument/SourceLinkMap.cs b/src/Features/Core/Portable/PdbSourceDocument/SourceLinkMap.cs index d4b009283bb12..31eeb6f056ce4 100644 --- a/src/Features/Core/Portable/PdbSourceDocument/SourceLinkMap.cs +++ b/src/Features/Core/Portable/PdbSourceDocument/SourceLinkMap.cs @@ -10,7 +10,7 @@ using System.Linq; using System.Text.Json; -#if NETCOREAPP +#if NET using System.Diagnostics.CodeAnalysis; #endif @@ -167,7 +167,7 @@ private static bool TryParseEntry(string key, string value, out Entry entry) /// is null. public bool TryGetUri( string path, -#if NETCOREAPP +#if NET [NotNullWhen(true)] #endif out string? uri) diff --git a/src/Features/Core/Portable/PickMembers/IPickMembersService.cs b/src/Features/Core/Portable/PickMembers/IPickMembersService.cs index 0591de324ff9f..94c2d1120ddab 100644 --- a/src/Features/Core/Portable/PickMembers/IPickMembersService.cs +++ b/src/Features/Core/Portable/PickMembers/IPickMembersService.cs @@ -17,7 +17,7 @@ PickMembersResult PickMembers( bool selectAll = true); } -internal class PickMembersOption(string id, string title, bool value) +internal sealed class PickMembersOption(string id, string title, bool value) { public string Id { get; } = id; public string Title { get; } = title; diff --git a/src/Features/Core/Portable/PickMembers/PickMembersResult.cs b/src/Features/Core/Portable/PickMembers/PickMembersResult.cs index 324b65964ed4f..1a3658f55554a 100644 --- a/src/Features/Core/Portable/PickMembers/PickMembersResult.cs +++ b/src/Features/Core/Portable/PickMembers/PickMembersResult.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.PickMembers; -internal class PickMembersResult +internal sealed class PickMembersResult { public static readonly PickMembersResult Canceled = new(isCanceled: true); diff --git a/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs index 9805e08ad8516..e4c2eb07f7c2e 100644 --- a/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs +++ b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.PreferFrameworkType; [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.PreferFrameworkType), Shared] -internal class PreferFrameworkTypeCodeFixProvider : SyntaxEditorBasedCodeFixProvider +internal sealed class PreferFrameworkTypeCodeFixProvider : SyntaxEditorBasedCodeFixProvider { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] diff --git a/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs b/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs index f17ef72b7a1d2..889b117aefd05 100644 --- a/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs +++ b/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs @@ -386,7 +386,6 @@ private static async Task PullMembersIntoClassAsync( var destinationDocument = await removeImportsService.RemoveUnnecessaryImportsAsync( destinationEditor.GetChangedDocument(), node => node.HasAnnotation(s_removableImportAnnotation), - options.CleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); // Format whitespace trivia within the import statements we pull up diff --git a/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptions.cs b/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptions.cs index 31964b48f898a..78b372851381e 100644 --- a/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptions.cs +++ b/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptions.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.PullMemberUp; /// This class contains all the operations needs to be done on members and destination to complete the pull up operation. /// If user clicked the cancel button, it will be null. /// -internal class PullMembersUpOptions +internal sealed class PullMembersUpOptions { /// /// Destination of where members should be pulled up to. diff --git a/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptionsBuilder.cs b/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptionsBuilder.cs index 1ceaf0dc00540..d2f9b65dfc93b 100644 --- a/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptionsBuilder.cs +++ b/src/Features/Core/Portable/PullMemberUp/PullMembersUpOptionsBuilder.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.PullMemberUp; -internal class PullMembersUpOptionsBuilder +internal sealed class PullMembersUpOptionsBuilder { public static PullMembersUpOptions BuildPullMembersUpOptions( INamedTypeSymbol destination, diff --git a/src/Features/Core/Portable/QuickInfo/AbstractEmbeddedLanguageQuickInfoProvider.cs b/src/Features/Core/Portable/QuickInfo/AbstractEmbeddedLanguageQuickInfoProvider.cs index 64cfd58dbd643..afc008ed9610e 100644 --- a/src/Features/Core/Portable/QuickInfo/AbstractEmbeddedLanguageQuickInfoProvider.cs +++ b/src/Features/Core/Portable/QuickInfo/AbstractEmbeddedLanguageQuickInfoProvider.cs @@ -58,7 +58,7 @@ public AbstractEmbeddedLanguageQuickInfoProvider( /// have multiple inheritance, we'll create a separate class here and delegate to the protected methods. We can remove this if we /// switch Quick Info over to a pattern like the rest of our features. /// - private class EmbeddedLanguageProviderFeatureService : + private sealed class EmbeddedLanguageProviderFeatureService : AbstractEmbeddedLanguageFeatureService { public EmbeddedLanguageProviderFeatureService(string languageName, EmbeddedLanguageInfo info, ISyntaxKinds syntaxKinds, IEnumerable> allServices) diff --git a/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.ErrorVisitor.cs b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.ErrorVisitor.cs index 532ea9b96cc13..6d1a5ddf191af 100644 --- a/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.ErrorVisitor.cs +++ b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.ErrorVisitor.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.QuickInfo; internal abstract partial class CommonSemanticQuickInfoProvider { - private class ErrorVisitor : SymbolVisitor + private sealed class ErrorVisitor : SymbolVisitor { private static readonly ErrorVisitor s_instance = new(); diff --git a/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs index 24ecd8843fa25..8accdd3c55718 100644 --- a/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs +++ b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs @@ -29,9 +29,9 @@ internal abstract partial class CommonSemanticQuickInfoProvider : CommonQuickInf var cancellationToken = context.CancellationToken; var semanticModel = await context.Document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var services = context.Document.Project.Solution.Services; - var onTheFlyDocsElement = await GetOnTheFlyDocsElementAsync(context, cancellationToken).ConfigureAwait(false); + var onTheFlyDocsInfo = await GetOnTheFlyDocsInfoAsync(context, cancellationToken).ConfigureAwait(false); return await CreateContentAsync( - services, semanticModel, token, tokenInformation, supportedPlatforms, context.Options, onTheFlyDocsElement, cancellationToken).ConfigureAwait(false); + services, semanticModel, token, tokenInformation, supportedPlatforms, context.Options, onTheFlyDocsInfo, cancellationToken).ConfigureAwait(false); } protected override async Task BuildQuickInfoAsync( @@ -41,9 +41,9 @@ internal abstract partial class CommonSemanticQuickInfoProvider : CommonQuickInf if (tokenInformation.Symbols.IsDefaultOrEmpty) return null; - // onTheFlyDocElement is null here since On-The-Fly Docs are being computed at the document level. + // onTheFlyDocInfo is null here since On-The-Fly Docs are being computed at the document level. return await CreateContentAsync( - context.Services, context.SemanticModel, token, tokenInformation, supportedPlatforms: null, context.Options, onTheFlyDocsElement: null, context.CancellationToken).ConfigureAwait(false); + context.Services, context.SemanticModel, token, tokenInformation, supportedPlatforms: null, context.Options, onTheFlyDocsInfo: null, context.CancellationToken).ConfigureAwait(false); } private async Task<(TokenInformation tokenInformation, SupportedPlatformData? supportedPlatforms)> ComputeQuickInfoDataAsync( @@ -157,7 +157,7 @@ protected static Task CreateContentAsync( TokenInformation tokenInformation, SupportedPlatformData? supportedPlatforms, SymbolDescriptionOptions options, - OnTheFlyDocsElement? onTheFlyDocsElement, + OnTheFlyDocsInfo? onTheFlyDocsInfo, CancellationToken cancellationToken) { var syntaxFactsService = services.GetRequiredLanguageService(semanticModel.Language); @@ -175,15 +175,15 @@ protected static Task CreateContentAsync( return QuickInfoUtilities.CreateQuickInfoItemAsync( services, semanticModel, token.Span, symbols, supportedPlatforms, - tokenInformation.ShowAwaitReturn, tokenInformation.NullableFlowState, options, onTheFlyDocsElement, cancellationToken); + tokenInformation.ShowAwaitReturn, tokenInformation.NullableFlowState, options, onTheFlyDocsInfo, cancellationToken); } protected abstract bool GetBindableNodeForTokenIndicatingLambda(SyntaxToken token, [NotNullWhen(returnValue: true)] out SyntaxNode? found); protected abstract bool GetBindableNodeForTokenIndicatingPossibleIndexerAccess(SyntaxToken token, [NotNullWhen(returnValue: true)] out SyntaxNode? found); protected abstract bool GetBindableNodeForTokenIndicatingMemberAccess(SyntaxToken token, out SyntaxToken found); - protected virtual Task GetOnTheFlyDocsElementAsync(QuickInfoContext context, CancellationToken cancellationToken) - => Task.FromResult(null); + protected virtual Task GetOnTheFlyDocsInfoAsync(QuickInfoContext context, CancellationToken cancellationToken) + => Task.FromResult(null); protected virtual NullableFlowState GetNullabilityAnalysis(SemanticModel semanticModel, ISymbol symbol, SyntaxNode node, CancellationToken cancellationToken) => NullableFlowState.None; diff --git a/src/Features/Core/Portable/QuickInfo/IndentationHelper.cs b/src/Features/Core/Portable/QuickInfo/IndentationHelper.cs index 9bbcd5aac43f3..eecfabd1f574d 100644 --- a/src/Features/Core/Portable/QuickInfo/IndentationHelper.cs +++ b/src/Features/Core/Portable/QuickInfo/IndentationHelper.cs @@ -3,9 +3,9 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -17,7 +17,7 @@ internal static class IndentationHelper { /// /// Recomputes span segments so that all text lines appear to have the same reduction in indentation. - /// This operation is typically used to align text for display when the initial span does not include all of the first line's identation. + /// This operation is typically used to align text for display when the initial span does not include all of the first line's indentation. /// This operation will potentially split spans that cover multiple lines into separate spans. /// /// @@ -29,56 +29,55 @@ public static ImmutableArray GetSpansWithAlignedIndentation( ImmutableArray classifiedSpans, int tabSize) { - if (!classifiedSpans.IsDefault && classifiedSpans.Length > 0) + if (classifiedSpans.IsDefaultOrEmpty) { - // We need to figure out the shortest indentation level of the exposed lines. We'll - // then remove that indentation from all lines. - var indentationColumn = DetermineIndentationColumn(text, classifiedSpans, tabSize); - var adjustedClassifiedSpans = new List(); + return []; + } - for (var i = 0; i < classifiedSpans.Length; i++) - { - var classifiedSpan = classifiedSpans[i]; - var spanClassificationType = classifiedSpan.ClassificationType; - var span = classifiedSpan.TextSpan; + // We need to figure out the shortest indentation level of the exposed lines. We'll + // then remove that indentation from all lines. + var indentationColumn = DetermineIndentationColumn(text, classifiedSpans, tabSize); + using var adjustedClassifiedSpans = TemporaryArray.Empty; - var startLineNumber = text.Lines.GetLineFromPosition(span.Start).LineNumber; - var endLineNumber = text.Lines.GetLineFromPosition(span.End).LineNumber; + var lines = text.Lines; - for (var lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) - { - var line = text.Lines[lineNumber]; - var lineOffsetOfColumn = line.GetLineOffsetFromColumn(indentationColumn, tabSize); + foreach (var classifiedSpan in classifiedSpans) + { + var spanClassificationType = classifiedSpan.ClassificationType; + var span = classifiedSpan.TextSpan; - var deletion = TextSpan.FromBounds(line.Start, line.Start + lineOffsetOfColumn); + var startLineNumber = lines.GetLineFromPosition(span.Start).LineNumber; + var endLineNumber = lines.GetLineFromPosition(span.End).LineNumber; - if (deletion.Start > span.Start) - { - var spanBeforeDeletion = TextSpan.FromBounds(span.Start, Math.Min(span.End, deletion.Start)); - if (spanBeforeDeletion.Length > 0) - { - adjustedClassifiedSpans.Add(new ClassifiedSpan(spanClassificationType, spanBeforeDeletion)); - } - } + for (var lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) + { + var line = lines[lineNumber]; + var lineOffsetOfColumn = line.GetLineOffsetFromColumn(indentationColumn, tabSize); - if (deletion.End > span.Start) + var deletion = TextSpan.FromBounds(line.Start, line.Start + lineOffsetOfColumn); + + if (deletion.Start > span.Start) + { + var spanBeforeDeletion = TextSpan.FromBounds(span.Start, Math.Min(span.End, deletion.Start)); + if (spanBeforeDeletion.Length > 0) { - span = TextSpan.FromBounds(Math.Min(deletion.End, span.End), span.End); + adjustedClassifiedSpans.Add(new(spanClassificationType, spanBeforeDeletion)); } } - if (span.Length > 0) + if (deletion.End > span.Start) { - adjustedClassifiedSpans.Add(new ClassifiedSpan(spanClassificationType, span)); + span = TextSpan.FromBounds(Math.Min(deletion.End, span.End), span.End); } } - return [.. adjustedClassifiedSpans]; - } - else - { - return []; + if (span.Length > 0) + { + adjustedClassifiedSpans.Add(new(spanClassificationType, span)); + } } + + return adjustedClassifiedSpans.ToImmutableAndClear(); } private static int DetermineIndentationColumn( @@ -86,11 +85,13 @@ private static int DetermineIndentationColumn( ImmutableArray spans, int tabSize) { + var lines = text.Lines; int? indentationColumn = null; + foreach (var span in spans) { - var startLineNumber = text.Lines.GetLineFromPosition(span.TextSpan.Start).LineNumber; - var endLineNumber = text.Lines.GetLineFromPosition(span.TextSpan.End).LineNumber; + var startLineNumber = lines.GetLineFromPosition(span.TextSpan.Start).LineNumber; + var endLineNumber = lines.GetLineFromPosition(span.TextSpan.End).LineNumber; // If the span starts after the first non-whitespace of the first line, we'll // exclude that line to avoid throwing off the calculation. Otherwise, the @@ -106,22 +107,22 @@ private static int DetermineIndentationColumn( // // Without throwing out the first line in the example above, the indentation column // used will be 4, rather than 8. - var startLineFirstNonWhitespace = text.Lines[startLineNumber].GetFirstNonWhitespacePosition(); - if (startLineFirstNonWhitespace.HasValue && startLineFirstNonWhitespace.Value < span.TextSpan.Start) + var startLineFirstNonWhitespace = lines[startLineNumber].GetFirstNonWhitespacePosition(); + if (startLineFirstNonWhitespace is int value && value < span.TextSpan.Start) { startLineNumber++; } for (var lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) { - var line = text.Lines[lineNumber]; + var line = lines[lineNumber]; if (line.IsEmptyOrWhitespace()) { continue; } - indentationColumn = indentationColumn.HasValue - ? Math.Min(indentationColumn.Value, line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(tabSize)) + indentationColumn = indentationColumn is int currentValue + ? Math.Min(currentValue, line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(tabSize)) : line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(tabSize); } } diff --git a/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsElement.cs b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsInfo.cs similarity index 80% rename from src/Features/Core/Portable/QuickInfo/OnTheFlyDocsElement.cs rename to src/Features/Core/Portable/QuickInfo/OnTheFlyDocsInfo.cs index 8879bbb5fd326..c1a69a7d374ff 100644 --- a/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsElement.cs +++ b/src/Features/Core/Portable/QuickInfo/OnTheFlyDocsInfo.cs @@ -13,11 +13,12 @@ namespace Microsoft.CodeAnalysis.QuickInfo; /// the symbol's declaration code /// the language of the symbol /// whether the symbol has comments -internal sealed class OnTheFlyDocsElement(string symbolSignature, ImmutableArray declarationCode, string language, bool hasComments = false) +internal sealed class OnTheFlyDocsInfo(string symbolSignature, ImmutableArray declarationCode, string language, bool isContentExcluded, bool hasComments = false) { public string SymbolSignature { get; } = symbolSignature; public ImmutableArray DeclarationCode { get; } = declarationCode; public string Language { get; } = language; + public bool IsContentExcluded { get; set; } = isContentExcluded; // Added for telemetry collection purposes. public bool HasComments { get; set; } = hasComments; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/IChecksummedObject.cs b/src/Features/Core/Portable/QuickInfo/Presentation/INavigationActionFactory.cs similarity index 51% rename from src/Workspaces/Core/Portable/Workspace/Solution/IChecksummedObject.cs rename to src/Features/Core/Portable/QuickInfo/Presentation/INavigationActionFactory.cs index 923e68f9acda3..7651ea57c67d1 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/IChecksummedObject.cs +++ b/src/Features/Core/Portable/QuickInfo/Presentation/INavigationActionFactory.cs @@ -2,14 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable +using System; -namespace Microsoft.CodeAnalysis; +namespace Microsoft.CodeAnalysis.QuickInfo.Presentation; -/// -/// Indicates whether a type has checksum or not -/// -internal interface IChecksummedObject +internal interface INavigationActionFactory { - Checksum Checksum { get; } + Action CreateNavigationAction(string navigationTarget); } diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoClassifiedTextElement.cs b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoClassifiedTextElement.cs new file mode 100644 index 0000000000000..41c9522f66d9a --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoClassifiedTextElement.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; + +namespace Microsoft.CodeAnalysis.QuickInfo.Presentation; + +internal sealed class QuickInfoClassifiedTextElement(params ImmutableArray runs) : QuickInfoElement +{ + public ImmutableArray Runs { get; } = runs; +} diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoClassifiedTextRun.cs b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoClassifiedTextRun.cs new file mode 100644 index 0000000000000..978f91ee884b9 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoClassifiedTextRun.cs @@ -0,0 +1,33 @@ +// 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.QuickInfo.Presentation; + +internal readonly struct QuickInfoClassifiedTextRun( + string classificationTypeName, + string text, + Action? navigationAction = null, + string? tooltip = null, + QuickInfoClassifiedTextStyle style = QuickInfoClassifiedTextStyle.Plain) +{ + // Note: MarkerTagType was not included from the VS ClassifiedTextRun + // because Roslyn doesn't create ClassifiedTextRuns with that value. + // If we eventually need that data, it should be added below. + + public string ClassificationTypeName { get; } = classificationTypeName; + public string Text { get; } = text; + public QuickInfoClassifiedTextStyle Style { get; } = style; + public string? Tooltip { get; } = tooltip; + public Action? NavigationAction { get; } = navigationAction; + + public QuickInfoClassifiedTextRun( + string classificationTypeName, + string text, + QuickInfoClassifiedTextStyle style) + : this(classificationTypeName, text, navigationAction: null, tooltip: null, style) + { + } +} diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoClassifiedTextStyle.cs b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoClassifiedTextStyle.cs new file mode 100644 index 0000000000000..7694b4ea2fff4 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoClassifiedTextStyle.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.CodeAnalysis.QuickInfo.Presentation; + +/// +/// The text style for a . +/// +/// +/// +/// By default, text is displayed using tooltip preferences, but colorized using +/// text editor colors in order to make tooltips that look visually like UI, but +/// match the semantic colorization of the code. +/// +[Flags] +internal enum QuickInfoClassifiedTextStyle +{ + /// + /// Plain text. + /// + Plain = 0, + + /// + /// Bolded text. + /// + Bold = 1 << 0, + + /// + /// Italic text. + /// + Italic = 1 << 1, + + /// + /// Underlined text. + /// + Underline = 1 << 2, + + /// + /// Use the font specified by the classification. + /// + /// + /// + /// If applied, the classification's code font is used instead of the default tooltip font. + /// + UseClassificationFont = 1 << 3, + + /// + /// Use the style specified by the classification. + /// + /// + /// + /// If applied, the classification's bold, italic, and underline settings are used + /// instead of the default tooltip style. Note that additional styles can be layered + /// on top of the classification's style by adding , , + /// or . + /// + UseClassificationStyle = 1 << 4 +} diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContainerElement.cs b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContainerElement.cs new file mode 100644 index 0000000000000..a613891a1855c --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContainerElement.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; + +namespace Microsoft.CodeAnalysis.QuickInfo.Presentation; + +internal sealed class QuickInfoContainerElement(QuickInfoContainerStyle style, params ImmutableArray elements) : QuickInfoElement +{ + public ImmutableArray Elements { get; } = elements; + public QuickInfoContainerStyle Style { get; } = style; +} diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContainerStyle.cs b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContainerStyle.cs new file mode 100644 index 0000000000000..269aaca6804f9 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContainerStyle.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; + +namespace Microsoft.CodeAnalysis.QuickInfo.Presentation; + +/// +/// The layout style for a . +/// +[Flags] +internal enum QuickInfoContainerStyle +{ + /// + /// Contents are end-to-end, and wrapped when the control becomes too wide. + /// + Wrapped = 0, + + /// + /// Contents are stacked vertically. + /// + Stacked = 1 << 0, + + /// + /// Additional padding above and below content. + /// + VerticalPadding = 1 << 1 +} diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContentBuilder.cs b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContentBuilder.cs new file mode 100644 index 0000000000000..06d398e237e5d --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContentBuilder.cs @@ -0,0 +1,239 @@ +// 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.Frozen; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Shared.Collections; + +namespace Microsoft.CodeAnalysis.QuickInfo.Presentation; + +internal static class QuickInfoContentBuilder +{ + private static readonly FrozenDictionary s_glyphToElementMap = CreateGlyphToElementMap(); + + private static FrozenDictionary CreateGlyphToElementMap() + { + var glyphs = (Glyph[])Enum.GetValues(typeof(Glyph)); + var result = new Dictionary(capacity: glyphs.Length); + + foreach (var glyph in glyphs) + { + result.Add(glyph, new QuickInfoGlyphElement(glyph)); + } + + return result.ToFrozenDictionary(); + } + + public static async Task BuildInteractiveContentAsync( + QuickInfoItem quickInfoItem, + QuickInfoContentBuilderContext context, + CancellationToken cancellationToken) + { + var (symbolGlyph, addWarningGlyph) = ComputeGlyphs(quickInfoItem); + + using var remainingSections = TemporaryArray.Empty; + var (descriptionSection, documentationCommentsSection) = ComputeSections(quickInfoItem, ref remainingSections.AsRef()); + + // We can't declare elements in a using statement because we need to assign to its indexer below. + // TemporaryArray's non-copyable semantics restrict this. + var elements = TemporaryArray.Empty; + try + { + // Add a dummy item that we'll replace with the first line below. + elements.Add(null!); + + // Build the first line of QuickInfo item, the images and the Description section should be on the first line with Wrapped style + using var firstLineElements = TemporaryArray.Empty; + + if (symbolGlyph != Glyph.None) + { + firstLineElements.Add(s_glyphToElementMap[symbolGlyph]); + } + + if (addWarningGlyph) + { + firstLineElements.Add(s_glyphToElementMap[Glyph.CompletionWarning]); + } + + var navigationActionFactory = context.NavigationActionFactory; + + if (descriptionSection is not null) + { + var isFirstElement = true; + + foreach (var element in descriptionSection.TaggedParts.ToInteractiveTextElements(navigationActionFactory)) + { + if (isFirstElement) + { + isFirstElement = false; + firstLineElements.Add(element); + } + else + { + // If the description section contains multiple paragraphs, the second and additional paragraphs + // are not wrapped in firstLineElements (they are normal paragraphs). + elements.Add(element); + } + } + } + + // Replace the dummy first element with the real first line elements. + elements[0] = new QuickInfoContainerElement(QuickInfoContainerStyle.Wrapped, firstLineElements.ToImmutableAndClear()); + + if (documentationCommentsSection is not null) + { + var isFirstElement = true; + + foreach (var element in documentationCommentsSection.TaggedParts.ToInteractiveTextElements(navigationActionFactory)) + { + if (isFirstElement) + { + isFirstElement = false; + + // Stack the first paragraph of the documentation comments with the last line of the description + // to avoid vertical padding between the two. + var lastIndex = elements.Count - 1; + var lastElement = elements[lastIndex]; + + elements[lastIndex] = new QuickInfoContainerElement( + QuickInfoContainerStyle.Stacked, + lastElement, + element); + } + else + { + elements.Add(element); + } + } + } + + // Add the remaining sections + if (remainingSections.Count > 0) + { + foreach (var section in remainingSections) + { + foreach (var element in section.TaggedParts.ToInteractiveTextElements(navigationActionFactory)) + { + elements.Add(element); + } + } + } + + // build text for RelatedSpan + if (quickInfoItem.RelatedSpans.Length > 0) + { + using var textRuns = TemporaryArray.Empty; + var document = context.Document; + var tabSize = context.LineFormattingOptions.TabSize; + var spanSeparatorNeededBefore = false; + + var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); + + foreach (var relatedSpan in quickInfoItem.RelatedSpans) + { + // We don't present additive-spans (like static/reassigned-variable) any differently, so strip them + // out of the classifications we get back. + var classifiedSpans = await ClassifierHelper.GetClassifiedSpansAsync( + document, relatedSpan, context.ClassificationOptions, includeAdditiveSpans: false, cancellationToken).ConfigureAwait(false); + + foreach (var span in IndentationHelper.GetSpansWithAlignedIndentation(text, classifiedSpans, tabSize)) + { + if (spanSeparatorNeededBefore) + { + textRuns.Add(new QuickInfoClassifiedTextRun( + ClassificationTypeNames.WhiteSpace, + "\r\n", + QuickInfoClassifiedTextStyle.UseClassificationFont)); + + spanSeparatorNeededBefore = false; + } + + textRuns.Add(new QuickInfoClassifiedTextRun( + span.ClassificationType, + text.ToString(span.TextSpan), + QuickInfoClassifiedTextStyle.UseClassificationFont)); + } + + spanSeparatorNeededBefore = true; + } + + if (textRuns.Count > 0) + { + elements.Add(new QuickInfoClassifiedTextElement(textRuns.ToImmutableAndClear())); + } + } + + // Add on-the-fly documentation + if (quickInfoItem.OnTheFlyDocsInfo is not null) + { + elements.Add(new QuickInfoOnTheFlyDocsElement(context.Document, quickInfoItem.OnTheFlyDocsInfo)); + } + + return new QuickInfoContainerElement( + QuickInfoContainerStyle.Stacked | QuickInfoContainerStyle.VerticalPadding, + elements.ToImmutableAndClear()); + } + finally + { + elements.Dispose(); + } + } + + private static (Glyph symbolGlyph, bool addWarningGlyph) ComputeGlyphs(QuickInfoItem quickInfoItem) + { + var symbolGlyph = Glyph.None; + var addWarningGlyph = false; + + foreach (var glyph in quickInfoItem.Tags.GetGlyphs()) + { + if (symbolGlyph != Glyph.None && addWarningGlyph) + { + break; + } + + if (symbolGlyph == Glyph.None && glyph != Glyph.CompletionWarning) + { + symbolGlyph = glyph; + } + else if (!addWarningGlyph && glyph == Glyph.CompletionWarning) + { + addWarningGlyph = true; + } + } + + return (symbolGlyph, addWarningGlyph); + } + + private static (QuickInfoSection? descriptionSection, QuickInfoSection? documentationCommentsSection) ComputeSections( + QuickInfoItem quickInfoItem, + ref TemporaryArray remainingSections) + { + QuickInfoSection? descriptionSection = null; + QuickInfoSection? documentationCommentsSection = null; + + foreach (var section in quickInfoItem.Sections) + { + switch (section.Kind) + { + case QuickInfoSectionKinds.Description: + descriptionSection ??= section; + break; + + case QuickInfoSectionKinds.DocumentationComments: + documentationCommentsSection ??= section; + break; + + default: + remainingSections.Add(section); + break; + } + } + + return (descriptionSection, documentationCommentsSection); + } +} diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContentBuilderContext.cs b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContentBuilderContext.cs new file mode 100644 index 0000000000000..671798d7bb6bf --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoContentBuilderContext.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Formatting; + +namespace Microsoft.CodeAnalysis.QuickInfo.Presentation; + +internal sealed class QuickInfoContentBuilderContext( + Document document, + ClassificationOptions classificationOptions, + LineFormattingOptions lineFormattingOptions, + INavigationActionFactory? navigationActionFactory) +{ + public Document Document { get; } = document; + public ClassificationOptions ClassificationOptions { get; } = classificationOptions; + public LineFormattingOptions LineFormattingOptions { get; } = lineFormattingOptions; + public INavigationActionFactory? NavigationActionFactory { get; } = navigationActionFactory; +} diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoElement.cs b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoElement.cs new file mode 100644 index 0000000000000..3164df1765498 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoElement.cs @@ -0,0 +1,9 @@ +// 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.QuickInfo.Presentation; + +internal abstract class QuickInfoElement +{ +} diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoGlyphElement.cs b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoGlyphElement.cs new file mode 100644 index 0000000000000..8e6b18d71238f --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoGlyphElement.cs @@ -0,0 +1,10 @@ +// 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.QuickInfo.Presentation; + +internal sealed class QuickInfoGlyphElement(Glyph glyph) : QuickInfoElement +{ + public Glyph Glyph { get; } = glyph; +} diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoOnTheFlyDocsElement.cs b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoOnTheFlyDocsElement.cs new file mode 100644 index 0000000000000..b5c2eee3b1cee --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/Presentation/QuickInfoOnTheFlyDocsElement.cs @@ -0,0 +1,11 @@ +// 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.QuickInfo.Presentation; + +internal sealed class QuickInfoOnTheFlyDocsElement(Document document, OnTheFlyDocsInfo info) : QuickInfoElement +{ + public Document Document { get; } = document; + public OnTheFlyDocsInfo Info { get; } = info; +} diff --git a/src/Features/Core/Portable/QuickInfo/Presentation/TaggedTextExtensions.cs b/src/Features/Core/Portable/QuickInfo/Presentation/TaggedTextExtensions.cs new file mode 100644 index 0000000000000..d235efc36a702 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/Presentation/TaggedTextExtensions.cs @@ -0,0 +1,280 @@ +// 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.Runtime.CompilerServices; +using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Shared.Collections; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.QuickInfo.Presentation; + +internal static class TaggedTextExtensions +{ + internal static ImmutableArray ToInteractiveTextElements( + this ImmutableArray taggedTexts, + INavigationActionFactory? navigationActionFactory) + { + using var builder = TextElementBuilder.Empty; + var span = taggedTexts.AsSpan(); + + BuildInteractiveTextElements(ref span, ref TextElementBuilder.AsRef(in builder), navigationActionFactory); + + return builder.ToImmutableAndClear(); + } + + private static void BuildInteractiveTextElements( + ref ReadOnlySpan taggedTexts, + ref TextElementBuilder builder, + INavigationActionFactory? navigationActionFactory) + { + var done = false; + + while (!done && taggedTexts is [var part, .. var remaining]) + { + taggedTexts = remaining; + + switch (part.Tag) + { + case TextTags.CodeBlockStart or TextTags.CodeBlockEnd: + // These tags can be ignored - they are for markdown formatting only. + break; + + case TextTags.ContainerStart: + // This is the start of a set of inline elements. + { + using var nestedBuilder = TextElementBuilder.Empty; + BuildInteractiveTextElements( + ref taggedTexts, + ref TextElementBuilder.AsRef(in nestedBuilder), + navigationActionFactory); + + var nestedElements = nestedBuilder.ToImmutableAndClear(); + builder.AddContainer(nestedElements, part.Text); + } + + break; + + case TextTags.ContainerEnd: + // We're finished processing inline elements. Break out and let the caller continue + done = true; + break; + + case TextTags.LineBreak: + builder.LineBreak(); + break; + + default: // This is tagged text getting added to the current line we are building. + + // If the tagged text has navigation target AND a NavigationActionFactory + // is available, we'll create the classified run with a navigation action. + var run = part.NavigationTarget is not null && navigationActionFactory is not null + ? CreateRunWithNavigationAction(part, navigationActionFactory) + : CreateRun(part); + + builder.Add(run); + break; + } + } + + static QuickInfoClassifiedTextRun CreateRun(TaggedText part) + { + return new( + part.Tag.ToClassificationTypeName(), + part.Text, + part.Style.ToClassifiedTextRunStyle()); + } + + static QuickInfoClassifiedTextRun CreateRunWithNavigationAction(TaggedText part, INavigationActionFactory navigationActionFactory) + { + Contract.ThrowIfNull(part.NavigationTarget); + + return new( + part.Tag.ToClassificationTypeName(), + part.Text, + navigationActionFactory.CreateNavigationAction(part.NavigationTarget), + tooltip: part.NavigationHint, + part.Style.ToClassifiedTextRunStyle()); + } + } + + [NonCopyable] + private struct TextElementBuilder : IDisposable + { + public static TextElementBuilder Empty => default; + + // This builder will produce zero or more paragraphs. + private TemporaryArray _paragraphs; + + // Each paragraph is constructed from one or more lines + private TemporaryArray _lines; + + // Each line is constructed from one or more runs + private TemporaryArray _runs; + + /// + /// Gets a mutable reference to a stored in a using variable. + /// + public static ref TextElementBuilder AsRef(ref readonly TextElementBuilder builder) +#pragma warning disable RS0042 // Do not copy value + => ref Unsafe.AsRef(in builder); +#pragma warning restore RS0042 // Do not copy value + + public void Dispose() + { + Contract.ThrowIfFalse(_paragraphs.Count == 0); + Contract.ThrowIfFalse(_lines.Count == 0); + Contract.ThrowIfFalse(_runs.Count == 0); + + _paragraphs.Dispose(); + _lines.Dispose(); + _runs.Dispose(); + } + + public void Add(QuickInfoClassifiedTextRun run) + { + _runs.Add(run); + } + + public void LineBreak() + { + if (_runs.Count > 0) + { + // This line break means the end of a line within a paragraph. + _lines.Add(ClassifiedText(_runs.ToImmutableAndClear())); + } + else + { + // This line break means the end of a paragraph. Empty paragraphs are ignored, but could appear + // in the input to this method: + // + // * Empty elements + // * Explicit line breaks at the start of a comment + // * Multiple line breaks between paragraphs + if (_lines.Count > 0) + { + AddLinesAndClear(); + } + else + { + // The current paragraph is empty, so we simply ignore it. + } + } + } + + public void AddContainer(ImmutableArray nestedElements, string text) + { + if (_runs.Count > 0) + { + // When a container is encountered, complete the current line. + _lines.Add(ClassifiedText(_runs.ToImmutableAndClear())); + } + + using var newElements = TemporaryArray.Empty; + newElements.Add(ClassifiedText(PlainText(text))); + + switch (nestedElements) + { + case [] or [_]: + newElements.Add(StackedContainer(nestedElements)); + break; + + case [var item, .. var rest]: + newElements.Add( + StackedContainer(item, + StackedContainer(includeVerticalPadding: true, rest))); + break; + } + + _lines.Add(WrappedContainer(newElements.ToImmutableAndClear())); + } + + public ImmutableArray ToImmutableAndClear() + { + if (_runs.Count > 0) + { + _lines.Add(ClassifiedText(_runs.ToImmutableAndClear())); + } + + if (_lines.Count > 0) + { + AddLinesAndClear(); + } + + return _paragraphs.ToImmutableAndClear(); + } + + private void AddLinesAndClear() + { + Contract.ThrowIfTrue(_lines.Count == 0); + + if (_lines.Count == 1) + { + // The paragraph contains only one line, so it doesn't need to be added to a container. Avoiding the + // wrapping container here also avoids a wrapping element in the WPF elements used for rendering, + // improving efficiency. + _paragraphs.Add(_lines[0]); + _lines.Clear(); + } + else + { + // The lines of a multi-line paragraph are stacked to produce the full paragraph. + var container = StackedContainer(_lines.ToImmutableAndClear()); + _paragraphs.Add(container); + } + } + + private static QuickInfoClassifiedTextRun PlainText(string text) + => new(ClassificationTypeNames.Text, text); + + private static QuickInfoClassifiedTextElement ClassifiedText(params ImmutableArray runs) + => new(runs); + + private static QuickInfoContainerElement StackedContainer(params ImmutableArray elements) + => StackedContainer(includeVerticalPadding: false, elements); + + private static QuickInfoContainerElement StackedContainer(bool includeVerticalPadding, params ImmutableArray elements) + { + var style = QuickInfoContainerStyle.Stacked; + + if (includeVerticalPadding) + { + style |= QuickInfoContainerStyle.VerticalPadding; + } + + return new(style, elements); + } + + private static QuickInfoContainerElement WrappedContainer(params ImmutableArray elements) + => new(QuickInfoContainerStyle.Wrapped, elements); + } + + public static QuickInfoClassifiedTextStyle ToClassifiedTextRunStyle(this TaggedTextStyle style) + { + var result = QuickInfoClassifiedTextStyle.Plain; + + if ((style & TaggedTextStyle.Emphasis) == TaggedTextStyle.Emphasis) + { + result |= QuickInfoClassifiedTextStyle.Italic; + } + + if ((style & TaggedTextStyle.Strong) == TaggedTextStyle.Strong) + { + result |= QuickInfoClassifiedTextStyle.Bold; + } + + if ((style & TaggedTextStyle.Underline) == TaggedTextStyle.Underline) + { + result |= QuickInfoClassifiedTextStyle.Underline; + } + + if ((style & TaggedTextStyle.Code) == TaggedTextStyle.Code) + { + result |= QuickInfoClassifiedTextStyle.UseClassificationFont; + } + + return result; + } +} diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoItem.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoItem.cs index 8c31c4d586d83..5b1e1987d3feb 100644 --- a/src/Features/Core/Portable/QuickInfo/QuickInfoItem.cs +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoItem.cs @@ -30,20 +30,20 @@ public sealed class QuickInfoItem /// public ImmutableArray RelatedSpans { get; } - internal OnTheFlyDocsElement? OnTheFlyDocsElement { get; } + internal OnTheFlyDocsInfo? OnTheFlyDocsInfo { get; } private QuickInfoItem( TextSpan span, ImmutableArray tags, ImmutableArray sections, ImmutableArray relatedSpans, - OnTheFlyDocsElement? onTheFlyDocsElement) + OnTheFlyDocsInfo? onTheFlyDocsInfo) { Span = span; Tags = tags.IsDefault ? [] : tags; Sections = sections.IsDefault ? [] : sections; RelatedSpans = relatedSpans.IsDefault ? [] : relatedSpans; - OnTheFlyDocsElement = onTheFlyDocsElement; + OnTheFlyDocsInfo = onTheFlyDocsInfo; } public static QuickInfoItem Create( @@ -52,7 +52,7 @@ public static QuickInfoItem Create( ImmutableArray sections = default, ImmutableArray relatedSpans = default) { - return Create(span, tags, sections, relatedSpans, onTheFlyDocsElement: null); + return Create(span, tags, sections, relatedSpans, onTheFlyDocsInfo: null); } internal static QuickInfoItem Create( @@ -60,8 +60,8 @@ internal static QuickInfoItem Create( ImmutableArray tags, ImmutableArray sections, ImmutableArray relatedSpans, - OnTheFlyDocsElement? onTheFlyDocsElement) + OnTheFlyDocsInfo? onTheFlyDocsInfo) { - return new QuickInfoItem(span, tags, sections, relatedSpans, onTheFlyDocsElement); + return new QuickInfoItem(span, tags, sections, relatedSpans, onTheFlyDocsInfo); } } diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoProviderMetadata.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoProviderMetadata.cs index c7d713dc570e5..e7d1ca126430f 100644 --- a/src/Features/Core/Portable/QuickInfo/QuickInfoProviderMetadata.cs +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoProviderMetadata.cs @@ -7,6 +7,6 @@ namespace Microsoft.CodeAnalysis.QuickInfo; -internal class QuickInfoProviderMetadata(IDictionary data) : OrderableLanguageMetadata(data) +internal sealed class QuickInfoProviderMetadata(IDictionary data) : OrderableLanguageMetadata(data) { } diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs index 3ccf8675fb98a..865997ee60408 100644 --- a/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.QuickInfo; internal static class QuickInfoUtilities { public static Task CreateQuickInfoItemAsync(SolutionServices services, SemanticModel semanticModel, TextSpan span, ImmutableArray symbols, SymbolDescriptionOptions options, CancellationToken cancellationToken) - => CreateQuickInfoItemAsync(services, semanticModel, span, symbols, supportedPlatforms: null, showAwaitReturn: false, flowState: NullableFlowState.None, options, onTheFlyDocsElement: null, cancellationToken); + => CreateQuickInfoItemAsync(services, semanticModel, span, symbols, supportedPlatforms: null, showAwaitReturn: false, flowState: NullableFlowState.None, options, onTheFlyDocsInfo: null, cancellationToken); public static async Task CreateQuickInfoItemAsync( SolutionServices services, @@ -30,7 +30,7 @@ public static async Task CreateQuickInfoItemAsync( bool showAwaitReturn, NullableFlowState flowState, SymbolDescriptionOptions options, - OnTheFlyDocsElement? onTheFlyDocsElement, + OnTheFlyDocsInfo? onTheFlyDocsInfo, CancellationToken cancellationToken) { var descriptionService = services.GetRequiredLanguageService(semanticModel.Language); @@ -72,9 +72,9 @@ public static async Task CreateQuickInfoItemAsync( if (groups.TryGetValue(SymbolDescriptionGroups.Documentation, out var docParts) && !docParts.IsDefaultOrEmpty) { AddSection(QuickInfoSectionKinds.DocumentationComments, docParts); - if (onTheFlyDocsElement != null) + if (onTheFlyDocsInfo != null) { - onTheFlyDocsElement.HasComments = true; + onTheFlyDocsInfo.HasComments = true; } } @@ -156,7 +156,7 @@ public static async Task CreateQuickInfoItemAsync( if (supportedPlatforms?.HasValidAndInvalidProjects() == true) tags = tags.Add(WellKnownTags.Warning); - return QuickInfoItem.Create(span, tags, sections.ToImmutable(), relatedSpans: default, onTheFlyDocsElement); + return QuickInfoItem.Create(span, tags, sections.ToImmutable(), relatedSpans: default, onTheFlyDocsInfo); bool TryGetGroupText(SymbolDescriptionGroups group, out ImmutableArray taggedParts) => groups.TryGetValue(group, out taggedParts) && !taggedParts.IsDefaultOrEmpty; diff --git a/src/Features/Core/Portable/RQName/Nodes/RQArrayType.cs b/src/Features/Core/Portable/RQName/Nodes/RQArrayType.cs index 7acdd57836e08..3ff0e73a55c5b 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQArrayType.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQArrayType.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQArrayType(int rank, RQType elementType) : RQArrayOrPointerType(elementType) +internal sealed class RQArrayType(int rank, RQType elementType) : RQArrayOrPointerType(elementType) { public readonly int Rank = rank; diff --git a/src/Features/Core/Portable/RQName/Nodes/RQConstructedType.cs b/src/Features/Core/Portable/RQName/Nodes/RQConstructedType.cs index 511b39615c71f..b7c786a46710e 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQConstructedType.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQConstructedType.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQConstructedType(RQUnconstructedType definingType, IList typeArguments) : RQType +internal sealed class RQConstructedType(RQUnconstructedType definingType, IList typeArguments) : RQType { public readonly RQUnconstructedType DefiningType = definingType; public readonly ReadOnlyCollection TypeArguments = new ReadOnlyCollection(typeArguments); diff --git a/src/Features/Core/Portable/RQName/Nodes/RQConstructor.cs b/src/Features/Core/Portable/RQName/Nodes/RQConstructor.cs index fcc727b08a110..56c36ed924b89 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQConstructor.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQConstructor.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQConstructor( +internal sealed class RQConstructor( RQUnconstructedType containingType, RQMethodPropertyOrEventName memberName, int typeParameterCount, diff --git a/src/Features/Core/Portable/RQName/Nodes/RQErrorType.cs b/src/Features/Core/Portable/RQName/Nodes/RQErrorType.cs index 70a98ec9e21dc..43ec6047a1c57 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQErrorType.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQErrorType.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQErrorType(string name) : RQType +internal sealed class RQErrorType(string name) : RQType { public readonly string Name = name; diff --git a/src/Features/Core/Portable/RQName/Nodes/RQEvent.cs b/src/Features/Core/Portable/RQName/Nodes/RQEvent.cs index 6e188518a55f5..d521d0b78ff1c 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQEvent.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQEvent.cs @@ -4,7 +4,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQEvent(RQUnconstructedType containingType, RQMethodPropertyOrEventName memberName) : RQMethodPropertyOrEvent(containingType, memberName) +internal sealed class RQEvent(RQUnconstructedType containingType, RQMethodPropertyOrEventName memberName) : RQMethodPropertyOrEvent(containingType, memberName) { protected override string RQKeyword { diff --git a/src/Features/Core/Portable/RQName/Nodes/RQExplicitInterfaceMemberName.cs b/src/Features/Core/Portable/RQName/Nodes/RQExplicitInterfaceMemberName.cs index 39b1d3e561bdd..95e9f502d46c0 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQExplicitInterfaceMemberName.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQExplicitInterfaceMemberName.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQExplicitInterfaceMemberName(RQType interfaceType, RQOrdinaryMethodPropertyOrEventName name) : RQMethodPropertyOrEventName +internal sealed class RQExplicitInterfaceMemberName(RQType interfaceType, RQOrdinaryMethodPropertyOrEventName name) : RQMethodPropertyOrEventName { public readonly RQType InterfaceType = interfaceType; public readonly RQOrdinaryMethodPropertyOrEventName Name = name; diff --git a/src/Features/Core/Portable/RQName/Nodes/RQIndexer.cs b/src/Features/Core/Portable/RQName/Nodes/RQIndexer.cs index a73202fde97a6..a984980df69e7 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQIndexer.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQIndexer.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQIndexer( +internal sealed class RQIndexer( RQUnconstructedType containingType, RQMethodPropertyOrEventName memberName, int typeParameterCount, diff --git a/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndex.cs b/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndex.cs index 7050550e799ec..660b3afa0f721 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndex.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndex.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQMemberParameterIndex( +internal abstract class RQMemberParameterIndex( RQMember containingMember, int parameterIndex) : RQNode { diff --git a/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndexFromPartialImplementation.cs b/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndexFromPartialImplementation.cs index b1ea532edc032..2ff855b854bb0 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndexFromPartialImplementation.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndexFromPartialImplementation.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQMemberParameterIndexFromPartialImplementation( +internal sealed class RQMemberParameterIndexFromPartialImplementation( RQMember containingMember, int parameterIndex) : RQMemberParameterIndex(containingMember, parameterIndex) { diff --git a/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndexFromPartialSignature.cs b/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndexFromPartialSignature.cs index 7066e49d96464..751c7700bb4bd 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndexFromPartialSignature.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQMemberParameterIndexFromPartialSignature.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQMemberParameterIndexFromPartialSignature( +internal sealed class RQMemberParameterIndexFromPartialSignature( RQMember containingMember, int parameterIndex) : RQMemberParameterIndex(containingMember, parameterIndex) { diff --git a/src/Features/Core/Portable/RQName/Nodes/RQMemberVariable.cs b/src/Features/Core/Portable/RQName/Nodes/RQMemberVariable.cs index face03c72d72e..b6370830e1ce1 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQMemberVariable.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQMemberVariable.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQMemberVariable(RQUnconstructedType containingType, string name) : RQMember(containingType) +internal sealed class RQMemberVariable(RQUnconstructedType containingType, string name) : RQMember(containingType) { public readonly string Name = name; diff --git a/src/Features/Core/Portable/RQName/Nodes/RQMethod.cs b/src/Features/Core/Portable/RQName/Nodes/RQMethod.cs index c83757bd9c619..59ff20947c61a 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQMethod.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQMethod.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQMethod( +internal sealed class RQMethod( RQUnconstructedType containingType, RQMethodPropertyOrEventName memberName, int typeParameterCount, diff --git a/src/Features/Core/Portable/RQName/Nodes/RQNamespace.cs b/src/Features/Core/Portable/RQName/Nodes/RQNamespace.cs index 2d1fe693ccd76..7429581414c89 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQNamespace.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQNamespace.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQNamespace(IList namespaceNames) : RQTypeOrNamespace(namespaceNames) +internal sealed class RQNamespace(IList namespaceNames) : RQTypeOrNamespace(namespaceNames) { protected override string RQKeyword { diff --git a/src/Features/Core/Portable/RQName/Nodes/RQNormalParameter.cs b/src/Features/Core/Portable/RQName/Nodes/RQNormalParameter.cs index a2dd00f3cbc0d..245cce89ed282 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQNormalParameter.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQNormalParameter.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQNormalParameter(RQType type) : RQParameter(type) +internal sealed class RQNormalParameter(RQType type) : RQParameter(type) { public override SimpleTreeNode CreateSimpleTreeForType() => Type.ToSimpleTree(); diff --git a/src/Features/Core/Portable/RQName/Nodes/RQNullType.cs b/src/Features/Core/Portable/RQName/Nodes/RQNullType.cs index 362adf88e2c0a..f14429b051d1e 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQNullType.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQNullType.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQNullType : RQType +internal sealed class RQNullType : RQType { public static readonly RQNullType Singleton = new(); private RQNullType() { } diff --git a/src/Features/Core/Portable/RQName/Nodes/RQOrdinaryMethodPropertyOrEventName.cs b/src/Features/Core/Portable/RQName/Nodes/RQOrdinaryMethodPropertyOrEventName.cs index ac72e1c1af50b..9f74b7da650a1 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQOrdinaryMethodPropertyOrEventName.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQOrdinaryMethodPropertyOrEventName.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQOrdinaryMethodPropertyOrEventName : RQMethodPropertyOrEventName +internal sealed class RQOrdinaryMethodPropertyOrEventName : RQMethodPropertyOrEventName { // the construct type should always match the containing member. // I don't think we need to expose this, shouldn't you know this from your containing member? diff --git a/src/Features/Core/Portable/RQName/Nodes/RQOutParameter.cs b/src/Features/Core/Portable/RQName/Nodes/RQOutParameter.cs index 5b104889001e9..0e2e77e4f60f5 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQOutParameter.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQOutParameter.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQOutParameter(RQType type) : RQParameter(type) +internal sealed class RQOutParameter(RQType type) : RQParameter(type) { public override SimpleTreeNode CreateSimpleTreeForType() => new SimpleGroupNode(RQNameStrings.ParamMod, new SimpleLeafNode(RQNameStrings.Out), Type.ToSimpleTree()); diff --git a/src/Features/Core/Portable/RQName/Nodes/RQPointerType.cs b/src/Features/Core/Portable/RQName/Nodes/RQPointerType.cs index 018c584a9dfdc..4a707b9dd9d27 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQPointerType.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQPointerType.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQPointerType(RQType elementType) : RQArrayOrPointerType(elementType) +internal sealed class RQPointerType(RQType elementType) : RQArrayOrPointerType(elementType) { public override SimpleTreeNode ToSimpleTree() => new SimpleGroupNode(RQNameStrings.Pointer, ElementType.ToSimpleTree()); diff --git a/src/Features/Core/Portable/RQName/Nodes/RQProperty.cs b/src/Features/Core/Portable/RQName/Nodes/RQProperty.cs index 85a914a2555c2..67d28604e88a5 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQProperty.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQProperty.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQProperty( +internal sealed class RQProperty( RQUnconstructedType containingType, RQMethodPropertyOrEventName memberName, int typeParameterCount, diff --git a/src/Features/Core/Portable/RQName/Nodes/RQRefParameter.cs b/src/Features/Core/Portable/RQName/Nodes/RQRefParameter.cs index 28aa8089cda42..c11bc66a99e49 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQRefParameter.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQRefParameter.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQRefParameter(RQType type) : RQParameter(type) +internal sealed class RQRefParameter(RQType type) : RQParameter(type) { public override SimpleTreeNode CreateSimpleTreeForType() => new SimpleGroupNode(RQNameStrings.ParamMod, new SimpleLeafNode(RQNameStrings.Ref), Type.ToSimpleTree()); diff --git a/src/Features/Core/Portable/RQName/Nodes/RQTypeVariableType.cs b/src/Features/Core/Portable/RQName/Nodes/RQTypeVariableType.cs index 74483f32df133..98a130d3ed9fd 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQTypeVariableType.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQTypeVariableType.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQTypeVariableType(string name) : RQType +internal sealed class RQTypeVariableType(string name) : RQType { public readonly string Name = name; diff --git a/src/Features/Core/Portable/RQName/Nodes/RQUnconstructedType.cs b/src/Features/Core/Portable/RQName/Nodes/RQUnconstructedType.cs index 12c535b64bf7e..e6dce7e84cf70 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQUnconstructedType.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQUnconstructedType.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQUnconstructedType(IList namespaceNames, IList typeInfos) : RQTypeOrNamespace(namespaceNames) +internal sealed class RQUnconstructedType(IList namespaceNames, IList typeInfos) : RQTypeOrNamespace(namespaceNames) { public readonly ReadOnlyCollection TypeInfos = new ReadOnlyCollection(typeInfos); diff --git a/src/Features/Core/Portable/RQName/Nodes/RQVoidType.cs b/src/Features/Core/Portable/RQName/Nodes/RQVoidType.cs index 1a55b2b5f2ffe..6f599520f852a 100644 --- a/src/Features/Core/Portable/RQName/Nodes/RQVoidType.cs +++ b/src/Features/Core/Portable/RQName/Nodes/RQVoidType.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Features.RQName.Nodes; -internal class RQVoidType : RQType +internal sealed class RQVoidType : RQType { public static readonly RQVoidType Singleton = new(); private RQVoidType() { } diff --git a/src/Features/Core/Portable/RQName/SimpleTree/SimpleGroupNode.cs b/src/Features/Core/Portable/RQName/SimpleTree/SimpleGroupNode.cs index 061c611c14c78..45e09af39352f 100644 --- a/src/Features/Core/Portable/RQName/SimpleTree/SimpleGroupNode.cs +++ b/src/Features/Core/Portable/RQName/SimpleTree/SimpleGroupNode.cs @@ -7,15 +7,13 @@ namespace Microsoft.CodeAnalysis.Features.RQName.SimpleTree; -internal class SimpleGroupNode(string text, IList children) : SimpleTreeNode(text) +internal sealed class SimpleGroupNode(string text, IList children) : SimpleTreeNode(text) { - private readonly IList _children = children; - public SimpleGroupNode(string text, string singleLeafChildText) : this(text, new SimpleLeafNode(singleLeafChildText)) { } public SimpleGroupNode(string text, params SimpleTreeNode[] children) : this(text, children.ToList()) { } - public IList Children { get { return _children; } } + public IList Children { get; } = children; public SimpleTreeNode this[int index] { get { return Children[index]; } } diff --git a/src/Features/Core/Portable/RQName/SimpleTree/SimpleLeafNode.cs b/src/Features/Core/Portable/RQName/SimpleTree/SimpleLeafNode.cs index ff498faabe8af..732f1ac0951ee 100644 --- a/src/Features/Core/Portable/RQName/SimpleTree/SimpleLeafNode.cs +++ b/src/Features/Core/Portable/RQName/SimpleTree/SimpleLeafNode.cs @@ -4,6 +4,6 @@ namespace Microsoft.CodeAnalysis.Features.RQName.SimpleTree; -internal class SimpleLeafNode(string text) : SimpleTreeNode(text) +internal sealed class SimpleLeafNode(string text) : SimpleTreeNode(text) { } diff --git a/src/Features/Core/Portable/RelatedDocuments/AbstractRelatedDocumentsService.cs b/src/Features/Core/Portable/RelatedDocuments/AbstractRelatedDocumentsService.cs new file mode 100644 index 0000000000000..42a8920a612fd --- /dev/null +++ b/src/Features/Core/Portable/RelatedDocuments/AbstractRelatedDocumentsService.cs @@ -0,0 +1,143 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Remote; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.RelatedDocuments; + +internal abstract class AbstractRelatedDocumentsService< + TExpressionSyntax, + TNameSyntax> : IRelatedDocumentsService + where TExpressionSyntax : SyntaxNode +{ + private static class ConcurrentSetPool where T : notnull + { + private static readonly ObjectPool> s_pool = new(() => []); + + public static PooledObject> GetInstance(out ConcurrentSet set) + => s_pool.GetPooledObject(out set); + } + + protected abstract IEnumerable<(TExpressionSyntax expression, SyntaxToken nameToken)> IteratePotentialTypeNodes(SyntaxNode root); + + public async ValueTask GetRelatedDocumentIdsAsync( + Document document, int position, Func, CancellationToken, ValueTask> callbackAsync, CancellationToken cancellationToken) + { + // This feature will bind a lot of the nodes in the file. Call out to the remote host to do this work if + // available, so that we won't cause resource/gc contention within our host. + + var project = document.Project; + var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false); + if (client != null) + { + var remoteCallback = new RelatedDocumentsServiceCallback(callbackAsync, cancellationToken); + + var result = await client.TryInvokeAsync( + // We don't need to sync the entire solution (only the project) to ask for the related files for a + // particular document. + document.Project, + (service, solutionChecksum, callbackId, cancellationToken) => service.GetRelatedDocumentIdsAsync( + solutionChecksum, document.Id, position, callbackId, cancellationToken), + remoteCallback, + cancellationToken).ConfigureAwait(false); + } + else + { + await GetRelatedDocumentIdsInCurrentProcessAsync( + document, position, callbackAsync, cancellationToken).ConfigureAwait(false); + } + } + + private async ValueTask GetRelatedDocumentIdsInCurrentProcessAsync( + Document document, + int position, + Func, CancellationToken, ValueTask> callbackAsync, + CancellationToken cancellationToken) + { + var solution = document.Project.Solution; + + // Don't need nullable analysis, and we're going to walk a lot of the tree, so speed things up by not doing + // excess semantic work. + var semanticModel = await document.GetRequiredNullableDisabledSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + // The core logic here is that we defer to the language to give us nodes of interest. We then bind those nodes + // (trying to avoid binding of nodes we don't think will change the resultant set). + + using var _1 = ConcurrentSetPool.GetInstance(out var seenDocumentIds); + using var _2 = ConcurrentSetPool.GetInstance(out var seenTypeNames); + + Debug.Assert(seenDocumentIds.Count == 0); + Debug.Assert(seenTypeNames.Count == 0); + + var syntaxFacts = document.GetRequiredLanguageService(); + var syntaxKinds = syntaxFacts.SyntaxKinds; + var identifierTokenKind = syntaxKinds.IdentifierToken; + + // Bind as much as we can in parallel to get the results as quickly as possible. We call into the + // ProducerConsumer overload that will batch up values into arrays, and call into the callback with them. While + // that callback is executing, the ProducerConsumer continues to run, computing more results and getting them + // ready for when that call returns. This approach ensures that we're not pausing while we're reporting the + // results to whatever client is calling into us. + await ProducerConsumer.RunParallelAsync( + // Order the nodes by the distance from the requested position. + IteratePotentialTypeNodes(root).OrderBy(t => Math.Abs(t.expression.SpanStart - position)), + produceItems: (tuple, callback, _, cancellationToken) => + { + ProduceItems(tuple.expression, tuple.nameToken, callback, cancellationToken); + return Task.CompletedTask; + }, + consumeItems: static async (array, callbackAsync, cancellationToken) => + await callbackAsync(array, cancellationToken).ConfigureAwait(false), + args: callbackAsync, + cancellationToken).ConfigureAwait(false); + + return; + + void ProduceItems( + TExpressionSyntax expression, + SyntaxToken nameToken, + Action callback, + CancellationToken cancellationToken) + { + if (nameToken.RawKind != identifierTokenKind) + return; + + // Ignore emtpy named types that appear in error scenarios. + if (nameToken.ValueText == "") + return; + + // Don't rebind a type name we've already seen. Note: this is a conservative/inaccurate check. + // Specifically, there could be different types with the same last name portion (from different + // namespaces). In that case, we'll miss the one that is further away. We can revisit this in the + // future if we think it's necessary. + if (!seenTypeNames.Add(nameToken.ValueText)) + return; + + // For now, we only care about binding to types. We can expand this in the future if we want. + var symbol = semanticModel.GetSymbolInfo(expression, cancellationToken).GetAnySymbol(); + if (symbol is not ITypeSymbol) + return; + + foreach (var syntaxReference in symbol.DeclaringSyntaxReferences) + { + var documentId = solution.GetDocument(syntaxReference.SyntaxTree)?.Id; + if (documentId != null && seenDocumentIds.Add(documentId)) + callback(documentId); + } + } + } +} diff --git a/src/Features/Core/Portable/RelatedDocuments/IRelatedDocumentsService.cs b/src/Features/Core/Portable/RelatedDocuments/IRelatedDocumentsService.cs new file mode 100644 index 0000000000000..ae0030d8c530b --- /dev/null +++ b/src/Features/Core/Portable/RelatedDocuments/IRelatedDocumentsService.cs @@ -0,0 +1,23 @@ +// 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 System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.RelatedDocuments; + +internal interface IRelatedDocumentsService : ILanguageService +{ + /// + /// Given an document, and an optional position in that document, streams a unique list of documents Ids that the + /// language think are "related". It is up to the language to define what "related" means. However, common + /// examples might be checking to see which symbols are used at that particular location and prioritizing documents + /// those symbols are defined in. + /// + ValueTask GetRelatedDocumentIdsAsync( + Document document, int position, Func, CancellationToken, ValueTask> callbackAsync, CancellationToken cancellationToken); +} diff --git a/src/Features/Core/Portable/RelatedDocuments/IRemoteRelatedDocumentsService.cs b/src/Features/Core/Portable/RelatedDocuments/IRemoteRelatedDocumentsService.cs new file mode 100644 index 0000000000000..fa28a8869ff93 --- /dev/null +++ b/src/Features/Core/Portable/RelatedDocuments/IRemoteRelatedDocumentsService.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Remote; + +namespace Microsoft.CodeAnalysis.RelatedDocuments; + +internal interface IRemoteRelatedDocumentsService +{ + ValueTask GetRelatedDocumentIdsAsync( + Checksum solutionChecksum, DocumentId documentId, int position, RemoteServiceCallbackId callbackId, CancellationToken cancellationToken); + + internal interface ICallback + { + ValueTask ReportRelatedDocumentAsync(RemoteServiceCallbackId callbackId, ImmutableArray documentIds, CancellationToken cancellationToken); + } +} + +[ExportRemoteServiceCallbackDispatcher(typeof(IRemoteRelatedDocumentsService)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class RelatedDocumentsServiceServerCallbackDispatcher() : RemoteServiceCallbackDispatcher, IRemoteRelatedDocumentsService.ICallback +{ + private new RelatedDocumentsServiceCallback GetCallback(RemoteServiceCallbackId callbackId) + => (RelatedDocumentsServiceCallback)base.GetCallback(callbackId); + + public ValueTask ReportRelatedDocumentAsync(RemoteServiceCallbackId callbackId, ImmutableArray documentIds, CancellationToken cancellationToken) + => GetCallback(callbackId).ReportRelatedDocumentAsync(documentIds); +} + +internal sealed class RelatedDocumentsServiceCallback( + Func, CancellationToken, ValueTask> onRelatedDocumentFoundAsync, + CancellationToken cancellationToken) +{ + public ValueTask ReportRelatedDocumentAsync(ImmutableArray documentIds) + => onRelatedDocumentFoundAsync(documentIds, cancellationToken); +} diff --git a/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs b/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs index 4ee3036711cf9..2a6788163b8ad 100644 --- a/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs @@ -26,7 +26,7 @@ namespace Microsoft.CodeAnalysis.ReplacePropertyWithMethods; [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.ReplacePropertyWithMethods), Shared] -internal class ReplacePropertyWithMethodsCodeRefactoringProvider : +internal sealed class ReplacePropertyWithMethodsCodeRefactoringProvider : CodeRefactoringProvider, IEqualityComparer<(IPropertySymbol property, ReferenceLocation location)> { @@ -275,6 +275,11 @@ private async Task ReplaceReferencesAsync( editor.ReplaceNode(parent, parent.WithAdditionalAnnotations( ConflictAnnotation.Create(FeaturesResources.Property_reference_cannot_be_updated))); } + else if (syntaxFacts.IsNameOfSubpattern(parent)) + { + editor.ReplaceNode(parent, parent.WithAdditionalAnnotations( + ConflictAnnotation.Create(FeaturesResources.Property_reference_cannot_be_updated))); + } else { var fieldSymbol = propertyToBackingField.GetValueOrDefault(property); diff --git a/src/Features/Core/Portable/SemanticSearch/AbstractSemanticSearchService.cs b/src/Features/Core/Portable/SemanticSearch/AbstractSemanticSearchService.cs index 3194bd7e2095d..81a53d7d5c53f 100644 --- a/src/Features/Core/Portable/SemanticSearch/AbstractSemanticSearchService.cs +++ b/src/Features/Core/Portable/SemanticSearch/AbstractSemanticSearchService.cs @@ -388,7 +388,7 @@ private static bool TryGetFindMethod(Assembly queryAssembly, [NotNullWhen(true)] { try { - var candidates = new ArrayBuilder(); + using var _ = ArrayBuilder.GetInstance(out var candidates); foreach (var candidate in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance)) { diff --git a/src/Features/Core/Portable/SemanticSearch/SemanticSearchDocumentSupportsFeatureService.cs b/src/Features/Core/Portable/SemanticSearch/SemanticSearchDocumentSupportsFeatureService.cs index bdee370068f02..59bae68dec57c 100644 --- a/src/Features/Core/Portable/SemanticSearch/SemanticSearchDocumentSupportsFeatureService.cs +++ b/src/Features/Core/Portable/SemanticSearch/SemanticSearchDocumentSupportsFeatureService.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.SemanticSearch; [ExportWorkspaceService(typeof(IDocumentSupportsFeatureService), WorkspaceKind.SemanticSearch), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal class SemanticSearchDocumentSupportsFeatureService() : IDocumentSupportsFeatureService +internal sealed class SemanticSearchDocumentSupportsFeatureService() : IDocumentSupportsFeatureService { public bool SupportsCodeFixes(Document document) => SemanticSearchUtilities.IsQueryDocument(document); diff --git a/src/Features/Core/Portable/Shared/Extensions/DocumentExtensions.cs b/src/Features/Core/Portable/Shared/Extensions/DocumentExtensions.cs index cfcc7666beea3..e1dbba9c7589e 100644 --- a/src/Features/Core/Portable/Shared/Extensions/DocumentExtensions.cs +++ b/src/Features/Core/Portable/Shared/Extensions/DocumentExtensions.cs @@ -93,18 +93,6 @@ public static async Task IsValidContextForDocumentOrLinkedDocumentsAsync( return false; } - /// - /// Gets the set of naming rules the user has set for this document. Will include a set of default naming rules - /// that match if the user hasn't specified any for a particular symbol type. The are added at the end so they - /// will only be used if the user hasn't specified a preference. - /// - public static async Task> GetNamingRulesAsync( - this Document document, CancellationToken cancellationToken) - { - var options = await document.GetNamingStylePreferencesAsync(cancellationToken).ConfigureAwait(false); - return options.CreateRules().NamingRules.AddRange(FallbackNamingRules.Default); - } - public static async Task GetApplicableNamingRuleAsync(this Document document, ISymbol symbol, CancellationToken cancellationToken) { var rules = await document.GetNamingRulesAsync(cancellationToken).ConfigureAwait(false); @@ -117,19 +105,6 @@ public static async Task GetApplicableNamingRuleAsync(this Document throw ExceptionUtilities.Unreachable(); } - public static async Task GetApplicableNamingRuleAsync( - this Document document, SymbolKind symbolKind, Accessibility accessibility, CancellationToken cancellationToken) - { - var rules = await document.GetNamingRulesAsync(cancellationToken).ConfigureAwait(false); - foreach (var rule in rules) - { - if (rule.SymbolSpecification.AppliesTo(symbolKind, accessibility)) - return rule; - } - - throw ExceptionUtilities.Unreachable(); - } - public static async Task GetApplicableNamingRuleAsync( this Document document, SymbolKindOrTypeKind kind, DeclarationModifiers modifiers, Accessibility? accessibility, CancellationToken cancellationToken) { diff --git a/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_Sorting.cs b/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_Sorting.cs index c871967799ac1..0af02e80b0828 100644 --- a/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_Sorting.cs +++ b/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_Sorting.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.Shared.Extensions; -internal partial class ISymbolExtensions2 +internal static partial class ISymbolExtensions2 { [Obsolete("Use overload without ISymbolDisplayService")] public static ImmutableArray Sort( diff --git a/src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.cs b/src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.cs index 4ec612084f6f9..6e4e21b57f012 100644 --- a/src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.cs +++ b/src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.cs @@ -21,7 +21,7 @@ internal interface IDocumentSupportsFeatureService : IWorkspaceService } [ExportWorkspaceService(typeof(IDocumentSupportsFeatureService), ServiceLayer.Default), Shared] -internal class DefaultDocumentSupportsFeatureService : IDocumentSupportsFeatureService +internal sealed class DefaultDocumentSupportsFeatureService : IDocumentSupportsFeatureService { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/Shared/Utilities/AnnotatedSymbolMapping.cs b/src/Features/Core/Portable/Shared/Utilities/AnnotatedSymbolMapping.cs index 6ea4326fda5d6..59dbce521aa14 100644 --- a/src/Features/Core/Portable/Shared/Utilities/AnnotatedSymbolMapping.cs +++ b/src/Features/Core/Portable/Shared/Utilities/AnnotatedSymbolMapping.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; -internal class AnnotatedSymbolMapping( +internal sealed class AnnotatedSymbolMapping( ImmutableDictionary symbolToDeclarationAnnotationMap, Solution annotatedSolution, ImmutableDictionary> documentIdsToSymbolMap, diff --git a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs index c2d7210ada60c..e8c2bce414eb0 100644 --- a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs +++ b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.SignatureHelp; internal abstract partial class AbstractSignatureHelpProvider { - internal class SymbolKeySignatureHelpItem( + internal sealed class SymbolKeySignatureHelpItem( ISymbol symbol, bool isVariadic, Func>? documentationFactory, diff --git a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs index 807ca75b919ea..90a53acab06ca 100644 --- a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs +++ b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs @@ -48,7 +48,7 @@ protected AbstractSignatureHelpProvider() (items, selectedItemIndex) = Filter(items, state.Value.ArgumentNames, selectedItemIndex); // If the caller provided a preferred parameter for us to be on then override whatever we found syntactically. - var argumentIndex = state.Value.ArgumentIndex; + var preferredParameterIndex = state.Value.SemanticParameterIndex; if (parameterIndexOverride >= 0) { // However, in the case where the overridden index is to a variadic member, and the syntactic index goes @@ -56,16 +56,16 @@ protected AbstractSignatureHelpProvider() // variadic member, and we still want to remember where we are syntactically so that if the user picks // another member that we correctly pick the right parameter for it. var keepSyntacticIndex = - argumentIndex > parameterIndexOverride && + preferredParameterIndex > parameterIndexOverride && selectedItemIndex != null && items[selectedItemIndex.Value].IsVariadic && - argumentIndex >= items[selectedItemIndex.Value].Parameters.Length; + preferredParameterIndex >= items[selectedItemIndex.Value].Parameters.Length; if (!keepSyntacticIndex) - argumentIndex = parameterIndexOverride; + preferredParameterIndex = parameterIndexOverride; } - return new SignatureHelpItems(items, applicableSpan, argumentIndex, state.Value.ArgumentCount, state.Value.ArgumentName, selectedItemIndex); + return new SignatureHelpItems(items, applicableSpan, preferredParameterIndex, state.Value.SyntacticArgumentCount, state.Value.ArgumentName, selectedItemIndex); } protected static SignatureHelpItems? CreateCollectionInitializerSignatureHelpItems( @@ -294,9 +294,10 @@ symbolKeyItem.SymbolKey is not SymbolKey symbolKey || } return new SignatureHelpItems( - finalItems, itemsForCurrentDocument.ApplicableSpan, - itemsForCurrentDocument.ArgumentIndex, - itemsForCurrentDocument.ArgumentCount, + finalItems, + itemsForCurrentDocument.ApplicableSpan, + itemsForCurrentDocument.SemanticParameterIndex, + itemsForCurrentDocument.SyntacticArgumentCount, itemsForCurrentDocument.ArgumentName, itemsForCurrentDocument.SelectedItemIndex); } diff --git a/src/Features/Core/Portable/SignatureHelp/ExportSignatureHelpProviderAttribute.cs b/src/Features/Core/Portable/SignatureHelp/ExportSignatureHelpProviderAttribute.cs index 9613808ba9833..0d98471f9a26d 100644 --- a/src/Features/Core/Portable/SignatureHelp/ExportSignatureHelpProviderAttribute.cs +++ b/src/Features/Core/Portable/SignatureHelp/ExportSignatureHelpProviderAttribute.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.SignatureHelp; [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] -internal class ExportSignatureHelpProviderAttribute(string name, string language) : ExportAttribute(typeof(ISignatureHelpProvider)) +internal sealed class ExportSignatureHelpProviderAttribute(string name, string language) : ExportAttribute(typeof(ISignatureHelpProvider)) { public string Name { get; } = name ?? throw new ArgumentNullException(nameof(name)); public string Language { get; } = language ?? throw new ArgumentNullException(nameof(language)); diff --git a/src/Features/Core/Portable/SignatureHelp/SignatureHelpItems.cs b/src/Features/Core/Portable/SignatureHelp/SignatureHelpItems.cs index 040aa06149dcb..179ea67ea04f3 100644 --- a/src/Features/Core/Portable/SignatureHelp/SignatureHelpItems.cs +++ b/src/Features/Core/Portable/SignatureHelp/SignatureHelpItems.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.SignatureHelp; -internal class SignatureHelpItems +internal sealed class SignatureHelpItems { /// /// The list of items to present to the user. @@ -26,16 +26,20 @@ internal class SignatureHelpItems public TextSpan ApplicableSpan { get; } /// - /// Returns the specified argument index that the provided position is at in the current document. This - /// index may be greater than the number of arguments in the selected . + /// Returns the specified parameter index that the provided position is at in the current document. This + /// index may be greater than the number of actual syntactic arguments in the selected . /// - public int ArgumentIndex { get; } + /// + /// This relates to the original semantic symbol that was used to create a particular item. In other words, + /// it may be using + /// + public int SemanticParameterIndex { get; } /// /// Returns the total number of arguments that have been typed in the current document. This may be /// greater than the ArgumentIndex if there are additional arguments after the provided position. /// - public int ArgumentCount { get; } + public int SyntacticArgumentCount { get; } /// /// Returns the name of specified argument at the current position in the document. @@ -57,8 +61,8 @@ internal class SignatureHelpItems public SignatureHelpItems( IList items, TextSpan applicableSpan, - int argumentIndex, - int argumentCount, + int semanticParameterIndex, + int syntacticArgumentCount, string? argumentName, int? selectedItem = null) { @@ -66,15 +70,8 @@ public SignatureHelpItems( Contract.ThrowIfTrue(items.IsEmpty()); Contract.ThrowIfTrue(selectedItem.HasValue && selectedItem.Value >= items.Count); - if (argumentIndex < 0) - { - throw new ArgumentException($"{nameof(argumentIndex)} < 0. {argumentIndex} < 0", nameof(argumentIndex)); - } - - if (argumentCount < argumentIndex) - { - throw new ArgumentException($"{nameof(argumentCount)} < {nameof(argumentIndex)}. {argumentCount} < {argumentIndex}", nameof(argumentIndex)); - } + if (semanticParameterIndex < 0) + throw new ArgumentException($"{nameof(semanticParameterIndex)} < 0. {semanticParameterIndex} < 0", nameof(semanticParameterIndex)); // Adjust the `selectedItem` index if duplicates are able to be removed. var distinctItems = items.Distinct().ToList(); @@ -96,8 +93,8 @@ public SignatureHelpItems( Items = distinctItems; ApplicableSpan = applicableSpan; - ArgumentIndex = argumentIndex; - ArgumentCount = argumentCount; + SemanticParameterIndex = semanticParameterIndex; + SyntacticArgumentCount = syntacticArgumentCount; SelectedItemIndex = selectedItem; ArgumentName = argumentName; } diff --git a/src/Features/Core/Portable/SignatureHelp/SignatureHelpParameter.cs b/src/Features/Core/Portable/SignatureHelp/SignatureHelpParameter.cs index 7a83abe7eed24..94250b831e95f 100644 --- a/src/Features/Core/Portable/SignatureHelp/SignatureHelpParameter.cs +++ b/src/Features/Core/Portable/SignatureHelp/SignatureHelpParameter.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.SignatureHelp; /// Once that it done, this will be converted to normal SignatureHelpParameters which only /// point to TaggedText parts. /// -internal class SignatureHelpSymbolParameter( +internal sealed class SignatureHelpSymbolParameter( string name, bool isOptional, Func>? documentationFactory, @@ -85,7 +85,7 @@ public static explicit operator SignatureHelpParameter(SignatureHelpSymbolParame } } -internal class SignatureHelpParameter( +internal sealed class SignatureHelpParameter( string name, bool isOptional, Func>? documentationFactory, diff --git a/src/Features/Core/Portable/SignatureHelp/SignatureHelpState.cs b/src/Features/Core/Portable/SignatureHelp/SignatureHelpState.cs index 324ae3da5a5a5..d338d9a86f3bf 100644 --- a/src/Features/Core/Portable/SignatureHelp/SignatureHelpState.cs +++ b/src/Features/Core/Portable/SignatureHelp/SignatureHelpState.cs @@ -6,10 +6,5 @@ namespace Microsoft.CodeAnalysis.SignatureHelp; -internal readonly struct SignatureHelpState(int argumentIndex, int argumentCount, string? argumentName, ImmutableArray argumentNames) -{ - public readonly int ArgumentIndex = argumentIndex; - public readonly int ArgumentCount = argumentCount; - public readonly string? ArgumentName = argumentName; - public readonly ImmutableArray ArgumentNames = argumentNames; -} +internal readonly record struct SignatureHelpState( + int SemanticParameterIndex, int SyntacticArgumentCount, string? ArgumentName, ImmutableArray ArgumentNames); diff --git a/src/Features/Core/Portable/Snippets/AbstractSnippetService.cs b/src/Features/Core/Portable/Snippets/AbstractSnippetService.cs index 55e4cbe47b1f9..69439dbed076c 100644 --- a/src/Features/Core/Portable/Snippets/AbstractSnippetService.cs +++ b/src/Features/Core/Portable/Snippets/AbstractSnippetService.cs @@ -8,7 +8,6 @@ using System.Diagnostics; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Snippets.SnippetProviders; @@ -37,26 +36,27 @@ public ISnippetProvider GetSnippetProvider(string snippetIdentifier) /// Iterates through all providers and determines if the snippet /// can be added to the Completion list at the corresponding position. /// - public async Task> GetSnippetsAsync(SnippetContext context, CancellationToken cancellationToken) + public ImmutableArray GetSnippets(SnippetContext context, CancellationToken cancellationToken) { using var _ = ArrayBuilder.GetInstance(out var arrayBuilder); - foreach (var provider in GetSnippetProviders(context.Document)) + EnsureSnippetsLoaded(context.Document.Project.Language); + foreach (var provider in _snippetProviders) { - var snippetData = await provider.GetSnippetDataAsync(context, cancellationToken).ConfigureAwait(false); - arrayBuilder.AddIfNotNull(snippetData); + if (provider.IsValidSnippetLocation(context, cancellationToken)) + arrayBuilder.Add(new(provider.Identifier, provider.Description, provider.AdditionalFilterTexts)); } return arrayBuilder.ToImmutableAndClear(); } - private ImmutableArray GetSnippetProviders(Document document) + internal void EnsureSnippetsLoaded(string language) { lock (_snippetProvidersLock) { if (_snippetProviders.IsDefault) { using var _ = ArrayBuilder.GetInstance(out var arrayBuilder); - foreach (var provider in _lazySnippetProviders.Where(p => p.Metadata.Language == document.Project.Language)) + foreach (var provider in _lazySnippetProviders.Where(p => p.Metadata.Language == language)) { var providerData = provider.Value; Debug.Assert(!_identifierToProviderMap.TryGetValue(providerData.Identifier, out var _)); @@ -67,7 +67,5 @@ private ImmutableArray GetSnippetProviders(Document document) _snippetProviders = arrayBuilder.ToImmutable(); } } - - return _snippetProviders; } } diff --git a/src/Features/Core/Portable/Snippets/ISnippetService.cs b/src/Features/Core/Portable/Snippets/ISnippetService.cs index b8e45d4bc0812..53f0f1aba624a 100644 --- a/src/Features/Core/Portable/Snippets/ISnippetService.cs +++ b/src/Features/Core/Portable/Snippets/ISnippetService.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Snippets.SnippetProviders; @@ -15,7 +14,7 @@ internal interface ISnippetService : ILanguageService /// /// Retrieves all possible types of snippets for a particular position /// - Task> GetSnippetsAsync(SnippetContext context, CancellationToken cancellationToken); + ImmutableArray GetSnippets(SnippetContext context, CancellationToken cancellationToken); /// /// Gets the corresponding provider from a snippet identifier. diff --git a/src/Features/Core/Portable/Snippets/RoslynLSPSnippetConverter.cs b/src/Features/Core/Portable/Snippets/RoslynLSPSnippetConverter.cs index 78f343931e30a..7052c0a1bb86b 100644 --- a/src/Features/Core/Portable/Snippets/RoslynLSPSnippetConverter.cs +++ b/src/Features/Core/Portable/Snippets/RoslynLSPSnippetConverter.cs @@ -37,10 +37,10 @@ private static string ConvertToLSPSnippetString(TextChange textChange, Immutable Contract.ThrowIfNull(textChangeText); using var _1 = PooledStringBuilder.GetInstance(out var lspSnippetString); - using var _2 = PooledDictionary.GetInstance(out var dictionary); + using var _2 = PooledDictionary.GetInstance(out var dictionary); PopulateMapOfSpanStartsToLSPStringItem(dictionary, placeholders, textChangeStart); - // Need to go through the length + 1 since caret postions occur before and after the + // Need to go through the length + 1 since caret positions occur before and after the // character position. // If there is a caret at the end of the line, then it's position // will be equivalent to the length of the TextChange. @@ -55,11 +55,11 @@ private static string ConvertToLSPSnippetString(TextChange textChange, Immutable // generates a string that is LSP formatted. if (dictionary.TryGetValue(i, out var placeholderInfo)) { - var str = $"${{{placeholderInfo.priority}:{placeholderInfo.identifier}}}"; + var str = $"${{{placeholderInfo.priority}:{placeholderInfo.text}}}"; lspSnippetString.Append(str); // Skip past the entire identifier in the TextChange text - i += placeholderInfo.identifier.Length; + i += placeholderInfo.text.Length; } else { @@ -87,13 +87,13 @@ private static void PopulateMapOfSpanStartsToLSPStringItem(Dictionary 0) { - startPosition = Math.Min(startPosition, placeholders.Min(placeholder => placeholder.PlaceHolderPositions.Min())); - endPosition = Math.Max(endPosition, placeholders.Max(placeholder => placeholder.PlaceHolderPositions.Max())); + startPosition = Math.Min(startPosition, placeholders.Min(placeholder => placeholder.StartingPositions.Min())); + endPosition = Math.Max(endPosition, placeholders.Max(placeholder => placeholder.StartingPositions.Max())); } startPosition = Math.Min(startPosition, caretPosition); diff --git a/src/Features/Core/Portable/Snippets/SnippetChange.cs b/src/Features/Core/Portable/Snippets/SnippetChange.cs index d369328e80e59..a1f3f3b14361a 100644 --- a/src/Features/Core/Portable/Snippets/SnippetChange.cs +++ b/src/Features/Core/Portable/Snippets/SnippetChange.cs @@ -18,21 +18,21 @@ internal readonly struct SnippetChange /// public readonly ImmutableArray TextChanges; - /// - /// The position that the cursor should end up on - /// - public readonly int CursorPosition; - /// /// The items that we will want to rename as well as the ordering /// in which to visit those items. /// public readonly ImmutableArray Placeholders; + /// + /// The position that the caret should end up on + /// + public readonly int FinalCaretPosition; + public SnippetChange( ImmutableArray textChanges, - int cursorPosition, - ImmutableArray placeholders) + ImmutableArray placeholders, + int finalCaretPosition) { if (textChanges.IsEmpty) { @@ -40,7 +40,7 @@ public SnippetChange( } TextChanges = textChanges; - CursorPosition = cursorPosition; Placeholders = placeholders; + FinalCaretPosition = finalCaretPosition; } } diff --git a/src/Features/Core/Portable/Snippets/SnippetContext.cs b/src/Features/Core/Portable/Snippets/SnippetContext.cs index 58d6437794bfe..034a4e0e10fef 100644 --- a/src/Features/Core/Portable/Snippets/SnippetContext.cs +++ b/src/Features/Core/Portable/Snippets/SnippetContext.cs @@ -28,5 +28,10 @@ internal SnippetContext(SyntaxContext syntaxContext) /// public int Position => SyntaxContext.Position; + /// + /// The semantic model of the document. + /// + public SemanticModel SemanticModel => SyntaxContext.SemanticModel; + internal SyntaxContext SyntaxContext { get; } } diff --git a/src/Features/Core/Portable/Snippets/SnippetData.cs b/src/Features/Core/Portable/Snippets/SnippetData.cs index ea9a52fb2f583..8cb59b49aa5eb 100644 --- a/src/Features/Core/Portable/Snippets/SnippetData.cs +++ b/src/Features/Core/Portable/Snippets/SnippetData.cs @@ -11,9 +11,9 @@ namespace Microsoft.CodeAnalysis.Snippets; /// Avoids using the Snippet and creating a TextChange/finding cursor /// position before we know it was the selected CompletionItem. /// -internal readonly struct SnippetData(string description, string identifier, ImmutableArray additionalFilterTexts) +internal readonly struct SnippetData(string identifier, string description, ImmutableArray additionalFilterTexts) { - public readonly string Description = description; public readonly string Identifier = identifier; + public readonly string Description = description; public readonly ImmutableArray AdditionalFilterTexts = additionalFilterTexts; } diff --git a/src/Features/Core/Portable/Snippets/SnippetPlaceholder.cs b/src/Features/Core/Portable/Snippets/SnippetPlaceholder.cs index a89e6aece8e2e..be91e76766823 100644 --- a/src/Features/Core/Portable/Snippets/SnippetPlaceholder.cs +++ b/src/Features/Core/Portable/Snippets/SnippetPlaceholder.cs @@ -10,15 +10,15 @@ namespace Microsoft.CodeAnalysis.Snippets; internal readonly struct SnippetPlaceholder { /// - /// The identifier in the snippet that needs to be renamed. + /// Editable text in the snippet. /// - public readonly string Identifier; + public readonly string Text; /// /// The positions associated with the identifier that will need to /// be converted into LSP formatted strings. /// - public readonly ImmutableArray PlaceHolderPositions; + public readonly ImmutableArray StartingPositions; /// /// @@ -26,26 +26,32 @@ internal readonly struct SnippetPlaceholder /// /// for (var {1:i} = 0; {1:i} < {2:length}; {1:i}++) /// - /// Identifier: i, 3 associated positions
- /// Identifier: length, 1 associated position
+ /// Text: i, 3 associated positions
+ /// Text: length, 1 associated position
///
///
- public SnippetPlaceholder(string identifier, ImmutableArray placeholderPositions) + public SnippetPlaceholder(string text, ImmutableArray startingPositions) { - if (string.IsNullOrEmpty(identifier)) + if (string.IsNullOrEmpty(text)) { - throw new ArgumentException($"{nameof(identifier)} must not be an null or empty."); + throw new ArgumentException($"{nameof(text)} must not be an null or empty."); } - Identifier = identifier; - PlaceHolderPositions = placeholderPositions; + Text = text; + StartingPositions = startingPositions; } /// /// Initialize a placeholder with a single position /// - public SnippetPlaceholder(string identifier, int placeholderPosition) - : this(identifier, [placeholderPosition]) + public SnippetPlaceholder(string text, int startingPosition) + : this(text, [startingPosition]) { } + + public void Deconstruct(out string text, out ImmutableArray startingPositions) + { + text = Text; + startingPositions = StartingPositions; + } } diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractInlineStatementSnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractInlineStatementSnippetProvider.cs index ac60dc0569394..a39f9f2d7d6c2 100644 --- a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractInlineStatementSnippetProvider.cs +++ b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractInlineStatementSnippetProvider.cs @@ -27,6 +27,8 @@ internal abstract class AbstractInlineStatementSnippetProvider /// Current compilation instance protected abstract bool IsValidAccessingType(ITypeSymbol type, Compilation compilation); + protected abstract bool CanInsertStatementAfterToken(SyntaxToken token); + /// /// Generate statement node /// @@ -39,10 +41,10 @@ internal abstract class AbstractInlineStatementSnippetProvider ///
protected bool ConstructedFromInlineExpression { get; private set; } - protected override bool IsValidSnippetLocation(in SnippetContext context, CancellationToken cancellationToken) + protected override bool IsValidSnippetLocationCore(SnippetContext context, CancellationToken cancellationToken) { var syntaxContext = context.SyntaxContext; - var semanticModel = syntaxContext.SemanticModel; + var semanticModel = context.SemanticModel; var targetToken = syntaxContext.TargetToken; var syntaxFacts = context.Document.GetRequiredLanguageService(); @@ -51,7 +53,7 @@ protected override bool IsValidSnippetLocation(in SnippetContext context, Cancel return IsValidAccessingType(type, semanticModel.Compilation); } - return base.IsValidSnippetLocation(in context, cancellationToken); + return base.IsValidSnippetLocationCore(context, cancellationToken); } protected sealed override async Task GenerateSnippetTextChangeAsync(Document document, int position, CancellationToken cancellationToken) @@ -75,14 +77,49 @@ protected sealed override async Task GenerateSnippetTextChangeAsync( return closestNode.FirstAncestorOrSelf(); } - private static bool TryGetInlineExpressionInfo(SyntaxToken targetToken, ISyntaxFactsService syntaxFacts, SemanticModel semanticModel, [NotNullWhen(true)] out InlineExpressionInfo? expressionInfo, CancellationToken cancellationToken) + private bool CanInsertStatementBeforeToken(SyntaxToken token) + { + var previousToken = token.GetPreviousToken(); + if (previousToken == default) + { + // Token is the first token in the file + return true; + } + + return CanInsertStatementAfterToken(previousToken); + } + + private bool TryGetInlineExpressionInfo( + SyntaxToken targetToken, + ISyntaxFactsService syntaxFacts, + SemanticModel semanticModel, + [NotNullWhen(true)] out InlineExpressionInfo? expressionInfo, + CancellationToken cancellationToken) { var parentNode = targetToken.Parent; if (syntaxFacts.IsMemberAccessExpression(parentNode) && - syntaxFacts.IsExpressionStatement(parentNode?.Parent)) + CanInsertStatementBeforeToken(parentNode.GetFirstToken())) { - var expression = syntaxFacts.GetExpressionOfMemberAccessExpression(parentNode)!; + syntaxFacts.GetPartsOfMemberAccessExpression(parentNode, out var expression, out var dotToken, out var name); + var sourceText = parentNode.SyntaxTree.GetText(cancellationToken); + + if (sourceText.AreOnSameLine(dotToken, name.GetFirstToken())) + { + expressionInfo = null; + return false; + } + + var symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken); + + // Forbid a case when we are dotting of a type, e.g. `string.$$`. + // Inline statement snippets are not valid in this context + if (symbolInfo.Symbol is ITypeSymbol) + { + expressionInfo = null; + return false; + } + var typeInfo = semanticModel.GetTypeInfo(expression, cancellationToken); expressionInfo = new(expression, typeInfo); return true; @@ -95,9 +132,27 @@ private static bool TryGetInlineExpressionInfo(SyntaxToken targetToken, ISyntaxF // var a = 0; // ... // Here `flag.var` is parsed as a qualified name, so this case requires its own handling - if (syntaxFacts.IsQualifiedName(parentNode)) + if (syntaxFacts.IsQualifiedName(parentNode) && CanInsertStatementBeforeToken(parentNode.GetFirstToken())) { - syntaxFacts.GetPartsOfQualifiedName(parentNode, out var expression, out _, out _); + syntaxFacts.GetPartsOfQualifiedName(parentNode, out var expression, out var dotToken, out var right); + var sourceText = parentNode.SyntaxTree.GetText(cancellationToken); + + if (sourceText.AreOnSameLine(dotToken, right.GetFirstToken())) + { + expressionInfo = null; + return false; + } + + var symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken); + + // Forbid a case when we are dotting of a type, e.g. `string.$$`. + // Inline statement snippets are not valid in this context + if (symbolInfo.Symbol is ITypeSymbol) + { + expressionInfo = null; + return false; + } + var typeInfo = semanticModel.GetSpeculativeTypeInfo(expression.SpanStart, expression, SpeculativeBindingOption.BindAsExpression); expressionInfo = new(expression, typeInfo); return true; diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractSnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractSnippetProvider.cs index b8ce95c38c466..7dd77c9c9d2a7 100644 --- a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractSnippetProvider.cs +++ b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractSnippetProvider.cs @@ -27,13 +27,13 @@ internal abstract class AbstractSnippetProvider : ISnippetProvid public virtual ImmutableArray AdditionalFilterTexts => []; - protected readonly SyntaxAnnotation FindSnippetAnnotation = new(); + protected static readonly SyntaxAnnotation FindSnippetAnnotation = new(); /// /// Implemented by each SnippetProvider to determine if that particular position is a valid /// location for the snippet to be inserted. /// - protected abstract bool IsValidSnippetLocation(in SnippetContext context, CancellationToken cancellationToken); + protected abstract bool IsValidSnippetLocationCore(SnippetContext context, CancellationToken cancellationToken); /// /// Generates the new snippet's TextChanges that are being inserted into the document. @@ -50,25 +50,16 @@ internal abstract class AbstractSnippetProvider : ISnippetProvid /// protected abstract ImmutableArray GetPlaceHolderLocationsList(TSnippetSyntax node, ISyntaxFacts syntaxFacts, CancellationToken cancellationToken); - /// - /// Determines if the location is valid for a snippet, - /// if so, then it creates a SnippetData. - /// - public ValueTask GetSnippetDataAsync(SnippetContext context, CancellationToken cancellationToken) + public bool IsValidSnippetLocation(SnippetContext context, CancellationToken cancellationToken) { var syntaxFacts = context.Document.GetRequiredLanguageService(); var syntaxTree = context.SyntaxContext.SyntaxTree; if (syntaxFacts.IsInNonUserCode(syntaxTree, context.Position, cancellationToken)) { - return ValueTaskFactory.FromResult(null); - } - - if (!IsValidSnippetLocation(in context, cancellationToken)) - { - return ValueTaskFactory.FromResult(null); + return false; } - return ValueTaskFactory.FromResult(new SnippetData(Description, Identifier, AdditionalFilterTexts)); + return IsValidSnippetLocationCore(context, cancellationToken); } /// @@ -76,7 +67,7 @@ internal abstract class AbstractSnippetProvider : ISnippetProvid /// Reformats the document with the snippet TextChange and annotates /// appropriately for the cursor to get the target cursor position. /// - public async Task GetSnippetAsync(Document document, int position, CancellationToken cancellationToken) + public async Task GetSnippetChangeAsync(Document document, int position, CancellationToken cancellationToken) { var syntaxFacts = document.GetRequiredLanguageService(); @@ -119,8 +110,8 @@ public async Task GetSnippetAsync(Document document, int position return new SnippetChange( textChanges: changesArray, - cursorPosition: GetTargetCaretPosition(mainChangeNode, sourceText), - placeholders: placeholders); + placeholders: placeholders, + finalCaretPosition: GetTargetCaretPosition(mainChangeNode, sourceText)); } /// @@ -145,7 +136,7 @@ public async Task GetSnippetAsync(Document document, int position return nodeWithTrivia; } - private async Task CleanupDocumentAsync( + private static async Task CleanupDocumentAsync( Document document, CancellationToken cancellationToken) { if (document.SupportsSyntaxTree) diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractStatementSnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractStatementSnippetProvider.cs index 16b98b988c8e9..2cc624a4e736f 100644 --- a/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractStatementSnippetProvider.cs +++ b/src/Features/Core/Portable/Snippets/SnippetProviders/AbstractStatementSnippetProvider.cs @@ -9,6 +9,6 @@ namespace Microsoft.CodeAnalysis.Snippets.SnippetProviders; internal abstract class AbstractStatementSnippetProvider : AbstractSingleChangeSnippetProvider where TStatementSyntax : SyntaxNode { - protected override bool IsValidSnippetLocation(in SnippetContext context, CancellationToken cancellationToken) + protected override bool IsValidSnippetLocationCore(SnippetContext context, CancellationToken cancellationToken) => context.SyntaxContext.IsStatementContext || context.SyntaxContext.IsGlobalStatementContext; } diff --git a/src/Features/Core/Portable/Snippets/SnippetProviders/ISnippetProvider.cs b/src/Features/Core/Portable/Snippets/SnippetProviders/ISnippetProvider.cs index c9e8267f2e25b..56052399364ae 100644 --- a/src/Features/Core/Portable/Snippets/SnippetProviders/ISnippetProvider.cs +++ b/src/Features/Core/Portable/Snippets/SnippetProviders/ISnippetProvider.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -19,13 +20,18 @@ internal interface ISnippetProvider /// string Description { get; } + /// + /// Additional filter texts for snippet completion item + /// + ImmutableArray AdditionalFilterTexts { get; } + /// /// Determines if a snippet can exist at a particular location. /// - ValueTask GetSnippetDataAsync(SnippetContext context, CancellationToken cancellationToken); + bool IsValidSnippetLocation(SnippetContext context, CancellationToken cancellationToken); /// - /// Gets the Snippet from the corresponding snippet provider. + /// Gets the Snippet change from the corresponding snippet provider. /// - Task GetSnippetAsync(Document document, int position, CancellationToken cancellationToken); + Task GetSnippetChangeAsync(Document document, int position, CancellationToken cancellationToken); } diff --git a/src/Features/Core/Portable/Snippets/SnippetUtilities.cs b/src/Features/Core/Portable/Snippets/SnippetUtilities.cs index 21704b61251e7..c8f9105313e1a 100644 --- a/src/Features/Core/Portable/Snippets/SnippetUtilities.cs +++ b/src/Features/Core/Portable/Snippets/SnippetUtilities.cs @@ -7,7 +7,7 @@ using System.Diagnostics.CodeAnalysis; namespace Microsoft.CodeAnalysis; -internal class SnippetUtilities +internal sealed class SnippetUtilities { public static bool TryGetWordOnLeft(int position, SourceText currentText, ISyntaxFactsService syntaxFactsService, [NotNullWhen(true)] out TextSpan? wordSpan) { diff --git a/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerService.cs b/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerService.cs index 12a64f92dfa8b..4dfc88ec81f92 100644 --- a/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerService.cs +++ b/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerService.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.SolutionCrawler; -internal partial class SolutionCrawlerRegistrationService +internal sealed partial class SolutionCrawlerRegistrationService { internal static readonly Option2 EnableSolutionCrawler = new("dotnet_enable_solution_crawler", defaultValue: true); } diff --git a/src/Features/Core/Portable/StackTraceExplorer/StackFrameLocalMethodResolver.cs b/src/Features/Core/Portable/StackTraceExplorer/StackFrameLocalMethodResolver.cs index 6ecf960f9adad..6f8c559742bfd 100644 --- a/src/Features/Core/Portable/StackTraceExplorer/StackFrameLocalMethodResolver.cs +++ b/src/Features/Core/Portable/StackTraceExplorer/StackFrameLocalMethodResolver.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.StackTraceExplorer; -internal class StackFrameLocalMethodResolver : AbstractStackTraceSymbolResolver +internal sealed class StackFrameLocalMethodResolver : AbstractStackTraceSymbolResolver { public override async Task TryGetBestMatchAsync( Project project, diff --git a/src/Features/Core/Portable/StackTraceExplorer/StackFrameMethodSymbolResolver.cs b/src/Features/Core/Portable/StackTraceExplorer/StackFrameMethodSymbolResolver.cs index cdadee9cd3bcd..042560f30f3f2 100644 --- a/src/Features/Core/Portable/StackTraceExplorer/StackFrameMethodSymbolResolver.cs +++ b/src/Features/Core/Portable/StackTraceExplorer/StackFrameMethodSymbolResolver.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.StackTraceExplorer; -internal class StackFrameMethodSymbolResolver : AbstractStackTraceSymbolResolver +internal sealed class StackFrameMethodSymbolResolver : AbstractStackTraceSymbolResolver { public override Task TryGetBestMatchAsync(Project project, INamedTypeSymbol type, diff --git a/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs b/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs index 95f8370e937c2..e809b29c3f232 100644 --- a/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs +++ b/src/Features/Core/Portable/StackTraceExplorer/StackTraceExplorerService.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.StackTraceExplorer; [ExportWorkspaceService(typeof(IStackTraceExplorerService)), Shared] -internal class StackTraceExplorerService : IStackTraceExplorerService +internal sealed class StackTraceExplorerService : IStackTraceExplorerService { [ImportingConstructor] [System.Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/Structure/BlockStructure.cs b/src/Features/Core/Portable/Structure/BlockStructure.cs index 3aed119c12fbb..a7353954b5d01 100644 --- a/src/Features/Core/Portable/Structure/BlockStructure.cs +++ b/src/Features/Core/Portable/Structure/BlockStructure.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.Structure; -internal class BlockStructure(ImmutableArray spans) +internal sealed class BlockStructure(ImmutableArray spans) { public ImmutableArray Spans { get; } = spans; } diff --git a/src/Features/Core/Portable/Structure/BlockStructureContext.cs b/src/Features/Core/Portable/Structure/BlockStructureContext.cs index 1c9097211fa32..da3d108b1d6c7 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureContext.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureContext.cs @@ -12,12 +12,20 @@ namespace Microsoft.CodeAnalysis.Structure; [NonCopyable] internal readonly struct BlockStructureContext(SyntaxTree syntaxTree, BlockStructureOptions options, CancellationToken cancellationToken) : IDisposable { - public readonly ArrayBuilder Spans = ArrayBuilder.GetInstance(); + // We keep our own ObjectPool of ArrayBuilders as we want to use ArrayBuilders for their ability to efficiently create ImmutableArrays, but don't + // want the maximum capacity the default pool uses for dropping items from the pool. + private static readonly ObjectPool> _blockSpanArrayBuilderPool = new ObjectPool>(() => new ArrayBuilder()); + + public readonly ArrayBuilder Spans = _blockSpanArrayBuilderPool.Allocate(); public readonly SyntaxTree SyntaxTree = syntaxTree; public readonly BlockStructureOptions Options = options; public readonly CancellationToken CancellationToken = cancellationToken; public void Dispose() - => Spans.Free(); + { + // Do not call Free on the builder as we are not using the default pool + Spans.Clear(); + _blockSpanArrayBuilderPool.Free(Spans); + } } diff --git a/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs b/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs index 3cccea1c60fae..3d92420228326 100644 --- a/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs +++ b/src/Features/Core/Portable/Structure/BlockStructureServiceWithProviders.cs @@ -73,11 +73,10 @@ private static BlockStructure GetBlockStructure( private static BlockStructure CreateBlockStructure(in BlockStructureContext context) { - var updatedSpans = new FixedSizeArrayBuilder(context.Spans.Count); - foreach (var span in context.Spans) - updatedSpans.Add(UpdateBlockSpan(span, context.Options)); + for (var i = 0; i < context.Spans.Count; i++) + context.Spans[i] = UpdateBlockSpan(context.Spans[i], context.Options); - return new BlockStructure(updatedSpans.MoveToImmutable()); + return new BlockStructure(context.Spans.ToImmutable()); } private static BlockSpan UpdateBlockSpan(BlockSpan blockSpan, in BlockStructureOptions options) diff --git a/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs b/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs index 69a511be152fc..1aab427e8a04b 100644 --- a/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs +++ b/src/Features/Core/Portable/Structure/Syntax/AbstractBlockStructureProvider.cs @@ -3,9 +3,9 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Shared.Collections; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Structure; @@ -16,6 +16,8 @@ namespace Microsoft.CodeAnalysis.Structure; ///
internal abstract class AbstractBlockStructureProvider : BlockStructureProvider { + private static readonly IComparer s_blockSpanComparer = Comparer.Create(static (x, y) => y.TextSpan.Start.CompareTo(x.TextSpan.Start)); + private readonly ImmutableDictionary> _nodeProviderMap; private readonly ImmutableDictionary> _triviaProviderMap; @@ -32,11 +34,9 @@ public override void ProvideBlockStructure(in BlockStructureContext context) try { var syntaxRoot = context.SyntaxTree.GetRoot(context.CancellationToken); - using var spans = TemporaryArray.Empty; + var initialContextCount = context.Spans.Count; BlockSpanCollector.CollectBlockSpans( - syntaxRoot, context.Options, _nodeProviderMap, _triviaProviderMap, ref spans.AsRef(), context.CancellationToken); - - context.Spans.EnsureCapacity(context.Spans.Count + spans.Count); + syntaxRoot, context.Options, _nodeProviderMap, _triviaProviderMap, context.Spans, context.CancellationToken); // Sort descending, and keep track of the "last added line". // Then, ignore if we found a span on the same line. @@ -48,20 +48,28 @@ public override void ProvideBlockStructure(in BlockStructureContext context) // ) // // We only collapse the "inner" span which has larger start. - spans.Sort(static (x, y) => y.TextSpan.Start.CompareTo(x.TextSpan.Start)); + context.Spans.Sort(initialContextCount, s_blockSpanComparer); - var lastAddedLine = -1; + var lastAddedLineStart = -1; + var lastAddedLineEnd = -1; var text = context.SyntaxTree.GetText(context.CancellationToken); + context.Spans.RemoveWhere((span, index, _) => + { + // do not remove items before the first item that we added + if (index < initialContextCount) + return false; + + var lineStart = text.Lines.GetLinePosition(span.TextSpan.Start).Line; + var lineEnd = text.Lines.GetLinePosition(span.TextSpan.End).Line; + if (lineStart == lastAddedLineStart && lastAddedLineEnd == lineEnd) + return true; - foreach (var span in spans) - { - var line = text.Lines.GetLinePosition(span.TextSpan.Start).Line; - if (line == lastAddedLine) - continue; + lastAddedLineStart = lineStart; + lastAddedLineEnd = lineEnd; - lastAddedLine = line; - context.Spans.Add(span); - } + return false; + }, + arg: default(VoidResult)); } catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) { diff --git a/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxNodeStructureProvider.cs b/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxNodeStructureProvider.cs index b23d3e60ae1e2..2c7ad28faa713 100644 --- a/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxNodeStructureProvider.cs +++ b/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxNodeStructureProvider.cs @@ -4,7 +4,7 @@ using System; using System.Threading; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Structure; @@ -13,7 +13,7 @@ internal abstract class AbstractSyntaxNodeStructureProvider : Abstr { public sealed override void CollectBlockSpans( SyntaxTrivia trivia, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { @@ -23,20 +23,20 @@ public sealed override void CollectBlockSpans( public sealed override void CollectBlockSpans( SyntaxToken previousToken, SyntaxNode node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { if (node is TSyntaxNode tSyntax) { - CollectBlockSpans(previousToken, tSyntax, ref spans, options, cancellationToken); + CollectBlockSpans(previousToken, tSyntax, spans, options, cancellationToken); } } protected abstract void CollectBlockSpans( SyntaxToken previousToken, TSyntaxNode node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken); } diff --git a/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxStructureProvider.cs b/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxStructureProvider.cs index 9e2bcaf528816..911d67442d3f8 100644 --- a/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxStructureProvider.cs +++ b/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxStructureProvider.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Structure; @@ -12,13 +12,13 @@ internal abstract class AbstractSyntaxStructureProvider public abstract void CollectBlockSpans( SyntaxToken previousToken, SyntaxNode node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken); public abstract void CollectBlockSpans( SyntaxTrivia trivia, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken); } diff --git a/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxTriviaStructureProvider.cs b/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxTriviaStructureProvider.cs index d9a923b755027..d4bfcc30f8f7c 100644 --- a/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxTriviaStructureProvider.cs +++ b/src/Features/Core/Portable/Structure/Syntax/AbstractSyntaxTriviaStructureProvider.cs @@ -4,7 +4,7 @@ using System; using System.Threading; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Structure; @@ -13,7 +13,7 @@ internal abstract class AbstractSyntaxTriviaStructureProvider : AbstractSyntaxSt public sealed override void CollectBlockSpans( SyntaxToken previousToken, SyntaxNode node, - ref TemporaryArray spans, + ArrayBuilder spans, BlockStructureOptions options, CancellationToken cancellationToken) { diff --git a/src/Features/Core/Portable/Structure/Syntax/BlockSpanCollector.cs b/src/Features/Core/Portable/Structure/Syntax/BlockSpanCollector.cs index 6e5ac0636cf34..564188c00c510 100644 --- a/src/Features/Core/Portable/Structure/Syntax/BlockSpanCollector.cs +++ b/src/Features/Core/Portable/Structure/Syntax/BlockSpanCollector.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Immutable; using System.Threading; -using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Structure; @@ -34,14 +34,14 @@ public static void CollectBlockSpans( BlockStructureOptions options, ImmutableDictionary> nodeOutlinerMap, ImmutableDictionary> triviaOutlinerMap, - ref TemporaryArray spans, + ArrayBuilder spans, CancellationToken cancellationToken) { var collector = new BlockSpanCollector(options, nodeOutlinerMap, triviaOutlinerMap, cancellationToken); - collector.Collect(syntaxRoot, ref spans); + collector.Collect(syntaxRoot, spans); } - private void Collect(SyntaxNode root, ref TemporaryArray spans) + private void Collect(SyntaxNode root, ArrayBuilder spans) { _cancellationToken.ThrowIfCancellationRequested(); @@ -50,17 +50,17 @@ private void Collect(SyntaxNode root, ref TemporaryArray spans) { if (nodeOrToken.AsNode(out var childNode)) { - GetBlockSpans(previousToken, childNode, ref spans); + GetBlockSpans(previousToken, childNode, spans); } else { - GetBlockSpans(nodeOrToken.AsToken(), ref spans); + GetBlockSpans(nodeOrToken.AsToken(), spans); previousToken = nodeOrToken.AsToken(); } } } - private void GetBlockSpans(SyntaxToken previousToken, SyntaxNode node, ref TemporaryArray spans) + private void GetBlockSpans(SyntaxToken previousToken, SyntaxNode node, ArrayBuilder spans) { if (_nodeProviderMap.TryGetValue(node.GetType(), out var providers)) { @@ -68,18 +68,18 @@ private void GetBlockSpans(SyntaxToken previousToken, SyntaxNode node, ref Tempo { _cancellationToken.ThrowIfCancellationRequested(); - provider.CollectBlockSpans(previousToken, node, ref spans, _options, _cancellationToken); + provider.CollectBlockSpans(previousToken, node, spans, _options, _cancellationToken); } } } - private void GetBlockSpans(SyntaxToken token, ref TemporaryArray spans) + private void GetBlockSpans(SyntaxToken token, ArrayBuilder spans) { - GetOutliningSpans(token.LeadingTrivia, ref spans); - GetOutliningSpans(token.TrailingTrivia, ref spans); + GetOutliningSpans(token.LeadingTrivia, spans); + GetOutliningSpans(token.TrailingTrivia, spans); } - private void GetOutliningSpans(SyntaxTriviaList triviaList, ref TemporaryArray spans) + private void GetOutliningSpans(SyntaxTriviaList triviaList, ArrayBuilder spans) { foreach (var trivia in triviaList) { @@ -90,7 +90,7 @@ private void GetOutliningSpans(SyntaxTriviaList triviaList, ref TemporaryArray SearchReferenceAssemblies = new( + "dotnet_search_reference_assemblies", + SymbolSearchOptions.Default.SearchReferenceAssemblies, + isEditorConfigOption: true, + group: s_optionGroup); + + public static PerLanguageOption2 SearchNuGetPackages = new( + "dotnet_unsupported_search_nuget_packages", + SymbolSearchOptions.Default.SearchNuGetPackages, + isEditorConfigOption: true, + group: s_optionGroup); + + public static readonly ImmutableArray EditorConfigOptions = [SearchReferenceAssemblies]; + public static readonly ImmutableArray UnsupportedOptions = [SearchNuGetPackages]; +} + +internal static class SymbolSearchOptionsProviders +{ + internal static SymbolSearchOptions GetSymbolSearchOptions(this IOptionsReader options, string language) + => new() + { + SearchReferenceAssemblies = options.GetOption(SymbolSearchOptionsStorage.SearchReferenceAssemblies, language), + SearchNuGetPackages = options.GetOption(SymbolSearchOptionsStorage.SearchNuGetPackages, language) + }; + + public static async ValueTask GetSymbolSearchOptionsAsync(this Document document, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + return configOptions.GetSymbolSearchOptions(document.Project.Language); + } +} diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/IAddReferenceDatabaseWrapper.cs b/src/Features/Core/Portable/SymbolSearch/Windows/IAddReferenceDatabaseWrapper.cs index 28f752b6a0606..85cc85b9ace5d 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/IAddReferenceDatabaseWrapper.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/IAddReferenceDatabaseWrapper.cs @@ -14,7 +14,7 @@ internal interface IAddReferenceDatabaseWrapper AddReferenceDatabase Database { get; } } -internal class AddReferenceDatabaseWrapper(AddReferenceDatabase database) : IAddReferenceDatabaseWrapper +internal sealed class AddReferenceDatabaseWrapper(AddReferenceDatabase database) : IAddReferenceDatabaseWrapper { public AddReferenceDatabase Database { get; } = database; } diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DatabaseFactoryService.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DatabaseFactoryService.cs index bcedaa455c9fa..8ac528e4e1604 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DatabaseFactoryService.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DatabaseFactoryService.cs @@ -9,9 +9,9 @@ namespace Microsoft.CodeAnalysis.SymbolSearch; -internal partial class SymbolSearchUpdateEngine +internal sealed partial class SymbolSearchUpdateEngine { - private class DatabaseFactoryService : IDatabaseFactoryService + private sealed class DatabaseFactoryService : IDatabaseFactoryService { public AddReferenceDatabase CreateDatabaseFromBytes(byte[] bytes) { diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DelayService.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DelayService.cs index 7303e33a915f2..f7f27b62241df 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DelayService.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.DelayService.cs @@ -8,9 +8,9 @@ namespace Microsoft.CodeAnalysis.SymbolSearch; -internal partial class SymbolSearchUpdateEngine +internal sealed partial class SymbolSearchUpdateEngine { - private class DelayService : IDelayService + private sealed class DelayService : IDelayService { public TimeSpan CachePollDelay { get; } = TimeSpan.FromMinutes(1); public TimeSpan FileWriteDelay { get; } = TimeSpan.FromSeconds(10); diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.IOService.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.IOService.cs index 9832d22239a8b..c0c445f60d68f 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.IOService.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.IOService.cs @@ -8,9 +8,9 @@ namespace Microsoft.CodeAnalysis.SymbolSearch; -internal partial class SymbolSearchUpdateEngine +internal sealed partial class SymbolSearchUpdateEngine { - private class IOService : IIOService + private sealed class IOService : IIOService { public void Create(DirectoryInfo directory) => directory.Create(); diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.PatchService.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.PatchService.cs index 012a0daf9e320..1390a65cf5497 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.PatchService.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.PatchService.cs @@ -6,9 +6,9 @@ namespace Microsoft.CodeAnalysis.SymbolSearch; -internal partial class SymbolSearchUpdateEngine +internal sealed partial class SymbolSearchUpdateEngine { - private class PatchService : IPatchService + private sealed class PatchService : IPatchService { public byte[] ApplyPatch(byte[] databaseBytes, byte[] patchBytes) => NativePatching.ApplyPatch(databaseBytes, patchBytes); diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.Update.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.Update.cs index 8cae5c243f16f..88e9c33b6b644 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.Update.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.Update.cs @@ -29,7 +29,7 @@ namespace Microsoft.CodeAnalysis.SymbolSearch; /// This implementation also spawns a task which will attempt to keep that database up to /// date by downloading patches on a daily basis. ///
-internal partial class SymbolSearchUpdateEngine +internal sealed partial class SymbolSearchUpdateEngine { // Internal for testing purposes. internal const string ContentAttributeName = "content"; @@ -653,7 +653,7 @@ private static async Task ConvertContentAttributeAsync(XAttribute conten using (var inStream = new MemoryStream(compressedBytes)) using (var deflateStream = new DeflateStream(inStream, CompressionMode.Decompress)) { -#if NETCOREAPP +#if NET await deflateStream.CopyToAsync(outStream, cancellationToken).ConfigureAwait(false); #else await deflateStream.CopyToAsync(outStream).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.cs b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.cs index e5db69773fdd4..25ef6bf741d6d 100644 --- a/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.cs +++ b/src/Features/Core/Portable/SymbolSearch/Windows/SymbolSearchUpdateEngine.cs @@ -28,7 +28,7 @@ namespace Microsoft.CodeAnalysis.SymbolSearch; /// This implementation also spawns a task which will attempt to keep that database up to /// date by downloading patches on a daily basis. ///
-internal partial class SymbolSearchUpdateEngine : ISymbolSearchUpdateEngine +internal sealed partial class SymbolSearchUpdateEngine : ISymbolSearchUpdateEngine { private readonly ConcurrentDictionary _sourceToDatabase = []; diff --git a/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesService.cs b/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesService.cs index ecf0c6fcdbb95..6e6a68408a0d7 100644 --- a/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesService.cs +++ b/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesService.cs @@ -30,7 +30,6 @@ internal abstract class AbstractSyncNamespacesService public async Task SyncNamespacesAsync( ImmutableArray projects, - CodeActionOptionsProvider options, IProgress progressTracker, CancellationToken cancellationToken) { @@ -48,7 +47,7 @@ public async Task SyncNamespacesAsync( } var fixAllContext = await GetFixAllContextAsync( - solution, CodeFixProvider, diagnosticsByProject, options, progressTracker, cancellationToken).ConfigureAwait(false); + solution, CodeFixProvider, diagnosticsByProject, progressTracker, cancellationToken).ConfigureAwait(false); var fixAllProvider = CodeFixProvider.GetFixAllProvider(); RoslynDebug.AssertNotNull(fixAllProvider); @@ -94,7 +93,6 @@ private static async Task GetFixAllContextAsync( Solution solution, CodeFixProvider codeFixProvider, ImmutableDictionary> diagnosticsByProject, - CodeActionOptionsProvider options, IProgress progressTracker, CancellationToken cancellationToken) { @@ -114,7 +112,6 @@ private static async Task GetFixAllContextAsync( firstDiagnostic.Location.SourceSpan, [firstDiagnostic], (a, _) => action ??= a, - options, cancellationToken); await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false); @@ -128,8 +125,7 @@ private static async Task GetFixAllContextAsync( FixAllScope.Solution, codeActionEquivalenceKey: action?.EquivalenceKey!, // FixAllState supports null equivalence key. This should still be supported. diagnosticIds: codeFixProvider.FixableDiagnosticIds, - fixAllDiagnosticProvider: diagnosticProvider, - options), + fixAllDiagnosticProvider: diagnosticProvider), progressTracker, cancellationToken); } @@ -150,7 +146,7 @@ private static async Task ApplyCodeFixAsync( return applyChangesOperation.ChangedSolution; } - private class DiagnosticProvider : FixAllContext.DiagnosticProvider + private sealed class DiagnosticProvider : FixAllContext.DiagnosticProvider { private static readonly Task> EmptyDiagnosticResult = Task.FromResult(Enumerable.Empty()); diff --git a/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs b/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs index f6b694ba5d4c8..a64225f234aab 100644 --- a/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs +++ b/src/Features/Core/Portable/SyncNamespaces/ISyncNamespacesService.cs @@ -18,5 +18,5 @@ internal interface ISyncNamespacesService : ILanguageService /// and their relative folder path. ///
Task SyncNamespacesAsync( - ImmutableArray projects, CodeActionOptionsProvider options, IProgress progressTracker, CancellationToken cancellationToken); + ImmutableArray projects, IProgress progressTracker, CancellationToken cancellationToken); } diff --git a/src/Features/Core/Portable/Testing/TestFrameworks/MSTestTestFrameworkMetadata.cs b/src/Features/Core/Portable/Testing/TestFrameworks/MSTestTestFrameworkMetadata.cs index 3fcb9aa6b4eb8..71afcf9758ac2 100644 --- a/src/Features/Core/Portable/Testing/TestFrameworks/MSTestTestFrameworkMetadata.cs +++ b/src/Features/Core/Portable/Testing/TestFrameworks/MSTestTestFrameworkMetadata.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Features.Testing; [Export(typeof(ITestFrameworkMetadata)), Shared] -internal class MSTestTestFrameworkMetadata : ITestFrameworkMetadata +internal sealed class MSTestTestFrameworkMetadata : ITestFrameworkMetadata { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/Testing/TestFrameworks/NUnitTestFrameworkMetadata.cs b/src/Features/Core/Portable/Testing/TestFrameworks/NUnitTestFrameworkMetadata.cs index 6ec629390e8b5..ce402166747f7 100644 --- a/src/Features/Core/Portable/Testing/TestFrameworks/NUnitTestFrameworkMetadata.cs +++ b/src/Features/Core/Portable/Testing/TestFrameworks/NUnitTestFrameworkMetadata.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Features.Testing; [Export(typeof(ITestFrameworkMetadata)), Shared] -internal class NUnitTestFrameworkMetadata : ITestFrameworkMetadata +internal sealed class NUnitTestFrameworkMetadata : ITestFrameworkMetadata { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/Testing/TestFrameworks/XUnitTestFrameworkMetadata.cs b/src/Features/Core/Portable/Testing/TestFrameworks/XUnitTestFrameworkMetadata.cs index e2cc29ab09ddc..16c88e7c6d3a1 100644 --- a/src/Features/Core/Portable/Testing/TestFrameworks/XUnitTestFrameworkMetadata.cs +++ b/src/Features/Core/Portable/Testing/TestFrameworks/XUnitTestFrameworkMetadata.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Features.Testing; [Export(typeof(ITestFrameworkMetadata)), Shared] -internal class XUnitTestFrameworkMetadata : ITestFrameworkMetadata +internal sealed class XUnitTestFrameworkMetadata : ITestFrameworkMetadata { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs b/src/Features/Core/Portable/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs index 8201a65af9481..e5135a3abfc89 100644 --- a/src/Features/Core/Portable/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs +++ b/src/Features/Core/Portable/UnusedReferences/ProjectAssets/ProjectAssetsModel.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.UnusedReferences.ProjectAssets; // parse out the dependency tree and compilation assemblies that each reference brings // in to the project. -internal class ProjectAssetsFile +internal sealed class ProjectAssetsFile { public int Version { get; set; } public Dictionary>? Targets { get; set; } @@ -19,42 +19,42 @@ internal class ProjectAssetsFile public ProjectAssetsProject? Project { get; set; } } -internal class ProjectAssetsTargetLibrary +internal sealed class ProjectAssetsTargetLibrary { public string? Type { get; set; } public Dictionary? Dependencies { get; set; } public Dictionary? Compile { get; set; } } -internal class ProjectAssetsTargetLibraryCompile +internal sealed class ProjectAssetsTargetLibraryCompile { } -internal class ProjectAssetsLibrary +internal sealed class ProjectAssetsLibrary { public string? Path { get; set; } } -internal class ProjectAssetsProject +internal sealed class ProjectAssetsProject { public ProjectAssetsProjectRestore? Restore { get; set; } public Dictionary? Frameworks { get; set; } } -internal class ProjectAssetsProjectRestore +internal sealed class ProjectAssetsProjectRestore { public string? ProjectPath { get; set; } public string? PackagesPath { get; set; } } -internal class ProjectAssetsProjectFramework +internal sealed class ProjectAssetsProjectFramework { public string? TargetAlias { get; set; } public Dictionary? Dependencies { get; set; } } -internal class ProjectAssetsProjectFrameworkDependency +internal sealed class ProjectAssetsProjectFrameworkDependency { public bool AutoReferenced { get; set; } } diff --git a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs index c80dd7d12dc0b..6a687339f93b5 100644 --- a/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs +++ b/src/Features/Core/Portable/UnusedReferences/ReferenceInfo.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.UnusedReferences; [DataContract] -internal class ReferenceInfo(ReferenceType referenceType, string itemSpecification, bool treatAsUsed, ImmutableArray compilationAssemblies, ImmutableArray dependencies) +internal sealed class ReferenceInfo(ReferenceType referenceType, string itemSpecification, bool treatAsUsed, ImmutableArray compilationAssemblies, ImmutableArray dependencies) { /// /// Indicates the type of reference. diff --git a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs index 08bd17a7fad6e..1c8118dd50c9a 100644 --- a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs +++ b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs @@ -23,6 +23,8 @@ namespace Microsoft.CodeAnalysis.UseAutoProperty; +using static UseAutoPropertiesHelpers; + internal abstract class AbstractUseAutoPropertyCodeFixProvider : CodeFixProvider where TTypeDeclarationSyntax : SyntaxNode where TPropertyDeclaration : SyntaxNode @@ -39,12 +41,23 @@ public sealed override ImmutableArray FixableDiagnosticIds protected abstract TPropertyDeclaration GetPropertyDeclaration(SyntaxNode node); protected abstract SyntaxNode GetNodeToRemove(TVariableDeclarator declarator); + protected abstract TPropertyDeclaration RewriteFieldReferencesInProperty( + TPropertyDeclaration property, LightweightRenameLocations fieldLocations, CancellationToken cancellationToken); - protected abstract ImmutableArray GetFormattingRules(Document document); + protected abstract ImmutableArray GetFormattingRules( + Document document, SyntaxNode finalPropertyDeclaration); protected abstract Task UpdatePropertyAsync( - Document propertyDocument, Compilation compilation, IFieldSymbol fieldSymbol, IPropertySymbol propertySymbol, - TPropertyDeclaration propertyDeclaration, bool isWrittenOutsideConstructor, CancellationToken cancellationToken); + Document propertyDocument, + Compilation compilation, + IFieldSymbol fieldSymbol, + IPropertySymbol propertySymbol, + TVariableDeclarator fieldDeclarator, + TPropertyDeclaration propertyDeclaration, + bool isWrittenOutsideConstructor, + bool isTrivialGetAccessor, + bool isTrivialSetAccessor, + CancellationToken cancellationToken); public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { @@ -56,7 +69,7 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) context.RegisterCodeFix(CodeAction.SolutionChangeAction.Create( AnalyzersResources.Use_auto_property, - c => ProcessResultAsync(context, diagnostic, c), + cancellationToken => ProcessResultAsync(context, diagnostic, cancellationToken), equivalenceKey: nameof(AnalyzersResources.Use_auto_property), priority), diagnostic); @@ -68,6 +81,7 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) private async Task ProcessResultAsync(CodeFixContext context, Diagnostic diagnostic, CancellationToken cancellationToken) { var locations = diagnostic.AdditionalLocations; + var propertyLocation = locations[0]; var declaratorLocation = locations[1]; @@ -82,6 +96,9 @@ private async Task ProcessResultAsync(CodeFixContext context, Diagnost var propertySemanticModel = await propertyDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var propertySymbol = (IPropertySymbol)propertySemanticModel.GetRequiredDeclaredSymbol(property, cancellationToken); + var isTrivialGetAccessor = diagnostic.Properties.ContainsKey(IsTrivialGetAccessor); + var isTrivialSetAccessor = diagnostic.Properties.ContainsKey(IsTrivialSetAccessor); + Debug.Assert(fieldDocument.Project == propertyDocument.Project); var project = fieldDocument.Project; var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); @@ -92,10 +109,23 @@ private async Task ProcessResultAsync(CodeFixContext context, Diagnost solution, fieldSymbol, renameOptions, cancellationToken).ConfigureAwait(false); // First, create the updated property we want to replace the old property with - var isWrittenToOutsideOfConstructor = IsWrittenToOutsideOfConstructorOrProperty(fieldSymbol, fieldLocations, property, cancellationToken); + var isWrittenToOutsideOfConstructor = IsWrittenToOutsideOfConstructorOrProperty( + fieldSymbol, fieldLocations, property, cancellationToken); + + if (!isTrivialGetAccessor || + (propertySymbol.SetMethod != null && !isTrivialSetAccessor)) + { + // We have at least a non-trivial getter/setter. Those will not be rewritten to `get;/set;`. As such, we + // need to update the property to reference `field` or itself instead of the actual field. + property = RewriteFieldReferencesInProperty(property, fieldLocations, cancellationToken); + } + var updatedProperty = await UpdatePropertyAsync( - propertyDocument, compilation, fieldSymbol, propertySymbol, property, - isWrittenToOutsideOfConstructor, cancellationToken).ConfigureAwait(false); + propertyDocument, compilation, + fieldSymbol, propertySymbol, + declarator, property, + isWrittenToOutsideOfConstructor, isTrivialGetAccessor, isTrivialSetAccessor, + cancellationToken).ConfigureAwait(false); // Note: rename will try to update all the references in linked files as well. However, // this can lead to some very bad behavior as we will change the references in linked files @@ -211,7 +241,7 @@ private async Task ProcessResultAsync(CodeFixContext context, Diagnost editor.RemoveNode(nodeToRemove, syntaxRemoveOptions); var newRoot = editor.GetChangedRoot(); - newRoot = await FormatAsync(newRoot, fieldDocument, cancellationToken).ConfigureAwait(false); + newRoot = await FormatAsync(newRoot, fieldDocument, updatedProperty, cancellationToken).ConfigureAwait(false); return solution.WithDocumentSyntaxRoot(fieldDocument.Id, newRoot); } @@ -225,8 +255,8 @@ private async Task ProcessResultAsync(CodeFixContext context, Diagnost Contract.ThrowIfNull(newFieldTreeRoot); var newPropertyTreeRoot = propertyTreeRoot.ReplaceNode(property, updatedProperty); - newFieldTreeRoot = await FormatAsync(newFieldTreeRoot, fieldDocument, cancellationToken).ConfigureAwait(false); - newPropertyTreeRoot = await FormatAsync(newPropertyTreeRoot, propertyDocument, cancellationToken).ConfigureAwait(false); + newFieldTreeRoot = await FormatAsync(newFieldTreeRoot, fieldDocument, updatedProperty, cancellationToken).ConfigureAwait(false); + newPropertyTreeRoot = await FormatAsync(newPropertyTreeRoot, propertyDocument, updatedProperty, cancellationToken).ConfigureAwait(false); var updatedSolution = solution.WithDocumentSyntaxRoot(fieldDocument.Id, newFieldTreeRoot); updatedSolution = updatedSolution.WithDocumentSyntaxRoot(propertyDocument.Id, newPropertyTreeRoot); @@ -277,9 +307,13 @@ private static bool CanEditDocument( return canEditDocument; } - private async Task FormatAsync(SyntaxNode newRoot, Document document, CancellationToken cancellationToken) + private async Task FormatAsync( + SyntaxNode newRoot, + Document document, + SyntaxNode finalPropertyDeclaration, + CancellationToken cancellationToken) { - var formattingRules = GetFormattingRules(document); + var formattingRules = GetFormattingRules(document, finalPropertyDeclaration); if (formattingRules.IsDefault) return newRoot; diff --git a/src/Features/Core/Portable/ValueTracking/ValueTrackedItem.cs b/src/Features/Core/Portable/ValueTracking/ValueTrackedItem.cs index 3440d3992caea..50eaca6dbf26a 100644 --- a/src/Features/Core/Portable/ValueTracking/ValueTrackedItem.cs +++ b/src/Features/Core/Portable/ValueTracking/ValueTrackedItem.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.ValueTracking; -internal class ValueTrackedItem +internal sealed class ValueTrackedItem { public SymbolKey SymbolKey { get; } public ValueTrackedItem? Parent { get; } diff --git a/src/Features/Core/Portable/ValueTracking/ValueTracker.FindReferencesProgress.cs b/src/Features/Core/Portable/ValueTracking/ValueTracker.FindReferencesProgress.cs index 0387a4b37414c..9345417dad381 100644 --- a/src/Features/Core/Portable/ValueTracking/ValueTracker.FindReferencesProgress.cs +++ b/src/Features/Core/Portable/ValueTracking/ValueTracker.FindReferencesProgress.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.ValueTracking; internal static partial class ValueTracker { - private class FindReferencesProgress(OperationCollector valueTrackingProgressCollector) : IStreamingFindReferencesProgress, IStreamingProgressTracker + private sealed class FindReferencesProgress(OperationCollector valueTrackingProgressCollector) : IStreamingFindReferencesProgress, IStreamingProgressTracker { private readonly OperationCollector _operationCollector = valueTrackingProgressCollector; diff --git a/src/Features/Core/Portable/ValueTracking/ValueTracker.OperationCollector.cs b/src/Features/Core/Portable/ValueTracking/ValueTracker.OperationCollector.cs index a62f976c6c69b..b3be53ca8a5e4 100644 --- a/src/Features/Core/Portable/ValueTracking/ValueTracker.OperationCollector.cs +++ b/src/Features/Core/Portable/ValueTracking/ValueTracker.OperationCollector.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.ValueTracking; internal static partial class ValueTracker { - private class OperationCollector(ValueTrackingProgressCollector progressCollector, Solution solution) + private sealed class OperationCollector(ValueTrackingProgressCollector progressCollector, Solution solution) { public ValueTrackingProgressCollector ProgressCollector { get; } = progressCollector; public Solution Solution { get; } = solution; diff --git a/src/Features/Core/Portable/ValueTracking/ValueTrackingProgressCollector.cs b/src/Features/Core/Portable/ValueTracking/ValueTrackingProgressCollector.cs index 36cc24bc78513..2d33720225623 100644 --- a/src/Features/Core/Portable/ValueTracking/ValueTrackingProgressCollector.cs +++ b/src/Features/Core/Portable/ValueTracking/ValueTrackingProgressCollector.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.ValueTracking; -internal class ValueTrackingProgressCollector : IProgress +internal sealed class ValueTrackingProgressCollector : IProgress { private readonly object _lock = new(); private readonly Stack _items = new(); diff --git a/src/Features/Core/Portable/ValueTracking/ValueTrackingService.cs b/src/Features/Core/Portable/ValueTracking/ValueTrackingService.cs index 7649c38f797d4..cbe5e42d44d9b 100644 --- a/src/Features/Core/Portable/ValueTracking/ValueTrackingService.cs +++ b/src/Features/Core/Portable/ValueTracking/ValueTrackingService.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.ValueTracking; [ExportWorkspaceService(typeof(IValueTrackingService)), Shared] -internal partial class ValueTrackingService : IValueTrackingService +internal sealed partial class ValueTrackingService : IValueTrackingService { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs b/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs index 1c2f021c4dcaa..b7f4fc33ddcc3 100644 --- a/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs +++ b/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs @@ -55,7 +55,7 @@ public Factory() /// /// Cached compile-time solution corresponding to an existing design-time solution. /// -#if NETCOREAPP +#if NET private readonly ConditionalWeakTable _designTimeToCompileTimeSolution = []; #else private ConditionalWeakTable _designTimeToCompileTimeSolution = new(); @@ -71,7 +71,7 @@ public CompileTimeSolutionProvider(Workspace workspace) { lock (_gate) { -#if NETCOREAPP +#if NET _designTimeToCompileTimeSolution.Clear(); #else _designTimeToCompileTimeSolution = new(); diff --git a/src/Features/Core/Portable/Workspace/MiscellaneousFileUtilities.cs b/src/Features/Core/Portable/Workspace/MiscellaneousFileUtilities.cs index d75b527b6da24..ae6b395c8da0a 100644 --- a/src/Features/Core/Portable/Workspace/MiscellaneousFileUtilities.cs +++ b/src/Features/Core/Portable/Workspace/MiscellaneousFileUtilities.cs @@ -101,7 +101,7 @@ private static CompilationOptions GetCompilationOptionsWithScriptReferenceResolv } } -internal class LanguageInformation(string languageName, string scriptExtension) +internal sealed class LanguageInformation(string languageName, string scriptExtension) { public string LanguageName { get; } = languageName; public string ScriptExtension { get; } = scriptExtension; diff --git a/src/Features/Core/Portable/Wrapping/BinaryExpression/BinaryExpressionCodeActionComputer.cs b/src/Features/Core/Portable/Wrapping/BinaryExpression/BinaryExpressionCodeActionComputer.cs index 34d657cdc1884..c489f4e9e46e7 100644 --- a/src/Features/Core/Portable/Wrapping/BinaryExpression/BinaryExpressionCodeActionComputer.cs +++ b/src/Features/Core/Portable/Wrapping/BinaryExpression/BinaryExpressionCodeActionComputer.cs @@ -16,9 +16,9 @@ namespace Microsoft.CodeAnalysis.Wrapping.BinaryExpression; -internal partial class AbstractBinaryExpressionWrapper +internal abstract partial class AbstractBinaryExpressionWrapper { - private class BinaryExpressionCodeActionComputer : + private sealed class BinaryExpressionCodeActionComputer : AbstractCodeActionComputer> { private readonly ImmutableArray _exprsAndOperators; diff --git a/src/Features/Core/Portable/Wrapping/ChainedExpression/ChainedExpressionCodeActionComputer.cs b/src/Features/Core/Portable/Wrapping/ChainedExpression/ChainedExpressionCodeActionComputer.cs index f060dede4bab5..69e99583a0b64 100644 --- a/src/Features/Core/Portable/Wrapping/ChainedExpression/ChainedExpressionCodeActionComputer.cs +++ b/src/Features/Core/Portable/Wrapping/ChainedExpression/ChainedExpressionCodeActionComputer.cs @@ -35,7 +35,7 @@ internal abstract partial class AbstractChainedExpressionWrapper< /// if wrap-long produces the same results as wrap-each, then the caller will /// filter it out. /// - private class CallExpressionCodeActionComputer : + private sealed class CallExpressionCodeActionComputer : AbstractCodeActionComputer> { /// diff --git a/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs b/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs index 870885fd73295..5fa29164d5cca 100644 --- a/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs +++ b/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs @@ -83,7 +83,7 @@ public static ImmutableArray SortByMostRecentlyUsed( private static string GetSortTitle(CodeAction codeAction) => (codeAction as WrapItemsAction)?.SortTitle ?? codeAction.Title; - private class RecordCodeActionOperation(string sortTitle, string parentTitle) : CodeActionOperation + private sealed class RecordCodeActionOperation(string sortTitle, string parentTitle) : CodeActionOperation { private readonly string _sortTitle = sortTitle; private readonly string _parentTitle = parentTitle; diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index 80b2136a163bb..7e1015fd27637 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -85,16 +85,6 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Přidání {0} kolem aktivního příkazu vyžaduje restartování aplikace. - - Adding {0} into a {1} requires restarting the application. - Přidání {0} do {1} vyžaduje restartování aplikace. - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - Přidání {0} do třídy s explicitním nebo sekvenčním rozložením vyžaduje restartování aplikace. - - Adding {0} into an interface method requires restarting the application. Přidání {0} do metody rozhraní vyžaduje restartování aplikace. @@ -155,6 +145,21 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Přidání importované metody vyžaduje restartování aplikace. + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments Zarovnat zalomené argumenty @@ -315,11 +320,6 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Očekávaná úloha nevrací žádnou hodnotu. - - Base classes contain inaccessible unimplemented members - Základní třídy obsahují nepřístupné nenaimplementované členy. - - Built-in Copilot analysis Integrovaná analýza Copilot @@ -665,11 +665,6 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Zavřít - - Do not change this code. Put cleanup code in '{0}' method - Neměňte tento kód. Kód pro vyčištění vložte do metody {0}. - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. Aktuální obsah zdrojového souboru {0} se neshoduje se sestaveným zdrojem. Případné změny provedené v tomto souboru během ladění se nepoužijí, dokud se jeho obsah nebude shodovat se sestaveným zdrojem. @@ -830,81 +825,16 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Našlo se jedno sestavení: {0} - - Generate abstract method '{0}' - Generovat abstraktní metodu {0} - - - - Generate abstract property '{0}' - Generovat abstraktní vlastnost {0} - - Generate comparison operators Vygenerovat operátory porovnání - - Generate constant '{0}' - Generovat konstantu {0} - - - - Generate constructor in '{0}' (with fields) - Vygenerovat konstruktor v {0} (s poli) - - - - Generate constructor in '{0}' (with properties) - Vygenerovat konstruktor v {0} (s vlastnostmi) - - - - Generate enum member '{0}' - Generovat člena výčtu {0} - - - - Generate field '{0}' - Generovat pole {0} - - Generate for '{0}' Vygenerovat pro {0} - - Generate method '{0}' - Generovat metodu {0} - - - - Generate parameter '{0}' - Generovat parametr {0} - - - - Generate parameter '{0}' (and overrides/implementations) - Generovat parametr {0} (a přepsání/implementace) - - - - Generate property '{0}' - Generovat vlastnost {0} - - - - Generate read-only field '{0}' - Generovat pole {0} jen pro čtení - - - - Generate read-only property '{0}' - Generovat vlastnost {0} jen pro čtení - - Illegal \ at end of pattern Znak \ na konci vzorku je neplatný. @@ -935,11 +865,6 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Implementovat rozhraní {0} implicitně - - Implement abstract class - Implementovat abstraktní třídu - - Implement all interfaces explicitly Implementovat všechna rozhraní explicitně @@ -950,11 +875,6 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Implementovat všechna rozhraní implicitně - - Implement all members explicitly - Implementovat všechny členy explicitně - - Implement explicitly Implementovat explicitně @@ -965,16 +885,6 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Implementovat implicitně - - Implement remaining members explicitly - Implementovat zbývající členy explicitně - - - - Implement through '{0}' - Implementovat přes {0} - - Incomplete \p{X} character escape Neúplné uvození znaků \p{X} @@ -1287,7 +1197,7 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn .NET Code Actions - .NET Code Actions + Akce kódu .NET @@ -2725,6 +2635,11 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv V cestě sestavení {0} byl nalezen symbol. + + Symbol search + Hledání symbolů + + Symbols Symboly @@ -2735,16 +2650,6 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Chyba syntaxe - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: Uvolněte nespravované prostředky (nespravované objekty) a přepište finalizační metodu. - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: Finalizační metodu přepište, jen pokud metoda {0} obsahuje kód pro uvolnění nespravovaných prostředků. - - Target type matches Shody cílového typu @@ -2810,11 +2715,6 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Čárka na konci není povolená - - Type members - Type members - - Types: Typy: @@ -3025,6 +2925,11 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Aktualizace velikosti {0} vyžaduje restartování aplikace. + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + Aktualizace typu {0} (z {1} na {2}) kolem aktivního příkazu vyžaduje restartování aplikace. + + Updating the type of {0} requires restarting the application. Aktualizace typu {0} vyžaduje restartování aplikace. @@ -3920,16 +3825,6 @@ Pokud se specifikátor formátu M použije bez dalších specifikátorů vlastn Generovat delegující konstruktor {0}({1}) - - Generate constructor '{0}({1})' - Generovat konstruktor {0}({1}) - - - - Generate field assigning constructor '{0}({1})' - Generovat konstruktor přiřazující pole {0}({1}) - - Generate Equals and GetHashCode Generovat Equals a GetHashCode @@ -3945,21 +3840,6 @@ Pokud se specifikátor formátu M použije bez dalších specifikátorů vlastn Generovat GetHashCode() - - Generate constructor in '{0}' - Generovat konstruktor v: {0} - - - - Generate all - Generovat všechno - - - - Generate local '{0}' - Generovat místní: {0} - - Generate {0} '{1}' in new file Generovat {0} {1} v novém souboru @@ -3970,21 +3850,6 @@ Pokud se specifikátor formátu M použije bez dalších specifikátorů vlastn Generovat vnořené {0} {1} - - Implement interface abstractly - Implementovat rozhraní abstraktně - - - - Implement interface through '{0}' - Implementovat rozhraní přes {0} - - - - Implement interface - Implementujte rozhraní. - - Introduce field for '{0}' Zavést pole pro {0} @@ -4265,16 +4130,6 @@ Chcete pokračovat? Poznámka: Pro vložení fragmentu {0} stiskněte dvakrát tabulátor. - - Implement interface explicitly with Dispose pattern - Implementovat rozhraní explicitně se vzorem Dispose - - - - Implement interface with Dispose pattern - Implementovat rozhraní se vzorem Dispose - - Computing fix all occurrences code fix... Vypočítává se oprava kódu pro opravu všech výskytů... @@ -4300,16 +4155,6 @@ Chcete pokračovat? Řešení - - TODO: dispose managed state (managed objects) - TODO: Uvolněte spravovaný stav (spravované objekty). - - - - TODO: set large fields to null - TODO: Nastavte velká pole na hodnotu null. - - Compiler Kompilátor @@ -4660,11 +4505,6 @@ Tato verze se používá zde: {2}. Nainstalovat verzi {0} - - Generate variable '{0}' - Generovat proměnnou {0} - - Classes Třídy diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index 3e9ed612bd629..1ed73b6c96936 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -85,16 +85,6 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Das Hinzufügen von {0} um eine aktive Anweisung erfordert einen Neustart der Anwendung. - - Adding {0} into a {1} requires restarting the application. - Das Hinzufügen von {0} zu einer {1} erfordert einen Neustart der Anwendung. - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - Das Hinzufügen von {0} zu einer Klasse mit explizitem oder sequenziellem Layout erfordert einen Neustart der Anwendung. - - Adding {0} into an interface method requires restarting the application. Das Hinzufügen von {0} zu einer Schnittstellenmethode erfordert einen Neustart der Anwendung. @@ -155,6 +145,21 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Das Hinzufügen einer importierten Methode erfordert einen Neustart der Anwendung. + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments Umschlossene Argumente ausrichten @@ -315,11 +320,6 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Erwartete Aufgabe gibt keinen Wert zurück - - Base classes contain inaccessible unimplemented members - Basisklassen enthalten nicht implementierte Member, auf die nicht zugegriffen werden kann. - - Built-in Copilot analysis Integrierte Copilot-Analyse @@ -665,11 +665,6 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Schließen - - Do not change this code. Put cleanup code in '{0}' method - Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "{0}" ein. - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. Der aktuelle Inhalt der Quelldatei "{0}" stimmt nicht mit dem kompilierten Quellcode überein. Alle Änderungen, die während des Debuggens an dieser Datei vorgenommen wurden, werden erst angewendet, wenn der Inhalt dem kompilierten Quellcode entspricht. @@ -830,81 +825,16 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Einzelne Assembly gefunden: {0} - - Generate abstract method '{0}' - Abstrakte Methode „{0}“ generieren - - - - Generate abstract property '{0}' - Abstrakte Eigenschaft „{0}X generieren - - Generate comparison operators Vergleichsoperatoren generieren - - Generate constant '{0}' - Konstante „{0}“ generieren - - - - Generate constructor in '{0}' (with fields) - Konstruktor in "{0}" (mit Feldern) generieren - - - - Generate constructor in '{0}' (with properties) - Konstruktor in "{0}" (mit Eigenschaften) generieren - - - - Generate enum member '{0}' - Aufzählungselement „{0}“ generieren - - - - Generate field '{0}' - Feld „{0}“ generieren - - Generate for '{0}' Für "{0}" generieren - - Generate method '{0}' - Methode „{0}“ generieren - - - - Generate parameter '{0}' - Parameter "{0}" generieren - - - - Generate parameter '{0}' (and overrides/implementations) - Parameter "{0}" (und Außerkraftsetzungen/Implementierungen) generieren - - - - Generate property '{0}' - Eigenschaft „{0}“ generieren - - - - Generate read-only field '{0}' - Schreibgeschütztes Feld „{0}“ generieren - - - - Generate read-only property '{0}' - Schreibgeschützte Eigenschaft „{0}“ generieren - - Illegal \ at end of pattern Nicht zulässiges \-Zeichen am Ende des Musters. @@ -935,11 +865,6 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d "{0}" implizit implementieren - - Implement abstract class - Abstrakte Klasse implementieren - - Implement all interfaces explicitly Alle Schnittstellen explizit implementieren @@ -950,11 +875,6 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Alle Schnittstellen implizit implementieren - - Implement all members explicitly - Alle Member explizit implementieren - - Implement explicitly Explizit implementieren @@ -965,16 +885,6 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Implizit implementieren - - Implement remaining members explicitly - Verbleibende Member explizit implementieren - - - - Implement through '{0}' - Über "{0}" implementieren - - Incomplete \p{X} character escape Unvollständiges \p{X}-Escapezeichen. @@ -1287,7 +1197,7 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d .NET Code Actions - .NET Code Actions + .NET Codeaktionen @@ -2725,6 +2635,11 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Das Symbol wurde unter dem Assemblypfad „{0}“ gefunden + + Symbol search + Symbolsuche + + Symbols Symbole @@ -2735,16 +2650,6 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Syntaxfehler - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalizer überschreiben - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: Finalizer nur überschreiben, wenn "{0}" Code für die Freigabe nicht verwalteter Ressourcen enthält - - Target type matches Übereinstimmungen mit Zieltyp @@ -2810,11 +2715,6 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Ein nachgestelltes Komma ist unzulässig - - Type members - Type members - - Types: Typen: @@ -3025,6 +2925,11 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Das Aktualisieren der Größe einer {0} erfordert einen Neustart der Anwendung. + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + Das Aktualisieren des Typs von {0} (von „{1}“ auf „{2}“) um eine aktive Anweisung erfordert einen Neustart der Anwendung. + + Updating the type of {0} requires restarting the application. Das Aktualisieren des Typs von {0} erfordert einen Neustart der Anwendung. @@ -3920,16 +3825,6 @@ Bei Verwendung des Formatbezeichners "M" ohne weitere benutzerdefinierte Formatb Delegierenden Konstruktor "{0}({1})" generieren - - Generate constructor '{0}({1})' - Konstruktor "{0}({1})" generieren - - - - Generate field assigning constructor '{0}({1})' - Feldzuweisungskonstruktor "{0}({1})" generieren - - Generate Equals and GetHashCode "Equals" und "GetHashCode" generieren @@ -3945,21 +3840,6 @@ Bei Verwendung des Formatbezeichners "M" ohne weitere benutzerdefinierte Formatb "GetHashCode()" generieren - - Generate constructor in '{0}' - Konstruktor in "{0}" generieren - - - - Generate all - Alle generieren - - - - Generate local '{0}' - Lokales "{0}" generieren - - Generate {0} '{1}' in new file {0}-Objekt "{1}" in neuer Datei generieren @@ -3970,21 +3850,6 @@ Bei Verwendung des Formatbezeichners "M" ohne weitere benutzerdefinierte Formatb Geschachteltes {0}-Objekt "{1}" generieren - - Implement interface abstractly - Schnittstelle abstrakt implementieren - - - - Implement interface through '{0}' - Schnittstelle über "{0}" implementieren - - - - Implement interface - Schnittstelle implementieren - - Introduce field for '{0}' Feld für "{0}" bereitstellen @@ -4265,16 +4130,6 @@ Möchten Sie fortfahren? Hinweis: Drücken Sie zweimal die TAB-TASTE, um den Schnipsel "{0}" einzufügen. - - Implement interface explicitly with Dispose pattern - Schnittstelle explizit mit Dispose-Muster implementieren - - - - Implement interface with Dispose pattern - Schnittstelle mit Dispose-Muster implementieren - - Computing fix all occurrences code fix... Berechnen der Codefehlerbehebung für alle Vorkommen... @@ -4300,16 +4155,6 @@ Möchten Sie fortfahren? Projektmappe - - TODO: dispose managed state (managed objects) - TODO: Verwalteten Zustand (verwaltete Objekte) bereinigen - - - - TODO: set large fields to null - TODO: Große Felder auf NULL setzen - - Compiler Compiler @@ -4660,11 +4505,6 @@ Diese Version wird verwendet in: {2} Version "{0}" installieren - - Generate variable '{0}' - Variable "{0}" generieren - - Classes Klassen diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index 076317affdb1a..b9286ae1a3c91 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -85,16 +85,6 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Para agregar {0} alrededor de una instrucción de acción es necesario reiniciar la aplicación. - - Adding {0} into a {1} requires restarting the application. - Para agregar {0} a un {1} es necesario reiniciar la aplicación. - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - Para agregar {0} en una clase con un diseño secuencial o explícito es necesario reiniciar la aplicación. - - Adding {0} into an interface method requires restarting the application. Para agregar {0} en un método de interfaz es necesario reiniciar la aplicación. @@ -155,6 +145,21 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Para agregar un método importado es necesario reiniciar la aplicación. + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments Alinear argumentos ajustados @@ -315,11 +320,6 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa La tarea esperada no devuelve ningún valor. - - Base classes contain inaccessible unimplemented members - Las clases base contienen miembros no implementados que son inaccesibles. - - Built-in Copilot analysis Análisis integrado de Copilot @@ -665,11 +665,6 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Descartar - - Do not change this code. Put cleanup code in '{0}' method - No cambie este código. Coloque el código de limpieza en el método "{0}". - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. El contenido actual del archivo de código fuente "{0}" no coincide con el del código fuente compilado, así que los cambios realizados en este archivo durante la depuración no se aplicarán hasta que coincida. @@ -830,81 +825,16 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Se encontró un solo ensamblado: "{0}" - - Generate abstract method '{0}' - Generar método abstracto "{0}" - - - - Generate abstract property '{0}' - Generar propiedad abstracta "{0}" - - Generate comparison operators Generar operadores de comparación - - Generate constant '{0}' - Generar constante "{0}" - - - - Generate constructor in '{0}' (with fields) - Generar un constructor en "{0}" (con campos) - - - - Generate constructor in '{0}' (with properties) - Generar un constructor en "{0}" (con propiedades) - - - - Generate enum member '{0}' - Generar miembro de enumeración "{0}" - - - - Generate field '{0}' - Generar campo "{0}" - - Generate for '{0}' Generar para "{0}" - - Generate method '{0}' - Generar método "{0}" - - - - Generate parameter '{0}' - Generar el parámetro "{0}" - - - - Generate parameter '{0}' (and overrides/implementations) - Generar el parámetro "{0}" (y reemplazos/implementaciones) - - - - Generate property '{0}' - Generar propiedad "{0}" - - - - Generate read-only field '{0}' - Generar un campo de sólo lectura "{0}" - - - - Generate read-only property '{0}' - Generar propiedad de solo lectura "{0}" - - Illegal \ at end of pattern \ no válido al final del modelo @@ -935,11 +865,6 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Implementar "{0}" de forma implícita - - Implement abstract class - Implementar clase abstracta - - Implement all interfaces explicitly Implementar todas las interfaces de forma explícita @@ -950,11 +875,6 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Implementar todas las interfaces de forma implícita - - Implement all members explicitly - Implementar todos los miembros de forma explícita - - Implement explicitly Implementar de forma explícita @@ -965,16 +885,6 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Implementar de forma implícita - - Implement remaining members explicitly - Implementar los miembros restantes de forma explícita - - - - Implement through '{0}' - Implementar a través de "{0}" - - Incomplete \p{X} character escape Escape de carácter incompleto \p{X} @@ -1287,7 +1197,7 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa .NET Code Actions - .NET Code Actions + Acciones de código de .NET @@ -2725,6 +2635,11 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Símbolo encontrado en la ruta de acceso del ensamblado '{0}' + + Symbol search + Búsqueda de símbolos + + Symbols Símbolos @@ -2735,16 +2650,6 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Error de sintaxis - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: liberar los recursos no administrados (objetos no administrados) y reemplazar el finalizador - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: reemplazar el finalizador solo si "{0}" tiene código para liberar los recursos no administrados - - Target type matches El tipo de destino coincide con @@ -2810,11 +2715,6 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Coma final no permitida - - Type members - Type members - - Types: Tipos: @@ -3025,6 +2925,11 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Para actualizar el tamaño de un {0} es necesario reiniciar la aplicación. + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + Actualizar el tipo de {0} (de "{1}" a "{2}") alrededor de una instrucción activa requiere reiniciar la aplicación. + + Updating the type of {0} requires restarting the application. Para actualizar el tipo de {0} es necesario reiniciar la aplicación. @@ -3920,16 +3825,6 @@ Si el especificador de formato "M" se usa sin otros especificadores de formato p Generar el constructor delegado '{0}({1})' - - Generate constructor '{0}({1})' - Generar el constructor '{0}({1})' - - - - Generate field assigning constructor '{0}({1})' - Generar campo asignando constructor '{0}({1})' - - Generate Equals and GetHashCode Generar Equals y GetHashCode @@ -3945,21 +3840,6 @@ Si el especificador de formato "M" se usa sin otros especificadores de formato p Generar "GetHashCode()" - - Generate constructor in '{0}' - Generar constructor en '{0}' - - - - Generate all - Generar todo - - - - Generate local '{0}' - Generar la variable local '{0}' - - Generate {0} '{1}' in new file Generar {0} '{1}' en archivo nuevo @@ -3970,21 +3850,6 @@ Si el especificador de formato "M" se usa sin otros especificadores de formato p Generar {0} anidado '{1}' - - Implement interface abstractly - Implementar interfaz de forma abstracta - - - - Implement interface through '{0}' - Implementar interfaz a través de '{0}' - - - - Implement interface - Implementar interfaz - - Introduce field for '{0}' Introducir el campo de '{0}' @@ -4265,16 +4130,6 @@ Do you want to continue? Nota: Presione dos veces la tecla Tab para insertar el fragmento de código '{0}'. - - Implement interface explicitly with Dispose pattern - Implementar la interfaz de forma explícita con el patrón de Dispose - - - - Implement interface with Dispose pattern - Implementar la interfaz con el patrón de Dispose - - Computing fix all occurrences code fix... Calculando corrección de todas las repeticiones de corrección de código... @@ -4300,16 +4155,6 @@ Do you want to continue? Solución - - TODO: dispose managed state (managed objects) - TODO: eliminar el estado administrado (objetos administrados) - - - - TODO: set large fields to null - TODO: establecer los campos grandes como NULL - - Compiler Compilador @@ -4660,11 +4505,6 @@ Esta versión se utiliza en: {2} Instalar la versión '{0}' - - Generate variable '{0}' - Generar variable '{0}' - - Classes Clases diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index 63d7c23de2a9d..23e9ffd7d1948 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -85,16 +85,6 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai L’ajout de {0} autour d’une instruction active requiert le redémarrage de l’application. - - Adding {0} into a {1} requires restarting the application. - L’ajout de {0} dans un {1} requiert le redémarrage de l’application. - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - L’ajout de {0} dans une classe avec une disposition explicite ou séquentielle requiert le redémarrage de l’application. - - Adding {0} into an interface method requires restarting the application. L’ajout de {0} dans une méthode d’interface requiert le redémarrage de l’application. @@ -155,6 +145,21 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai L’ajout d’une méthode importée requiert le redémarrage de l’application. + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments Aligner les arguments enveloppés @@ -315,11 +320,6 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai La tâche attendue ne retourne aucune valeur - - Base classes contain inaccessible unimplemented members - Les classes de base contiennent des membres non implémentés inaccessibles - - Built-in Copilot analysis Analyse Copilot intégrée @@ -665,11 +665,6 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Ignorer - - Do not change this code. Put cleanup code in '{0}' method - Ne changez pas ce code. Placez le code de nettoyage dans la méthode '{0}' - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. Le contenu actuel du fichier source '{0}' ne correspond pas à la source générée. Les changements apportés à ce fichier durant le débogage ne seront pas appliqués tant que son contenu ne correspondra pas à la source générée. @@ -830,81 +825,16 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Un seul assembly trouvé : '{0}' - - Generate abstract method '{0}' - Générer la méthode abstraite '{0}' - - - - Generate abstract property '{0}' - Générer la propriété abstraite '{0}' - - Generate comparison operators Générer des opérateurs de comparaison - - Generate constant '{0}' - Générer une constante '{0}' - - - - Generate constructor in '{0}' (with fields) - Générer le constructeur dans '{0}' (avec les champs) - - - - Generate constructor in '{0}' (with properties) - Générer le constructeur dans '{0}' (avec les propriétés) - - - - Generate enum member '{0}' - Générer le membre enum '{0}' - - - - Generate field '{0}' - Générer le champ '{0}' - - Generate for '{0}' Générer pour '{0}' - - Generate method '{0}' - Générer la méthode '{0}' - - - - Generate parameter '{0}' - Générer le paramètre '{0}' - - - - Generate parameter '{0}' (and overrides/implementations) - Générer le paramètre '{0}' (et les substitutions/implémentations) - - - - Generate property '{0}' - Générer la propriété '{0}' - - - - Generate read-only field '{0}' - Générer le champ en lecture seule '{0}' - - - - Generate read-only property '{0}' - Générer la propriété en lecture seule '{0}' - - Illegal \ at end of pattern Caractère \ non autorisé à la fin du modèle @@ -935,11 +865,6 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Implémenter '{0}' implicitement - - Implement abstract class - Implémenter une classe abstraite - - Implement all interfaces explicitly Implémenter toutes les interfaces explicitement @@ -950,11 +875,6 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Implémenter toutes les interfaces implicitement - - Implement all members explicitly - Implémenter tous les membres explicitement - - Implement explicitly Implémenter explicitement @@ -965,16 +885,6 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Implémenter implicitement - - Implement remaining members explicitly - Implémenter les membres restants explicitement - - - - Implement through '{0}' - Implémenter via '{0}' - - Incomplete \p{X} character escape Caractère d'échappement \p{X} incomplet @@ -1287,7 +1197,7 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai .NET Code Actions - .NET Code Actions + Actions du code .NET @@ -2725,6 +2635,11 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Symbole trouvé dans le chemin d’accès de l’assembly '{0}' + + Symbol search + Recherche de symbole + + Symbols Symboles @@ -2735,16 +2650,6 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Erreur de syntaxe - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: libérer les ressources non managées (objets non managés) et substituer le finaliseur - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: substituer le finaliseur uniquement si '{0}' a du code pour libérer les ressources non managées - - Target type matches Cibler les correspondances de types @@ -2810,11 +2715,6 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Virgule de fin non autorisée - - Type members - Type members - - Types: Types : @@ -3025,6 +2925,11 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée La mise à jour de la taille d’un {0} requiert le redémarrage de l’application. + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + La mise à jour du type de {0} (de '{1}' à '{2}') autour d'une instruction active nécessite le redémarrage de l'application. + + Updating the type of {0} requires restarting the application. La mise à jour du type de {0} requiert le redémarrage de l’application. @@ -3920,16 +3825,6 @@ Si le spécificateur de format "M" est utilisé sans autres spécificateurs de f Générer le constructeur de délégation '{0}({1})' - - Generate constructor '{0}({1})' - Générer le constructeur '{0}({1})' - - - - Generate field assigning constructor '{0}({1})' - Générer un constructeur d'assignation de champ '{0}({1})' - - Generate Equals and GetHashCode Générer Equals et GetHashCode @@ -3945,21 +3840,6 @@ Si le spécificateur de format "M" est utilisé sans autres spécificateurs de f Générer GetHashCode() - - Generate constructor in '{0}' - Générer un constructeur dans '{0}' - - - - Generate all - Générer tout - - - - Generate local '{0}' - Générer le '{0}' local - - Generate {0} '{1}' in new file Générer {0} '{1}' dans un nouveau fichier @@ -3970,21 +3850,6 @@ Si le spécificateur de format "M" est utilisé sans autres spécificateurs de f Générer un {0} '{1}' imbriqué - - Implement interface abstractly - Implémenter l'interface abstraitement - - - - Implement interface through '{0}' - Implémenter l'interface via '{0}' - - - - Implement interface - Implémenter l'interface - - Introduce field for '{0}' Introduire un champ pour '{0}' @@ -4265,16 +4130,6 @@ Voulez-vous continuer ? Remarque : appuyez deux fois sur la touche Tab pour insérer l'extrait de code '{0}'. - - Implement interface explicitly with Dispose pattern - Implémenter l'interface explicitement avec le modèle Dispose - - - - Implement interface with Dispose pattern - Implémenter l'interface avec le modèle Dispose - - Computing fix all occurrences code fix... Calcul de la correction de toutes les occurrences (correction du code)... @@ -4300,16 +4155,6 @@ Voulez-vous continuer ? Solution - - TODO: dispose managed state (managed objects) - TODO: supprimer l'état managé (objets managés) - - - - TODO: set large fields to null - TODO: affecter aux grands champs une valeur null - - Compiler Compilateur @@ -4660,11 +4505,6 @@ Version utilisée dans : {2} Installer la version '{0}' - - Generate variable '{0}' - Générer la variable '{0}' - - Classes Classes diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index 99110700674ac..6bb8dd3d96c3c 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -85,16 +85,6 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Se si aggiunge {0} all'inizio di un'istruzione attiva, è necessario riavviare l'applicazione. - - Adding {0} into a {1} requires restarting the application. - Se si aggiunge {0} in un elemento {1}, è necessario riavviare l'applicazione. - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - Se si aggiunge {0} in una classe con layout esplicito o sequenziale, è necessario riavviare l'applicazione. - - Adding {0} into an interface method requires restarting the application. Se si aggiunge {0} in un metodo di interfaccia, è necessario riavviare l'applicazione. @@ -155,6 +145,21 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Se si aggiunge un metodo importato, è necessario riavviare l'applicazione. + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments Allinea gli argomenti con ritorno a capo @@ -315,11 +320,6 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa L'attività attesa non restituisce alcun valore - - Base classes contain inaccessible unimplemented members - Le classi di base contengono membri non implementati inaccessibili - - Built-in Copilot analysis Analisi Copilot predefinita @@ -665,11 +665,6 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Chiudi - - Do not change this code. Put cleanup code in '{0}' method - Non modificare questo codice. Inserire il codice di pulizia nel metodo '{0}' - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. Il contenuto corrente del file di origine '{0}' non corrisponde al codice sorgente compilato. Tutte le modifiche apportate a questo file durante il debug non verranno applicate finché il relativo contenuto non corrisponde al codice sorgente compilato. @@ -830,81 +825,16 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa È stato trovato un solo assembly: '{0}' - - Generate abstract method '{0}' - Genera il metodo astratto '{0}' - - - - Generate abstract property '{0}' - Genera la proprietà astratta '{0}' - - Generate comparison operators Genera gli operatori di confronto - - Generate constant '{0}' - Genera la costante '{0}' - - - - Generate constructor in '{0}' (with fields) - Genera il costruttore in '{0}' (con campi) - - - - Generate constructor in '{0}' (with properties) - Genera il costruttore in '{0}' (con proprietà) - - - - Generate enum member '{0}' - Genera il membro di enumerazione '{0}' - - - - Generate field '{0}' - Genera il campo '{0}' - - Generate for '{0}' Genera per '{0}' - - Generate method '{0}' - Genera il metodo '{0}' - - - - Generate parameter '{0}' - Generare il parametro '{0}' - - - - Generate parameter '{0}' (and overrides/implementations) - Generare il parametro '{0}' (e override/implementazioni) - - - - Generate property '{0}' - Genera la proprietà '{0}' - - - - Generate read-only field '{0}' - Genera il campo di sola lettura '{0}' - - - - Generate read-only property '{0}' - Genera la proprietà di sola lettura '{0}' - - Illegal \ at end of pattern Carattere \ non valido alla fine del criterio @@ -935,11 +865,6 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Implementa '{0}' in modo implicito - - Implement abstract class - Implementa la classe astratta - - Implement all interfaces explicitly Implementa tutte le interfacce in modo esplicito @@ -950,11 +875,6 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Implementa tutte le interfacce in modo implicito - - Implement all members explicitly - Implementare tutti i membri in modo esplicito - - Implement explicitly Implementa in modo esplicito @@ -965,16 +885,6 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Implementa in modo implicito - - Implement remaining members explicitly - Implementare i membri rimanenti in modo esplicito - - - - Implement through '{0}' - Implementa tramite '{0}' - - Incomplete \p{X} character escape Sequenza di caratteri di escape \p{X} incompleta @@ -1287,7 +1197,7 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa .NET Code Actions - .NET Code Actions + Azioni codice .NET @@ -2725,6 +2635,11 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Simbolo trovato nel percorso assembly '{0}' + + Symbol search + Ricerca simboli + + Symbols Simboli @@ -2735,16 +2650,6 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Errore di sintassi - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: liberare risorse non gestite (oggetti non gestiti) ed eseguire l'override del finalizzatore - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: eseguire l'override del finalizzatore solo se '{0}' contiene codice per liberare risorse non gestite - - Target type matches Imposta destinazione per corrispondenze di tipo @@ -2810,11 +2715,6 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Virgola finale non consentita - - Type members - Type members - - Types: Tipi: @@ -3025,6 +2925,11 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Se si aggiornano le dimensioni di un elemento {0}, è necessario riavviare l'applicazione. + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + L'aggiornamento del tipo di {0} (da '{1}' a '{2}') per un'istruzione attiva richiede il riavvio dell'applicazione. + + Updating the type of {0} requires restarting the application. Se si aggiorna il tipo di {0}, è necessario riavviare l'applicazione. @@ -3920,16 +3825,6 @@ Se l'identificatore di formato "M" viene usato senza altri identificatori di for Genera il costruttore delegante '{0}({1})' - - Generate constructor '{0}({1})' - Genera il costruttore '{0}({1})' - - - - Generate field assigning constructor '{0}({1})' - Genera il costruttore per l'assegnazione dei campi '{0}({1})' - - Generate Equals and GetHashCode Genera Equals e GetHashCode @@ -3945,21 +3840,6 @@ Se l'identificatore di formato "M" viene usato senza altri identificatori di for Genera GetHashCode() - - Generate constructor in '{0}' - Genera il costruttore in '{0}' - - - - Generate all - Genera tutto - - - - Generate local '{0}' - Genera l'elemento '{0}' locale - - Generate {0} '{1}' in new file Genera l'elemento {0} '{1}' nel nuovo file @@ -3970,21 +3850,6 @@ Se l'identificatore di formato "M" viene usato senza altri identificatori di for Genera l'elemento {0} '{1}' annidato - - Implement interface abstractly - Implementa l'interfaccia in modo astratto - - - - Implement interface through '{0}' - Implementa l'interfaccia tramite '{0}' - - - - Implement interface - Implementa l'interfaccia - - Introduce field for '{0}' Introduce il campo per '{0}' @@ -4265,16 +4130,6 @@ Continuare? Nota: premere due volte TAB per inserire il frammento di codice '{0}'. - - Implement interface explicitly with Dispose pattern - Implementa l'interfaccia in modo esplicito con il criterio Dispose - - - - Implement interface with Dispose pattern - Implementa l'interfaccia con il criterio Dispose - - Computing fix all occurrences code fix... Calcolo di tutte le occorrenze da correggere nel codice... @@ -4300,16 +4155,6 @@ Continuare? Soluzione - - TODO: dispose managed state (managed objects) - TODO: eliminare lo stato gestito (oggetti gestiti) - - - - TODO: set large fields to null - TODO: impostare campi di grandi dimensioni su Null - - Compiler Compilatore @@ -4660,11 +4505,6 @@ Questa versione è usata {2} Installa la versione '{0}' - - Generate variable '{0}' - Genera la variabile '{0}' - - Classes Classi diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index be4d32f6ba45f..dd5559fc36b49 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -85,16 +85,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma アクティブ ステートメントの前後に {0} を追加するには、アプリケーションを再起動する必要があります。 - - Adding {0} into a {1} requires restarting the application. - {0} を {1} に追加するには、アプリケーションを再起動する必要があります。 - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - 明示的またはシーケンシャルなレイアウトのクラスに {0} を追加するには、アプリケーションを再起動する必要があります。 - - Adding {0} into an interface method requires restarting the application. インターフェイス メソッドに {0} を追加するには、アプリケーションを再起動する必要があります。 @@ -155,6 +145,21 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma インポートされたメソッドを追加するには、アプリケーションを再起動する必要があります。 + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments 折り返された引数を揃える @@ -315,11 +320,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 待機中のタスクは値を返しません - - Base classes contain inaccessible unimplemented members - アクセス不可能な未実装のメンバーが基底クラスに含まれています - - Built-in Copilot analysis 組み込みの Copilot の分析 @@ -665,11 +665,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 無視 - - Do not change this code. Put cleanup code in '{0}' method - このコードを変更しないでください。クリーンアップ コードを '{0}' メソッドに記述します - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. ソース ファイル '{0}' の現在のコンテンツが、ビルドされたソースと一致しません。デバッグ中にこのファイルに加えられた変更は、そのコンテンツがビルドされたソースと一致するまで適用されません。 @@ -830,81 +825,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 1 つのアセンブリが見つかりました: '{0}' - - Generate abstract method '{0}' - 抽象メソッド '{0}' を生成する - - - - Generate abstract property '{0}' - 抽象プロパティ '{0}' を生成する - - Generate comparison operators 比較演算子の生成 - - Generate constant '{0}' - 定数 '{0}' を生成する - - - - Generate constructor in '{0}' (with fields) - '{0}' にコンストラクターを生成します (フィールドを含む) - - - - Generate constructor in '{0}' (with properties) - '{0}' にコンストラクターを生成します (プロパティを含む) - - - - Generate enum member '{0}' - 列挙型メンバー '{0}' を生成する - - - - Generate field '{0}' - フィールド '{0}' を生成する - - Generate for '{0}' '{0}' の生成 - - Generate method '{0}' - メソッド '{0}' を生成する - - - - Generate parameter '{0}' - パラメーター '{0}' の生成 - - - - Generate parameter '{0}' (and overrides/implementations) - パラメーター '{0}' の生成 (およびオーバーライド/実装) - - - - Generate property '{0}' - プロパティ '{0}' を生成する - - - - Generate read-only field '{0}' - 読み取り専用フィールド '{0}' を生成する - - - - Generate read-only property '{0}' - 読み取り専用プロパティ '{0}' を生成する - - Illegal \ at end of pattern 無効\末尾のパターン @@ -935,11 +865,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma '{0}' を暗黙的に実装する - - Implement abstract class - 抽象クラスの実装 - - Implement all interfaces explicitly すべてのインターフェイスを明示的に実装する @@ -950,11 +875,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma すべてのインターフェイスを暗黙的に実装する - - Implement all members explicitly - すべてのメンバーを明示的に実装する - - Implement explicitly 明示的に実装する @@ -965,16 +885,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 暗黙的に実装する - - Implement remaining members explicitly - 残りのメンバーを明示的に実装する - - - - Implement through '{0}' - '{0}' を通じて実装します - - Incomplete \p{X} character escape 不完全な \p{X} 文字エスケープです @@ -1287,7 +1197,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma .NET Code Actions - .NET Code Actions + .NET コード アクション @@ -2725,6 +2635,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of アセンブリ パス '{0}' にシンボルが見つかりました + + Symbol search + シンボルの検索 + + Symbols シンボル @@ -2735,16 +2650,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 構文エラー - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: アンマネージド リソース (アンマネージド オブジェクト) を解放し、ファイナライザーをオーバーライドします - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: '{0}' にアンマネージド リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします - - Target type matches ターゲットの種類が一致します @@ -2810,11 +2715,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 末尾にコンマは使用できない - - Type members - Type members - - Types: 型: @@ -3025,6 +2925,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of {0} のサイズを更新するには、アプリケーションを再起動する必要があります。 + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + アクティブなステートメントの前後の {0} の型を ('{1}' から '{2}' に) 更新するには、アプリケーションを再起動する必要があります。 + + Updating the type of {0} requires restarting the application. {0} の種類を更新するには、アプリケーションを再起動する必要があります。 @@ -3920,16 +3825,6 @@ If the "M" format specifier is used without other custom format specifiers, it's デリゲート コンストラクター '{0}({1})' を生成します - - Generate constructor '{0}({1})' - コンストラクター '{0}({1})' を生成します - - - - Generate field assigning constructor '{0}({1})' - フィールドを割り当てるコンストラクター '{0}({1})' を生成します - - Generate Equals and GetHashCode Equals および GetHashCode を生成する @@ -3945,21 +3840,6 @@ If the "M" format specifier is used without other custom format specifiers, it's GetHashCode() を生成する - - Generate constructor in '{0}' - '{0}' にコンストラクターを生成します - - - - Generate all - すべてを生成します - - - - Generate local '{0}' - ローカルの '{0}' を生成します - - Generate {0} '{1}' in new file 新しいファイルに {0} '{1}' を生成する @@ -3970,21 +3850,6 @@ If the "M" format specifier is used without other custom format specifiers, it's 入れ子 {0} '{1}' を生成する - - Implement interface abstractly - インタ フェースを抽象的に実装します - - - - Implement interface through '{0}' - '{0}' を通じてインターフェイスを実装します - - - - Implement interface - インターフェイスを実装します - - Introduce field for '{0}' '{0}' に対してフィールドを導入します @@ -4265,16 +4130,6 @@ Do you want to continue? メモ: '{0}' スニペットを挿入するには、Tab キーを 2 回押してください。 - - Implement interface explicitly with Dispose pattern - 破棄パターンを使って明示的にインターフェイスを実装します - - - - Implement interface with Dispose pattern - 破棄パターンを使ってインターフェイスを実装します - - Computing fix all occurrences code fix... 出現箇所をすべて修正するコード修正プログラムを計算しています... @@ -4300,16 +4155,6 @@ Do you want to continue? ソリューション - - TODO: dispose managed state (managed objects) - TODO: マネージド状態を破棄します (マネージド オブジェクト) - - - - TODO: set large fields to null - TODO: 大きなフィールドを null に設定します - - Compiler コンパイラ @@ -4660,11 +4505,6 @@ This version used in: {2} バージョン '{0}' のインストール - - Generate variable '{0}' - 変数 '{0}' を生成する - - Classes クラス diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index 5dc90d79ad7b2..2dc354351b933 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -85,16 +85,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 활성 문 주위에 {0}을(를) 추가하려면 응용 프로그램을 다시 시작해야 합니다. - - Adding {0} into a {1} requires restarting the application. - {0}을(를) {1}에 추가하려면 응용 프로그램을 다시 시작해야 합니다. - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - 명시적 또는 순차 레이아웃이 있는 클래스에 {0}을(를) 추가하려면 응용 프로그램을 다시 시작해야 합니다. - - Adding {0} into an interface method requires restarting the application. 인터페이스 메소드에 {0}을(를) 추가하려면 응용 프로그램을 다시 시작해야 합니다. @@ -155,6 +145,21 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 가져온 메서드를 추가하려면 응용 프로그램을 다시 시작해야 합니다. + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments 래핑된 인수 맞춤 @@ -315,11 +320,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 대기된 작업에서 값이 반환되지 않음 - - Base classes contain inaccessible unimplemented members - 기본 클래스에 구현되지 않아 액세스할 수 없는 멤버가 포함되어 있습니다. - - Built-in Copilot analysis 기본 제공 Copilot 분석 @@ -665,11 +665,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 해제 - - Do not change this code. Put cleanup code in '{0}' method - 이 코드를 변경하지 마세요. '{0}' 메서드에 정리 코드를 입력합니다. - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. 소스 파일 '{0}'의 현재 콘텐츠가 빌드된 소스와 일치하지 않습니다. 디버그하는 동안 이 파일의 변경된 모든 내용은 해당 콘텐츠가 빌드된 소스와 일치할 때까지 적용되지 않습니다. @@ -830,81 +825,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 단일 어셈블리를 찾았습니다. '{0}' - - Generate abstract method '{0}' - '{0}' 요약 메서드 생성 - - - - Generate abstract property '{0}' - '{0}' 요약 속성 생성 - - Generate comparison operators 비교 연산자 생성 - - Generate constant '{0}' - '{0}' 상수 생성 - - - - Generate constructor in '{0}' (with fields) - '{0}'에 생성자 생성(필드 포함) - - - - Generate constructor in '{0}' (with properties) - '{0}'에 생성자 생성(속성 포함) - - - - Generate enum member '{0}' - '{0}' 열거형 멤버 생성 - - - - Generate field '{0}' - '{0}' 필드 생성 - - Generate for '{0}' '{0}'에 대해 생성 - - Generate method '{0}' - ‘{0}’ 메서드 생성 - - - - Generate parameter '{0}' - '{0}' 매개 변수 생성 - - - - Generate parameter '{0}' (and overrides/implementations) - '{0}' 매개 변수(및 재정의/구현) 생성 - - - - Generate property '{0}' - '{0}' 속성 생성 - - - - Generate read-only field '{0}' - '{0}' 읽기 전용 필드 생성 - - - - Generate read-only property '{0}' - '{0}' 읽기 전용 속성 생성 - - Illegal \ at end of pattern 패턴 끝에 \를 사용할 수 없습니다. @@ -935,11 +865,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma '{0}'을(를) 암시적으로 구현 - - Implement abstract class - 추상 클래스 구현 - - Implement all interfaces explicitly 모든 인터페이스를 명시적으로 구현 @@ -950,11 +875,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 모든 인터페이스를 암시적으로 구현 - - Implement all members explicitly - 모든 멤버를 명시적으로 구현 - - Implement explicitly 명시적으로 구현 @@ -965,16 +885,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 암시적으로 구현 - - Implement remaining members explicitly - 나머지 멤버를 명시적으로 구현 - - - - Implement through '{0}' - '{0}'을(를) 통해 구현 - - Incomplete \p{X} character escape 불완전한 \p{X} 문자 이스케이프 @@ -1287,7 +1197,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma .NET Code Actions - .NET Code Actions + .NET 코드 작업 @@ -2725,6 +2635,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 어셈블리 경로 '{0}'에서 기호를 찾음 + + Symbol search + 기호 검색 + + Symbols 기호 @@ -2735,16 +2650,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 구문 오류 - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: 비관리형 리소스(비관리형 개체)를 해제하고 종료자를 재정의합니다. - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: 비관리형 리소스를 해제하는 코드가 '{0}'에 포함된 경우에만 종료자를 재정의합니다. - - Target type matches 대상 유형 일치 @@ -2810,11 +2715,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 후행 쉼표는 허용되지 않습니다. - - Type members - Type members - - Types: 형식: @@ -3025,6 +2925,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of {0}의 크기를 업데이트하려면 응용 프로그램을 다시 시작해야 합니다. + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + 활성 문 주변의 {0} 유형을 '{1}'에서 '{2}'(으)로 업데이트하려면 애플리케이션을 다시 시작해야 합니다. + + Updating the type of {0} requires restarting the application. {0} 유형을 업데이트하려면 애플리케이션을 다시 시작해야 합니다. @@ -3920,16 +3825,6 @@ If the "M" format specifier is used without other custom format specifiers, it's 위임하는 생성자 '{0}({1})' 생성 - - Generate constructor '{0}({1})' - 생성자 '{0}({1})' 생성 - - - - Generate field assigning constructor '{0}({1})' - 생성자 '{0}({1})'을(를) 할당하는 필드 생성 - - Generate Equals and GetHashCode Equals 및 GetHashCode 생성 @@ -3945,21 +3840,6 @@ If the "M" format specifier is used without other custom format specifiers, it's GetHashCode() 생성 - - Generate constructor in '{0}' - '{0}'에서 생성자 생성 - - - - Generate all - 모두 생성 - - - - Generate local '{0}' - '{0}' 로컬을 생성합니다. - - Generate {0} '{1}' in new file 새 파일에서 {0} '{1}' 생성 @@ -3970,21 +3850,6 @@ If the "M" format specifier is used without other custom format specifiers, it's 중첩된 {0} '{1}' 생성 - - Implement interface abstractly - 추상적으로 인터페이스 구현 - - - - Implement interface through '{0}' - '{0}'을(를) 통해 인터페이스 구현 - - - - Implement interface - 인터페이스 구현 - - Introduce field for '{0}' '{0}'에 대한 필드 지정 @@ -4265,16 +4130,6 @@ Do you want to continue? 참고: '{0}' 코드 조각을 삽입하려면 두 번 탭하세요. - - Implement interface explicitly with Dispose pattern - 인터페이스를 Dispose 패턴으로 명시적으로 구현 - - - - Implement interface with Dispose pattern - 인터페이스를 Dispose 패턴으로 구현 - - Computing fix all occurrences code fix... 모든 항목 코드 수정 사항을 계산하는 중... @@ -4300,16 +4155,6 @@ Do you want to continue? 솔루션 - - TODO: dispose managed state (managed objects) - TODO: 관리형 상태(관리형 개체)를 삭제합니다. - - - - TODO: set large fields to null - TODO: 큰 필드를 null로 설정합니다. - - Compiler 컴파일러 @@ -4660,11 +4505,6 @@ This version used in: {2} '{0}' 버전 설치 - - Generate variable '{0}' - '{0}' 변수 생성 - - Classes 클래스 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index 8eab32df69692..055583a50262f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -85,16 +85,6 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Dodawanie elementu {0} wokół aktywnej instrukcji wymaga ponownego uruchomienia aplikacji. - - Adding {0} into a {1} requires restarting the application. - Dodanie elementu {0} do {1} wymaga ponownego uruchomienia aplikacji. - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - Dodawanie elementu {0} do klasy za pomocą jawnego lub sekwencyjnego układu wymaga ponownego uruchomienia aplikacji. - - Adding {0} into an interface method requires restarting the application. Dodanie elementu {0} do metody interfejsu wymaga ponownego uruchomienia aplikacji. @@ -155,6 +145,21 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Dodawanie zaimportowanej metody wymaga ponownego uruchomienia aplikacji. + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments Wyrównaj zawinięte argumenty @@ -315,11 +320,6 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Zadanie, na które oczekiwano, nie zwraca wartości - - Base classes contain inaccessible unimplemented members - Klasy podstawowe zawierają niedostępne niezaimplementowane składowe - - Built-in Copilot analysis Wbudowana analiza funkcji Copilot @@ -665,11 +665,6 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Odrzuć - - Do not change this code. Put cleanup code in '{0}' method - Nie zmieniaj tego kodu. Umieść kod czyszczący w metodzie „{0}”. - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. Bieżąca zawartość pliku źródłowego „{0}” nie pasuje do skompilowanego źródła. Wszystkie zmiany wprowadzone w tym pliku podczas debugowania nie zostaną zastosowane do czasu, aż jego zawartość będzie zgodna ze skompilowanym źródłem. @@ -830,81 +825,16 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Znaleziono pojedynczy zestaw: „{0}” - - Generate abstract method '{0}' - Generuj metodę abstrakcyjną „{0}” - - - - Generate abstract property '{0}' - Generuj właściwość abstrakcyjną „{0}” - - Generate comparison operators Generuj operatory porównania - - Generate constant '{0}' - Generuj stałą „{0}” - - - - Generate constructor in '{0}' (with fields) - Generuj konstruktor w elemencie „{0}” (z polami) - - - - Generate constructor in '{0}' (with properties) - Generuj konstruktor w elemencie „{0}” (z właściwościami) - - - - Generate enum member '{0}' - Generuj składową wyliczenia „{0}” - - - - Generate field '{0}' - Generuj pole „{0}” - - Generate for '{0}' Wygeneruj dla elementu „{0}” - - Generate method '{0}' - Generuj metodę „{0}” - - - - Generate parameter '{0}' - Generuj parametr „{0}” - - - - Generate parameter '{0}' (and overrides/implementations) - Generowanie parametru „{0}” (i przesłonięć/implementacji) - - - - Generate property '{0}' - Generuj właściwość „{0}” - - - - Generate read-only field '{0}' - Generuj pole tylko do odczytu „{0}” - - - - Generate read-only property '{0}' - Generuj właściwość tylko do odczytu „{0}” - - Illegal \ at end of pattern Niedozwolony znak \ na końcu wzorca @@ -935,11 +865,6 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Niejawnie zaimplementuj interfejs „{0}” - - Implement abstract class - Implementuj klasę abstrakcyjną - - Implement all interfaces explicitly Jawnie zaimplementuj wszystkie interfejsy @@ -950,11 +875,6 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Niejawnie zaimplementuj wszystkie interfejsy - - Implement all members explicitly - Jawnie zaimplementuj wszystkie składowe - - Implement explicitly Zaimplementuj jawnie @@ -965,16 +885,6 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Zaimplementuj niejawnie - - Implement remaining members explicitly - Jawnie zaimplementuj pozostałe składowe - - - - Implement through '{0}' - Implementuj za pomocą elementu „{0}” - - Incomplete \p{X} character escape Niekompletna sekwencja ucieczki znaku \p{X} @@ -1287,7 +1197,7 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k .NET Code Actions - .NET Code Actions + Akcje kodu platformy .NET @@ -2725,6 +2635,11 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Znaleziono symbol w ścieżce zestawu „{0}” + + Symbol search + Wyszukiwanie symboli + + Symbols Symbole @@ -2735,16 +2650,6 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Błąd składniowy - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: Zwolnić niezarządzane zasoby (niezarządzane obiekty) i przesłonić finalizator - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: Przesłonić finalizator tylko w sytuacji, gdy powyższa metoda „{0}” zawiera kod służący do zwalniania niezarządzanych zasobów - - Target type matches Dopasowania typu docelowego @@ -2810,11 +2715,6 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Końcowy przecinek jest niedozwolony. - - Type members - Type members - - Types: Typy: @@ -3025,6 +2925,11 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Aktualizowanie rozmiaru elementu {0} wymaga ponownego uruchomienia aplikacji. + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + Aktualizacja typu {0} (z „{1}” na „{2}”) dotycząca aktywnej instrukcji wymaga ponownego uruchomienia aplikacji. + + Updating the type of {0} requires restarting the application. Aktualizacja typu elementu {0} wymaga ponownego uruchomienia aplikacji. @@ -3920,16 +3825,6 @@ Jeśli specyfikator formatu „M” jest używany bez innych niestandardowych sp Generuj konstruktor delegowania „{0}({1})” - - Generate constructor '{0}({1})' - Generuj konstruktor „{0}({1})” - - - - Generate field assigning constructor '{0}({1})' - Generuj konstruktor przypisujący pola „{0}({1})” - - Generate Equals and GetHashCode Generuj element Equals i GetHashCode @@ -3945,21 +3840,6 @@ Jeśli specyfikator formatu „M” jest używany bez innych niestandardowych sp Generuj element GetHashCode() - - Generate constructor in '{0}' - Generuj konstruktor w elemencie „{0}” - - - - Generate all - Generuj wszystko - - - - Generate local '{0}' - Generuj lokalny element „{0}” - - Generate {0} '{1}' in new file Generuj element {0} „{1}” w nowym pliku @@ -3970,21 +3850,6 @@ Jeśli specyfikator formatu „M” jest używany bez innych niestandardowych sp Generuj zagnieżdżony element {0} „{1}” - - Implement interface abstractly - Implementuj interfejs abstrakcyjnie - - - - Implement interface through '{0}' - Implementuj interfejs za pomocą elementu „{0}” - - - - Implement interface - Zaimplementuj interfejs - - Introduce field for '{0}' Wprowadź pole dla elementu „{0}” @@ -4265,16 +4130,6 @@ Czy chcesz kontynuować? Uwaga: naciśnij dwa razy klawisz Tab, aby wstawić fragment kodu „{0}”. - - Implement interface explicitly with Dispose pattern - Jawnie implementuj interfejs za pomocą wzorca likwidacji - - - - Implement interface with Dispose pattern - Implementuj interfejs za pomocą wzorca likwidacji - - Computing fix all occurrences code fix... Trwa obliczanie poprawki kodu naprawiającej wszystkie obliczenia... @@ -4300,16 +4155,6 @@ Czy chcesz kontynuować? Rozwiązanie - - TODO: dispose managed state (managed objects) - TODO: Wyczyścić stan zarządzany (obiekty zarządzane) - - - - TODO: set large fields to null - TODO: Ustawić wartość null dla dużych pól - - Compiler Kompilator @@ -4660,11 +4505,6 @@ Ta wersja jest używana wersja: {2} Zainstaluj wersję „{0}” - - Generate variable '{0}' - Generuj zmienną „{0}” - - Classes Klasy diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index 4c59a203b786e..57b63326b5c4f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -85,16 +85,6 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Adicionar {0} em torno de uma instrução ativa requer a reinicialização do aplicativo. - - Adding {0} into a {1} requires restarting the application. - Adicionar {0} a um {1} requer a reinicialização do aplicativo. - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - Adicionar {0} a uma classe com layout explícito ou sequencial requer a reinicialização do aplicativo. - - Adding {0} into an interface method requires restarting the application. Adicionar {0} a um método de interface requer a reinicialização do aplicativo. @@ -155,6 +145,21 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Adicionar um método importado requer a reinicialização do aplicativo. + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments Alinhar argumentos encapsulados @@ -315,11 +320,6 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess A tarefa esperada não retorna nenhum valor - - Base classes contain inaccessible unimplemented members - As classes base contêm membros não implementados inacessíveis - - Built-in Copilot analysis Análise interna do Copilot @@ -665,11 +665,6 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Ignorar - - Do not change this code. Put cleanup code in '{0}' method - Não altere este código. Coloque o código de limpeza no método '{0}' - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. O conteúdo atual do arquivo de origem '{0}' não corresponde à origem criada. Todas as alterações feitas neste arquivo durante a depuração não serão aplicadas até que o conteúdo corresponda à origem criada. @@ -830,81 +825,16 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Foi encontrado um assembly: '{0}' - - Generate abstract method '{0}' - Gerar o método abstrato '{0}' - - - - Generate abstract property '{0}' - Gerar a propriedade abstrata '{0}' - - Generate comparison operators Gerar operadores de comparação - - Generate constant '{0}' - Gerar constante '{0}' - - - - Generate constructor in '{0}' (with fields) - Gerar o construtor em '{0}' (com campos) - - - - Generate constructor in '{0}' (with properties) - Gerar o construtor em '{0}' (com propriedades) - - - - Generate enum member '{0}' - Gerar o membro de enumeração '{0}' - - - - Generate field '{0}' - Gerar campo '{0}' - - Generate for '{0}' Gerar para '{0}' - - Generate method '{0}' - Gerar método '{0}' - - - - Generate parameter '{0}' - Gerar o parâmetro '{0}' - - - - Generate parameter '{0}' (and overrides/implementations) - Gerar o parâmetro '{0}' (e as substituições/implementações) - - - - Generate property '{0}' - Gerar propriedade '{0}' - - - - Generate read-only field '{0}' - Gerar o campo somente leitura '{0}' - - - - Generate read-only property '{0}' - Gerar a propriedade somente leitura '{0}' - - Illegal \ at end of pattern \ ilegal no final do padrão @@ -935,11 +865,6 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Implementar '{0}' implicitamente - - Implement abstract class - Implementar classe abstrata - - Implement all interfaces explicitly Implementar todas as interfaces explicitamente @@ -950,11 +875,6 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Implementar todas as interfaces implicitamente - - Implement all members explicitly - Implementar todos os membros explicitamente - - Implement explicitly Implementar explicitamente @@ -965,16 +885,6 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Implementar implicitamente - - Implement remaining members explicitly - Implementar os membros restantes explicitamente - - - - Implement through '{0}' - Implementar por meio de '{0}' - - Incomplete \p{X} character escape Escape de caractere incompleto \p{X} @@ -1287,7 +1197,7 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess .NET Code Actions - .NET Code Actions + Ações de código do .NET @@ -2725,6 +2635,11 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Símbolo encontrado no caminho de montagem '{0}' + + Symbol search + Pesquisa de símbolo + + Symbols Símbolos @@ -2735,16 +2650,6 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Erro de sintaxe - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: liberar recursos não gerenciados (objetos não gerenciados) e substituir o finalizador - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: substituir o finalizador somente se '{0}' tiver o código para liberar recursos não gerenciados - - Target type matches Correspondências de tipos de destino @@ -2810,11 +2715,6 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Vírgula à direita não permitida - - Type members - Type members - - Types: Tipos: @@ -3025,6 +2925,11 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Atualizar o tamanho de um {0} requer a reinicialização do aplicativo. + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + Atualizar o tipo de {0} (de '{1}' para '{2}') em torno de uma instrução ativa requer a reinicialização do aplicativo. + + Updating the type of {0} requires restarting the application. Atualizar o tipo de {0} requer a reinicialização do aplicativo. @@ -3920,16 +3825,6 @@ Se o especificador de formato "M" for usado sem outros especificadores de format Gerar construtor delegante "{0}({1})" - - Generate constructor '{0}({1})' - Gerar construtor "{0}({1})" - - - - Generate field assigning constructor '{0}({1})' - Gerar construtor de atribuição de campo "{0}({1})" - - Generate Equals and GetHashCode Gerar Equals e GetHashCode @@ -3945,21 +3840,6 @@ Se o especificador de formato "M" for usado sem outros especificadores de format Gerar GetHashCode() - - Generate constructor in '{0}' - Gerar construtor em '{0}' - - - - Generate all - Gerar todos - - - - Generate local '{0}' - Gerar local '{0}' - - Generate {0} '{1}' in new file Gerar {0} '{1}' no novo arquivo @@ -3970,21 +3850,6 @@ Se o especificador de formato "M" for usado sem outros especificadores de format Gerar {0} '{1}' aninhado - - Implement interface abstractly - Implementar interface de forma abstrata - - - - Implement interface through '{0}' - Implementar interface por meio de "{0}" - - - - Implement interface - Implementar a interface - - Introduce field for '{0}' Encapsular campo para "{0}" @@ -4265,16 +4130,6 @@ Deseja continuar? Observação: pressione Tab duas vezes para inserir o snippet '{0}'. - - Implement interface explicitly with Dispose pattern - Implementar interface explicitamente com Padrão de descarte - - - - Implement interface with Dispose pattern - Implementar interface com Padrão de descarte - - Computing fix all occurrences code fix... Computando a correção de todas as correções de código de ocorrências… @@ -4300,16 +4155,6 @@ Deseja continuar? Solução - - TODO: dispose managed state (managed objects) - TODO: descartar o estado gerenciado (objetos gerenciados) - - - - TODO: set large fields to null - TODO: definir campos grandes como nulos - - Compiler Compilador @@ -4660,11 +4505,6 @@ Essa versão é usada no: {2} Instalar a versão '{0}' - - Generate variable '{0}' - Gerar variável '{0}' - - Classes Classes diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index e18ca3476aca1..b5fb73b44bf19 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -85,16 +85,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Для добавления {0} вокруг активного оператора требуется перезапустить приложение. - - Adding {0} into a {1} requires restarting the application. - Для добавления {0} в {1} требуется перезапустить приложение. - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - Для добавления {0} в класс с явным или последовательным макетом требуется перезапустить приложение. - - Adding {0} into an interface method requires restarting the application. Для добавления {0} в метод интерфейса требуется перезапустить приложение. @@ -155,6 +145,21 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Для добавления импортированного метода требуется перезапустить приложение. + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments Выровнять свернутые аргументы @@ -315,11 +320,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Ожидаемая задача не возвращает значение. - - Base classes contain inaccessible unimplemented members - Базовые классы содержат недоступные нереализованные члены - - Built-in Copilot analysis Встроенный анализ Copilot @@ -665,11 +665,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Отклонить - - Do not change this code. Put cleanup code in '{0}' method - Не изменяйте этот код. Разместите код очистки в методе "{0}". - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. Текущее содержимое исходного файла "{0}" не соответствует созданному источнику. Все изменения, внесенные в этот файл во время отладки, не будут применены, пока содержимое файла не будет соответствовать созданному источнику. @@ -830,81 +825,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Найдена одна сборка: "{0}" - - Generate abstract method '{0}' - Создать абстрактный метод "{0}" - - - - Generate abstract property '{0}' - Создать абстрактное свойство "{0}" - - Generate comparison operators Создать операторы сравнения - - Generate constant '{0}' - Создать константу "{0}" - - - - Generate constructor in '{0}' (with fields) - Создать конструктор в "{0}" (с полями) - - - - Generate constructor in '{0}' (with properties) - Создать конструктор в "{0}" (со свойствами) - - - - Generate enum member '{0}' - Создать элемент перечисления "{0}" - - - - Generate field '{0}' - Создать поле "{0}" - - Generate for '{0}' Создать для "{0}" - - Generate method '{0}' - Создать метод "{0}" - - - - Generate parameter '{0}' - Создать параметр "{0}" - - - - Generate parameter '{0}' (and overrides/implementations) - Создать параметр "{0}" (а также переопределения или реализации) - - - - Generate property '{0}' - Создать свойство "{0}" - - - - Generate read-only field '{0}' - Создать поле только для чтения "{0}" - - - - Generate read-only property '{0}' - Создать свойство только для чтения "{0}" - - Illegal \ at end of pattern Недопустимый символ "\" в конце шаблона @@ -935,11 +865,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Реализовать "{0}" неявно - - Implement abstract class - Реализовать абстрактный класс - - Implement all interfaces explicitly Реализовать все интерфейсы явно @@ -950,11 +875,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Реализовать все интерфейсы неявно - - Implement all members explicitly - Реализовать все элементы явно - - Implement explicitly Реализовать явно @@ -965,16 +885,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Реализовать неявно - - Implement remaining members explicitly - Реализовать оставшиеся элементы явно - - - - Implement through '{0}' - Реализовать через "{0}" - - Incomplete \p{X} character escape Незавершенная escape-последовательность \p{X} @@ -1287,7 +1197,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma .NET Code Actions - .NET Code Actions + Действия кода .NET @@ -2725,6 +2635,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Найден символ в пути сборки "{0}" + + Symbol search + Поиск символов + + Symbols Символы @@ -2735,16 +2650,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Синтаксическая ошибка - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: освободить неуправляемые ресурсы (неуправляемые объекты) и переопределить метод завершения - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: переопределить метод завершения, только если "{0}" содержит код для освобождения неуправляемых ресурсов - - Target type matches Соответствия целевого типа @@ -2810,11 +2715,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Завершающая запятая не разрешена - - Type members - Type members - - Types: Типы: @@ -3025,6 +2925,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Для обновления размера {0} требуется перезапустить приложение. + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + Для обновления типа {0} (с "{1}" на 2{2}") вокруг активного оператора требуется перезапустить приложение. + + Updating the type of {0} requires restarting the application. Для обновления типа {0} требуется перезапустить приложение. @@ -3920,16 +3825,6 @@ If the "M" format specifier is used without other custom format specifiers, it's Создать делегирующий конструктор "{0}({1})" - - Generate constructor '{0}({1})' - Создать конструктор "{0}({1})" - - - - Generate field assigning constructor '{0}({1})' - Создать назначающий поля конструктор "{0}({1})" - - Generate Equals and GetHashCode Создать Equals и GetHashCode @@ -3945,21 +3840,6 @@ If the "M" format specifier is used without other custom format specifiers, it's Создать "GetHashCode()" - - Generate constructor in '{0}' - Создайте конструктор в "{0}" - - - - Generate all - Создать все - - - - Generate local '{0}' - Создайте локальную переменную "{0}" - - Generate {0} '{1}' in new file Создать {0} "{1}" в новом файле @@ -3970,21 +3850,6 @@ If the "M" format specifier is used without other custom format specifiers, it's Создать вложенный {0} "{1}" - - Implement interface abstractly - Реализовать интерфейс абстрактно - - - - Implement interface through '{0}' - Реализовать интерфейс через "{0}" - - - - Implement interface - Реализовать интерфейс - - Introduce field for '{0}' Введите поле для "{0}" @@ -4265,16 +4130,6 @@ Do you want to continue? Примечание. Два раза нажмите клавишу TAB, чтобы вставить фрагмент кода "{0}". - - Implement interface explicitly with Dispose pattern - Явно внедрите интерфейс с шаблоном освобождения - - - - Implement interface with Dispose pattern - Внедрите интерфейс с шаблоном освобождения - - Computing fix all occurrences code fix... Вычисление изменения кода для исправления всех вхождений... @@ -4300,16 +4155,6 @@ Do you want to continue? Решение - - TODO: dispose managed state (managed objects) - TODO: освободить управляемое состояние (управляемые объекты) - - - - TODO: set large fields to null - TODO: установить значение NULL для больших полей - - Compiler Компилятор @@ -4660,11 +4505,6 @@ This version used in: {2} Установить версию "{0}" - - Generate variable '{0}' - Создать переменную "{0}" - - Classes Классы diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index 2d2ed5ed366e8..2b409d687a5b9 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -85,16 +85,6 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Etkin bir deyim etrafında bir {0} öğesinin eklenmesi, uygulamanın yeniden başlatılmasını gerektirir. - - Adding {0} into a {1} requires restarting the application. - {1} öğesine {0} eklemek, uygulamanın yeniden başlatılmasını gerektir. - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - Açık veya sıralı düzene sahip bir sınıfa {0} eklemek, uygulamanın yeniden başlatılmasını gerektirir. - - Adding {0} into an interface method requires restarting the application. Bir arabirim yöntemine {0} eklemek, uygulamanın yeniden başlatılmasını gerektirir. @@ -155,6 +145,21 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be İçeri aktarılan bir yöntemin eklenmesi uygulamanın yeniden başlatılmasını gerektiriyor. + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments Sarmalanan bağımsız değişkenleri hizala @@ -315,11 +320,6 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Beklenen görev değer döndürmüyor - - Base classes contain inaccessible unimplemented members - Temel sınıflarda erişilemeyen, uygulanmamış üyeler var - - Built-in Copilot analysis Yerleşik Copilot analizi @@ -665,11 +665,6 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Kapat - - Do not change this code. Put cleanup code in '{0}' method - Bu kodu değiştirmeyin. Temizleme kodunu '{0}' metodunun içine yerleştirin. - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. '{0}' kaynak dosyasının geçerli içeriği, derlenen kaynakla eşleşmiyor. Hata ayıklama işlemi sırasında bu dosyada yapılan değişiklikler, dosyanın içeriği derlenen kaynakla eşleşene kadar uygulanmaz. @@ -830,81 +825,16 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Tek bütünleştirilmiş kod bulundu: '{0}' - - Generate abstract method '{0}' - '{0}' soyut metodunu üret - - - - Generate abstract property '{0}' - '{0}' soyut özelliğini üret - - Generate comparison operators Karşılaştırma işleçlerini oluştur - - Generate constant '{0}' - '{0}' sabitini üret - - - - Generate constructor in '{0}' (with fields) - '{0}' içinde oluşturucu üret (alanlarla birlikte) - - - - Generate constructor in '{0}' (with properties) - '{0}' içinde oluşturucu üret (özelliklerle birlikte) - - - - Generate enum member '{0}' - '{0}' sabit listesi üyesini üret - - - - Generate field '{0}' - '{0}' alanını üret - - Generate for '{0}' '{0}' için oluştur - - Generate method '{0}' - '{0}' metodunu üret - - - - Generate parameter '{0}' - '{0}' parametresini üret - - - - Generate parameter '{0}' (and overrides/implementations) - '{0}' parametresini (ve geçersiz kılmaları/uygulamaları) üret - - - - Generate property '{0}' - '{0}' özelliğini üret - - - - Generate read-only field '{0}' - '{0}' salt okunur alanını üret - - - - Generate read-only property '{0}' - '{0}' salt okunur özelliğini üret - - Illegal \ at end of pattern Yasadışı \ model sonunda @@ -935,11 +865,6 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be '{0}' öğesini örtük olarak uygula - - Implement abstract class - Soyut sınıfı uygula - - Implement all interfaces explicitly Tüm arabirimleri açıkça uygula @@ -950,11 +875,6 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Tüm arabirimleri örtük olarak uygula - - Implement all members explicitly - Tüm üyeleri açıkça uygula - - Implement explicitly Açıkça uygula @@ -965,16 +885,6 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Örtük olarak uygula - - Implement remaining members explicitly - Kalan üyeleri açıkça uygula - - - - Implement through '{0}' - '{0}' aracılığıyla uygula - - Incomplete \p{X} character escape Tamamlanmamış \p{X} karakter kaçış @@ -1287,7 +1197,7 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be .NET Code Actions - .NET Code Actions + .NET Kod Eylemleri @@ -2725,6 +2635,11 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri “{0}” derleme yolunda sembol bulundu + + Symbol search + Sembol araması + + Symbols Semboller @@ -2735,16 +2650,6 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Söz dizimi hatası - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: yönetilmeyen kaynakları (yönetilmeyen nesneleri) serbest bırakın ve sonlandırıcıyı geçersiz kılın - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: sonlandırıcıyı yalnızca '{0}' içinde yönetilmeyen kaynakları serbest bırakacak kod varsa geçersiz kılın - - Target type matches Hedef tür eşleşmeleri @@ -2810,11 +2715,6 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Sona eklenen virgüle izin verilmiyor - - Type members - Type members - - Types: Türler: @@ -3025,6 +2925,11 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri {0} öğesinin boyutunu güncelleştirmek, uygulamanın yeniden başlatılmasını gerektirir. + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + Etkin bir deyim etrafında {0} türünün ('{1}' değerinden '{2}' değerine) güncelleştirilmesi uygulamanın yeniden başlatılmasını gerektirir. + + Updating the type of {0} requires restarting the application. {0} öğesinin türünün güncelleştirilmesi, uygulamanın yeniden başlatılmasını gerektirir. @@ -3920,16 +3825,6 @@ If the "M" format specifier is used without other custom format specifiers, it's {0}({1})' temsilci oluşturucusunu üret - - Generate constructor '{0}({1})' - {0}({1})' oluşturucusunu üret - - - - Generate field assigning constructor '{0}({1})' - {0}({1})' alan atama oluşturucusunu üret - - Generate Equals and GetHashCode Equals ve GetHashCode oluştur @@ -3945,21 +3840,6 @@ If the "M" format specifier is used without other custom format specifiers, it's GetHashCode() oluştur - - Generate constructor in '{0}' - '{0}' içinde oluşturucu üretin - - - - Generate all - Tümünü üret - - - - Generate local '{0}' - Yerel '{0}' üretin - - Generate {0} '{1}' in new file Yeni dosyada {0} '{1}' oluştur @@ -3970,21 +3850,6 @@ If the "M" format specifier is used without other custom format specifiers, it's İç içe {0} '{1}' oluştur - - Implement interface abstractly - Arabirimi soyut olarak uygula - - - - Implement interface through '{0}' - Arabirimi '{0}' aracılığıyla uygula - - - - Implement interface - Arabirimi uygula - - Introduce field for '{0}' '{0}' için alanı ortaya çıkar @@ -4265,16 +4130,6 @@ Devam etmek istiyor musunuz? Not: '{0}' kod parçacığını eklemek için iki kez sekme yapın. - - Implement interface explicitly with Dispose pattern - Ara birimi açık olarak Dispose düzeniyle uygula - - - - Implement interface with Dispose pattern - Ara birimi Dispose düzeniyle uygula - - Computing fix all occurrences code fix... Geçtiği her yerde düzeltme kod düzeltmesi hesaplanıyor... @@ -4300,16 +4155,6 @@ Devam etmek istiyor musunuz? Çözüm - - TODO: dispose managed state (managed objects) - TODO: yönetilen durumu (yönetilen nesneleri) atın - - - - TODO: set large fields to null - TODO: büyük alanları null olarak ayarlayın - - Compiler Derleyici @@ -4660,11 +4505,6 @@ Bu sürüm şurada kullanılır: {2} '{0}' sürümünü yükle - - Generate variable '{0}' - '{0}' değişkenini oluştur - - Classes Sınıflar diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index c03a012df542b..03533f977762a 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -85,16 +85,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 在活动语句周围添加 {0} 需要重新启动应用程序。 - - Adding {0} into a {1} requires restarting the application. - 将 {0} 添加进 {1} 中需要重新启动应用程序。 - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - 将 {0} 添加到具有显式或顺序布局的类中需要重新启动应用程序。 - - Adding {0} into an interface method requires restarting the application. 将 {0} 添加到接口方法中需要重新启动应用程序。 @@ -155,6 +145,21 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 添加导入的方法需要重新启动应用程序。 + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments 对齐包装的参数 @@ -315,11 +320,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 等待任务没有返回任何值 - - Base classes contain inaccessible unimplemented members - 基类包含无法访问的未实现成员 - - Built-in Copilot analysis 内置 Copilot 分析 @@ -665,11 +665,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 消除 - - Do not change this code. Put cleanup code in '{0}' method - 不要更改此代码。请将清理代码放入“{0}”方法中 - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. 源文件 "{0}" 的当前内容与生成的源不匹配。在调试期间对此文件所做的任何更改都不会应用,直到其内容与生成的源匹配为止。 @@ -830,81 +825,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 找到单个程序集: "{0}" - - Generate abstract method '{0}' - 生成抽象方法“{0}” - - - - Generate abstract property '{0}' - 生成抽象属性“{0}” - - Generate comparison operators 生成比较运算符 - - Generate constant '{0}' - 生成常数“{0}” - - - - Generate constructor in '{0}' (with fields) - 在“{0}”中生成构造函数(包含字段) - - - - Generate constructor in '{0}' (with properties) - 在“{0}”中生成构造函数(包含属性) - - - - Generate enum member '{0}' - 生成枚举成员“{0}” - - - - Generate field '{0}' - 生成字段“{0}” - - Generate for '{0}' 为 "{0}" 生成 - - Generate method '{0}' - 生成方法“{0}” - - - - Generate parameter '{0}' - 生成参数 "{0}" - - - - Generate parameter '{0}' (and overrides/implementations) - 生成参数 {0}(和重写/实现) - - - - Generate property '{0}' - 生成属性“{0}” - - - - Generate read-only field '{0}' - 生成只读字段“{0}” - - - - Generate read-only property '{0}' - 生成只读属性“{0}” - - Illegal \ at end of pattern 模式末尾的 \ 非法 @@ -935,11 +865,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 隐式实现 "{0}" - - Implement abstract class - 实现抽象类 - - Implement all interfaces explicitly 显式实现所有接口 @@ -950,11 +875,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 隐式实现所有接口 - - Implement all members explicitly - 显式实现所有成员 - - Implement explicitly 显式实现 @@ -965,16 +885,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 隐式实现 - - Implement remaining members explicitly - 显式实现剩余成员 - - - - Implement through '{0}' - 通过“{0}”实现 - - Incomplete \p{X} character escape \p{X} 字符转义不完整 @@ -1287,7 +1197,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma .NET Code Actions - .NET Code Actions + .NET 代码操作 @@ -2725,6 +2635,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 在程序集路径 "{0}" 中找到符号 + + Symbol search + 符号搜索 + + Symbols 符号 @@ -2735,16 +2650,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 语法错误 - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: 释放未托管的资源(未托管的对象)并重写终结器 - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: 仅当“{0}”拥有用于释放未托管资源的代码时才替代终结器 - - Target type matches 目标类型匹配 @@ -2810,11 +2715,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 不允许使用尾随逗号 - - Type members - Type members - - Types: 类型: @@ -3025,6 +2925,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 更新 {0} 的大小需要重新启动应用程序。 + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + 更新活动语句周围 {0} 的类型(从 '{1}' 到 '{2}')需要重启应用程序。 + + Updating the type of {0} requires restarting the application. 更新 {0} 的类型需要重启应用程序。 @@ -3920,16 +3825,6 @@ If the "M" format specifier is used without other custom format specifiers, it's 生成委托构造函数“{0}({1})” - - Generate constructor '{0}({1})' - 生成构造函数 “{0}({1})” - - - - Generate field assigning constructor '{0}({1})' - 生成字段分配构造函数“{0}({1})” - - Generate Equals and GetHashCode 生成 Equals 和 GetHashCode @@ -3945,21 +3840,6 @@ If the "M" format specifier is used without other custom format specifiers, it's 生成 GetHashCode() - - Generate constructor in '{0}' - 在“{0}”中生成构造函数 - - - - Generate all - 生成所有 - - - - Generate local '{0}' - 生成本地“{0}” - - Generate {0} '{1}' in new file 在新文件中生成 {0}“{1}” @@ -3970,21 +3850,6 @@ If the "M" format specifier is used without other custom format specifiers, it's 生成嵌套的 {0}“{1}” - - Implement interface abstractly - 以抽象方式实现接口 - - - - Implement interface through '{0}' - 通过“{0}”实现接口 - - - - Implement interface - 实现接口 - - Introduce field for '{0}' 为“{0}”引入字段 @@ -4265,16 +4130,6 @@ Do you want to continue? 注意: 两次 Tab 插入“{0}”片段。 - - Implement interface explicitly with Dispose pattern - 通过释放模式显式实现接口 - - - - Implement interface with Dispose pattern - 通过释放模式实现接口 - - Computing fix all occurrences code fix... 正在计算“修复所有出现的地方”代码修复... @@ -4300,16 +4155,6 @@ Do you want to continue? 解决方案 - - TODO: dispose managed state (managed objects) - TODO: 释放托管状态(托管对象) - - - - TODO: set large fields to null - TODO: 将大型字段设置为 null - - Compiler 编译器 @@ -4660,11 +4505,6 @@ This version used in: {2} 安装版本“{0}” - - Generate variable '{0}' - 生成变量 {0} - - Classes diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index 9dec3caef3487..ee02eac9cef45 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -85,16 +85,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 新增作用中陳述式前後的 {0} 需要重新啟動應用程式。 - - Adding {0} into a {1} requires restarting the application. - 新增 {0} 到 {1} 需要重新啟動應用程式。 - - - - Adding {0} into a class with explicit or sequential layout requires restarting the application. - 在具有明確或循序配置的類別中新增 {0} 需要重新啟動應用程式。 - - Adding {0} into an interface method requires restarting the application. 在介面方法中新增 {0} 需要重新啟動應用程式。 @@ -155,6 +145,21 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 新增匯入的方法需要重新啟動應用程式。 + + Adding or moving {0} of {1} requires restarting the application. + Adding or moving {0} of {1} requires restarting the application. + + + + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + Adding or moving {0} of {1} with explicit or sequential layout requires restarting the application. + + + + Adding or moving {0} of a COM interface requires restarting the application. + Adding or moving {0} of a COM interface requires restarting the application. + + Align wrapped arguments 對齊包裝的引數 @@ -315,11 +320,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 等待的工作不會傳回任何值 - - Base classes contain inaccessible unimplemented members - 基底類別包含無法存取的未實作成員 - - Built-in Copilot analysis 內建 Copilot 分析 @@ -665,11 +665,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 關閉 - - Do not change this code. Put cleanup code in '{0}' method - 請勿變更此程式碼。請將清除程式碼放入 '{0}' 方法 - - The current content of source file '{0}' does not match the built source. Any changes made to this file while debugging won't be applied until its content matches the built source. 來源檔案 '{0}' 目前的內容與已建置的來源不一致。等到此檔案的內容與已建置的來源一致後,才會套用於偵錯期間對此檔案所做的所有變更。 @@ -830,81 +825,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 找到單一組件: '{0}' - - Generate abstract method '{0}' - 產生抽象方法 '{0}' - - - - Generate abstract property '{0}' - 產生抽象屬性 '{0}' - - Generate comparison operators 產生比較運算子 - - Generate constant '{0}' - 產生常數 '{0}' - - - - Generate constructor in '{0}' (with fields) - 在 '{0}' 中產生建構函式 (使用欄位) - - - - Generate constructor in '{0}' (with properties) - 在 '{0}' 中產生建構函式 (使用屬性) - - - - Generate enum member '{0}' - 產生列舉成員 '{0}' - - - - Generate field '{0}' - 產生欄位 '{0}' - - Generate for '{0}' 為 '{0}' 產生 - - Generate method '{0}' - 產生方法 '{0}' - - - - Generate parameter '{0}' - 產生參數 '{0}' - - - - Generate parameter '{0}' (and overrides/implementations) - 產生參數 '{0}' (以及覆寫/實作) - - - - Generate property '{0}' - 產生屬性 '{0}' - - - - Generate read-only field '{0}' - 產生唯讀欄位 '{0}' - - - - Generate read-only property '{0}' - 產生唯讀屬性 '{0}' - - Illegal \ at end of pattern 模式結尾使用 \ 不符合格式規定 @@ -935,11 +865,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 隱含實作 '{0}' - - Implement abstract class - 實作抽象類別 - - Implement all interfaces explicitly 明確實作所有介面 @@ -950,11 +875,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 隱含實作所有介面 - - Implement all members explicitly - 明確實作所有成員 - - Implement explicitly 明確實作 @@ -965,16 +885,6 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 隱含實作 - - Implement remaining members explicitly - 明確實作剩餘的成員 - - - - Implement through '{0}' - 透過 '{0}' 實作 - - Incomplete \p{X} character escape 不完整的 \p{X} 字元逸出 @@ -1287,7 +1197,7 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma .NET Code Actions - .NET Code Actions + .NET 程式碼動作 @@ -2725,6 +2635,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 在組件路徑 '{0}' 中找到符號 + + Symbol search + 符號搜尋 + + Symbols 符號 @@ -2735,16 +2650,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 語法錯誤 - - TODO: free unmanaged resources (unmanaged objects) and override finalizer - TODO: 釋出非受控資源 (非受控物件) 並覆寫完成項 - - - - TODO: override finalizer only if '{0}' has code to free unmanaged resources - TODO: 僅有當 '{0}' 具有會釋出非受控資源的程式碼時,才覆寫完成項 - - Target type matches 目標類型相符項目 @@ -2810,11 +2715,6 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 尾端不得為逗號 - - Type members - Type members - - Types: 類型: @@ -3025,6 +2925,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 更新 {0} 的大小需要重新啟動應用程式。 + + Updating the type of {0} (from '{1}' to '{2}') around an active statement requires restarting the application. + 更新作用中陳述式的類型 {0} (從 '{1}' 到 '{2}') 需要重新啟動應用程式。 + + Updating the type of {0} requires restarting the application. 更新 {0} 的類型需要重新啟動應用程式。 @@ -3920,16 +3825,6 @@ If the "M" format specifier is used without other custom format specifiers, it's 產生委派建構函式 '{0}({1})' - - Generate constructor '{0}({1})' - 產生建構函式 '{0}({1})' - - - - Generate field assigning constructor '{0}({1})' - 產生欄位指派建構函式 '{0}({1})' - - Generate Equals and GetHashCode 產生 Equals 與 GetHashCode @@ -3945,21 +3840,6 @@ If the "M" format specifier is used without other custom format specifiers, it's 產生 GetHashCode() - - Generate constructor in '{0}' - 在 '{0}' 中產生建構函式 - - - - Generate all - 產生全部 - - - - Generate local '{0}' - 產生區域 '{0}' - - Generate {0} '{1}' in new file 在新檔案中產生 {0} '{1}' @@ -3970,21 +3850,6 @@ If the "M" format specifier is used without other custom format specifiers, it's 產生巢狀 {0} '{1}' - - Implement interface abstractly - 以抽象方式實作介面 - - - - Implement interface through '{0}' - 透過 '{0}' 實作介面 - - - - Implement interface - 實作介面 - - Introduce field for '{0}' 為 '{0}' 引進欄位 @@ -4265,16 +4130,6 @@ Do you want to continue? 注意: 按兩次 Tab 鍵即可插入 '{0}' 程式碼片段。 - - Implement interface explicitly with Dispose pattern - 使用 Dispose 模式明確地實作介面 - - - - Implement interface with Dispose pattern - 使用 Dispose 模式實作介面 - - Computing fix all occurrences code fix... 正在計算修正所有出現程式碼修正之處... @@ -4300,16 +4155,6 @@ Do you want to continue? 解決方案 - - TODO: dispose managed state (managed objects) - TODO: 處置受控狀態 (受控物件) - - - - TODO: set large fields to null - TODO: 將大型欄位設為 Null - - Compiler 編譯器 @@ -4660,11 +4505,6 @@ This version used in: {2} 安裝 '{0}' 版 - - Generate variable '{0}' - 產生變數 '{0}' - - Classes 類別 diff --git a/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs b/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs index 954848cdf0828..152ef7427e734 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs @@ -68,13 +68,6 @@ public Test() [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] public new string FixedCode { set => base.FixedCode = value; } -#if !CODE_STYLE - internal CodeActionOptionsProvider CodeActionOptions - { - get => _sharedState.CodeActionOptions; - set => _sharedState.CodeActionOptions = value; - } -#endif /// public string? EditorConfig { @@ -109,35 +102,6 @@ protected override CompilationOptions CreateCompilationOptions() return compilationOptions.WithSpecificDiagnosticOptions(compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings)); } -#if !CODE_STYLE - protected override CodeFixContext CreateCodeFixContext(Document document, TextSpan span, ImmutableArray diagnostics, Action> registerCodeFix, CancellationToken cancellationToken) - => new(document, span, diagnostics, registerCodeFix, _sharedState.CodeActionOptions, cancellationToken); - - protected override FixAllContext CreateFixAllContext( - Document? document, - TextSpan? diagnosticSpan, - Project project, - CodeFixProvider codeFixProvider, - FixAllScope scope, - string? codeActionEquivalenceKey, - IEnumerable diagnosticIds, - DiagnosticSeverity minimumSeverity, - FixAllContext.DiagnosticProvider fixAllDiagnosticProvider, - CancellationToken cancellationToken) - => new(new FixAllState( - fixAllProvider: NoOpFixAllProvider.Instance, - diagnosticSpan, - document, - project, - codeFixProvider, - scope, - codeActionEquivalenceKey, - diagnosticIds, - fixAllDiagnosticProvider, - _sharedState.CodeActionOptions), - CodeAnalysisProgress.None, cancellationToken); -#endif - protected override Diagnostic? TrySelectDiagnosticToFix(ImmutableArray fixableDiagnostics) { return DiagnosticSelector?.Invoke(fixableDiagnostics) diff --git a/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2.cs b/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2.cs index f84a43aa103a1..d534c9087c602 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Testing; @@ -36,7 +37,8 @@ public static void VerifyStandardProperty(AnalyzerProperty property) => CodeFixVerifierHelper.VerifyStandardProperty(new TAnalyzer(), property); /// - public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) + public static async Task VerifyAnalyzerAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string source, params DiagnosticResult[] expected) { var test = new Test { @@ -48,7 +50,9 @@ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticRes } /// - public static async Task VerifyCodeFixAsync(string source, string fixedSource) + public static async Task VerifyCodeFixAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string source, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string fixedSource) => await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); /// diff --git a/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeRefactoringVerifier`1+Test.cs b/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeRefactoringVerifier`1+Test.cs index d73b99c5dc1d6..6fd4da954a54d 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeRefactoringVerifier`1+Test.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActions/CSharpCodeRefactoringVerifier`1+Test.cs @@ -66,14 +66,6 @@ public Test() [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] public new string FixedCode { set => base.FixedCode = value; } -#if !CODE_STYLE - internal CodeActionOptionsProvider CodeActionOptions - { - get => _sharedState.CodeActionOptions; - set => _sharedState.CodeActionOptions = value; - } -#endif - /// public string? EditorConfig { @@ -118,9 +110,6 @@ protected override CompilationOptions CreateCompilationOptions() } #if !CODE_STYLE - protected override CodeRefactoringContext CreateCodeRefactoringContext(Document document, TextSpan span, Action registerRefactoring, CancellationToken cancellationToken) - => new CodeRefactoringContext(document, span, (action, textSpan) => registerRefactoring(action), _sharedState.CodeActionOptions, cancellationToken); - /// /// The we want this test to run in. Defaults to if unspecified. /// diff --git a/src/Features/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs b/src/Features/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs index a22caa9cf08c8..7a8ddc3c69d2e 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActions/SharedVerifierState.cs @@ -47,9 +47,6 @@ public SharedVerifierState(AnalyzerTest test, string defaultFil /// internal OptionsCollection Options { get; } -#if !CODE_STYLE - internal CodeActionOptionsProvider CodeActionOptions { get; set; } = CodeAnalysis.CodeActions.CodeActionOptions.DefaultProvider; -#endif internal void Apply() { var analyzerConfigSource = CodeFixVerifierHelper.ConvertOptionsToAnalyzerConfig(_defaultFileExt, EditorConfig, Options); diff --git a/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeFixVerifier`2+Test.cs b/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeFixVerifier`2+Test.cs index 688a1a0267fb7..8d6a064c5614a 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeFixVerifier`2+Test.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeFixVerifier`2+Test.cs @@ -87,11 +87,6 @@ protected override ParseOptions CreateParseOptions() return parseOptions.WithLanguageVersion(LanguageVersion); } -#if !CODE_STYLE - protected override CodeFixContext CreateCodeFixContext(Document document, TextSpan span, ImmutableArray diagnostics, Action> registerCodeFix, CancellationToken cancellationToken) - => new(document, span, diagnostics, registerCodeFix, _sharedState.CodeActionOptions, cancellationToken); -#endif - protected override Diagnostic? TrySelectDiagnosticToFix(ImmutableArray fixableDiagnostics) { return DiagnosticSelector?.Invoke(fixableDiagnostics) diff --git a/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1+Test.cs b/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1+Test.cs index 184faebe03e87..04e8e02286e81 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1+Test.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1+Test.cs @@ -97,9 +97,6 @@ protected override ParseOptions CreateParseOptions() } #if !CODE_STYLE - protected override CodeRefactoringContext CreateCodeRefactoringContext(Document document, TextSpan span, Action registerRefactoring, CancellationToken cancellationToken) - => new CodeRefactoringContext(document, span, (action, textSpan) => registerRefactoring(action), _sharedState.CodeActionOptions, cancellationToken); - /// /// The we want this test to run in. Defaults to /// if unspecified. diff --git a/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionOrUserDiagnosticTest_NoEditor.cs b/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionOrUserDiagnosticTest_NoEditor.cs index 7d7a155a89239..90e3da1b21eb3 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionOrUserDiagnosticTest_NoEditor.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionOrUserDiagnosticTest_NoEditor.cs @@ -411,7 +411,6 @@ internal Task TestInRegularAndScriptAsync( CodeActionPriority? priority = null, CompilationOptions compilationOptions = null, OptionsCollectionAlias options = null, - OptionsCollectionAlias globalOptions = null, object fixProviderData = null, ParseOptions parseOptions = null, string title = null, @@ -419,7 +418,7 @@ internal Task TestInRegularAndScriptAsync( { return TestInRegularAndScript1Async( initialMarkup, expectedMarkup, - new TestParameters(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, title: title, testHost: testHost)); + new TestParameters(parseOptions, compilationOptions, options, globalOptions: null, fixProviderData, index, priority, title: title, testHost: testHost)); } internal Task TestInRegularAndScript1Async( diff --git a/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionTest_NoEditor.cs b/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionTest_NoEditor.cs index 2fafd2e1e644e..6bdc87a7bb3f0 100644 --- a/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionTest_NoEditor.cs +++ b/src/Features/DiagnosticsTestUtilities/CodeActionsLegacy/AbstractCodeActionTest_NoEditor.cs @@ -62,7 +62,7 @@ protected abstract CodeRefactoringProvider CreateCodeRefactoringProvider( return (actions, actionToInvoke); var fixAllCodeAction = await GetFixAllFixAsync(actionToInvoke, - refactoring.Provider, refactoring.CodeActionOptionsProvider, document, span, fixAllScope.Value).ConfigureAwait(false); + refactoring.Provider, document, span, fixAllScope.Value).ConfigureAwait(false); if (fixAllCodeAction == null) return ([], null); @@ -72,7 +72,6 @@ protected abstract CodeRefactoringProvider CreateCodeRefactoringProvider( private static async Task GetFixAllFixAsync( CodeAction originalCodeAction, CodeRefactoringProvider provider, - CodeActionOptionsProvider optionsProvider, Document document, TextSpan selectionSpan, FixAllScope scope) @@ -81,7 +80,7 @@ private static async Task GetFixAllFixAsync( if (fixAllProvider == null || !fixAllProvider.GetSupportedFixAllScopes().Contains(scope)) return null; - var fixAllState = new FixAllState(fixAllProvider, document, selectionSpan, provider, optionsProvider, scope, originalCodeAction); + var fixAllState = new FixAllState(fixAllProvider, document, selectionSpan, provider, scope, originalCodeAction); var fixAllContext = new FixAllContext(fixAllState, CodeAnalysisProgress.None, CancellationToken.None); return await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false); } @@ -106,10 +105,9 @@ internal async Task GetCodeRefactoringAsync( using var _ = ArrayBuilder<(CodeAction, TextSpan?)>.GetInstance(out var actions); - var codeActionOptionsProvider = CodeActionOptions.DefaultProvider; - var context = new CodeRefactoringContext(document, selectedOrAnnotatedSpan, (a, t) => actions.Add((a, t)), codeActionOptionsProvider, CancellationToken.None); + var context = new CodeRefactoringContext(document, selectedOrAnnotatedSpan, (a, t) => actions.Add((a, t)), CancellationToken.None); await provider.ComputeRefactoringsAsync(context); - var result = actions.Count > 0 ? new CodeRefactoring(provider, actions.ToImmutable(), FixAllProviderInfo.Create(provider), codeActionOptionsProvider) : null; + var result = actions.Count > 0 ? new CodeRefactoring(provider, actions.ToImmutable(), FixAllProviderInfo.Create(provider)) : null; return result; } diff --git a/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs b/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs index edb6800439dd1..73b9f96d3a192 100644 --- a/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs +++ b/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs @@ -69,7 +69,7 @@ protected async Task TestPragmaOrAttributeAsync( var (analyzer, fixer) = CreateDiagnosticProviderAndFixer(workspace); var analyzerReference = new AnalyzerImageReference(ImmutableArray.Create(analyzer)); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); var document = workspace.CurrentSolution.Projects.Single().Documents.Single(); var root = document.GetSyntaxRootAsync().GetAwaiter().GetResult(); diff --git a/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_NoEditor.cs b/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_NoEditor.cs index 2a8744972f341..24c875aa18842 100644 --- a/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_NoEditor.cs +++ b/src/Features/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest_NoEditor.cs @@ -163,7 +163,6 @@ protected static Document GetDocumentAndSelectSpan(TestWorkspace workspace, out diagnostic.Location.SourceSpan, ImmutableArray.Create(diagnostic), (a, d) => fixes.Add(new CodeFix(document.Project, a, d)), - testDriver.FallbackOptions, CancellationToken.None); await fixer.RegisterCodeFixesAsync(context); @@ -187,7 +186,7 @@ protected static Document GetDocumentAndSelectSpan(TestWorkspace workspace, out var fixAllState = GetFixAllState( fixAllProvider, diagnostics, fixer, testDriver, document, - scope.Value, equivalenceKey, testDriver.FallbackOptions); + scope.Value, equivalenceKey); var fixAllContext = new FixAllContext(fixAllState, CodeAnalysisProgress.None, CancellationToken.None); var fixAllFix = await fixAllProvider.GetFixAsync(fixAllContext); @@ -203,8 +202,7 @@ private static FixAllState GetFixAllState( TestDiagnosticAnalyzerDriver testDriver, Document document, FixAllScope scope, - string equivalenceKey, - CodeActionOptionsProvider optionsProvider) + string equivalenceKey) { Assert.NotEmpty(diagnostics); @@ -212,7 +210,7 @@ private static FixAllState GetFixAllState( { // Bulk fixing diagnostics in selected scope. var diagnosticsToFix = ImmutableDictionary.CreateRange([KeyValuePairUtil.Create(document, diagnostics.ToImmutableArray())]); - return FixAllState.Create(fixAllProvider, diagnosticsToFix, fixer, equivalenceKey, optionsProvider); + return FixAllState.Create(fixAllProvider, diagnosticsToFix, fixer, equivalenceKey); } var diagnostic = diagnostics.First(); @@ -220,8 +218,8 @@ private static FixAllState GetFixAllState( var fixAllDiagnosticProvider = new FixAllDiagnosticProvider(testDriver, diagnosticIds); return diagnostic.Location.IsInSource - ? new FixAllState(fixAllProvider, diagnostic.Location.SourceSpan, document, document.Project, fixer, scope, equivalenceKey, diagnosticIds, fixAllDiagnosticProvider, optionsProvider) - : new FixAllState(fixAllProvider, diagnosticSpan: null, document: null, document.Project, fixer, scope, equivalenceKey, diagnosticIds, fixAllDiagnosticProvider, optionsProvider); + ? new FixAllState(fixAllProvider, diagnostic.Location.SourceSpan, document, document.Project, fixer, scope, equivalenceKey, diagnosticIds, fixAllDiagnosticProvider) + : new FixAllState(fixAllProvider, diagnosticSpan: null, document: null, document.Project, fixer, scope, equivalenceKey, diagnosticIds, fixAllDiagnosticProvider); } private protected Task TestActionCountInAllFixesAsync( diff --git a/src/Features/DiagnosticsTestUtilities/Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities.csproj b/src/Features/DiagnosticsTestUtilities/Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities.csproj index bf970ecc5d708..7562820dd9d50 100644 --- a/src/Features/DiagnosticsTestUtilities/Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities.csproj +++ b/src/Features/DiagnosticsTestUtilities/Microsoft.CodeAnalysis.Features.DiagnosticsTests.Utilities.csproj @@ -8,7 +8,7 @@ true false true - true + true diff --git a/src/Features/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs b/src/Features/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs index c3f3ae37a82d2..93af5aa56d894 100644 --- a/src/Features/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs +++ b/src/Features/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs @@ -19,15 +19,14 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.NamingStyles internal sealed class NamingStylesTestOptionSets { private readonly string _languageName; - private readonly OptionKey2 _optionKey; public NamingStylesTestOptionSets(string languageName) { _languageName = languageName; - _optionKey = new OptionKey2(NamingStyleOptions.NamingPreferences, languageName); + OptionKey = new OptionKey2(NamingStyleOptions.NamingPreferences, languageName); } - public OptionKey2 OptionKey => _optionKey; + public OptionKey2 OptionKey { get; } internal OptionsCollection MergeStyles(OptionsCollection first, OptionsCollection second) { diff --git a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreCSharpVirtualCharService.cs b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreCSharpVirtualCharService.cs index e805ffd76f46d..94c9102be13e7 100644 --- a/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreCSharpVirtualCharService.cs +++ b/src/Features/ExternalAccess/AspNetCore/EmbeddedLanguages/AspNetCoreCSharpVirtualCharService.cs @@ -11,9 +11,6 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.EmbeddedLanguages { internal sealed class AspNetCoreCSharpVirtualCharService { - private static readonly AspNetCoreCSharpVirtualCharService _instance = - new AspNetCoreCSharpVirtualCharService(CSharpVirtualCharService.Instance); - private readonly IVirtualCharService _virtualCharService; private AspNetCoreCSharpVirtualCharService(IVirtualCharService virtualCharService) @@ -22,7 +19,7 @@ private AspNetCoreCSharpVirtualCharService(IVirtualCharService virtualCharServic } /// - public static AspNetCoreCSharpVirtualCharService Instance => _instance; + public static AspNetCoreCSharpVirtualCharService Instance { get; } = new AspNetCoreCSharpVirtualCharService(CSharpVirtualCharService.Instance); /// public AspNetCoreVirtualCharSequence TryConvertToVirtualChars(SyntaxToken token) diff --git a/src/Features/ExternalAccess/AspNetCore/Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.csproj b/src/Features/ExternalAccess/AspNetCore/Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.csproj index 05c425bd0b5bc..21cb2a3586cd5 100644 --- a/src/Features/ExternalAccess/AspNetCore/Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.csproj +++ b/src/Features/ExternalAccess/AspNetCore/Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.csproj @@ -13,7 +13,7 @@ https://github.com/dotnet/aspnetcore - false + false diff --git a/src/Features/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs b/src/Features/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs index b1ece57d5dc27..9ad0bf9fef5f0 100644 --- a/src/Features/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs +++ b/src/Features/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeActionOptions.cs @@ -2,33 +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 Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeCleanup; +using System; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ImplementType; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Options; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.ImplementType; -using Microsoft.CodeAnalysis.SymbolSearch; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.CodeActions { internal readonly record struct OmniSharpCodeActionOptions( OmniSharpImplementTypeOptions ImplementTypeOptions, - OmniSharpLineFormattingOptions LineFormattingOptions) - { -#pragma warning disable IDE0060 // Remove unused parameter - internal CodeActionOptions GetCodeActionOptions(LanguageServices languageServices) -#pragma warning restore IDE0060 // Remove unused parameter - { - return CodeActionOptions.Default with - { - ImplementTypeOptions = new() - { - InsertionBehavior = (ImplementTypeInsertionBehavior)ImplementTypeOptions.InsertionBehavior, - PropertyGenerationBehavior = (ImplementTypePropertyGenerationBehavior)ImplementTypeOptions.PropertyGenerationBehavior - } - }; - } - } + OmniSharpLineFormattingOptions LineFormattingOptions); } diff --git a/src/Features/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs b/src/Features/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs index a1b17e290d85e..4e7271697ec57 100644 --- a/src/Features/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs +++ b/src/Features/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs @@ -8,7 +8,6 @@ using System.Threading; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.CodeActions @@ -20,17 +19,21 @@ public static CodeFixContext CreateCodeFixContext( TextSpan span, ImmutableArray diagnostics, Action> registerCodeFix, +#pragma warning disable IDE0060 // Remove unused parameter OmniSharpCodeActionOptions options, +#pragma warning restore IDE0060 // Remove unused parameter CancellationToken cancellationToken) - => new(document, span, diagnostics, registerCodeFix, new DelegatingCodeActionOptionsProvider(options.GetCodeActionOptions), cancellationToken); + => new(document, span, diagnostics, registerCodeFix, cancellationToken); public static CodeAnalysis.CodeRefactorings.CodeRefactoringContext CreateCodeRefactoringContext( Document document, TextSpan span, Action registerRefactoring, +#pragma warning disable IDE0060 // Remove unused parameter OmniSharpCodeActionOptions options, +#pragma warning restore IDE0060 // Remove unused parameter CancellationToken cancellationToken) - => new(document, span, registerRefactoring, new DelegatingCodeActionOptionsProvider(options.GetCodeActionOptions), cancellationToken); + => new(document, span, registerRefactoring, cancellationToken); public static FixAllContext CreateFixAllContext( Document? document, @@ -41,7 +44,9 @@ public static FixAllContext CreateFixAllContext( string? codeActionEquivalenceKey, IEnumerable diagnosticIds, FixAllContext.DiagnosticProvider fixAllDiagnosticProvider, +#pragma warning disable IDE0060 // Remove unused parameter Func optionsProvider, +#pragma warning restore IDE0060 // Remove unused parameter CancellationToken cancellationToken) => new(new FixAllState( fixAllProvider: NoOpFixAllProvider.Instance, @@ -52,8 +57,7 @@ public static FixAllContext CreateFixAllContext( scope, codeActionEquivalenceKey, diagnosticIds, - fixAllDiagnosticProvider, - new DelegatingCodeActionOptionsProvider(languageServices => optionsProvider(languageServices.Language).GetCodeActionOptions(languageServices))), + fixAllDiagnosticProvider), CodeAnalysisProgress.None, cancellationToken); } } diff --git a/src/Features/Lsif/Directory.Build.props b/src/Features/Lsif/Directory.Build.props index 6eef643958f56..9dd0ddea9df26 100644 --- a/src/Features/Lsif/Directory.Build.props +++ b/src/Features/Lsif/Directory.Build.props @@ -1,6 +1,6 @@ - true + true diff --git a/src/Features/Lsif/Generator/Generator.cs b/src/Features/Lsif/Generator/Generator.cs index 57dfd14b41197..a4b485bd593e0 100644 --- a/src/Features/Lsif/Generator/Generator.cs +++ b/src/Features/Lsif/Generator/Generator.cs @@ -210,9 +210,9 @@ public async Task GenerateForProjectAsync( // use this document can benefit from that single shared model. var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken); - var (uri, contentBase64Encoded) = await GetUriAndContentAsync(document, cancellationToken); + var contentBase64Encoded = await GetBase64EncodedContentAsync(document, cancellationToken); - var documentVertex = new Graph.LsifDocument(uri, GetLanguageKind(semanticModel.Language), contentBase64Encoded, idFactory); + var documentVertex = new Graph.LsifDocument(document.GetURI(), GetLanguageKind(semanticModel.Language), contentBase64Encoded, idFactory); lsifJsonWriter.Write(documentVertex); lsifJsonWriter.Write(new Event(Event.EventKind.Begin, documentVertex.GetId(), idFactory)); @@ -443,32 +443,21 @@ private static (DefinitionRangeTag tag, TextSpan fullRange)? CreateRangeTagAndCo return (new DefinitionRangeTag(syntaxToken.Text, symbolKind, fullRange), fullRangeSpan); } - private static async Task<(Uri uri, string? contentBase64Encoded)> GetUriAndContentAsync( + private static async Task GetBase64EncodedContentAsync( Document document, CancellationToken cancellationToken) { - Contract.ThrowIfNull(document.FilePath); - - string? contentBase64Encoded = null; - Uri uri; - if (document is SourceGeneratedDocument) { var text = await document.GetValueTextAsync(cancellationToken); // We always use UTF-8 encoding when writing out file contents, as that's expected by LSIF implementations. // TODO: when we move to .NET Core, is there a way to reduce allocations here? - contentBase64Encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(text.ToString())); - - // There is a triple slash here, so the "host" portion of the URI is empty, similar to - // how file URIs work. - uri = ProtocolConversions.CreateUriFromSourceGeneratedFilePath(document.FilePath); + return Convert.ToBase64String(Encoding.UTF8.GetBytes(text.ToString())); } else { - uri = ProtocolConversions.CreateAbsoluteUri(document.FilePath); + return null; } - - return (uri, contentBase64Encoded); } private static async Task GenerateSemanticTokensAsync( diff --git a/src/Features/Lsif/Generator/ResultSetTracking/IResultSetTrackerExtensions.cs b/src/Features/Lsif/Generator/ResultSetTracking/IResultSetTrackerExtensions.cs index 2f39eae80379d..c2859c74cc92e 100644 --- a/src/Features/Lsif/Generator/ResultSetTracking/IResultSetTrackerExtensions.cs +++ b/src/Features/Lsif/Generator/ResultSetTracking/IResultSetTrackerExtensions.cs @@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Graph; using Roslyn.LanguageServer.Protocol; +using Moniker = Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Graph.Moniker; namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.ResultSetTracking { diff --git a/src/Features/Lsif/GeneratorTest/HoverTests.vb b/src/Features/Lsif/GeneratorTest/HoverTests.vb index 108e3ff2ce181..ea85e9660d473 100644 --- a/src/Features/Lsif/GeneratorTest/HoverTests.vb +++ b/src/Features/Lsif/GeneratorTest/HoverTests.vb @@ -36,7 +36,7 @@ class C Dim rangeVertex = Await lsif.GetSelectedRangeAsync() Dim resultSetVertex = lsif.GetLinkedVertices(Of Graph.ResultSet)(rangeVertex, "next").Single() Dim hoverVertex = lsif.GetLinkedVertices(Of Graph.HoverResult)(resultSetVertex, Methods.TextDocumentHoverName).SingleOrDefault() - Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Value.Fourth, MarkupContent) + Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Fourth, MarkupContent) Dim expectedHoverContents As String Select Case code @@ -110,7 +110,7 @@ class C Dim rangeVertex = Await lsif.GetSelectedRangeAsync() Dim resultSetVertex = lsif.GetLinkedVertices(Of Graph.ResultSet)(rangeVertex, "next").Single() Dim hoverVertex = lsif.GetLinkedVertices(Of Graph.HoverResult)(resultSetVertex, Methods.TextDocumentHoverName).SingleOrDefault() - Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Value.Fourth, MarkupContent) + Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Fourth, MarkupContent) Dim expectedHoverContents As String Select Case code @@ -196,7 +196,7 @@ void C.M() End If Next - Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Value.Fourth, MarkupContent) + Dim hoverMarkupContent = DirectCast(hoverVertex.Result.Contents.Fourth, MarkupContent) Assert.Equal(MarkupKind.Markdown, hoverMarkupContent.Kind) Assert.Equal("```csharp class System.String diff --git a/src/Features/Lsif/GeneratorTest/OutputFormatTests.vb b/src/Features/Lsif/GeneratorTest/OutputFormatTests.vb index 5b01bbd5725c8..bf8c20bd1e9ba 100644 --- a/src/Features/Lsif/GeneratorTest/OutputFormatTests.vb +++ b/src/Features/Lsif/GeneratorTest/OutputFormatTests.vb @@ -27,7 +27,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests , openDocuments:=False, composition:=TestLsifOutput.TestComposition), jsonWriter) AssertEx.EqualOrDiff( -"{""hoverProvider"":true,""declarationProvider"":false,""definitionProvider"":true,""referencesProvider"":true,""typeDefinitionProvider"":false,""documentSymbolProvider"":true,""foldingRangeProvider"":true,""diagnosticProvider"":false,""semanticTokensProvider"":{""tokenTypes"":[""namespace"",""type"",""class"",""enum"",""interface"",""struct"",""typeParameter"",""parameter"",""variable"",""property"",""enumMember"",""event"",""function"",""method"",""macro"",""keyword"",""modifier"",""comment"",""string"",""number"",""regexp"",""operator"",""class name"",""constant name"",""delegate name"",""enum member name"",""enum name"",""event name"",""excluded code"",""extension method name"",""field name"",""interface name"",""json - array"",""json - comment"",""json - constructor name"",""json - keyword"",""json - number"",""json - object"",""json - operator"",""json - property name"",""json - punctuation"",""json - string"",""json - text"",""keyword - control"",""label name"",""local name"",""method name"",""module name"",""namespace name"",""operator - overloaded"",""parameter name"",""preprocessor keyword"",""preprocessor text"",""property name"",""punctuation"",""record class name"",""record struct name"",""regex - alternation"",""regex - anchor"",""regex - character class"",""regex - comment"",""regex - grouping"",""regex - other escape"",""regex - quantifier"",""regex - self escaped character"",""regex - text"",""roslyn test code markdown"",""string - escape character"",""string - verbatim"",""struct name"",""text"",""type parameter name"",""whitespace"",""xml doc comment - attribute name"",""xml doc comment - attribute quotes"",""xml doc comment - attribute value"",""xml doc comment - cdata section"",""xml doc comment - comment"",""xml doc comment - delimiter"",""xml doc comment - entity reference"",""xml doc comment - name"",""xml doc comment - processing instruction"",""xml doc comment - text"",""xml literal - attribute name"",""xml literal - attribute quotes"",""xml literal - attribute value"",""xml literal - cdata section"",""xml literal - comment"",""xml literal - delimiter"",""xml literal - embedded expression"",""xml literal - entity reference"",""xml literal - name"",""xml literal - processing instruction"",""xml literal - text""],""tokenModifiers"":[""static"",""deprecated""]},""id"":1,""type"":""vertex"",""label"":""capabilities""} +"{""hoverProvider"":true,""declarationProvider"":false,""definitionProvider"":true,""referencesProvider"":true,""typeDefinitionProvider"":false,""documentSymbolProvider"":true,""foldingRangeProvider"":true,""diagnosticProvider"":false,""semanticTokensProvider"":{""tokenTypes"":[""namespace"",""type"",""class"",""enum"",""interface"",""struct"",""typeParameter"",""parameter"",""variable"",""property"",""enumMember"",""event"",""function"",""method"",""macro"",""keyword"",""modifier"",""comment"",""string"",""number"",""regexp"",""operator"",""decorator"",""class name"",""constant name"",""delegate name"",""enum member name"",""enum name"",""event name"",""excluded code"",""extension method name"",""field name"",""interface name"",""json - array"",""json - comment"",""json - constructor name"",""json - keyword"",""json - number"",""json - object"",""json - operator"",""json - property name"",""json - punctuation"",""json - string"",""json - text"",""keyword - control"",""label name"",""local name"",""method name"",""module name"",""namespace name"",""operator - overloaded"",""parameter name"",""preprocessor keyword"",""preprocessor text"",""property name"",""punctuation"",""record class name"",""record struct name"",""regex - alternation"",""regex - anchor"",""regex - character class"",""regex - comment"",""regex - grouping"",""regex - other escape"",""regex - quantifier"",""regex - self escaped character"",""regex - text"",""roslyn test code markdown"",""string - escape character"",""string - verbatim"",""struct name"",""text"",""type parameter name"",""whitespace"",""xml doc comment - attribute name"",""xml doc comment - attribute quotes"",""xml doc comment - attribute value"",""xml doc comment - cdata section"",""xml doc comment - comment"",""xml doc comment - delimiter"",""xml doc comment - entity reference"",""xml doc comment - name"",""xml doc comment - processing instruction"",""xml doc comment - text"",""xml literal - attribute name"",""xml literal - attribute quotes"",""xml literal - attribute value"",""xml literal - cdata section"",""xml literal - comment"",""xml literal - delimiter"",""xml literal - embedded expression"",""xml literal - entity reference"",""xml literal - name"",""xml literal - processing instruction"",""xml literal - text""],""tokenModifiers"":[""static"",""deprecated""]},""id"":1,""type"":""vertex"",""label"":""capabilities""} {""kind"":""csharp"",""resource"":""file:///Z:/%EE%89%9B/TestProject.csproj"",""name"":""TestProject"",""id"":2,""type"":""vertex"",""label"":""project""} {""kind"":""begin"",""scope"":""project"",""data"":2,""id"":3,""type"":""vertex"",""label"":""$event""} {""uri"":""file:///Z:/%EE%89%9B/a.cs"",""languageId"":""csharp"",""id"":4,""type"":""vertex"",""label"":""document""} @@ -94,6 +94,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests ""number"", ""regexp"", ""operator"", + ""decorator"", ""class name"", ""constant name"", ""delegate name"", diff --git a/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb b/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb index d0fa45dd8cfed..3b7f729aaf3f5 100644 --- a/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb +++ b/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb @@ -4,8 +4,7 @@ Imports System.IO Imports System.Text -Imports System.Text.Json.Nodes -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.LanguageServer Imports Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Writing Imports Microsoft.CodeAnalysis.Test.Utilities Imports Roslyn.Test.Utilities @@ -58,7 +57,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests Dim contents = Encoding.UTF8.GetString(Convert.FromBase64String(contentBase64Encoded)) Dim compilation = Await workspace.CurrentSolution.Projects.Single().GetCompilationAsync() - Dim tree = Assert.Single(compilation.SyntaxTrees, Function(t) "source-generated:///" + t.FilePath.Replace("\"c, "/"c) = generatedDocumentVertex.Uri.OriginalString) + Dim tree = Assert.Single(compilation.SyntaxTrees, Function(t) generatedDocumentVertex.Uri.OriginalString.Contains(Path.GetFileName(t.FilePath))) Assert.Equal(tree.GetText().ToString(), contents) Next @@ -77,8 +76,9 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests Await TestLsifOutput.GenerateForWorkspaceAsync(workspace, New LineModeLsifJsonWriter(stringWriter)) Dim generatedDocument = Assert.Single(Await workspace.CurrentSolution.Projects.Single().GetSourceGeneratedDocumentsAsync()) + Dim uri = SourceGeneratedDocumentUri.Create(generatedDocument.Identity) Dim outputText = stringWriter.ToString() - Assert.Contains($"""uri"":""source-generated:///{generatedDocument.FilePath.Replace("\", "/")}""", outputText) + Assert.Contains(uri.AbsoluteUri, outputText) End Function End Class End Namespace diff --git a/src/Features/Lsif/GeneratorTest/SemanticTokensTests.vb b/src/Features/Lsif/GeneratorTest/SemanticTokensTests.vb index ce1bdcd6704e8..445cdebfd6a2f 100644 --- a/src/Features/Lsif/GeneratorTest/SemanticTokensTests.vb +++ b/src/Features/Lsif/GeneratorTest/SemanticTokensTests.vb @@ -16,9 +16,9 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests - - - + + + Public Async Function TestSemanticTokensData(code As String, expectedTokens As String) As Task ' This test performs LSIF specific validation of the semantic tokens output. As of this writing ' this feature is based on the same code path used to generate semantic tokens information in LSP diff --git a/src/Features/Test/EditAndContinue/ActiveStatementsMapTests.cs b/src/Features/Test/EditAndContinue/ActiveStatementsMapTests.cs index 8f2b12dc7db8c..d8599d06b4fd2 100644 --- a/src/Features/Test/EditAndContinue/ActiveStatementsMapTests.cs +++ b/src/Features/Test/EditAndContinue/ActiveStatementsMapTests.cs @@ -142,8 +142,8 @@ ManagedActiveStatementDebugInfo CreateInfo(int startLine, int startColumn, int e var oldSpans = await map.GetOldActiveStatementsAsync(analyzer, document, CancellationToken.None); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "[48..52) -> (1,0)-(1,4) #6", "[55..59) -> (2,0)-(2,4) #3", "[62..66) -> (3,0)-(3,4) #0", @@ -151,7 +151,7 @@ ManagedActiveStatementDebugInfo CreateInfo(int startLine, int startColumn, int e "[120..124) -> (4,0)-(4,4) #2", "[127..131) -> (5,0)-(5,4) #4", "[134..138) -> (6,0)-(6,4) #1" - }, oldSpans.Select(s => $"{s.UnmappedSpan} -> {s.Statement.Span} #{s.Statement.Id.Ordinal}")); + ], oldSpans.Select(s => $"{s.UnmappedSpan} -> {s.Statement.Span} #{s.Statement.Id.Ordinal}")); } [Fact] @@ -248,12 +248,12 @@ ManagedActiveStatementDebugInfo CreateInfo(int startLine, int startColumn, int e var map = ActiveStatementsMap.Create(debugInfos, remapping.ToImmutable()); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "(7,16)-(15,9)", "(9,17)-(9,18)", "(20,8)-(20,13)" - }, map.DocumentPathMap["a.cs"].OrderBy(s => s.Span.Start.Line).Select(s => $"{s.Span}")); + ], map.DocumentPathMap["a.cs"].OrderBy(s => s.Span.Start.Line).Select(s => $"{s.Span}")); void CreateRegion(int ordinal, SourceFileSpan oldSpan, SourceFileSpan newSpan) => remapping.Add(debugInfos[ordinal].ActiveInstruction.Method, ImmutableArray.Create(new NonRemappableRegion(oldSpan, newSpan, isExceptionRegion: false))); diff --git a/src/Features/Test/EditAndContinue/EditAndContinueMethodDebugInfoReaderTests.cs b/src/Features/Test/EditAndContinue/EditAndContinueMethodDebugInfoReaderTests.cs index 1d2c092917736..0b270846e28b9 100644 --- a/src/Features/Test/EditAndContinue/EditAndContinueMethodDebugInfoReaderTests.cs +++ b/src/Features/Test/EditAndContinue/EditAndContinueMethodDebugInfoReaderTests.cs @@ -86,9 +86,9 @@ public static void Main() // Main method var debugInfo = reader.GetDebugInfo(MetadataTokens.MethodDefinitionHandle(5)); Assert.Equal(0, debugInfo.GetMethodOrdinal()); - AssertEx.Equal(new[] { "Offset=0 Ordinal=0 Kind=LambdaDisplayClass", "Offset=33 Ordinal=0 Kind=UserDefined" }, debugInfo.InspectLocalSlots()); - AssertEx.Equal(new[] { "Offset=43 Id=0#0 Closure=0" }, debugInfo.InspectLambdas()); - AssertEx.Equal(new[] { "Offset=0 Id=0#0" }, debugInfo.InspectClosures()); + AssertEx.Equal(["Offset=0 Ordinal=0 Kind=LambdaDisplayClass", "Offset=33 Ordinal=0 Kind=UserDefined"], debugInfo.InspectLocalSlots()); + AssertEx.Equal(["Offset=43 Id=0#0 Closure=0"], debugInfo.InspectLambdas()); + AssertEx.Equal(["Offset=0 Id=0#0"], debugInfo.InspectClosures()); var localSig = reader.GetLocalSignature(MetadataTokens.MethodDefinitionHandle(5)); Assert.Equal(MetadataTokens.StandaloneSignatureHandle(1), localSig); diff --git a/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index c87e407278078..06b5bdba4ec25 100644 --- a/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -18,6 +18,7 @@ using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; @@ -68,7 +69,7 @@ public async Task StartDebuggingSession_CapturingDocuments(bool captureAllDocume var sourceTreeC1 = SyntaxFactory.ParseSyntaxTree(SourceText.From(sourceBytesC1, sourceBytesC1.Length, encodingC, SourceHashAlgorithm.Sha1), TestOptions.Regular, sourceFileC.Path); // E is not included in the compilation: - var compilation = CSharpTestBase.CreateCompilation(new[] { sourceTreeA1, sourceTreeB1, sourceTreeC1 }, options: TestOptions.DebugDll, targetFramework: DefaultTargetFramework, assemblyName: "P"); + var compilation = CSharpTestBase.CreateCompilation([sourceTreeA1, sourceTreeB1, sourceTreeC1], options: TestOptions.DebugDll, targetFramework: DefaultTargetFramework, assemblyName: "P"); EmitLibrary(compilation); // change content of B on disk: @@ -138,11 +139,11 @@ public async Task StartDebuggingSession_CapturingDocuments(bool captureAllDocume var debuggingSession = service.GetTestAccessor().GetDebuggingSession(sessionId); var matchingDocuments = debuggingSession.LastCommittedSolution.Test_GetDocumentStates(); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "(A, MatchesBuildOutput)", "(C, MatchesBuildOutput)" - }, matchingDocuments.Select(e => (solution.GetDocument(e.id).Name, e.state)).OrderBy(e => e.Name).Select(e => e.ToString())); + ], matchingDocuments.Select(e => (solution.GetDocument(e.id).Name, e.state)).OrderBy(e => e.Name).Select(e => e.ToString())); // change content of B on disk again: sourceFileB.WriteAllText(sourceB3, encodingB); @@ -219,10 +220,10 @@ public async Task DifferentDocumentWithSameContent() EndDebuggingSession(debuggingSession); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1" - }, _telemetryLog); + ], _telemetryLog); } [Theory, CombinatorialData] @@ -287,10 +288,10 @@ public async Task DesignTimeOnlyDocument() EndDebuggingSession(debuggingSession); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1" - }, _telemetryLog); + ], _telemetryLog); } [Fact] @@ -349,7 +350,7 @@ public async Task DesignTimeOnlyDocument_Wpf([CombinatorialValues(LanguageNames. using var _ = CreateWorkspace(out var solution, out var service); - // The workspace starts with + // The workspace starts with // [added == false] a version of the source that's not updated with the output of single file generator (or design-time build): // [added == true] without the output of single file generator (design-time build has not completed) @@ -497,21 +498,21 @@ public async Task ErrorReadingModuleFile(bool breakMode) if (breakMode) { - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=3", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges={6A6F7270-0000-4000-8000-000000000000}", "Debugging_EncSession_EditSession_EmitDeltaErrorId: SessionId=1|EditSessionId=2|ErrorId=ENC1001" - }, _telemetryLog); + ], _telemetryLog); } else { - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=1", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges={6A6F7270-0000-4000-8000-000000000000}", "Debugging_EncSession_EditSession_EmitDeltaErrorId: SessionId=1|EditSessionId=2|ErrorId=ENC1001" - }, _telemetryLog); + ], _telemetryLog); } } @@ -560,10 +561,10 @@ public async Task ErrorReadingPdbFile() EndDebuggingSession(debuggingSession); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=1|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1" - }, _telemetryLog); + ], _telemetryLog); } [Fact] @@ -616,11 +617,11 @@ public async Task ErrorReadingSourceFile() debuggingSession.DiscardSolutionUpdate(); EndDebuggingSession(debuggingSession); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=" - }, _telemetryLog); + ], _telemetryLog); } [Theory, CombinatorialData] @@ -674,19 +675,19 @@ public async Task FileAdded(bool breakMode) if (breakMode) { - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=" - }, _telemetryLog); + ], _telemetryLog); } else { - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=" - }, _telemetryLog); + ], _telemetryLog); } } @@ -844,18 +845,18 @@ void M() var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Equal(ModuleUpdateStatus.RestartRequired, updates.Status); Assert.Empty(updates.Updates); - AssertEx.Equal(new[] { $"{document2.FilePath}: (5,0)-(5,32): Error ENC2016: {string.Format(FeaturesResources.EditAndContinueDisallowedByProject, document2.Project.Name, "*message*")}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal([$"{document2.FilePath}: (5,0)-(5,32): Error ENC2016: {string.Format(FeaturesResources.EditAndContinueDisallowedByProject, document2.Project.Name, "*message*")}"], InspectDiagnostics(emitDiagnostics)); EndDebuggingSession(debuggingSession); - AssertEx.SetEqual(new[] { moduleId }, debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); + AssertEx.SetEqual([moduleId], debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", "Debugging_EncSession_EditSession_EmitDeltaErrorId: SessionId=1|EditSessionId=2|ErrorId=ENC2016" - }, _telemetryLog); + ], _telemetryLog); } [Fact] @@ -936,7 +937,7 @@ public async Task RudeEdits(bool breakMode) var document2 = solution.GetDocument(document1.Id); var diagnostics1 = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); - AssertEx.Equal(new[] { "ENC0110: " + string.Format(FeaturesResources.Changing_the_signature_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.method) }, + AssertEx.Equal(["ENC0110: " + string.Format(FeaturesResources.Changing_the_signature_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.method)], diagnostics1.Select(d => $"{d.Id}: {d.GetMessage()}")); // validate solution update status and emit: @@ -955,25 +956,25 @@ public async Task RudeEdits(bool breakMode) EndDebuggingSession(debuggingSession); } - AssertEx.SetEqual(new[] { moduleId }, debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); + AssertEx.SetEqual([moduleId], debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); if (breakMode) { - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=110|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={6A6F7270-0000-4000-8000-000000000000}" - }, _telemetryLog); + ], _telemetryLog); } else { - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=", "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=110|RudeEditSyntaxKind=8910|RudeEditBlocking=True|RudeEditProjectId={6A6F7270-0000-4000-8000-000000000000}" - }, _telemetryLog); + ], _telemetryLog); } } @@ -1007,7 +1008,7 @@ public async Task DeferredApplyChangeWithActiveStatementRudeEdits() var document2 = solution.GetDocument(document.Id); var diagnostics = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); - AssertEx.Equal(new[] { "ENC0001: " + string.Format(FeaturesResources.Updating_an_active_statement_requires_restarting_the_application) }, + AssertEx.Equal(["ENC0001: " + string.Format(FeaturesResources.Updating_an_active_statement_requires_restarting_the_application)], diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); // exit break state without applying the change: @@ -1021,7 +1022,7 @@ public async Task DeferredApplyChangeWithActiveStatementRudeEdits() EnterBreakState(debuggingSession, activeStatements); diagnostics = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); - AssertEx.Equal(new[] { "ENC0001: " + string.Format(FeaturesResources.Updating_an_active_statement_requires_restarting_the_application) }, + AssertEx.Equal(["ENC0001: " + string.Format(FeaturesResources.Updating_an_active_statement_requires_restarting_the_application)], diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); // exit break state without applying the change: @@ -1074,7 +1075,7 @@ class C { int Y => 2; } var generatedDocument = (await solution.Projects.Single().GetSourceGeneratedDocumentsAsync()).Single(); var diagnostics1 = await service.GetDocumentDiagnosticsAsync(generatedDocument, s_noActiveSpans, CancellationToken.None); - AssertEx.Equal(new[] { "ENC0110: " + string.Format(FeaturesResources.Changing_the_signature_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.method) }, + AssertEx.Equal(["ENC0110: " + string.Format(FeaturesResources.Changing_the_signature_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.method)], diagnostics1.Select(d => $"{d.Id}: {d.GetMessage()}")); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); @@ -1146,10 +1147,10 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) // now we see the rude edit: diagnostics = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "ENC0110: " + string.Format(FeaturesResources.Changing_the_signature_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.method) - }, + ], diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); @@ -1167,25 +1168,25 @@ public async Task RudeEdits_DocumentOutOfSync(bool breakMode) EndDebuggingSession(debuggingSession); } - AssertEx.SetEqual(new[] { moduleId }, debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); + AssertEx.SetEqual([moduleId], debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); if (breakMode) { - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=2", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=110|RudeEditSyntaxKind=8875|RudeEditBlocking=True|RudeEditProjectId={6A6F7270-0000-4000-8000-000000000000}" - }, _telemetryLog); + ], _telemetryLog); } else { - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=True|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=1|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=", "Debugging_EncSession_EditSession_RudeEdit: SessionId=1|EditSessionId=2|RudeEditKind=110|RudeEditSyntaxKind=8875|RudeEditBlocking=True|RudeEditProjectId={6A6F7270-0000-4000-8000-000000000000}" - }, _telemetryLog); + ], _telemetryLog); } } @@ -1220,7 +1221,7 @@ public async Task RudeEdits_DocumentWithoutSequencePoints() // Rude Edits reported: var diagnostics = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); AssertEx.Equal( - new[] { "ENC0023: " + string.Format(FeaturesResources.Adding_an_abstract_0_or_overriding_an_inherited_0_requires_restarting_the_application, FeaturesResources.method) }, + ["ENC0023: " + string.Format(FeaturesResources.Adding_an_abstract_0_or_overriding_an_inherited_0_requires_restarting_the_application, FeaturesResources.method)], diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); // validate solution update status and emit: @@ -1263,7 +1264,7 @@ public async Task RudeEdits_DelayLoadedModule() // Rude Edits reported: var diagnostics = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); AssertEx.Equal( - new[] { "ENC0110: " + string.Format(FeaturesResources.Changing_the_signature_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.method) }, + ["ENC0110: " + string.Format(FeaturesResources.Changing_the_signature_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.method)], diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); @@ -1277,7 +1278,7 @@ public async Task RudeEdits_DelayLoadedModule() // Rude Edits still reported: diagnostics = await service.GetDocumentDiagnosticsAsync(document2, s_noActiveSpans, CancellationToken.None); AssertEx.Equal( - new[] { "ENC0110: " + string.Format(FeaturesResources.Changing_the_signature_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.method) }, + ["ENC0110: " + string.Format(FeaturesResources.Changing_the_signature_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.method)], diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); @@ -1319,13 +1320,13 @@ public async Task SyntaxError() EndDebuggingSession(debuggingSession); - AssertEx.SetEqual(new[] { moduleId }, debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); + AssertEx.SetEqual([moduleId], debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=True|HadRudeEdits=False|HadValidChanges=False|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=" - }, _telemetryLog); + ], _telemetryLog); } [Fact] @@ -1360,18 +1361,18 @@ public async Task SemanticError() // TODO: https://github.com/dotnet/roslyn/issues/36061 // Semantic errors should not be reported in emit diagnostics. - AssertEx.Equal(new[] { $"{document2.FilePath}: (0,30)-(0,32): Error CS0266: {string.Format(CSharpResources.ERR_NoImplicitConvCast, "long", "int")}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal([$"{document2.FilePath}: (0,30)-(0,32): Error CS0266: {string.Format(CSharpResources.ERR_NoImplicitConvCast, "long", "int")}"], InspectDiagnostics(emitDiagnostics)); EndDebuggingSession(debuggingSession); - AssertEx.SetEqual(new[] { moduleId }, debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); + AssertEx.SetEqual([moduleId], debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", "Debugging_EncSession_EditSession_EmitDeltaErrorId: SessionId=1|EditSessionId=2|ErrorId=CS0266" - }, _telemetryLog); + ], _telemetryLog); } [Fact] @@ -1508,7 +1509,7 @@ public async Task HasChanges_Documents(DocumentKind documentKind) { DocumentKind.Source => solution.AddDocument(documentId, "X", CreateText("xxx"), filePath: pathX), DocumentKind.Additional => solution.AddAdditionalDocument(documentId, "X", CreateText("xxx"), filePath: pathX), - DocumentKind.AnalyzerConfig => solution.AddAnalyzerConfigDocument(documentId, "X", GetAnalyzerConfigText(new[] { ("x", "1") }), filePath: pathX), + DocumentKind.AnalyzerConfig => solution.AddAnalyzerConfigDocument(documentId, "X", GetAnalyzerConfigText([("x", "1")]), filePath: pathX), _ => throw ExceptionUtilities.Unreachable(), }; Assert.True(await EditSession.HasChangesAsync(oldSolution, solution, CancellationToken.None)); @@ -1520,10 +1521,12 @@ public async Task HasChanges_Documents(DocumentKind documentKind) // generator is not executed since we already know the solution changed without inspecting generated files: Assert.Equal(0, generatorExecutionCount); - AssertEx.Equal(new[] { generatedDocumentId }, + AssertEx.Equal([generatedDocumentId], await EditSession.GetChangedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None)); - await EditSession.PopulateChangedAndAddedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), changedOrAddedDocuments, CancellationToken.None); + var diagnostics = new ArrayBuilder(); + await EditSession.PopulateChangedAndAddedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), changedOrAddedDocuments, diagnostics, CancellationToken.None); + Assert.Empty(diagnostics); AssertEx.Equal(documentKind == DocumentKind.Source ? [documentId, generatedDocumentId] : [generatedDocumentId], changedOrAddedDocuments.Select(d => d.Id)); Assert.Equal(1, generatorExecutionCount); @@ -1539,7 +1542,7 @@ public async Task HasChanges_Documents(DocumentKind documentKind) { DocumentKind.Source => solution.WithDocumentText(documentId, CreateText("xxx")), DocumentKind.Additional => solution.WithAdditionalDocumentText(documentId, CreateText("xxx")), - DocumentKind.AnalyzerConfig => solution.WithAnalyzerConfigDocumentText(documentId, GetAnalyzerConfigText(new[] { ("x", "1") })), + DocumentKind.AnalyzerConfig => solution.WithAnalyzerConfigDocumentText(documentId, GetAnalyzerConfigText([("x", "1")])), _ => throw ExceptionUtilities.Unreachable(), }; Assert.False(await EditSession.HasChangesAsync(oldSolution, solution, CancellationToken.None)); @@ -1551,7 +1554,8 @@ public async Task HasChanges_Documents(DocumentKind documentKind) AssertEx.Equal(documentKind == DocumentKind.Source ? new[] { documentId } : [], await EditSession.GetChangedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None)); - await EditSession.PopulateChangedAndAddedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), changedOrAddedDocuments, CancellationToken.None); + await EditSession.PopulateChangedAndAddedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), changedOrAddedDocuments, diagnostics, CancellationToken.None); + Assert.Empty(diagnostics); Assert.Empty(changedOrAddedDocuments); Assert.Equal(1, generatorExecutionCount); @@ -1566,7 +1570,7 @@ public async Task HasChanges_Documents(DocumentKind documentKind) { DocumentKind.Source => solution.WithDocumentText(documentId, CreateText("xxx-changed")), DocumentKind.Additional => solution.WithAdditionalDocumentText(documentId, CreateText("xxx-changed")), - DocumentKind.AnalyzerConfig => solution.WithAnalyzerConfigDocumentText(documentId, GetAnalyzerConfigText(new[] { ("x", "2") })), + DocumentKind.AnalyzerConfig => solution.WithAnalyzerConfigDocumentText(documentId, GetAnalyzerConfigText([("x", "2")])), _ => throw ExceptionUtilities.Unreachable(), }; Assert.True(await EditSession.HasChangesAsync(oldSolution, solution, CancellationToken.None)); @@ -1575,7 +1579,8 @@ public async Task HasChanges_Documents(DocumentKind documentKind) AssertEx.Equal(documentKind == DocumentKind.Source ? [documentId, generatedDocumentId] : [generatedDocumentId], await EditSession.GetChangedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None)); - await EditSession.PopulateChangedAndAddedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), changedOrAddedDocuments, CancellationToken.None); + await EditSession.PopulateChangedAndAddedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), changedOrAddedDocuments, diagnostics, CancellationToken.None); + Assert.Empty(diagnostics); AssertEx.Equal(documentKind == DocumentKind.Source ? [documentId, generatedDocumentId] : [generatedDocumentId], changedOrAddedDocuments.Select(d => d.Id)); Assert.Equal(1, generatorExecutionCount); @@ -1598,15 +1603,93 @@ public async Task HasChanges_Documents(DocumentKind documentKind) Assert.Equal(0, generatorExecutionCount); - AssertEx.Equal(new[] { generatedDocumentId }, + AssertEx.Equal([generatedDocumentId], await EditSession.GetChangedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None)); - await EditSession.PopulateChangedAndAddedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), changedOrAddedDocuments, CancellationToken.None); - AssertEx.Equal(new[] { generatedDocumentId }, changedOrAddedDocuments.Select(d => d.Id)); + await EditSession.PopulateChangedAndAddedDocumentsAsync(oldSolution.GetProject(projectId), solution.GetProject(projectId), changedOrAddedDocuments, diagnostics, CancellationToken.None); + Assert.Empty(diagnostics); + AssertEx.Equal([generatedDocumentId], changedOrAddedDocuments.Select(d => d.Id)); Assert.Equal(1, generatorExecutionCount); } + [Fact] + public async Task HasChanges_SourceGeneratorFailure() + { + using var _ = CreateWorkspace(out var solution, out var service); + + var pathA = Path.Combine(TempRoot.Root, "A.txt"); + + var generatorExecutionCount = 0; + var generator = new TestSourceGenerator() + { + ExecuteImpl = context => + { + generatorExecutionCount++; + + var additionalText = context.AdditionalFiles.Single().GetText().ToString(); + if (additionalText.Contains("updated")) + { + throw new InvalidOperationException("Source generator failed"); + } + + context.AddSource("generated.cs", SourceText.From("generated: " + additionalText, Encoding.UTF8, SourceHashAlgorithm.Sha256)); + } + }; + + var project = solution + .AddProject("A", "A", "C#") + .AddAdditionalDocument("A.txt", "text", filePath: pathA) + .Project; + + var projectId = project.Id; + solution = project.Solution.AddAnalyzerReference(projectId, new TestGeneratorReference(generator)); + project = solution.GetRequiredProject(projectId); + var aId = project.AdditionalDocumentIds.Single(); + + var generatedDocuments = await project.Solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(project.State, CancellationToken.None); + + var generatedText = generatedDocuments.States.Single().Value.GetTextSynchronously(CancellationToken.None).ToString(); + AssertEx.AreEqual("generated: text", generatedText); + Assert.Equal(1, generatorExecutionCount); + + var generatorDiagnostics = await solution.CompilationState.GetSourceGeneratorDiagnosticsAsync(project.State, CancellationToken.None); + Assert.Empty(generatorDiagnostics); + + var debuggingSession = await StartDebuggingSessionAsync(service, solution); + EnterBreakState(debuggingSession); + + var changedOrAddedDocuments = new ArrayBuilder(); + + // + // Update document content + // + + var oldSolution = solution; + var oldProject = project; + solution = solution.WithAdditionalDocumentText(aId, CreateText("updated text")); + project = solution.GetRequiredProject(projectId); + + // Change in additional file is detected: + Assert.True(await EditSession.HasChangesAsync(oldSolution, solution, CancellationToken.None)); + + // No changed source documents since the generator failed: + AssertEx.Empty(await EditSession.GetChangedDocumentsAsync(oldProject, project, CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None)); + + var diagnostics = new ArrayBuilder(); + await EditSession.PopulateChangedAndAddedDocumentsAsync(oldProject, project, changedOrAddedDocuments, diagnostics, CancellationToken.None); + Assert.Contains("System.InvalidOperationException: Source generator failed", diagnostics.Single().Diagnostics.Single().GetMessage()); + AssertEx.Empty(changedOrAddedDocuments); + + Assert.Equal(2, generatorExecutionCount); + + generatedDocuments = await solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(project.State, CancellationToken.None); + Assert.Empty(generatedDocuments.States); + + generatorDiagnostics = await solution.CompilationState.GetSourceGeneratorDiagnosticsAsync(project.State, CancellationToken.None); + Assert.Contains("System.InvalidOperationException: Source generator failed", generatorDiagnostics.Single().GetMessage()); + } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/1204")] [WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1371694")] public async Task Project_Add() @@ -1626,7 +1709,7 @@ public async Task Project_Add() var sourceFileB = dir.CreateFile("b.cs").WriteAllText(sourceB1, Encoding.UTF8); using var _ = CreateWorkspace(out var solution, out var service); - solution = AddDefaultTestProject(solution, new[] { sourceA1 }); + solution = AddDefaultTestProject(solution, [sourceA1]); var documentA1 = solution.Projects.Single().Documents.Single(); var mvidA = EmitAndLoadLibraryToDebuggee(sourceA1, sourceFilePath: sourceFileA.Path, assemblyName: "A"); @@ -1663,11 +1746,11 @@ public async Task Project_Add() // TODO: https://github.com/dotnet/roslyn/issues/1204 // Should return span in document B since the document content matches the PDB. var baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentA1.Id, documentB2.Id), CancellationToken.None); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "", "(0,21)-(0,22)" - }, baseSpans.Select(spans => spans.IsEmpty ? "" : string.Join(",", spans.Select(s => s.LineSpan.ToString())))); + ], baseSpans.Select(spans => spans.IsEmpty ? "" : string.Join(",", spans.Select(s => s.LineSpan.ToString())))); var trackedActiveSpans = ImmutableArray.Create( new ActiveStatementSpan(new ActiveStatementId(0), activeLineSpanB1, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame)); @@ -1706,7 +1789,7 @@ public async Task Capabilities(bool breakState) var source2 = "[System.Obsolete]class C { void M() { } }"; using var _ = CreateWorkspace(out var solution, out var service); - solution = AddDefaultTestProject(solution, new[] { source1 }); + solution = AddDefaultTestProject(solution, [source1]); var documentId = solution.Projects.Single().Documents.Single().Id; EmitAndLoadLibraryToDebuggee(source1); @@ -1749,7 +1832,7 @@ public async Task Capabilities(bool breakState) } diagnostics = await service.GetDocumentDiagnosticsAsync(solution.GetDocument(documentId), s_noActiveSpans, CancellationToken.None); - AssertEx.Equal(new[] { "ENC0101: " + string.Format(FeaturesResources.Updating_the_attributes_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.class_) }, + AssertEx.Equal(["ENC0101: " + string.Format(FeaturesResources.Updating_the_attributes_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.class_)], diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); if (breakState) @@ -1758,7 +1841,7 @@ public async Task Capabilities(bool breakState) } diagnostics = await service.GetDocumentDiagnosticsAsync(solution.GetDocument(documentId), s_noActiveSpans, CancellationToken.None); - AssertEx.Equal(new[] { "ENC0101: " + string.Format(FeaturesResources.Updating_the_attributes_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.class_) }, + AssertEx.Equal(["ENC0101: " + string.Format(FeaturesResources.Updating_the_attributes_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.class_)], diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); // detach from processes that do not allow updating custom attributes: @@ -1783,10 +1866,10 @@ public async Task Capabilities(bool breakState) EndDebuggingSession(debuggingSession); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"Debugging_EncSession: SolutionSessionId={{00000000-AAAA-AAAA-AAAA-000000000000}}|SessionId=1|SessionCount=0|EmptySessionCount={(breakState ? 3 : 0)}|HotReloadSessionCount=0|EmptyHotReloadSessionCount={(breakState ? 4 : 3)}" - }, _telemetryLog); + ], _telemetryLog); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56431")] @@ -1852,7 +1935,7 @@ public async Task Capabilities_SynthesizedNewType() var source2 = "class C { void M() { var x = new { Goo = 1 }; } }"; using var _ = CreateWorkspace(out var solution, out var service); - solution = AddDefaultTestProject(solution, new[] { source1 }); + solution = AddDefaultTestProject(solution, [source1]); var project = solution.Projects.Single(); solution = solution.WithProjectParseOptions(project.Id, new CSharpParseOptions(LanguageVersion.CSharp10)); var documentId = solution.Projects.Single().Documents.Single().Id; @@ -1875,7 +1958,7 @@ public async Task Capabilities_SynthesizedNewType() // They are reported as emit diagnostics var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - AssertEx.Equal(new[] { $"proj.csproj: (0,0)-(0,0): Error ENC1007: {FeaturesResources.ChangesRequiredSynthesizedType}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal([$"proj.csproj: (0,0)-(0,0): Error ENC1007: {FeaturesResources.ChangesRequiredSynthesizedType}"], InspectDiagnostics(emitDiagnostics)); // no emitted delta: Assert.Empty(updates.Updates); @@ -1907,7 +1990,7 @@ public async Task ValidSignificantChange_EmitError() // validate solution update status and emit: var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); - AssertEx.Equal(new[] { $"{document2.FilePath}: (0,0)-(0,54): Error CS8055: {string.Format(CSharpResources.ERR_EncodinglessSyntaxTree)}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal([$"{document2.FilePath}: (0,0)-(0,54): Error CS8055: {string.Format(CSharpResources.ERR_EncodinglessSyntaxTree)}"], InspectDiagnostics(emitDiagnostics)); // no emitted delta: Assert.Empty(updates.Updates); @@ -1924,16 +2007,16 @@ public async Task ValidSignificantChange_EmitError() // solution update status after discarding an update (still has update ready): (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); Assert.Equal(ModuleUpdateStatus.Blocked, updates.Status); - AssertEx.Equal(new[] { $"{document2.FilePath}: (0,0)-(0,54): Error CS8055: {string.Format(CSharpResources.ERR_EncodinglessSyntaxTree)}" }, InspectDiagnostics(emitDiagnostics)); + AssertEx.Equal([$"{document2.FilePath}: (0,0)-(0,54): Error CS8055: {string.Format(CSharpResources.ERR_EncodinglessSyntaxTree)}"], InspectDiagnostics(emitDiagnostics)); EndDebuggingSession(debuggingSession); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", "Debugging_EncSession_EditSession_EmitDeltaErrorId: SessionId=1|EditSessionId=2|ErrorId=CS8055" - }, _telemetryLog); + ], _telemetryLog); } [Theory] @@ -2327,23 +2410,23 @@ void ValidateDelta(ManagedHotReloadUpdate delta) // open module readers should be disposed when the debugging session ends: VerifyReadersDisposed(readers); - AssertEx.SetEqual(new[] { moduleId }, debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); + AssertEx.SetEqual([moduleId], debuggingSession.GetTestAccessor().GetModulesPreparedForUpdate()); if (breakMode) { - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"Debugging_EncSession: SolutionSessionId={{00000000-AAAA-AAAA-AAAA-000000000000}}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount={(commitUpdate ? 3 : 2)}", $"Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges={(commitUpdate ? "{6A6F7270-0000-4000-8000-000000000000}" : "")}", - }, _telemetryLog); + ], _telemetryLog); } else { - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"Debugging_EncSession: SolutionSessionId={{00000000-AAAA-AAAA-AAAA-000000000000}}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount={(commitUpdate ? 1 : 0)}", $"Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges={(commitUpdate ? "{6A6F7270-0000-4000-8000-000000000000}" : "")}" - }, _telemetryLog); + ], _telemetryLog); } } @@ -2484,10 +2567,10 @@ partial class C { int Y = 2; } "; using var _ = CreateWorkspace(out var solution, out var service); - solution = AddDefaultTestProject(solution, new[] { sourceA1, sourceB1 }); + solution = AddDefaultTestProject(solution, [sourceA1, sourceB1]); var project = solution.Projects.Single(); - LoadLibraryToDebuggee(EmitLibrary(new[] { (sourceA1, "test1.cs"), (sourceB1, "test2.cs") })); + LoadLibraryToDebuggee(EmitLibrary([(sourceA1, "test1.cs"), (sourceB1, "test2.cs")])); var debuggingSession = await StartDebuggingSessionAsync(service, solution); @@ -2511,7 +2594,7 @@ partial class C { int Y = 2; } Assert.NotEmpty(delta.MetadataDelta); Assert.NotEmpty(delta.PdbDelta); Assert.Equal(6, delta.UpdatedMethods.Length); // F, C.C(), D.D(), E.E(int), E.E(int, int), lambda - AssertEx.SetEqual(new[] { 0x02000002, 0x02000003, 0x02000004, 0x02000005 }, delta.UpdatedTypes, itemInspector: t => "0x" + t.ToString("X")); + AssertEx.SetEqual([0x02000002, 0x02000003, 0x02000004, 0x02000005], delta.UpdatedTypes, itemInspector: t => "0x" + t.ToString("X")); debuggingSession.DiscardSolutionUpdate(); EndDebuggingSession(debuggingSession); @@ -2568,12 +2651,67 @@ class C { int Y => 2; } Assert.NotEmpty(delta.MetadataDelta); Assert.NotEmpty(delta.PdbDelta); Assert.Equal(2, delta.UpdatedMethods.Length); - AssertEx.Equal(new[] { 0x02000002, 0x02000003 }, delta.UpdatedTypes, itemInspector: t => "0x" + t.ToString("X")); + AssertEx.Equal([0x02000002, 0x02000003], delta.UpdatedTypes, itemInspector: t => "0x" + t.ToString("X")); debuggingSession.DiscardSolutionUpdate(); EndDebuggingSession(debuggingSession); } + [Theory] + [CombinatorialData] + [WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2169491")] + internal async Task RudeEdit_SourceGenerators_DocumentUpdate_GeneratedDocumentAdd(SourceGeneratorExecutionPreference executionPreference) + { + var sourceV1 = """ + class C { int Y => 1; } + """; + + var sourceV2 = """ + /* GENERATE: [assembly: System.Reflection.AssemblyMetadata("X", "Y")] */ + + class C { int Y => 2; } + """; + + var generator = new TestSourceGenerator() { ExecuteImpl = GenerateSource }; + + using var workspace = CreateWorkspace(out var solution, out var service); + var workspaceConfig = Assert.IsType(workspace.Services.GetRequiredService()); + workspaceConfig.Options = new WorkspaceConfigurationOptions(executionPreference); + + (solution, var document1) = AddDefaultTestProject(solution, sourceV1, generator); + + var moduleId = EmitLibrary(sourceV1, generator: generator); + LoadLibraryToDebuggee(moduleId); + + // Trigger initial source generation before debugging session starts. + // Causes source generator to run on the solution for the first time. + // Futher compilation access won't automatically trigger source generators, + // the EnC service has to do so. + _ = await solution.Projects.Single().GetCompilationAsync(CancellationToken.None); + + var debuggingSession = await StartDebuggingSessionAsync(service, solution); + + EnterBreakState(debuggingSession); + + // change the source (valid edit) + solution = solution.WithDocumentText(document1.Id, CreateText(sourceV2)); + + // validate solution update status and emit: + var results = (await debuggingSession.EmitSolutionUpdateAsync(solution, s_noActiveSpans, CancellationToken.None).ConfigureAwait(false)).Dehydrate(); + var diagnostics = results.GetAllDiagnostics(); + + AssertEx.Equal( + [ + @"ENC0021: 'Microsoft.CodeAnalysis.Test.Utilities\Roslyn.Test.Utilities.TestGenerators.TestSourceGenerator\Generated_test1.cs' (0,0)-(0,56): " + + string.Format(FeaturesResources.Adding_0_requires_restarting_the_application, FeaturesResources.attribute), + ], diagnostics.Select(d => $"{d.Id}: '{d.FilePath}' {d.Span.GetDebuggerDisplay()}: {d.Message}")); + + Assert.Equal(ModuleUpdateStatus.RestartRequired, results.ModuleUpdates.Status); + Assert.Empty(results.ModuleUpdates.Updates); + + EndDebuggingSession(debuggingSession); + } + [Fact] public async Task ValidSignificantChange_SourceGenerators_DocumentUpdate_GeneratedDocumentUpdate_LineChanges() { @@ -2626,7 +2764,7 @@ int M() Assert.Empty(delta.ActiveStatements); var lineUpdate = delta.SequencePoints.Single(); - AssertEx.Equal(new[] { "3 -> 4" }, lineUpdate.LineUpdates.Select(edit => $"{edit.OldLine} -> {edit.NewLine}")); + AssertEx.Equal(["3 -> 4"], lineUpdate.LineUpdates.Select(edit => $"{edit.OldLine} -> {edit.NewLine}")); Assert.NotEmpty(delta.ILDelta); Assert.NotEmpty(delta.MetadataDelta); Assert.NotEmpty(delta.PdbDelta); @@ -2822,7 +2960,7 @@ public async Task RudeEdit() var source2 = "class C { void M() { var x = new { Goo = 1 }; } }"; using var _ = CreateWorkspace(out var solution, out var service); - solution = AddDefaultTestProject(solution, new[] { source1 }); + solution = AddDefaultTestProject(solution, [source1]); var project = solution.Projects.Single(); solution = solution.WithProjectParseOptions(project.Id, new CSharpParseOptions(LanguageVersion.CSharp10)); var documentId = solution.Projects.Single().Documents.Single().Id; @@ -3067,12 +3205,12 @@ public async Task ValidSignificantChange_BaselineCreationFailed_AssemblyReadErro EndDebuggingSession(debuggingSession); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1", "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=", "Debugging_EncSession_EditSession_EmitDeltaErrorId: SessionId=1|EditSessionId=2|ErrorId=ENC1001" - }, _telemetryLog); + ], _telemetryLog); } [Fact] @@ -3131,11 +3269,11 @@ public async Task ActiveStatements() var activeStatementSpan12 = new ActiveStatementSpan(new ActiveStatementId(1), activeLineSpan12, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame); var baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(document1.Id), CancellationToken.None); - AssertEx.Equal(new[] - { - activeStatementSpan11, - activeStatementSpan12 - }, baseSpans.Single()); + AssertEx.Equal( + [ + activeStatementSpan11, + activeStatementSpan12 + ], baseSpans.Single()); var trackedActiveSpans1 = ImmutableArray.Create(activeStatementSpan11, activeStatementSpan12); @@ -3152,7 +3290,7 @@ public async Task ActiveStatements() var trackedActiveSpans2 = ImmutableArray.Create(activeStatementSpan21, activeStatementSpan22); currentSpans = await debuggingSession.GetAdjustedActiveStatementSpansAsync(document2, (_, _, _) => new(trackedActiveSpans2), CancellationToken.None); - AssertEx.Equal(new[] { adjustedActiveLineSpan1, adjustedActiveLineSpan2 }, currentSpans.Select(s => s.LineSpan)); + AssertEx.Equal([adjustedActiveLineSpan1, adjustedActiveLineSpan2], currentSpans.Select(s => s.LineSpan)); } [Theory, CombinatorialData] @@ -3204,11 +3342,11 @@ public async Task ActiveStatements_SyntaxErrorOrOutOfSyncDocument(bool isOutOfSy EnterBreakState(debuggingSession, activeStatements); var baseSpans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentId), CancellationToken.None)).Single(); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ new ActiveStatementSpan(new ActiveStatementId(0), activeLineSpan11, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.NonLeafFrame), new ActiveStatementSpan(new ActiveStatementId(1), activeLineSpan12, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame) - }, baseSpans); + ], baseSpans); // change the source (valid edit): solution = solution.WithDocumentText(documentId, sourceTextV2); @@ -3216,7 +3354,7 @@ public async Task ActiveStatements_SyntaxErrorOrOutOfSyncDocument(bool isOutOfSy // no adjustments made due to syntax error or out-of-sync document: var currentSpans = await debuggingSession.GetAdjustedActiveStatementSpansAsync(document2, (_, _, _) => ValueTaskFactory.FromResult(baseSpans), CancellationToken.None); - AssertEx.Equal(new[] { activeLineSpan11, activeLineSpan12 }, currentSpans.Select(s => s.LineSpan)); + AssertEx.Equal([activeLineSpan11, activeLineSpan12], currentSpans.Select(s => s.LineSpan)); } [Theory, CombinatorialData] @@ -3322,16 +3460,16 @@ DocumentId AddProjectAndLinkDocument(string projectName, Document doc, SourceTex Assert.Equal(2, documentMap.Count); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"2: {doc1.FilePath}: (2,32)-(2,52) flags=[MethodUpToDate, NonLeafFrame]", $"1: {doc1.FilePath}: (3,29)-(3,49) flags=[MethodUpToDate, NonLeafFrame]" - }, documentMap[doc1.FilePath].Select(InspectActiveStatement)); + ], documentMap[doc1.FilePath].Select(InspectActiveStatement)); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0: {doc2.FilePath}: (0,39)-(0,59) flags=[LeafFrame, MethodUpToDate]", - }, documentMap[doc2.FilePath].Select(InspectActiveStatement)); + ], documentMap[doc2.FilePath].Select(InspectActiveStatement)); Assert.Equal(3, baseActiveStatementsMap.InstructionMap.Count); @@ -3350,14 +3488,14 @@ DocumentId AddProjectAndLinkDocument(string projectName, Document doc, SourceTex var spans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(doc1.Id, doc2.Id, docId3, docId4, docId5), CancellationToken.None); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "(2,32)-(2,52), (3,29)-(3,49)", // test1.cs "(0,39)-(0,59)", // test2.cs "(2,32)-(2,52), (3,29)-(3,49)", // link test1.cs "(2,32)-(2,52), (3,29)-(3,49)", // link test1.cs "(0,39)-(0,59)" // link test2.cs - }, spans.Select(docSpans => string.Join(", ", docSpans.Select(span => span.LineSpan)))); + ], spans.Select(docSpans => string.Join(", ", docSpans.Select(span => span.LineSpan)))); } [Fact] @@ -3426,10 +3564,10 @@ static void M() Assert.Single(baseActiveStatementMap.DocumentPathMap); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0: {document.FilePath}: (9,18)-(9,22) flags=[LeafFrame, MethodUpToDate]", - }, baseActiveStatementMap.DocumentPathMap[document.FilePath].Select(InspectActiveStatement)); + ], baseActiveStatementMap.DocumentPathMap[document.FilePath].Select(InspectActiveStatement)); Assert.Equal(1, baseActiveStatementMap.InstructionMap.Count); @@ -3440,14 +3578,14 @@ static void M() // Active statement reported as unchanged as the containing document is out-of-sync: var baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(document.Id), CancellationToken.None); - AssertEx.Equal(new[] { $"(9,18)-(9,22)" }, baseSpans.Single().Select(s => s.LineSpan.ToString())); + AssertEx.Equal([$"(9,18)-(9,22)"], baseSpans.Single().Select(s => s.LineSpan.ToString())); // Document got synchronized: debuggingSession.LastCommittedSolution.Test_SetDocumentState(document.Id, CommittedSolution.DocumentState.MatchesBuildOutput); // New location of the active statement reported: baseSpans = await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(document.Id), CancellationToken.None); - AssertEx.Equal(new[] { $"(10,12)-(10,16)" }, baseSpans.Single().Select(s => s.LineSpan.ToString())); + AssertEx.Equal([$"(10,12)-(10,16)"], baseSpans.Single().Select(s => s.LineSpan.ToString())); } [Fact] @@ -3499,8 +3637,8 @@ void F() var debuggingSession = await StartDebuggingSessionAsync(service, solution); EnterBreakState(debuggingSession, GetActiveStatementDebugInfosCSharp( - new[] { GetGeneratedCodeFromMarkedSource(markedSource1) }, - filePaths: new[] { generatedDocument1.FilePath }, + [GetGeneratedCodeFromMarkedSource(markedSource1)], + filePaths: [generatedDocument1.FilePath], modules: [moduleId], methodRowIds: [1], methodVersions: [1], @@ -3526,10 +3664,10 @@ void F() Assert.Empty(delta.UpdatedMethods); Assert.Empty(delta.UpdatedTypes); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "a.razor: [0 -> 1]" - }, delta.SequencePoints.Inspect()); + ], delta.SequencePoints.Inspect()); debuggingSession.DiscardSolutionUpdate(); EndDebuggingSession(debuggingSession); @@ -3582,7 +3720,7 @@ int F() var debuggingSession = await StartDebuggingSessionAsync(service, solution); EnterBreakState(debuggingSession, GetActiveStatementDebugInfosCSharp( - new[] { markedSource1 }, + [markedSource1], modules: [moduleId], methodRowIds: [1], methodVersions: [1], @@ -3596,7 +3734,7 @@ int F() document = solution.GetDocument(document.Id); var diagnostics = await service.GetDocumentDiagnosticsAsync(document, s_noActiveSpans, CancellationToken.None); - AssertEx.Equal(new[] { "ENC0063: " + string.Format(FeaturesResources.Updating_a_0_around_an_active_statement_requires_restarting_the_application, CSharpFeaturesResources.catch_clause) }, + AssertEx.Equal(["ENC0063: " + string.Format(FeaturesResources.Updating_a_0_around_an_active_statement_requires_restarting_the_application, CSharpFeaturesResources.catch_clause)], diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(debuggingSession, solution); @@ -3668,7 +3806,7 @@ static void F() // EnC update F v1 -> v2 EnterBreakState(debuggingSession, GetActiveStatementDebugInfosCSharp( - new[] { markedSourceV1 }, + [markedSourceV1], modules: [moduleId, moduleId], methodRowIds: [2, 3], methodVersions: [1, 1], @@ -3688,11 +3826,11 @@ static void F() CommitSolutionUpdate(debuggingSession); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0x06000002 v1 | AS {document.FilePath}: (4,41)-(4,42) => (4,41)-(4,42)", $"0x06000003 v1 | AS {document.FilePath}: (9,14)-(9,18) => (10,14)-(10,18)", - }, InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); + ], InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); ExitBreakState(debuggingSession); @@ -3709,16 +3847,16 @@ static void F() CommitSolutionUpdate(debuggingSession); // the regions remain unchanged - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0x06000002 v1 | AS {document.FilePath}: (4,41)-(4,42) => (4,41)-(4,42)", $"0x06000003 v1 | AS {document.FilePath}: (9,14)-(9,18) => (10,14)-(10,18)", - }, InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); + ], InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); // EnC update F v3 -> v4 EnterBreakState(debuggingSession, GetActiveStatementDebugInfosCSharp( - new[] { markedSourceV1 }, // matches F v1 + [markedSourceV1], // matches F v1 modules: [moduleId, moduleId], methodRowIds: [2, 3], methodVersions: [1, 1], // frame F v1 is still executing (G has not returned) @@ -3729,10 +3867,10 @@ static void F() ])); var spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentId), CancellationToken.None)).Single(); - AssertEx.Equal(new[] - { - new ActiveStatementSpan(new ActiveStatementId(0), new LinePositionSpan(new(4,41), new(4,42)), ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame), - }, spans); + AssertEx.Equal( + [ + new ActiveStatementSpan(new ActiveStatementId(0), new LinePositionSpan(new(4, 41), new(4, 42)), ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame), + ], spans); solution = solution.WithDocumentText(documentId, CreateText(SourceMarkers.Clear(markedSourceV4))); @@ -3745,10 +3883,10 @@ static void F() CommitSolutionUpdate(debuggingSession); // Stale active statement region is gone. - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0x06000002 v1 | AS {document.FilePath}: (4,41)-(4,42) => (4,41)-(4,42)", - }, InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); + ], InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); ExitBreakState(debuggingSession); } @@ -3816,7 +3954,7 @@ static void F() // EnC update F v2 -> v3 EnterBreakState(debuggingSession, GetActiveStatementDebugInfosCSharp( - new[] { markedSource1 }, + [markedSource1], modules: [moduleId, moduleId], methodRowIds: [2, 3], methodVersions: [1, 1], @@ -3831,11 +3969,11 @@ static void F() var expectedSpanF1 = new LinePositionSpan(new LinePosition(8, 14), new LinePosition(8, 18)); var spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentId), CancellationToken.None)).Single(); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ new ActiveStatementSpan(new ActiveStatementId(0), expectedSpanG1, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame, documentId), new ActiveStatementSpan(new ActiveStatementId(1), expectedSpanF1, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.NonLeafFrame, documentId) - }, spans); + ], spans); solution = solution.WithDocumentText(documentId, CreateText(SourceMarkers.Clear(markedSource3))); @@ -3844,11 +3982,11 @@ static void F() var expectedSpanF2 = new LinePositionSpan(new LinePosition(9, 14), new LinePosition(9, 18)); spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentId), CancellationToken.None)).Single(); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ new ActiveStatementSpan(new ActiveStatementId(0), expectedSpanG2, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame, documentId), new ActiveStatementSpan(new ActiveStatementId(1), expectedSpanF2, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.NonLeafFrame, documentId) - }, spans); + ], spans); // no rude edits: var document1 = solution.GetDocument(documentId); @@ -3863,11 +4001,11 @@ static void F() CommitSolutionUpdate(debuggingSession); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0x06000002 v1 | AS {document.FilePath}: (3,41)-(3,42) => (3,41)-(3,42)", $"0x06000003 v1 | AS {document.FilePath}: (7,14)-(7,18) => (9,14)-(9,18)", - }, InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); + ], InspectNonRemappableRegions(debuggingSession.EditSession.NonRemappableRegions)); ExitBreakState(debuggingSession); } @@ -3926,7 +4064,7 @@ static void F() // Break EnterBreakState(debuggingSession, GetActiveStatementDebugInfosCSharp( - new[] { markedSource1 }, + [markedSource1], modules: [moduleId, moduleId], methodRowIds: [2, 3], methodVersions: [1, 1], // frame F v1 is still executing (G has not returned) @@ -3940,11 +4078,11 @@ static void F() var expectedSpanG1 = new LinePositionSpan(new LinePosition(3, 41), new LinePosition(3, 42)); var spans = (await debuggingSession.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentId), CancellationToken.None)).Single(); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ new ActiveStatementSpan(new ActiveStatementId(0), expectedSpanG1, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.LeafFrame) // active statement in F has been deleted - }, spans); + ], spans); ExitBreakState(debuggingSession); } diff --git a/src/Features/Test/EditAndContinue/EditSessionActiveStatementsTests.cs b/src/Features/Test/EditAndContinue/EditSessionActiveStatementsTests.cs index 2e294ab3d7f8a..7f29f64aeebba 100644 --- a/src/Features/Test/EditAndContinue/EditSessionActiveStatementsTests.cs +++ b/src/Features/Test/EditAndContinue/EditSessionActiveStatementsTests.cs @@ -184,8 +184,8 @@ static void Main() // Active Statements var statements = baseActiveStatementsMap.InstructionMap.Values.OrderBy(v => v.Id.Ordinal).ToArray(); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0: {document1.FilePath}: (9,14)-(9,35) flags=[LeafFrame, MethodUpToDate] mvid=11111111-1111-1111-1111-111111111111 0x06000001 v1 IL_0001", $"1: {document1.FilePath}: (4,32)-(4,37) flags=[MethodUpToDate, NonLeafFrame] mvid=11111111-1111-1111-1111-111111111111 0x06000002 v1 IL_0001", $"2: {document2.FilePath}: (21,14)-(21,24) flags=[MethodUpToDate, NonLeafFrame] mvid=22222222-2222-2222-2222-222222222222 0x06000003 v1 IL_0001", // [|Test1.M1()|] in F2 @@ -193,53 +193,53 @@ static void Main() $"4: {document2.FilePath}: (26,20)-(26,25) flags=[MethodUpToDate, NonLeafFrame] mvid=22222222-2222-2222-2222-222222222222 0x06000005 v1 IL_0003", // [|M2();|] in Main $"5: NonRoslynDocument.mcpp: (1,1)-(1,10) flags=[MethodUpToDate, NonLeafFrame] mvid={module3} 0x06000005 v1 IL_000A", $"6: a.dummy: (2,1)-(2,10) flags=[MethodUpToDate, NonLeafFrame] mvid={module4} 0x06000005 v1 IL_000A" - }, statements.Select(InspectActiveStatementAndInstruction)); + ], statements.Select(InspectActiveStatementAndInstruction)); // Active Statements per document Assert.Equal(4, baseActiveStatementsMap.DocumentPathMap.Count); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"1: {document1.FilePath}: (4,32)-(4,37) flags=[MethodUpToDate, NonLeafFrame]", $"0: {document1.FilePath}: (9,14)-(9,35) flags=[LeafFrame, MethodUpToDate]" - }, baseActiveStatementsMap.DocumentPathMap[document1.FilePath].Select(InspectActiveStatement)); + ], baseActiveStatementsMap.DocumentPathMap[document1.FilePath].Select(InspectActiveStatement)); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"3: {document2.FilePath}: (8,20)-(8,25) flags=[MethodUpToDate, NonLeafFrame]", // [|F2();|] in M2 $"2: {document2.FilePath}: (21,14)-(21,24) flags=[MethodUpToDate, NonLeafFrame]", // [|Test1.M1()|] in F2 $"4: {document2.FilePath}: (26,20)-(26,25) flags=[MethodUpToDate, NonLeafFrame]" // [|M2();|] in Main - }, baseActiveStatementsMap.DocumentPathMap[document2.FilePath].Select(InspectActiveStatement)); + ], baseActiveStatementsMap.DocumentPathMap[document2.FilePath].Select(InspectActiveStatement)); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"5: NonRoslynDocument.mcpp: (1,1)-(1,10) flags=[MethodUpToDate, NonLeafFrame]", - }, baseActiveStatementsMap.DocumentPathMap["NonRoslynDocument.mcpp"].Select(InspectActiveStatement)); + ], baseActiveStatementsMap.DocumentPathMap["NonRoslynDocument.mcpp"].Select(InspectActiveStatement)); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"6: a.dummy: (2,1)-(2,10) flags=[MethodUpToDate, NonLeafFrame]", - }, baseActiveStatementsMap.DocumentPathMap["a.dummy"].Select(InspectActiveStatement)); + ], baseActiveStatementsMap.DocumentPathMap["a.dummy"].Select(InspectActiveStatement)); // Exception Regions var analyzer = solution.GetProject(projectId).Services.GetRequiredService(); var oldActiveStatements1 = await baseActiveStatementsMap.GetOldActiveStatementsAsync(analyzer, document1, CancellationToken.None).ConfigureAwait(false); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"[{document1.FilePath}: (4,8)-(4,46)]", "[]", - }, oldActiveStatements1.Select(s => "[" + string.Join(", ", s.ExceptionRegions.Spans) + "]")); + ], oldActiveStatements1.Select(s => "[" + string.Join(", ", s.ExceptionRegions.Spans) + "]")); var oldActiveStatements2 = await baseActiveStatementsMap.GetOldActiveStatementsAsync(analyzer, document2, CancellationToken.None).ConfigureAwait(false); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"[{document2.FilePath}: (14,8)-(16,9), {document2.FilePath}: (10,10)-(12,11)]", "[]", $"[{document2.FilePath}: (26,35)-(26,46)]", - }, oldActiveStatements2.Select(s => "[" + string.Join(", ", s.ExceptionRegions.Spans) + "]")); + ], oldActiveStatements2.Select(s => "[" + string.Join(", ", s.ExceptionRegions.Spans) + "]")); // GetActiveStatementAndExceptionRegionSpans @@ -269,25 +269,25 @@ static void Main() out var nonRemappableRegions, out var exceptionRegionUpdates); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0x06000004 v1 | AS {document2.FilePath}: (8,20)-(8,25) => (9,20)-(9,25)", $"0x06000004 v1 | ER {document2.FilePath}: (14,8)-(16,9) => (15,8)-(17,9)", $"0x06000004 v1 | ER {document2.FilePath}: (10,10)-(12,11) => (11,10)-(13,11)", $"0x06000003 v1 | AS {document2.FilePath}: (21,14)-(21,24) => (21,14)-(21,24)", $"0x06000005 v1 | AS {document2.FilePath}: (26,20)-(26,25) => (26,20)-(26,25)" - }, nonRemappableRegions.Select(r => $"{r.Method.GetDebuggerDisplay()} | {r.Region.GetDebuggerDisplay()}")); + ], nonRemappableRegions.Select(r => $"{r.Method.GetDebuggerDisplay()} | {r.Region.GetDebuggerDisplay()}")); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0x06000004 v1 | (15,8)-(17,9) Delta=-1", $"0x06000004 v1 | (11,10)-(13,11) Delta=-1" - }, exceptionRegionUpdates.Select(InspectExceptionRegionUpdate)); + ], exceptionRegionUpdates.Select(InspectExceptionRegionUpdate)); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0x06000004 v1 IL_0002: (9,20)-(9,25)" - }, activeStatementsInUpdatedMethods.Select(InspectActiveStatementUpdate)); + ], activeStatementsInUpdatedMethods.Select(InspectActiveStatementUpdate)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24439")] @@ -343,11 +343,11 @@ static void F2() var baseActiveStatements = baseActiveStatementMap.InstructionMap.Values.OrderBy(v => v.Id.Ordinal).ToArray(); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0: {document.FilePath}: (6,18)-(6,23) flags=[MethodUpToDate, NonLeafFrame] mvid=11111111-1111-1111-1111-111111111111 0x06000001 v1 IL_0000 'F2();'", $"1: {document.FilePath}: (18,14)-(18,36) flags=[LeafFrame, MethodUpToDate] mvid=11111111-1111-1111-1111-111111111111 0x06000002 v1 IL_0000 'throw new Exception();'" - }, baseActiveStatements.Select(s => InspectActiveStatementAndInstruction(s, baseText))); + ], baseActiveStatements.Select(s => InspectActiveStatementAndInstruction(s, baseText))); // Exception Regions @@ -355,11 +355,11 @@ static void F2() var oldActiveStatements = await baseActiveStatementMap.GetOldActiveStatementsAsync(analyzer, document, CancellationToken.None).ConfigureAwait(false); // Note that the spans correspond to the base snapshot (V2). - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"[{document.FilePath}: (8,8)-(12,9) 'catch (Exception) {{']", "[]", - }, oldActiveStatements.Select(s => "[" + string.Join(", ", s.ExceptionRegions.Spans.Select(span => $"{span} '{GetFirstLineText(span.Span, baseText)}'")) + "]")); + ], oldActiveStatements.Select(s => "[" + string.Join(", ", s.ExceptionRegions.Spans.Select(span => $"{span} '{GetFirstLineText(span.Span, baseText)}'")) + "]")); // GetActiveStatementAndExceptionRegionSpans @@ -384,22 +384,22 @@ static void F2() out var nonRemappableRegions, out var exceptionRegionUpdates); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0x06000001 v1 | AS {document.FilePath}: (6,18)-(6,23) => (6,18)-(6,23)", $"0x06000001 v1 | ER {document.FilePath}: (8,8)-(12,9) => (8,8)-(12,9)", $"0x06000002 v1 | AS {document.FilePath}: (18,14)-(18,36) => (18,14)-(18,36)", - }, nonRemappableRegions.OrderBy(r => r.Region.OldSpan.Span.Start.Line).Select(r => $"{r.Method.GetDebuggerDisplay()} | {r.Region.GetDebuggerDisplay()}")); + ], nonRemappableRegions.OrderBy(r => r.Region.OldSpan.Span.Start.Line).Select(r => $"{r.Method.GetDebuggerDisplay()} | {r.Region.GetDebuggerDisplay()}")); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "0x06000001 v1 | (8,8)-(12,9) Delta=0", - }, exceptionRegionUpdates.Select(InspectExceptionRegionUpdate)); + ], exceptionRegionUpdates.Select(InspectExceptionRegionUpdate)); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ "0x06000001 v1 IL_0000: (6,18)-(6,23) 'F2();'" - }, activeStatementsInUpdatedMethods.Select(update => $"{InspectActiveStatementUpdate(update)} '{GetFirstLineText(update.NewSpan.ToLinePositionSpan(), updatedText)}'")); + ], activeStatementsInUpdatedMethods.Select(update => $"{InspectActiveStatementUpdate(update)} '{GetFirstLineText(update.NewSpan.ToLinePositionSpan(), updatedText)}'")); } [Fact] @@ -526,13 +526,13 @@ static void F4() var baseActiveStatements = baseActiveStatementMap.InstructionMap.Values.OrderBy(v => v.Id.Ordinal).ToArray(); // Note that the spans of AS:2 and AS:3 correspond to the base snapshot (V2). - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0: {document.FilePath}: (6,18)-(6,22) flags=[MethodUpToDate, NonLeafFrame] mvid=11111111-1111-1111-1111-111111111111 0x06000001 v2 IL_0000 'M();'", $"1: {document.FilePath}: (20,18)-(20,22) flags=[MethodUpToDate, NonLeafFrame] mvid=11111111-1111-1111-1111-111111111111 0x06000002 v2 IL_0000 'M();'", $"2: {document.FilePath}: (29,22)-(29,26) flags=[NonLeafFrame] mvid=11111111-1111-1111-1111-111111111111 0x06000003 v1 IL_0000 '{{ M();'", $"3: {document.FilePath}: (53,22)-(53,26) flags=[NonLeafFrame] mvid=11111111-1111-1111-1111-111111111111 0x06000004 v1 IL_0000 'M();'" - }, baseActiveStatements.Select(s => InspectActiveStatementAndInstruction(s, sourceTextV2))); + ], baseActiveStatements.Select(s => InspectActiveStatementAndInstruction(s, sourceTextV2))); // Exception Regions @@ -540,13 +540,13 @@ static void F4() var oldActiveStatements = await baseActiveStatementMap.GetOldActiveStatementsAsync(analyzer, document, CancellationToken.None).ConfigureAwait(false); // Note that the spans correspond to the base snapshot (V2). - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"[{document.FilePath}: (8,16)-(10,9) 'catch']", $"[{document.FilePath}: (18,16)-(21,9) 'catch']", $"[{document.FilePath}: (38,16)-(40,9) 'catch', {document.FilePath}: (34,20)-(36,13) 'finally']", $"[{document.FilePath}: (56,16)-(58,9) 'catch', {document.FilePath}: (51,20)-(54,13) 'catch']", - }, oldActiveStatements.Select(s => "[" + string.Join(", ", s.ExceptionRegions.Spans.Select(span => $"{span} '{GetFirstLineText(span.Span, sourceTextV2)}'")) + "]")); + ], oldActiveStatements.Select(s => "[" + string.Join(", ", s.ExceptionRegions.Spans.Select(span => $"{span} '{GetFirstLineText(span.Span, sourceTextV2)}'")) + "]")); // GetActiveStatementAndExceptionRegionSpans @@ -578,8 +578,8 @@ static void F4() out var exceptionRegionUpdates); // Note: Since no method have been remapped yet all the following spans are in their pre-remap locations: - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0x06000001 v2 | AS {document.FilePath}: (6,18)-(6,22) => (6,18)-(6,22)", $"0x06000002 v2 | ER {document.FilePath}: (18,16)-(21,9) => (17,16)-(20,9)", $"0x06000002 v2 | AS {document.FilePath}: (20,18)-(20,22) => (19,18)-(19,22)", @@ -589,22 +589,22 @@ static void F4() $"0x06000004 v1 | ER {document.FilePath}: (50,20)-(53,13) => (53,20)-(56,13)", // ER:3.0 moved +1 in first edit, +2 in second $"0x06000004 v1 | AS {document.FilePath}: (52,22)-(52,26) => (55,22)-(55,26)", // AS:3 moved +1 in first edit, +2 in second $"0x06000004 v1 | ER {document.FilePath}: (55,16)-(57,9) => (58,16)-(60,9)", // ER:3.1 moved +1 in first edit, +2 in second - }, nonRemappableRegions.OrderBy(r => r.Region.OldSpan.Span.Start.Line).Select(r => $"{r.Method.GetDebuggerDisplay()} | {r.Region.GetDebuggerDisplay()}")); + ], nonRemappableRegions.OrderBy(r => r.Region.OldSpan.Span.Start.Line).Select(r => $"{r.Method.GetDebuggerDisplay()} | {r.Region.GetDebuggerDisplay()}")); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0x06000002 v2 | (17,16)-(20,9) Delta=1", $"0x06000003 v1 | (34,20)-(36,13) Delta=-2", $"0x06000003 v1 | (38,16)-(40,9) Delta=-2", $"0x06000004 v1 | (53,20)-(56,13) Delta=-3", $"0x06000004 v1 | (58,16)-(60,9) Delta=-3", - }, exceptionRegionUpdates.OrderBy(r => r.NewSpan.StartLine).Select(InspectExceptionRegionUpdate)); + ], exceptionRegionUpdates.OrderBy(r => r.NewSpan.StartLine).Select(InspectExceptionRegionUpdate)); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"0x06000002 v2 IL_0000: (19,18)-(19,22) 'M();'", $"0x06000004 v1 IL_0000: (55,22)-(55,26) 'M();'" - }, activeStatementsInUpdatedMethods.Select(update => $"{InspectActiveStatementUpdate(update)} '{GetFirstLineText(update.NewSpan.ToLinePositionSpan(), sourceTextV3)}'")); + ], activeStatementsInUpdatedMethods.Select(update => $"{InspectActiveStatementUpdate(update)} '{GetFirstLineText(update.NewSpan.ToLinePositionSpan(), sourceTextV3)}'")); } [Fact] @@ -660,11 +660,11 @@ static void F() Assert.Equal(1, baseActiveStatementMap.DocumentPathMap.Count); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"1: {document.FilePath}: (6,18)-(6,22) flags=[LeafFrame, MethodUpToDate, NonLeafFrame]", $"0: {document.FilePath}: (15,14)-(15,18) flags=[PartiallyExecuted, NonUserCode, MethodUpToDate, NonLeafFrame]", - }, baseActiveStatementMap.DocumentPathMap[document.FilePath].Select(InspectActiveStatement)); + ], baseActiveStatementMap.DocumentPathMap[document.FilePath].Select(InspectActiveStatement)); Assert.Equal(2, baseActiveStatementMap.InstructionMap.Count); @@ -685,11 +685,11 @@ static void F() var analyzer = solution.GetProject(project.Id).Services.GetRequiredService(); var oldActiveStatements = await baseActiveStatementMap.GetOldActiveStatementsAsync(analyzer, document, CancellationToken.None).ConfigureAwait(false); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ $"[{document.FilePath}: (8,8)-(10,9)]", "[]" - }, oldActiveStatements.Select(s => "[" + string.Join(",", s.ExceptionRegions.Spans) + "]")); + ], oldActiveStatements.Select(s => "[" + string.Join(",", s.ExceptionRegions.Spans) + "]")); } } } diff --git a/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs b/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs index 47e40768b8bde..7a79ae129f31d 100644 --- a/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs +++ b/src/Features/Test/EditAndContinue/EmitSolutionUpdateResultsTests.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Contracts.EditAndContinue; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; @@ -45,11 +46,12 @@ private static ManagedHotReloadUpdate CreateMockUpdate(ProjectId projectId) activeStatements: [], exceptionRegions: []); - private static EmitSolutionUpdateResults CreateMockResults(IEnumerable updates, IEnumerable rudeEdits) + private static EmitSolutionUpdateResults CreateMockResults(Solution solution, IEnumerable updates, IEnumerable rudeEdits) => new() { + Solution = solution, ModuleUpdates = new ModuleUpdates(ModuleUpdateStatus.Blocked, [.. updates.Select(CreateMockUpdate)]), - RudeEdits = [.. rudeEdits.Select(id => (DocumentId.CreateNewId(id), ImmutableArray.Create(new RudeEditDiagnostic(RudeEditKind.InternalError, span: default))))], + RudeEdits = [.. rudeEdits.Select(id => new ProjectDiagnostics(id, [Diagnostic.Create(EditAndContinueDiagnosticDescriptors.GetDescriptor(RudeEditKind.InternalError), location: null)]))], Diagnostics = [], SyntaxError = null, }; @@ -69,8 +71,9 @@ public async Task GetHotReloadDiagnostics() AddDocument(sourcePath, SourceText.From("class C {}", Encoding.UTF8), filePath: Path.Combine(TempRoot.Root, sourcePath)); var solution = document.Project.Solution; + var tree = await document.GetRequiredSyntaxTreeAsync(CancellationToken.None); - var diagnosticData = ImmutableArray.Create( + var diagnostics = ImmutableArray.Create( new DiagnosticData( id: "CS0001", category: "Test", @@ -121,21 +124,30 @@ public async Task GetHotReloadDiagnostics() description: "description", helpLink: "http://link"); - var rudeEdits = ImmutableArray.Create( - (document.Id, ImmutableArray.Create(new RudeEditDiagnostic(RudeEditKind.Insert, TextSpan.FromBounds(1, 10), 123, ["a"]))), - (document.Id, ImmutableArray.Create(new RudeEditDiagnostic(RudeEditKind.Delete, TextSpan.FromBounds(1, 10), 123, ["b"])))); + var rudeEdits = ImmutableArray.Create(new ProjectDiagnostics(document.Project.Id, + [ + new RudeEditDiagnostic(RudeEditKind.Insert, TextSpan.FromBounds(1, 10), 123, ["a"]).ToDiagnostic(tree), + new RudeEditDiagnostic(RudeEditKind.Delete, TextSpan.FromBounds(1, 10), 123, ["b"]).ToDiagnostic(tree) + ])).ToDiagnosticData(solution); - var updateStatus = ModuleUpdateStatus.Blocked; - var actual = await EmitSolutionUpdateResults.GetAllDiagnosticsAsync(solution, diagnosticData, rudeEdits, syntaxError, updateStatus, CancellationToken.None); - - AssertEx.Equal(new[] + var data = new EmitSolutionUpdateResults.Data() { + Diagnostics = diagnostics, + RudeEdits = rudeEdits, + SyntaxError = syntaxError, + ModuleUpdates = new ModuleUpdates(ModuleUpdateStatus.Blocked, Updates: []) + }; + + var actual = data.GetAllDiagnostics(); + + AssertEx.Equal( + [ $@"Warning CS0001: {razorPath1} (10,10)-(10,15): warning", $@"Error CS0012: {razorPath2} (10,10)-(10,15): error", $@"Error CS0002: {sourcePath} (0,1)-(0,5): syntax error", $@"RestartRequired ENC0021: {sourcePath} (0,1)-(0,10): {string.Format(FeaturesResources.Adding_0_requires_restarting_the_application, "a")}", $@"RestartRequired ENC0033: {sourcePath} (0,1)-(0,10): {string.Format(FeaturesResources.Deleting_0_requires_restarting_the_application, "b")}", - }, actual.Select(d => $"{d.Severity} {d.Id}: {d.FilePath} {d.Span.GetDebuggerDisplay()}: {d.Message}")); + ], actual.Select(d => $"{d.Severity} {d.Id}: {d.FilePath} {d.Span.GetDebuggerDisplay()}: {d.Message}")); } [Fact] @@ -150,7 +162,7 @@ public void RunningProjects_Updates() .AddTestProject("B", out var b).AddProjectReferences([new(c), new(d)]).Solution; var runningProjects = new[] { a, b }; - var results = CreateMockResults(updates: [c, d], rudeEdits: []); + var results = CreateMockResults(solution, updates: [c, d], rudeEdits: []); var projectsToRestart = new HashSet(); var projectsToRebuild = new HashSet(); @@ -173,7 +185,7 @@ public void RunningProjects_RudeEdits() .AddTestProject("B", out var b).AddProjectReferences([new(c), new(d)]).Solution; var runningProjects = new[] { a, b }; - var results = CreateMockResults(updates: [], rudeEdits: [d]); + var results = CreateMockResults(solution, updates: [], rudeEdits: [d]); var projectsToRestart = new HashSet(); var projectsToRebuild = new HashSet(); @@ -199,7 +211,7 @@ public void RunningProjects_RudeEdits_NotImpactingRunningProjects() .AddTestProject("B", out var b).AddProjectReferences([new(c), new(d)]).Solution; var runningProjects = new[] { a }; - var results = CreateMockResults(updates: [], rudeEdits: [d]); + var results = CreateMockResults(solution, updates: [], rudeEdits: [d]); var projectsToRestart = new HashSet(); var projectsToRebuild = new HashSet(); @@ -222,7 +234,7 @@ public void RunningProjects_RudeEditAndUpdate_Dependent() .AddTestProject("B", out var b).AddProjectReferences([new(c), new(d)]).Solution; var runningProjects = new[] { a, b }; - var results = CreateMockResults(updates: [c], rudeEdits: [d]); + var results = CreateMockResults(solution, updates: [c], rudeEdits: [d]); var projectsToRestart = new HashSet(); var projectsToRebuild = new HashSet(); @@ -249,7 +261,7 @@ public void RunningProjects_RudeEditAndUpdate_Independent() .AddTestProject("B", out var b).AddProjectReferences([new(d)]).Solution; var runningProjects = new[] { a, b }; - var results = CreateMockResults(updates: [c], rudeEdits: [d]); + var results = CreateMockResults(solution, updates: [c], rudeEdits: [d]); var projectsToRestart = new HashSet(); var projectsToRebuild = new HashSet(); @@ -280,7 +292,7 @@ public void RunningProjects_RudeEditAndUpdate_Chain(bool reverse) .AddTestProject("R4", out var r4).AddProjectReferences([new(p4)]).Solution; var runningProjects = new[] { r1, r2, r3, r4 }; - var results = CreateMockResults(updates: reverse ? [p4, p3, p2] : [p2, p3, p4], rudeEdits: [p1]); + var results = CreateMockResults(solution, updates: reverse ? [p4, p3, p2] : [p2, p3, p4], rudeEdits: [p1]); var projectsToRestart = new HashSet(); var projectsToRebuild = new HashSet(); diff --git a/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs b/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs index c61ef840ee077..472aef5156b4f 100644 --- a/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs +++ b/src/Features/Test/EditAndContinue/RemoteEditAndContinueServiceTests.cs @@ -200,24 +200,25 @@ await localWorkspace.ChangeSolutionAsync(localWorkspace.CurrentSolution var syntaxError = Diagnostic.Create(diagnosticDescriptor1, Location.Create(syntaxTree, TextSpan.FromBounds(1, 2)), new[] { "doc", "syntax error" }); var updates = new ModuleUpdates(ModuleUpdateStatus.Ready, deltas); - var diagnostics = ImmutableArray.Create(new ProjectDiagnostics(project.Id, ImmutableArray.Create(documentDiagnostic, projectDiagnostic))); - var documentsWithRudeEdits = ImmutableArray.Create((documentId, ImmutableArray.Empty)); + var diagnostics = ImmutableArray.Create(new ProjectDiagnostics(project.Id, [documentDiagnostic, projectDiagnostic])); + var documentsWithRudeEdits = ImmutableArray.Create(new ProjectDiagnostics(project.Id, [])); return new() { + Solution = solution, ModuleUpdates = updates, Diagnostics = diagnostics, - RudeEdits = documentsWithRudeEdits, + RudeEdits = [], SyntaxError = syntaxError }; }; - var (updates, _, _, syntaxErrorData) = await sessionProxy.EmitSolutionUpdateAsync(localWorkspace.CurrentSolution, activeStatementSpanProvider, CancellationToken.None); - AssertEx.Equal($"[{projectId}] Error ENC1001: test.cs(0, 1, 0, 2): {string.Format(FeaturesResources.ErrorReadingFile, "doc", "syntax error")}", Inspect(syntaxErrorData!)); + var results = await sessionProxy.EmitSolutionUpdateAsync(localWorkspace.CurrentSolution, activeStatementSpanProvider, CancellationToken.None); + AssertEx.Equal($"[{projectId}] Error ENC1001: test.cs(0, 1, 0, 2): {string.Format(FeaturesResources.ErrorReadingFile, "doc", "syntax error")}", Inspect(results.SyntaxError!)); - Assert.Equal(ModuleUpdateStatus.Ready, updates.Status); + Assert.Equal(ModuleUpdateStatus.Ready, results.ModuleUpdates.Status); - var delta = updates.Updates.Single(); + var delta = results.ModuleUpdates.Updates.Single(); Assert.Equal(moduleId1, delta.Module); AssertEx.Equal(new byte[] { 1, 2 }, delta.ILDelta); AssertEx.Equal(new byte[] { 3, 4 }, delta.MetadataDelta); diff --git a/src/Features/Test/EditAndContinue/RudeEditDiagnosticTests.cs b/src/Features/Test/EditAndContinue/RudeEditDiagnosticTests.cs index c5fdc1551a471..04f4c36afcd54 100644 --- a/src/Features/Test/EditAndContinue/RudeEditDiagnosticTests.cs +++ b/src/Features/Test/EditAndContinue/RudeEditDiagnosticTests.cs @@ -55,15 +55,15 @@ public void ToDiagnostic() var arg2 = new HashSet() { - RudeEditKind.InsertIntoStruct, - RudeEditKind.InsertIntoStruct, + RudeEditKind.InsertOrMoveStructMember, + RudeEditKind.InsertOrMoveTypeWithLayoutMember, RudeEditKind.ChangingCapturedVariableType, RudeEditKind.RenamingCapturedVariable, RudeEditKind.ChangingStateMachineShape, RudeEditKind.InternalError, RudeEditKind.MemberBodyInternalError, RudeEditKind.ChangingNonCustomAttribute, - RudeEditKind.NotCapturingPrimaryConstructorParameter, + RudeEditKind.NotCapturingPrimaryConstructorParameter }; var arg3 = new HashSet() diff --git a/src/Features/Test/EditAndContinue/TraceLogTests.cs b/src/Features/Test/EditAndContinue/TraceLogTests.cs index 385f44ed450be..72f344f4bc8c0 100644 --- a/src/Features/Test/EditAndContinue/TraceLogTests.cs +++ b/src/Features/Test/EditAndContinue/TraceLogTests.cs @@ -26,14 +26,14 @@ public void Write() log.Write("e"); log.Write("f"); - AssertEx.Equal(new[] - { - "f", - "b 1 x 0x000000FF", - "c", - $"d str= projectId=MyProject summary=RudeEdits diagnostic=`{diagnostic}`", - "e" - }, log.GetTestAccessor().Entries.Select(e => e.GetDebuggerDisplay())); + AssertEx.Equal( + [ + "f", + "b 1 x 0x000000FF", + "c", + $"d str= projectId=MyProject summary=RudeEdits diagnostic=`{diagnostic}`", + "e" + ], log.GetTestAccessor().Entries.Select(e => e.GetDebuggerDisplay())); } } } diff --git a/src/Features/Test/EditAndContinue/UnitTestingHotReloadServiceTests.cs b/src/Features/Test/EditAndContinue/UnitTestingHotReloadServiceTests.cs index 7756b4b6da791..fe44ddf327e40 100644 --- a/src/Features/Test/EditAndContinue/UnitTestingHotReloadServiceTests.cs +++ b/src/Features/Test/EditAndContinue/UnitTestingHotReloadServiceTests.cs @@ -71,7 +71,7 @@ public async Task Test() // Rude edit result = await hotReload.EmitSolutionUpdateAsync(solution, commitUpdates: true, CancellationToken.None); AssertEx.Equal( - new[] { "ENC0110: " + string.Format(FeaturesResources.Changing_the_signature_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.method) }, + ["ENC0110: " + string.Format(FeaturesResources.Changing_the_signature_of_0_requires_restarting_the_application_because_it_is_not_supported_by_the_runtime, FeaturesResources.method)], result.diagnostics.Select(d => $"{d.Id}: {d.GetMessage()}")); Assert.Empty(result.updates); diff --git a/src/Features/Test/EditAndContinue/WatchHotReloadServiceTests.cs b/src/Features/Test/EditAndContinue/WatchHotReloadServiceTests.cs index 7018226b5df27..364197f4a8a09 100644 --- a/src/Features/Test/EditAndContinue/WatchHotReloadServiceTests.cs +++ b/src/Features/Test/EditAndContinue/WatchHotReloadServiceTests.cs @@ -5,7 +5,9 @@ #if NET #nullable disable +using System; using System.Collections.Immutable; +using System.IO; using System.Linq; using System.Text; using System.Threading; @@ -13,8 +15,11 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.ExternalAccess.Watch.Api; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; +using Roslyn.Test.Utilities.TestGenerators; using Roslyn.Utilities; using Xunit; @@ -109,5 +114,59 @@ public async Task Test() hotReload.EndSession(); } + + [Fact] + public async Task SourceGeneratorFailure() + { + using var workspace = CreateWorkspace(out var solution, out var encService); + + var generatorExecutionCount = 0; + var generator = new TestSourceGenerator() + { + ExecuteImpl = context => + { + generatorExecutionCount++; + + var additionalText = context.AdditionalFiles.Single().GetText().ToString(); + if (additionalText.Contains("updated")) + { + throw new InvalidOperationException("Source generator failed"); + } + + context.AddSource("generated.cs", SourceText.From("generated: " + additionalText, Encoding.UTF8, SourceHashAlgorithm.Sha256)); + } + }; + + var project = solution + .AddTestProject("A") + .AddAdditionalDocument("A.txt", "text", filePath: Path.Combine(TempRoot.Root, "A.txt")) + .Project; + + var projectId = project.Id; + solution = project.Solution.AddAnalyzerReference(projectId, new TestGeneratorReference(generator)); + project = solution.GetRequiredProject(projectId); + var aId = project.AdditionalDocumentIds.Single(); + + var generatedDocuments = await project.Solution.CompilationState.GetSourceGeneratedDocumentStatesAsync(project.State, CancellationToken.None); + + var generatedText = generatedDocuments.States.Single().Value.GetTextSynchronously(CancellationToken.None).ToString(); + AssertEx.AreEqual("generated: text", generatedText); + Assert.Equal(1, generatorExecutionCount); + + var generatorDiagnostics = await solution.CompilationState.GetSourceGeneratorDiagnosticsAsync(project.State, CancellationToken.None); + Assert.Empty(generatorDiagnostics); + + var hotReload = new WatchHotReloadService(workspace.Services, ["Baseline", "AddDefinitionToExistingType", "NewTypeDefinition"]); + + await hotReload.StartSessionAsync(solution, CancellationToken.None); + + solution = solution.WithAdditionalDocumentText(aId, CreateText("updated text")); + + var result = await hotReload.GetUpdatesAsync(solution, isRunningProject: _ => true, CancellationToken.None); + var diagnostic = result.Diagnostics.Single(); + Assert.Equal("CS8785", diagnostic.Id); + Assert.Contains("Source generator failed", diagnostic.GetMessage()); + hotReload.EndSession(); + } } #endif diff --git a/src/Features/Test/FindUsages/DefinitionItemFactoryTests.cs b/src/Features/Test/FindUsages/DefinitionItemFactoryTests.cs index da8274c896593..8795dc2a44e8c 100644 --- a/src/Features/Test/FindUsages/DefinitionItemFactoryTests.cs +++ b/src/Features/Test/FindUsages/DefinitionItemFactoryTests.cs @@ -112,7 +112,7 @@ void verify(Action assert) { assert(); } - catch (AssertActualExpectedException e) + catch (Exception e) when (e is IAssertionException) { failures.Add(e); } @@ -353,8 +353,8 @@ public async Task ToClassifiedDefinitionItemAsync_Namespace_Metadata() "mscorlib 4.0.0.0 'Z:\\FxReferenceAssembliesUri'", "System 4.0.0.0 ''", "System.Core 4.0.0.0 ''", - "System.ValueTuple 4.0.1.0 ''", - "System.Runtime 4.0.10.0 ''" + "System.ValueTuple 4.0.3.0 'System.ValueTuple.dll'", + "System.Runtime 4.0.20.0 ''" ], tags: [ @@ -405,8 +405,8 @@ namespace System { class D {} } "mscorlib 4.0.0.0 'Z:\\FxReferenceAssembliesUri'", "System 4.0.0.0 ''", "System.Core 4.0.0.0 ''", - "System.ValueTuple 4.0.1.0 ''", - "System.Runtime 4.0.10.0 ''" + "System.ValueTuple 4.0.3.0 'System.ValueTuple.dll'", + "System.Runtime 4.0.20.0 ''" ], sourceSpans: [ @@ -735,7 +735,7 @@ public async Task ToClassifiedDefinitionItemAsync_TupleSyntax() // the symbol has metadata locations because the generic type is in metadata: metadataLocations: [ - "System.ValueTuple 4.0.1.0 ''" + "System.ValueTuple 4.0.3.0 'System.ValueTuple.dll'" ], tags: [ @@ -791,7 +791,7 @@ public async Task ToClassifiedDefinitionItemAsync_ValueTuple() ], metadataLocations: [ - "System.ValueTuple 4.0.1.0 ''" + "System.ValueTuple 4.0.3.0 'System.ValueTuple.dll'" ], tags: [ diff --git a/src/Features/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs b/src/Features/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs index f5767ebb02d68..8627649d954d6 100644 --- a/src/Features/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs +++ b/src/Features/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs @@ -25,18 +25,11 @@ public class TestDiagnosticAnalyzerDriver private readonly bool _includeSuppressedDiagnostics; private readonly bool _includeNonLocalDocumentDiagnostics; - internal readonly IGlobalOptionService GlobalOptions; - internal readonly CodeActionOptionsProvider FallbackOptions; - public TestDiagnosticAnalyzerDriver(Workspace workspace, bool includeSuppressedDiagnostics = false, bool includeNonLocalDocumentDiagnostics = false) { var mefServices = workspace.Services.SolutionServices.ExportProvider; _diagnosticAnalyzerService = Assert.IsType(mefServices.GetExportedValue()); - - GlobalOptions = mefServices.GetExportedValue(); - FallbackOptions = GlobalOptions.CreateProvider(); - _diagnosticAnalyzerService.CreateIncrementalAnalyzer(workspace); _includeSuppressedDiagnostics = includeSuppressedDiagnostics; _includeNonLocalDocumentDiagnostics = includeNonLocalDocumentDiagnostics; diff --git a/src/Features/TestUtilities/EditAndContinue/ActiveStatementsDescription.cs b/src/Features/TestUtilities/EditAndContinue/ActiveStatementsDescription.cs index c7dcbbf56cf69..46b1ff47b7d2e 100644 --- a/src/Features/TestUtilities/EditAndContinue/ActiveStatementsDescription.cs +++ b/src/Features/TestUtilities/EditAndContinue/ActiveStatementsDescription.cs @@ -52,8 +52,8 @@ public ActiveStatementsDescription(string oldMarkedSource, string newMarkedSourc var activeStatementCount = Math.Max(OldStatements.Length, (newActiveStatementMarkers.Length == 0) ? -1 : newActiveStatementMarkers.Max(m => m.Id)); - var newMappedSpans = new ArrayBuilder(); - var newMappedRegions = new ArrayBuilder>(); + using var _1 = ArrayBuilder.GetInstance(out var newMappedSpans); + using var _2 = ArrayBuilder>.GetInstance(out var newMappedRegions); var newExceptionRegionMarkers = SourceMarkers.GetExceptionRegions(newMarkedSource); newMappedSpans.ZeroInit(activeStatementCount); @@ -137,7 +137,7 @@ internal static ImmutableArray GetUnmappedActiveStateme { var map = new Dictionary>(); - var activeStatements = new ArrayBuilder(); + using var _ = ArrayBuilder.GetInstance(out var activeStatements); var sourceIndex = 0; foreach (var markedSource in markedSources) diff --git a/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs b/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs index 71932011549d6..7a3b064a24196 100644 --- a/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs +++ b/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs @@ -322,12 +322,11 @@ SymbolKey CreateSymbolKey(SemanticEditDescription edit) // Symbol key will happily resolve to a definition part that has no implementation, so we validate that // differently - // https://github.com/dotnet/roslyn/issues/73772: what about deletion of partial property? - if (expectedOldSymbol is IMethodSymbol { IsPartialDefinition: true } && - symbolKey.Resolve(oldCompilation, ignoreAssemblyKey: true).Symbol is IMethodSymbol resolvedMethod) + if (expectedOldSymbol.IsPartialDefinition() && + symbolKey.Resolve(oldCompilation, ignoreAssemblyKey: true).Symbol is ISymbol resolvedSymbol) { - Assert.Equal(expectedOldSymbol, resolvedMethod.PartialDefinitionPart); - Assert.Equal(null, resolvedMethod.PartialImplementationPart); + Assert.Equal(expectedOldSymbol, resolvedSymbol.PartialDefinitionPart()); + Assert.Equal(null, resolvedSymbol.PartialImplementationPart()); } else { @@ -522,7 +521,13 @@ public static void SetDocumentsState(DebuggingSession session, Solution solution internal static class EditScriptTestUtils { + public static void VerifyEdits(this EditScript actual) + => VerifyEdits(actual, Array.Empty()); + public static void VerifyEdits(this EditScript actual, params string[] expected) => AssertEx.Equal(expected, actual.Edits.Select(e => e.GetDebuggerDisplay()), itemSeparator: ",\r\n", itemInspector: s => $"\"{s}\""); + + public static void VerifyEdits(this EditScript actual, params EditKind[] expected) + => AssertEx.Equal(expected, actual.Edits.Select(e => e.Kind)); } } diff --git a/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs b/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs index b702d1023e075..c3d1e45a08f0c 100644 --- a/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs +++ b/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs @@ -73,7 +73,7 @@ internal static (Solution, Document) AddDefaultTestProject( string? additionalFileText = null, (string key, string value)[]? analyzerConfig = null) { - solution = AddDefaultTestProject(solution, new[] { source }, generator, additionalFileText, analyzerConfig); + solution = AddDefaultTestProject(solution, [source], generator, additionalFileText, analyzerConfig); return (solution, solution.Projects.Single().Documents.Single()); } @@ -263,7 +263,7 @@ internal Guid EmitLibrary( { var optionsProvider = (analyzerOptions != null) ? new EditAndContinueTestAnalyzerConfigOptionsProvider(analyzerOptions) : null; var additionalTexts = (additionalFileText != null) ? new[] { new InMemoryAdditionalText("additional_file", additionalFileText) } : null; - var generatorDriver = CSharpGeneratorDriver.Create(new[] { generator }, additionalTexts, parseOptions, optionsProvider); + var generatorDriver = CSharpGeneratorDriver.Create([generator], additionalTexts, parseOptions, optionsProvider); generatorDriver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generatorDiagnostics); generatorDiagnostics.Verify(); compilation = outputCompilation; @@ -414,7 +414,7 @@ void Generate(string source, string fileName) const string ClosingMarker = "*/"; var index = markedSource.IndexOf(OpeningMarker); - if (index > 0) + if (index >= 0) { index += OpeningMarker.Length; var closing = markedSource.IndexOf(ClosingMarker, index); diff --git a/src/Features/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs b/src/Features/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs index e2b1c7288c47c..c0bbfe82cd205 100644 --- a/src/Features/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs +++ b/src/Features/TestUtilities/EditAndContinue/RudeEditDiagnosticDescription.cs @@ -12,7 +12,6 @@ namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests internal readonly struct RudeEditDiagnosticDescription : IEquatable { public readonly RudeEditKind RudeEditKind; - private readonly string? _firstLine; private readonly string? _squiggle; private readonly string[] _arguments; @@ -20,11 +19,11 @@ internal RudeEditDiagnosticDescription(RudeEditKind rudeEditKind, string? squigg { RudeEditKind = rudeEditKind; _squiggle = squiggle; - _firstLine = firstLine; + FirstLine = firstLine; _arguments = arguments ?? []; } - public string? FirstLine => _firstLine; + public string? FirstLine { get; } public RudeEditDiagnosticDescription WithFirstLine(string value) => new(RudeEditKind, _squiggle, _arguments, value.Trim()); @@ -33,7 +32,7 @@ public bool Equals(RudeEditDiagnosticDescription other) { return RudeEditKind == other.RudeEditKind && _squiggle == other._squiggle - && (_firstLine == other._firstLine || _firstLine == null || other._firstLine == null) + && (FirstLine == other.FirstLine || FirstLine == null || other.FirstLine == null) && _arguments.SequenceEqual(other._arguments, object.Equals); } @@ -59,7 +58,7 @@ public string ToString(Func? tryGetResource) : $"\"{_squiggle}\""; string[] arguments = [formattedSquiggle, .. _arguments.Select(a => tryGetResource?.Invoke(a) is { } ? $"GetResource(\"{a}\")" : $"\"{a}\"")]; - var withLine = (_firstLine != null) ? $".WithFirstLine(\"{_firstLine}\")" : null; + var withLine = (FirstLine != null) ? $".WithFirstLine(\"{FirstLine}\")" : null; return $"Diagnostic(RudeEditKind.{RudeEditKind}, {string.Join(", ", arguments)}){withLine}"; } diff --git a/src/Features/TestUtilities/Microsoft.CodeAnalysis.Features.Test.Utilities.csproj b/src/Features/TestUtilities/Microsoft.CodeAnalysis.Features.Test.Utilities.csproj index cc5520dcabc29..8c589af9025c2 100644 --- a/src/Features/TestUtilities/Microsoft.CodeAnalysis.Features.Test.Utilities.csproj +++ b/src/Features/TestUtilities/Microsoft.CodeAnalysis.Features.Test.Utilities.csproj @@ -8,7 +8,7 @@ true false true - true + true diff --git a/src/Features/TestUtilities/RelatedDocuments/AbstractRelatedDocumentsTests.cs b/src/Features/TestUtilities/RelatedDocuments/AbstractRelatedDocumentsTests.cs new file mode 100644 index 0000000000000..46cfcd94b8037 --- /dev/null +++ b/src/Features/TestUtilities/RelatedDocuments/AbstractRelatedDocumentsTests.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.RelatedDocuments; +using Microsoft.CodeAnalysis.Remote.Testing; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Test.Utilities; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Test.Utilities.RelatedDocuments; + +[UseExportProvider] +public abstract class AbstractRelatedDocumentsTests +{ + protected static async Task TestAsync(string testMarkup, TestHost testHost) + { + using var workspace = TestWorkspace.Create( + testMarkup, + composition: FeaturesTestCompositions.Features.WithTestHostParts(testHost)); + + var caretDocument = workspace.Documents.Single(d => d.CursorPosition.HasValue); + var caretPosition = caretDocument.CursorPosition!.Value; + var documentId = caretDocument.Id; + + var startingDocument = workspace.CurrentSolution.GetRequiredDocument(documentId); + var service = startingDocument.GetRequiredLanguageService(); + + var results = new List(); + await service.GetRelatedDocumentIdsAsync( + startingDocument, caretPosition, (documentIds, _) => + { + lock (results) + results.AddRange(documentIds); + + return ValueTaskFactory.CompletedTask; + }, CancellationToken.None); + + Assert.True(results.Distinct().Count() == results.Count); + + var actualSortedResults = results.OrderBy(d => d.Id); + var expectedSortedResults = workspace.Documents.Where(d => d.SelectedSpans.Count > 0).Select(d => d.Id).OrderBy(d => d.Id); + + AssertEx.Equal(expectedSortedResults, actualSortedResults); + } +} diff --git a/src/Features/TestUtilities/Snippets/AbstractSnippetProviderTests.cs b/src/Features/TestUtilities/Snippets/AbstractSnippetProviderTests.cs new file mode 100644 index 0000000000000..838958b955dd1 --- /dev/null +++ b/src/Features/TestUtilities/Snippets/AbstractSnippetProviderTests.cs @@ -0,0 +1,139 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; +using Xunit; + +namespace Microsoft.CodeAnalysis.Test.Utilities.Snippets; + +[UseExportProvider] +public abstract class AbstractSnippetProviderTests +{ + protected abstract string SnippetIdentifier { get; } + + protected abstract string LanguageName { get; } + + protected async Task VerifySnippetAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string markupBeforeCommit, + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string markupAfterCommit, + string? editorconfig = null, + ReferenceAssemblies? referenceAssemblies = null) + { + using var workspace = new TestWorkspace(FeaturesTestCompositions.Features); + + referenceAssemblies ??= ReferenceAssemblies.Default; + var metadataReferences = await referenceAssemblies.ResolveAsync(LanguageName, CancellationToken.None); + var project = workspace.CurrentSolution. + AddProject("TestProject", "TestAssembly", LanguageName) + .WithMetadataReferences(metadataReferences); + + TestFileMarkupParser.GetPosition(markupBeforeCommit, out markupBeforeCommit, out var snippetRequestPosition); + var document = project.AddDocument("TestDocument", markupBeforeCommit, filePath: "/TestDocument"); + + if (editorconfig is not null) + { + var editorConfigDoc = document.Project.AddAnalyzerConfigDocument(".editorconfig", SourceText.From(editorconfig), filePath: "/.editorconfig"); + document = editorConfigDoc.Project.GetDocument(document.Id)!; + } + + var snippetServiceInterface = document.GetRequiredLanguageService(); + var snippetService = Assert.IsAssignableFrom(snippetServiceInterface); + + snippetService.EnsureSnippetsLoaded(LanguageName); + var snippetProvider = snippetService.GetSnippetProvider(SnippetIdentifier); + + var syntaxContextService = document.GetRequiredLanguageService(); + var semanticModel = await document.GetRequiredSemanticModelAsync(CancellationToken.None); + var syntaxContext = syntaxContextService.CreateContext(document, semanticModel, snippetRequestPosition, CancellationToken.None); + + var snippetContext = new SnippetContext(syntaxContext); + var isValidSnippetLocation = snippetProvider.IsValidSnippetLocation(snippetContext, CancellationToken.None); + Assert.True(isValidSnippetLocation, "Snippet is unexpectedly invalid on a given position"); + + var snippetChange = await snippetProvider.GetSnippetChangeAsync(document, snippetRequestPosition, CancellationToken.None); + var documentSourceText = await document.GetTextAsync(); + var documentTextAfterSnippet = documentSourceText.WithChanges(snippetChange.TextChanges); + + TestFileMarkupParser.GetPositionAndSpans(markupAfterCommit, out markupAfterCommit, out int finalCaretPosition, out ImmutableDictionary> placeholderLocations); + Assert.Equal(markupAfterCommit, documentTextAfterSnippet.ToString()); + + var placeholderLocationsArray = new ImmutableArray[placeholderLocations.Count]; + var snippetPlaceholders = snippetChange.Placeholders; + Assert.Equal(placeholderLocationsArray.Length, snippetPlaceholders.Length); + + foreach (var placeholderLocationPair in placeholderLocations) + { + if (!int.TryParse(placeholderLocationPair.Key, out var locationIndex)) + { + Assert.True(false, "Expected placeholder locations contains span with invalid annotation"); + return; + } + + placeholderLocationsArray[locationIndex] = placeholderLocationPair.Value; + } + + for (var i = 0; i < placeholderLocationsArray.Length; i++) + { + if (placeholderLocationsArray[i].IsDefault) + { + Assert.True(false, $"Placeholder location for index {i} was not specified"); + } + } + + for (var i = 0; i < snippetPlaceholders.Length; i++) + { + var expectedSpans = placeholderLocationsArray[i]; + var (placeholderText, placeholderPositions) = snippetPlaceholders[i]; + + Assert.Equal(expectedSpans.Length, placeholderPositions.Length); + + for (var j = 0; j < placeholderPositions.Length; j++) + { + var expectedSpan = expectedSpans[j]; + Assert.Contains(expectedSpan.Start, placeholderPositions); + Assert.Equal(documentTextAfterSnippet.ToString(expectedSpan), placeholderText); + } + } + + Assert.Equal(finalCaretPosition, snippetChange.FinalCaretPosition); + } + + protected async Task VerifySnippetIsAbsentAsync( + [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string markup, + ReferenceAssemblies? referenceAssemblies = null) + { + using var workspace = new TestWorkspace(FeaturesTestCompositions.Features); + + referenceAssemblies ??= ReferenceAssemblies.Default; + var metadataReferences = await referenceAssemblies.ResolveAsync(LanguageName, CancellationToken.None); + var project = workspace.CurrentSolution. + AddProject("TestProject", "TestAssembly", LanguageName) + .WithMetadataReferences(metadataReferences); + + TestFileMarkupParser.GetPosition(markup, out markup, out var snippetRequestPosition); + var document = project.AddDocument("TestDocument", markup); + + var snippetServiceInterface = document.GetRequiredLanguageService(); + var snippetService = Assert.IsAssignableFrom(snippetServiceInterface); + + snippetService.EnsureSnippetsLoaded(LanguageName); + var snippetProvider = snippetService.GetSnippetProvider(SnippetIdentifier); + + var syntaxContextService = document.GetRequiredLanguageService(); + var semanticModel = await document.GetRequiredSemanticModelAsync(CancellationToken.None); + var syntaxContext = syntaxContextService.CreateContext(document, semanticModel, snippetRequestPosition, CancellationToken.None); + + var snippetContext = new SnippetContext(syntaxContext); + var isValidSnippetLocation = snippetProvider.IsValidSnippetLocation(snippetContext, CancellationToken.None); + Assert.False(isValidSnippetLocation, "Snippet is unexpectedly valid on a given position"); + } +} diff --git a/src/Features/DiagnosticsTestUtilities/Utilities/StringSyntaxAttribute.cs b/src/Features/TestUtilities/Utilities/StringSyntaxAttribute.cs similarity index 89% rename from src/Features/DiagnosticsTestUtilities/Utilities/StringSyntaxAttribute.cs rename to src/Features/TestUtilities/Utilities/StringSyntaxAttribute.cs index 4c54aa7019884..9e06c3e595612 100644 --- a/src/Features/DiagnosticsTestUtilities/Utilities/StringSyntaxAttribute.cs +++ b/src/Features/TestUtilities/Utilities/StringSyntaxAttribute.cs @@ -7,7 +7,7 @@ namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] - public sealed class StringSyntaxAttribute : Attribute + internal sealed class StringSyntaxAttribute : Attribute { public StringSyntaxAttribute(string syntax) => Syntax = syntax; public string Syntax { get; } diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb index 206082535f804..0c4b60548073c 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb @@ -78,6 +78,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers ' If the user is typing in xml text, don't trigger on backspace. If token.IsKind(SyntaxKind.XmlTextLiteralToken) AndAlso + Not token.Parent.IsKind(SyntaxKind.XmlString) AndAlso trigger.Kind = CompletionTriggerKind.Deletion Then Return Nothing End If diff --git a/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb b/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb index 28556a2f30284..5b72758a44be3 100644 --- a/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb @@ -809,7 +809,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue Return End If - result.Add((oldSymbol.ContainingSymbol, newSymbol.ContainingSymbol, EditKind.Update)) + ' Reordering of data members is only allowed if the layout of the type doesn't change. + ' Reordering of other members is a no-op, although the new order won't be reflected in metadata (Reflection will report original order). + result.Add((oldSymbol, newSymbol, EditKind.Reorder)) Case EditKind.Delete result.Add((oldSymbol, Nothing, editKind)) @@ -913,7 +915,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue Case SyntaxKind.FieldDeclaration ' Attribute or modifier update - If editKind = EditKind.Update Then + If editKind = EditKind.Update OrElse editKind = EditKind.Reorder Then Dim field = CType(node, FieldDeclarationSyntax) If field.Declarators.Count = 1 AndAlso field.Declarators(0).Names.Count = 1 Then node = field.Declarators(0).Names(0) @@ -1796,55 +1798,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue Private Sub ClassifyReorder(oldNode As SyntaxNode, newNode As SyntaxNode) Select Case newNode.Kind - Case SyntaxKind.OptionStatement, - SyntaxKind.ImportsStatement, - SyntaxKind.AttributesStatement, - SyntaxKind.NamespaceBlock, - SyntaxKind.ClassBlock, - SyntaxKind.StructureBlock, - SyntaxKind.InterfaceBlock, - SyntaxKind.ModuleBlock, - SyntaxKind.EnumBlock, - SyntaxKind.DelegateFunctionStatement, - SyntaxKind.DelegateSubStatement, - SyntaxKind.SubBlock, - SyntaxKind.FunctionBlock, - SyntaxKind.DeclareSubStatement, - SyntaxKind.DeclareFunctionStatement, - SyntaxKind.ConstructorBlock, - SyntaxKind.OperatorBlock, - SyntaxKind.PropertyBlock, - SyntaxKind.EventBlock, - SyntaxKind.GetAccessorBlock, - SyntaxKind.SetAccessorBlock, - SyntaxKind.AddHandlerAccessorBlock, - SyntaxKind.RemoveHandlerAccessorBlock, - SyntaxKind.RaiseEventAccessorBlock, - SyntaxKind.ClassConstraint, - SyntaxKind.StructureConstraint, - SyntaxKind.NewConstraint, - SyntaxKind.TypeConstraint, - SyntaxKind.AttributeList, - SyntaxKind.Attribute, - SyntaxKind.Parameter - ' We'll ignore these edits. A general policy is to ignore edits that are only discoverable via reflection. - Return - - Case SyntaxKind.SubStatement, - SyntaxKind.FunctionStatement - ' Interface methods. We could allow reordering of non-COM interface methods. - Debug.Assert(oldNode.Parent.IsKind(SyntaxKind.InterfaceBlock) AndAlso newNode.Parent.IsKind(SyntaxKind.InterfaceBlock)) - ReportError(RudeEditKind.Move) - Return - - Case SyntaxKind.PropertyStatement, - SyntaxKind.FieldDeclaration, - SyntaxKind.EventStatement - ' Maybe we could allow changing order of field declarations unless the containing type layout is sequential, - ' and it's not a COM interface. - ReportError(RudeEditKind.Move) - Return - Case SyntaxKind.EnumMemberDeclaration ' To allow this change we would need to check that values of all fields of the enum ' are preserved, or make sure we can update all method bodies that accessed those that changed. @@ -1860,9 +1813,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue ' Identifier can be moved within the same type declaration. ' Determine validity of such change in semantic analysis. Return - - Case Else - Throw ExceptionUtilities.UnexpectedValue(newNode.Kind) End Select End Sub @@ -2335,16 +2285,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue forwardMap As IReadOnlyDictionary(Of SyntaxNode, SyntaxNode), oldActiveStatement As SyntaxNode, oldBody As DeclarationBody, + oldModel As SemanticModel, newActiveStatement As SyntaxNode, newBody As DeclarationBody, - isNonLeaf As Boolean) + newModel As SemanticModel, + isNonLeaf As Boolean, + cancellationToken As CancellationToken) Dim onErrorOrResumeStatement = FindOnErrorOrResumeStatement(newBody) If onErrorOrResumeStatement IsNot Nothing Then AddAroundActiveStatementRudeDiagnostic(diagnostics, oldActiveStatement, onErrorOrResumeStatement, newActiveStatement.Span) End If - ReportRudeEditsForAncestorsDeclaringInterStatementTemps(diagnostics, forwardMap, oldActiveStatement, oldBody.EncompassingAncestor, newActiveStatement, newBody.EncompassingAncestor) + ReportRudeEditsForAncestorsDeclaringInterStatementTemps(diagnostics, forwardMap, oldActiveStatement, oldBody.EncompassingAncestor, oldModel, newActiveStatement, newBody.EncompassingAncestor, newModel, cancellationToken) End Sub Private Shared Function FindOnErrorOrResumeStatement(newBody As DeclarationBody) As SyntaxNode @@ -2370,8 +2323,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue forwardMap As IReadOnlyDictionary(Of SyntaxNode, SyntaxNode), oldActiveStatement As SyntaxNode, oldEncompassingAncestor As SyntaxNode, + oldModel As SemanticModel, newActiveStatement As SyntaxNode, - newEncompassingAncestor As SyntaxNode) + newEncompassingAncestor As SyntaxNode, + newModel As SemanticModel, + cancellationToken As CancellationToken) ' Rude Edits for Using/SyncLock/With/ForEach statements that are added/updated around an active statement. ' Although such changes are technically possible, they might lead to confusion since @@ -2382,22 +2338,34 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue ' ' Unlike exception regions matching where we use LCS, we allow reordering of the statements. - ReportUnmatchedStatements(Of SyncLockBlockSyntax)(diagnostics, forwardMap, Function(node) node.IsKind(SyntaxKind.SyncLockBlock), oldActiveStatement, oldEncompassingAncestor, newActiveStatement, newEncompassingAncestor, + ReportUnmatchedStatements(Of SyncLockBlockSyntax)(diagnostics, forwardMap, oldActiveStatement, oldEncompassingAncestor, oldModel, newActiveStatement, newEncompassingAncestor, newModel, + nodeSelector:=Function(node) node.IsKind(SyntaxKind.SyncLockBlock), + getTypedNodes:=Function(n) OneOrMany.Create(Of SyntaxNode)(n.SyncLockStatement.Expression), areEquivalent:=Function(n1, n2) AreEquivalentIgnoringLambdaBodies(n1.SyncLockStatement.Expression, n2.SyncLockStatement.Expression), - areSimilar:=Nothing) + areSimilar:=Nothing, + cancellationToken) - ReportUnmatchedStatements(Of WithBlockSyntax)(diagnostics, forwardMap, Function(node) node.IsKind(SyntaxKind.WithBlock), oldActiveStatement, oldEncompassingAncestor, newActiveStatement, newEncompassingAncestor, + ReportUnmatchedStatements(Of WithBlockSyntax)(diagnostics, forwardMap, oldActiveStatement, oldEncompassingAncestor, oldModel, newActiveStatement, newEncompassingAncestor, newModel, + nodeSelector:=Function(node) node.IsKind(SyntaxKind.WithBlock), + getTypedNodes:=Function(n) OneOrMany.Create(Of SyntaxNode)(n.WithStatement.Expression), areEquivalent:=Function(n1, n2) AreEquivalentIgnoringLambdaBodies(n1.WithStatement.Expression, n2.WithStatement.Expression), - areSimilar:=Nothing) + areSimilar:=Nothing, + cancellationToken) - ReportUnmatchedStatements(Of UsingBlockSyntax)(diagnostics, forwardMap, Function(node) node.IsKind(SyntaxKind.UsingBlock), oldActiveStatement, oldEncompassingAncestor, newActiveStatement, newEncompassingAncestor, + ReportUnmatchedStatements(Of UsingBlockSyntax)(diagnostics, forwardMap, oldActiveStatement, oldEncompassingAncestor, oldModel, newActiveStatement, newEncompassingAncestor, newModel, + nodeSelector:=Function(node) node.IsKind(SyntaxKind.UsingBlock), + getTypedNodes:=Function(n) OneOrMany.Create(Of SyntaxNode)(n.UsingStatement.Expression), areEquivalent:=Function(n1, n2) AreEquivalentIgnoringLambdaBodies(n1.UsingStatement.Expression, n2.UsingStatement.Expression), - areSimilar:=Nothing) + areSimilar:=Nothing, + cancellationToken) - ReportUnmatchedStatements(Of ForOrForEachBlockSyntax)(diagnostics, forwardMap, Function(node) node.IsKind(SyntaxKind.ForEachBlock), oldActiveStatement, oldEncompassingAncestor, newActiveStatement, newEncompassingAncestor, + ReportUnmatchedStatements(Of ForEachBlockSyntax)(diagnostics, forwardMap, oldActiveStatement, oldEncompassingAncestor, oldModel, newActiveStatement, newEncompassingAncestor, newModel, + nodeSelector:=Function(node) node.IsKind(SyntaxKind.ForEachBlock), + getTypedNodes:=Function(n) OneOrMany.Create(Of SyntaxNode)(n.ForEachStatement.Expression), areEquivalent:=Function(n1, n2) AreEquivalentIgnoringLambdaBodies(n1.ForOrForEachStatement, n2.ForOrForEachStatement), areSimilar:=Function(n1, n2) AreEquivalentIgnoringLambdaBodies(DirectCast(n1.ForOrForEachStatement, ForEachStatementSyntax).ControlVariable, - DirectCast(n2.ForOrForEachStatement, ForEachStatementSyntax).ControlVariable)) + DirectCast(n2.ForOrForEachStatement, ForEachStatementSyntax).ControlVariable), + cancellationToken) End Sub #End Region diff --git a/src/Features/VisualBasic/Portable/EncapsulateField/VisualBasicEncapsulateFieldService.vb b/src/Features/VisualBasic/Portable/EncapsulateField/VisualBasicEncapsulateFieldService.vb index 5a0bb2cc393ba..443cb7745a2da 100644 --- a/src/Features/VisualBasic/Portable/EncapsulateField/VisualBasicEncapsulateFieldService.vb +++ b/src/Features/VisualBasic/Portable/EncapsulateField/VisualBasicEncapsulateFieldService.vb @@ -5,7 +5,6 @@ Imports System.Collections.Immutable Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.EncapsulateField Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef @@ -13,9 +12,9 @@ Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.EncapsulateField - - Friend Class VisualBasicEncapsulateFieldService - Inherits AbstractEncapsulateFieldService + + Friend NotInheritable Class VisualBasicEncapsulateFieldService + Inherits AbstractEncapsulateFieldService(Of ConstructorBlockSyntax) @@ -129,10 +128,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EncapsulateField Return NameGenerator.GenerateUniqueName(propertyName, containingTypeMemberNames.ToSet(), StringComparer.OrdinalIgnoreCase) End Function - Protected Overrides Function GetConstructorNodes(containingType As INamedTypeSymbol) As IEnumerable(Of SyntaxNode) - Return containingType.Constructors.SelectMany(Function(c As IMethodSymbol) - Return c.DeclaringSyntaxReferences.Select(Function(d) d.GetSyntax().Parent) - End Function) + Protected Overrides Function GetConstructorNodes(containingType As INamedTypeSymbol) As IEnumerable(Of ConstructorBlockSyntax) + Return containingType.Constructors. + SelectMany(Function(c As IMethodSymbol) c.DeclaringSyntaxReferences.Select(Function(d) d.GetSyntax().Parent)). + OfType(Of ConstructorBlockSyntax)() End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicSemanticQuickInfoProvider.vb b/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicSemanticQuickInfoProvider.vb index 695f312588b15..a279801a7ba31 100644 --- a/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicSemanticQuickInfoProvider.vb +++ b/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicSemanticQuickInfoProvider.vb @@ -197,7 +197,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.QuickInfo Return QuickInfoItem.Create(token.Span, sections:=ImmutableArray.Create(QuickInfoSection.Create(QuickInfoSectionKinds.Description, ImmutableArray.Create(New TaggedText(TextTags.Text, VBFeaturesResources.Multiple_Types))))) End If - Return Await CreateContentAsync(services, semanticModel, token, New TokenInformation(types), supportedPlatforms:=Nothing, options, onTheFlyDocsElement:=Nothing, cancellationToken).ConfigureAwait(False) + Return Await CreateContentAsync(services, semanticModel, token, New TokenInformation(types), supportedPlatforms:=Nothing, options, onTheFlyDocsInfo:=Nothing, cancellationToken).ConfigureAwait(False) End Function Private Shared Function BuildContentForIntrinsicOperator( diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb index bc6d68bd38726..a3744fa7264cb 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb @@ -95,9 +95,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp ' Count how many commas are before us Return New SignatureHelpState( - argumentIndex:=commaTokens.Where(Function(token) token.SpanStart < position).Count(), - argumentCount:=commaTokens.Count() + 1, - argumentName:=Nothing, argumentNames:=Nothing) + SemanticParameterIndex:=commaTokens.Where(Function(token) token.SpanStart < position).Count(), + SyntacticArgumentCount:=commaTokens.Count() + 1, + ArgumentName:=Nothing, + ArgumentNames:=Nothing) End Function Private Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/AccessorDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/AccessorDeclarationStructureProvider.vb index e5c0ad0f10bbf..7503eb4c94722 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/AccessorDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/AccessorDeclarationStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, accessorDeclaration As AccessorStatementSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(accessorDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/CollectionInitializerStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/CollectionInitializerStructureProvider.vb index 5fdc2a85b6887..dd95bbe2bc34b 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/CollectionInitializerStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/CollectionInitializerStructureProvider.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.[Shared].Collections +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -15,7 +15,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As CollectionInitializerSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/CompilationUnitStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/CompilationUnitStructureProvider.vb index efe88ec1e34a3..3eeb0a464ef06 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/CompilationUnitStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/CompilationUnitStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.Text @@ -14,7 +15,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, compilationUnit As CompilationUnitSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(compilationUnit, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/ConstructorDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/ConstructorDeclarationStructureProvider.vb index 8a34075867c20..dc913f7c978ea 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/ConstructorDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/ConstructorDeclarationStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, constructorDeclaration As SubNewStatementSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/DelegateDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/DelegateDeclarationStructureProvider.vb index 3c6309b2177c3..95a925acbc252 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/DelegateDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/DelegateDeclarationStructureProvider.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.[Shared].Collections +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, delegateDeclaration As DelegateStatementSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(delegateDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.vb index ffc46e6c907e9..7e34ae199554b 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/DisabledTextTriviaStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.Text @@ -12,7 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Inherits AbstractSyntaxTriviaStructureProvider Public Overrides Sub CollectBlockSpans(trivia As SyntaxTrivia, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) If trivia.Kind = SyntaxKind.DisabledTextTrivia Then diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/DoLoopBlockStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/DoLoopBlockStructureProvider.vb index 15f50596fcfee..5b2450693a35a 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/DoLoopBlockStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/DoLoopBlockStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As DoLoopBlockSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) spans.AddIfNotNull(CreateBlockSpanFromBlock( diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/DocumentationCommentStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/DocumentationCommentStructureProvider.vb index fbb1cc3928648..0ba7f6e19e8b0 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/DocumentationCommentStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/DocumentationCommentStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.Text @@ -15,7 +16,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, documentationComment As DocumentationCommentTriviaSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) Dim firstCommentToken = documentationComment.ChildNodesAndTokens().FirstOrNull() diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/EnumDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/EnumDeclarationStructureProvider.vb index d80a4c8a8a9c1..0209d7791950f 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/EnumDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/EnumDeclarationStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, enumDeclaration As EnumStatementSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(enumDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/EnumMemberDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/EnumMemberDeclarationStructureProvider.vb index 6f69be4eeaaec..293a4bc05c87b 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/EnumMemberDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/EnumMemberDeclarationStructureProvider.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.[Shared].Collections +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, enumMemberDeclaration As EnumMemberDeclarationSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(enumMemberDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/EventDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/EventDeclarationStructureProvider.vb index 63c589135d134..57242308f18a6 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/EventDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/EventDeclarationStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, eventDeclaration As EventStatementSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(eventDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/ExternalMethodDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/ExternalMethodDeclarationStructureProvider.vb index d6ece26c30a5f..c2c3ae7409ea1 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/ExternalMethodDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/ExternalMethodDeclarationStructureProvider.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.[Shared].Collections +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, externalMethodDeclaration As DeclareStatementSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(externalMethodDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/FieldDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/FieldDeclarationStructureProvider.vb index 169e8a679159f..39bd9533e142c 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/FieldDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/FieldDeclarationStructureProvider.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.[Shared].Collections +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, fieldDeclaration As FieldDeclarationSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(fieldDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/ForBlockStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/ForBlockStructureProvider.vb index fd91efe945f8d..6c77c281595f1 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/ForBlockStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/ForBlockStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As ForBlockSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) spans.AddIfNotNull(CreateBlockSpanFromBlock( diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/ForEachBlockStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/ForEachBlockStructureProvider.vb index 8d52dad6ad464..3ee935ce92775 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/ForEachBlockStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/ForEachBlockStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As ForEachBlockSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) spans.AddIfNotNull(CreateBlockSpanFromBlock( diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/InterpolatedStringExpressionStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/InterpolatedStringExpressionStructureProvider.vb index 7ea0896215908..3e8ccd38716ce 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/InterpolatedStringExpressionStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/InterpolatedStringExpressionStructureProvider.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.[Shared].Collections +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As InterpolatedStringExpressionSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) If node.DollarSignDoubleQuoteToken.IsMissing OrElse diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/MethodDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/MethodDeclarationStructureProvider.vb index 749e31acb30eb..de808bcce7245 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/MethodDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/MethodDeclarationStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, methodDeclaration As MethodStatementSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(methodDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/MultiLineIfBlockStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/MultiLineIfBlockStructureProvider.vb index 2063bab8cb731..5ee042b81cc5e 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/MultiLineIfBlockStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/MultiLineIfBlockStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As MultiLineIfBlockSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) spans.AddIfNotNull(CreateBlockSpanFromBlock( diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/MultilineLambdaStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/MultilineLambdaStructureProvider.vb index be48cb907c22b..ed268aeb2ada1 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/MultilineLambdaStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/MultilineLambdaStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, lambdaExpression As MultiLineLambdaExpressionSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) If Not lambdaExpression.EndSubOrFunctionStatement.IsMissing Then diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/NamespaceDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/NamespaceDeclarationStructureProvider.vb index 6beafc9da0139..1b6be20eac78b 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/NamespaceDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/NamespaceDeclarationStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, namespaceDeclaration As NamespaceStatementSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(namespaceDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/ObjectCreationInitializerStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/ObjectCreationInitializerStructureProvider.vb index b46b720965b1b..c6dd85c85b58e 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/ObjectCreationInitializerStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/ObjectCreationInitializerStructureProvider.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.[Shared].Collections +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -15,7 +15,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As ObjectCreationInitializerSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/OperatorDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/OperatorDeclarationStructureProvider.vb index 8d93bf24cb82b..36af439f9edfe 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/OperatorDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/OperatorDeclarationStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, operatorDeclaration As OperatorStatementSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(operatorDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/PropertyDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/PropertyDeclarationStructureProvider.vb index a17901d314ea3..2a96c12a29798 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/PropertyDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/PropertyDeclarationStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, propertyDeclaration As PropertyStatementSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(propertyDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/RegionDirectiveStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/RegionDirectiveStructureProvider.vb index 41889b9e2492e..3254a1baad003 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/RegionDirectiveStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/RegionDirectiveStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.Text @@ -24,7 +25,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, regionDirective As RegionDirectiveTriviaSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, CancellationToken As CancellationToken) Dim matchingDirective = regionDirective.GetMatchingStartOrEndDirective(CancellationToken) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/SelectBlockStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/SelectBlockStructureProvider.vb index 54d37a5db2190..81761336d54b1 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/SelectBlockStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/SelectBlockStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As SelectBlockSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) spans.AddIfNotNull(CreateBlockSpanFromBlock( diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.vb index edbc57ab0b12b..458794b49374c 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/StringLiteralExpressionStructureProvider.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading -Imports Microsoft.CodeAnalysis.[Shared].Collections +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +13,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As LiteralExpressionSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) If node.IsKind(SyntaxKind.StringLiteralExpression) AndAlso diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/SyncLockBlockStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/SyncLockBlockStructureProvider.vb index f80788c969027..71b5d3cd90075 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/SyncLockBlockStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/SyncLockBlockStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As SyncLockBlockSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) spans.AddIfNotNull(CreateBlockSpanFromBlock( diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/TryBlockStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/TryBlockStructureProvider.vb index 5521c8c9410fd..b923e6092aeb7 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/TryBlockStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/TryBlockStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As TryBlockSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) spans.AddIfNotNull(CreateBlockSpanFromBlock( diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/TypeDeclarationStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/TypeDeclarationStructureProvider.vb index 8b867f778f10f..1075d024d6ebc 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/TypeDeclarationStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/TypeDeclarationStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, typeDeclaration As TypeStatementSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) CollectCommentsRegions(typeDeclaration, spans, options) diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/UsingBlockStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/UsingBlockStructureProvider.vb index 6014ae7aff7c3..91ade5ad536c8 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/UsingBlockStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/UsingBlockStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As UsingBlockSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) spans.AddIfNotNull(CreateBlockSpanFromBlock( diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/WhileBlockStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/WhileBlockStructureProvider.vb index 44f15e4d5cb5c..369f9d9e2cfa0 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/WhileBlockStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/WhileBlockStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As WhileBlockSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) spans.AddIfNotNull(CreateBlockSpanFromBlock( diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/WithBlockStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/WithBlockStructureProvider.vb index b698ddbf2fd72..017c4f4f83b38 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/WithBlockStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/WithBlockStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Shared.Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, node As WithBlockSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) spans.AddIfNotNull(CreateBlockSpanFromBlock( diff --git a/src/Features/VisualBasic/Portable/Structure/Providers/XmlExpressionStructureProvider.vb b/src/Features/VisualBasic/Portable/Structure/Providers/XmlExpressionStructureProvider.vb index c9869c64055d1..31e9db9919c3b 100644 --- a/src/Features/VisualBasic/Portable/Structure/Providers/XmlExpressionStructureProvider.vb +++ b/src/Features/VisualBasic/Portable/Structure/Providers/XmlExpressionStructureProvider.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Shared.Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -13,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure Protected Overrides Sub CollectBlockSpans(previousToken As SyntaxToken, xmlExpression As XmlNodeSyntax, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions, cancellationToken As CancellationToken) ' If this XML expression is inside structured trivia (i.e. an XML doc comment), don't outline. diff --git a/src/Features/VisualBasic/Portable/Structure/VisualBasicStructureHelpers.vb b/src/Features/VisualBasic/Portable/Structure/VisualBasicStructureHelpers.vb index fcc30690997c3..3552e95a582eb 100644 --- a/src/Features/VisualBasic/Portable/Structure/VisualBasicStructureHelpers.vb +++ b/src/Features/VisualBasic/Portable/Structure/VisualBasicStructureHelpers.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports System.Runtime.InteropServices +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.[Shared].Collections Imports Microsoft.CodeAnalysis.Structure Imports Microsoft.CodeAnalysis.Text @@ -37,17 +38,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure ' For testing purposes Friend Function CreateCommentsRegions(triviaList As SyntaxTriviaList) As ImmutableArray(Of BlockSpan) - Dim spans = TemporaryArray(Of BlockSpan).Empty - Try - CollectCommentsRegions(triviaList, spans) - Return spans.ToImmutableAndClear() - Finally - spans.Dispose() - End Try + Dim spans = ArrayBuilder(Of BlockSpan).GetInstance() + CollectCommentsRegions(triviaList, spans) + Return spans.ToImmutableAndFree() End Function Friend Sub CollectCommentsRegions(triviaList As SyntaxTriviaList, - ByRef spans As TemporaryArray(Of BlockSpan)) + spans As ArrayBuilder(Of BlockSpan)) If triviaList.Count > 0 Then Dim startComment As SyntaxTrivia? = Nothing Dim endComment As SyntaxTrivia? = Nothing @@ -77,7 +74,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Structure End Sub Friend Sub CollectCommentsRegions(node As SyntaxNode, - ByRef spans As TemporaryArray(Of BlockSpan), + spans As ArrayBuilder(Of BlockSpan), options As BlockStructureOptions) If node Is Nothing Then Throw New ArgumentNullException(NameOf(node)) diff --git a/src/Features/VisualBasic/Portable/UseAutoProperty/VisualBasicUseAutoPropertyCodeFixProvider.vb b/src/Features/VisualBasic/Portable/UseAutoProperty/VisualBasicUseAutoPropertyCodeFixProvider.vb index 244c4a39c372c..0ba154e235d0f 100644 --- a/src/Features/VisualBasic/Portable/UseAutoProperty/VisualBasicUseAutoPropertyCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/UseAutoProperty/VisualBasicUseAutoPropertyCodeFixProvider.vb @@ -9,12 +9,13 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Formatting.Rules +Imports Microsoft.CodeAnalysis.Rename Imports Microsoft.CodeAnalysis.UseAutoProperty Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.UseAutoProperty - Friend Class VisualBasicUseAutoPropertyCodeFixProvider + Friend NotInheritable Class VisualBasicUseAutoPropertyCodeFixProvider Inherits AbstractUseAutoPropertyCodeFixProvider(Of TypeBlockSyntax, PropertyBlockSyntax, ModifiedIdentifierSyntax, ConstructorBlockSyntax, ExpressionSyntax) @@ -34,17 +35,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UseAutoProperty Return Utilities.GetNodeToRemove(identifier) End Function - Protected Overrides Function GetFormattingRules(document As Document) As ImmutableArray(Of AbstractFormattingRule) + Protected Overrides Function GetFormattingRules(document As Document, finalProperty As SyntaxNode) As ImmutableArray(Of AbstractFormattingRule) Return Nothing End Function - Protected Overrides Async Function UpdatePropertyAsync(propertyDocument As Document, - compilation As Compilation, - fieldSymbol As IFieldSymbol, - propertySymbol As IPropertySymbol, - propertyDeclaration As PropertyBlockSyntax, - isWrittenToOutsideOfConstructor As Boolean, - cancellationToken As CancellationToken) As Task(Of SyntaxNode) + Protected Overrides Function RewriteFieldReferencesInProperty([property] As PropertyBlockSyntax, fieldLocations As LightweightRenameLocations, cancellationToken As CancellationToken) As PropertyBlockSyntax + ' Only called to rewrite to `field` (which VB does not support). + Return [property] + End Function + + Protected Overrides Async Function UpdatePropertyAsync( + propertyDocument As Document, + compilation As Compilation, + fieldSymbol As IFieldSymbol, + propertySymbol As IPropertySymbol, + fieldDeclarator As ModifiedIdentifierSyntax, + propertyDeclaration As PropertyBlockSyntax, + isWrittenToOutsideOfConstructor As Boolean, + isTrivialGetAccessor As Boolean, + isTrivialSetAccessor As Boolean, + cancellationToken As CancellationToken) As Task(Of SyntaxNode) Dim statement = propertyDeclaration.PropertyStatement Dim generator = SyntaxGenerator.GetGenerator(propertyDocument.Project) diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx index 6d123e4e8801c..310eaf5dbd866 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx @@ -950,12 +950,6 @@ Sub(<parameterList>) <statement> NameOf function - - Generate narrowing conversion in '{0}' - - - Generate widening conversion in '{0}' - Try block {Locked="Try"} "Try" is a VB keyword and should not be localized. diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf index 840fc42e7a34f..931bbf61f7e04 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf @@ -1462,16 +1462,6 @@ Sub(<seznam_parametrů>) <výraz> Funkce NameOf - - Generate narrowing conversion in '{0}' - Generovat zužující převod v {0} - - - - Generate widening conversion in '{0}' - Generovat rozšiřující konverzi v {0} - - Try block Blok Try diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf index 6d3a48c606c0c..2a4ed298eeb31 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf @@ -1462,16 +1462,6 @@ Sub(<Parameterliste>) <Ausdruck> NameOf-Funktion - - Generate narrowing conversion in '{0}' - Einschränkende Konvertierung in "{0}" generieren - - - - Generate widening conversion in '{0}' - Erweiternde Konvertierung in "{0}" generieren - - Try block Try-Block diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf index eee87c7baf6e9..6d0d9953583e4 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf @@ -1462,16 +1462,6 @@ Sub(<listaDeParámetros>) <instrucción>wo laopo fuke Función NameOf - - Generate narrowing conversion in '{0}' - Generar conversión de restricción en "{0}" - - - - Generate widening conversion in '{0}' - Generar conversión de ampliación en "{0}" - - Try block Bloque Try diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf index a95b6b7cea7d3..44a54bf49d7d7 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf @@ -1462,16 +1462,6 @@ Sub(<parameterList>) <statement> Fonction NameOf - - Generate narrowing conversion in '{0}' - Générer une conversion restrictive dans '{0}' - - - - Generate widening conversion in '{0}' - Générer une conversation étendue dans '{0}' - - Try block Bloc Try diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf index d42d0763ad76b..dc38e5874667a 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf @@ -1462,16 +1462,6 @@ Sub(<elencoParametri>) <istruzione> Funzione NameOf - - Generate narrowing conversion in '{0}' - Genera la conversione che supporta un minor numero di dati in '{0}' - - - - Generate widening conversion in '{0}' - Genera la conversione che supporta un maggior numero di dati in '{0}' - - Try block blocco Try diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf index 7a0990edf1b28..9cbf48911c113 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf @@ -1462,16 +1462,6 @@ Sub(<parameterList>) <statement> NameOf 関数 - - Generate narrowing conversion in '{0}' - '{0}' で縮小変換を生成する - - - - Generate widening conversion in '{0}' - '{0}' で拡大変換を生成する - - Try block Try ブロック diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf index de88d3d832bab..b42832f0e0917 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf @@ -1462,16 +1462,6 @@ Sub(<parameterList>) <statement> 함수 이름 - - Generate narrowing conversion in '{0}' - '{0}'에서 축소 변환 생성 - - - - Generate widening conversion in '{0}' - '{0}'에서 확대 변환 생성 - - Try block Try 블록 diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf index 90add374cb980..b81329c2ca0bd 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf @@ -1462,16 +1462,6 @@ Sub(<listaParametrów>) <instrukcja> Funkcja NameOf - - Generate narrowing conversion in '{0}' - Generuj konwersję zawężającą w elemencie „{0}” - - - - Generate widening conversion in '{0}' - Generuj konwersję rozszerzającą w elemencie „{0}” - - Try block Blok Try diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf index 5e2f0a2a4d471..69dd91cda7e14 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf @@ -1462,16 +1462,6 @@ Sub(<parameterList>) <statement> Função NameOf - - Generate narrowing conversion in '{0}' - Gerar conversão de restrição no '{0}' - - - - Generate widening conversion in '{0}' - Gerar conversão de expansão no '{0}' - - Try block Bloco Try diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf index 91d69de03f6e9..d1a1cd855b1f8 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf @@ -1462,16 +1462,6 @@ Sub(<parameterList>) <statement> Имя функции - - Generate narrowing conversion in '{0}' - Создайте сужающее преобразование в "{0}" - - - - Generate widening conversion in '{0}' - Создайте расширяющееся преобразование в "{0}" - - Try block Блок Try diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf index cd8eaf046e561..7e7a4e90fa42b 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf @@ -1462,16 +1462,6 @@ Sub(<parameterList>) <statement> İşlev adı - - Generate narrowing conversion in '{0}' - '{0}' öğesinde daraltma dönüştürmesi oluştur - - - - Generate widening conversion in '{0}' - '{0}' öğesinde genişletme dönüşümü oluştur - - Try block Try bloğu diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf index d539438752ab0..36c5c449da042 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf @@ -1462,16 +1462,6 @@ Sub(<parameterList>) <statement> NameOf 函数 - - Generate narrowing conversion in '{0}' - 在“{0}”中生成收缩转换 - - - - Generate widening conversion in '{0}' - 在“{0}”中生成扩大转换 - - Try block Try 块 diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf index 40d3a0c44244f..e3089b0028533 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf @@ -1462,16 +1462,6 @@ Sub(<parameterList>) <statement> NameOf 函式 - - Generate narrowing conversion in '{0}' - 在 '{0}' 中產生縮小轉換 - - - - Generate widening conversion in '{0}' - 在 '{0}' 中產生放大轉換 - - Try block Try 區塊 diff --git a/src/Features/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb b/src/Features/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb index 9cec27573c6f9..236320d22580d 100644 --- a/src/Features/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb +++ b/src/Features/VisualBasicTest/EditAndContinue/ActiveStatementTests.vb @@ -2728,6 +2728,42 @@ End Class edits.VerifySemanticDiagnostics(active) End Sub + + Public Sub SyncLock_Update_TypeChange() + Dim src1 = " +Class C + Sub F() + Dim a = New Object() + Dim b = New Object() + + SyncLock a + SyncLock b + System.Console.Write() + End SyncLock + End SyncLock + End Sub +End Class +" + Dim src2 = " +Class C + Sub F() + Dim a = New Object() + Dim b = New C() ' type change + + SyncLock a + SyncLock b + System.Console.Write() + End SyncLock + End SyncLock + End Sub +End Class +" + Dim edits = GetTopEdits(src1, src2) + Dim active = GetActiveStatements(src1, src2) + edits.VerifySemanticDiagnostics(active, + Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "SyncLock b", VBFeaturesResources.SyncLock_statement, "Object", "C")) + End Sub + Public Sub SyncLock_Delete_Leaf() Dim src1 = " @@ -2905,6 +2941,42 @@ End Class Diagnostic(RudeEditKind.InsertAroundActiveStatement, "For Each a In e1", VBFeaturesResources.For_Each_block)) End Sub + + Public Sub ForEach_Update_Leaf_TypeChange() + Dim src1 = " +Class Test + Sub Main() + Dim e1 = {1} + Dim e2 = {1.0} + + For Each a In e1 + For Each b In e2 + System.Console.Write() + Next + Next + End Sub +End Class +" + Dim src2 = " +Class Test + Sub Main() + Dim e1 = {1} + Dim e2 = {1} ' type change + + For Each a In e1 + For Each b In e2 + System.Console.Write() + Next + Next + End Sub +End Class +" + Dim edits = GetTopEdits(src1, src2) + Dim active = GetActiveStatements(src1, src2) + edits.VerifySemanticDiagnostics(active, + Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "For Each b In e2", VBFeaturesResources.For_Each_statement, "Double()", "Integer()")) + End Sub + Public Sub ForEach_Delete_Leaf1() Dim src1 = " @@ -3125,6 +3197,74 @@ End Class edits.VerifySemanticDiagnostics(active, Diagnostic(RudeEditKind.InsertAroundActiveStatement, "Using c", VBFeaturesResources.Using_block)) End Sub + + Public Sub Using_Update_Leaf_TypeChange() + Dim src1 = " +Imports System + +Class Test + Sub Main() + Dim a = New D1() + Dim b = New D1() + + Using a + Using b + System.Console.Write() + End Using + End Using + End sub +End Class + +Class D1 + Implements IDisposable + + Sub Dispose() Implements IDisposable.Dispose + End Sub +End Class + +Class D2 + Implements IDisposable + + Sub Dispose() Implements IDisposable.Dispose + End Sub +End Class +" + Dim src2 = " +Imports System + +Class Test + Sub Main() + Dim a = New D1() + Dim b = New D2() ' type change + + Using a + Using b + System.Console.Write() + End Using + End Using + End Sub +End Class + +Class D1 + Implements IDisposable + + Sub Dispose() Implements IDisposable.Dispose + End Sub +End Class + +Class D2 + Implements IDisposable + + Sub Dispose() Implements IDisposable.Dispose + End Sub +End Class +" + Dim edits = GetTopEdits(src1, src2) + Dim active = GetActiveStatements(src1, src2) + edits.VerifySemanticDiagnostics(active, + Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "Using b", VBFeaturesResources.Using_statement, "D1", "D2")) + End Sub + Public Sub Using_Lambda1() Dim src1 = " @@ -3224,8 +3364,11 @@ End Class Public Sub With_Update_Leaf1() Dim src1 = " -Class Test - Sub Main() +Class C + Sub F() + Dim a = New Object() + Dim b = New Object() + With a With b System.Console.Write() @@ -3235,13 +3378,14 @@ Class Test End Class " Dim src2 = " -Class Test - Sub Main() +Class C + Sub F() + Dim a = New Object() + Dim b = New C() ' type change + With a - With c - With b - System.Console.Write() - End With + With b + System.Console.Write() End With End With End Sub @@ -3250,7 +3394,7 @@ End Class Dim edits = GetTopEdits(src1, src2) Dim active = GetActiveStatements(src1, src2) edits.VerifySemanticDiagnostics(active, - Diagnostic(RudeEditKind.InsertAroundActiveStatement, "With c", VBFeaturesResources.With_block)) + Diagnostic(RudeEditKind.TypeUpdateAroundActiveStatement, "With b", VBFeaturesResources.With_statement, "Object", "C")) End Sub diff --git a/src/Features/VisualBasicTest/EditAndContinue/LineEditTests.vb b/src/Features/VisualBasicTest/EditAndContinue/LineEditTests.vb index 32c515d18bda0..48948bf401f1d 100644 --- a/src/Features/VisualBasicTest/EditAndContinue/LineEditTests.vb +++ b/src/Features/VisualBasicTest/EditAndContinue/LineEditTests.vb @@ -47,11 +47,11 @@ End Class Public Sub Method_Reorder1() Dim src1 = " Class C - Shared Sub Goo() + Shared Sub G() Console.ReadLine(1) End Sub - Shared Sub Bar() + Shared Sub F() Console.ReadLine(2) End Sub End Class @@ -59,69 +59,76 @@ End Class Dim src2 = " Class C - Shared Sub Bar() + Shared Sub F() Console.ReadLine(2) End Sub - Shared Sub Goo() + Shared Sub G() Console.ReadLine(1) End Sub End Class " Dim edits = GetTopEdits(src1, src2) + + ' Consider: we could detect that the body of the method hasn't changed and avoid creating an update. edits.VerifyLineEdits( { New SourceLineUpdate(2, 6), New SourceLineUpdate(5, 5), New SourceLineUpdate(6, 2) - }, {}) + }, {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.F"))}) End Sub Public Sub Method_Reorder2() Dim src1 = " -Class Program +Class C Shared Sub Main() - Goo() - Bar() + G() + F() End Sub - Shared Function Goo() As Integer + Shared Function G() As Integer Return 1 End Function - Shared Function Bar() As Integer + Shared Function F() As Integer Return 2 End Function End Class " Dim src2 = " -Class Program - Shared Function Goo() As Integer +Class C + Shared Function G() As Integer Return 1 End Function Shared Sub Main() - Goo() - Bar() + G() + F() End Sub - Shared Function Bar() As Integer + Shared Function F() As Integer Return 2 End Function End Class " Dim edits = GetTopEdits(src1, src2) + + ' Consider: we could detect that the body of the method hasn't changed and create line edits instead of an update. edits.VerifyLineEdits( { New SourceLineUpdate(2, 6), New SourceLineUpdate(6, 6), New SourceLineUpdate(7, 2), New SourceLineUpdate(10, 10) - }, {}) + }, + { + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.G")) + }) End Sub @@ -556,8 +563,8 @@ End Class " Dim edits = GetTopEdits(src1, src2) edits.VerifyLineEdits( - Array.Empty(Of SequencePointUpdates), - diagnostics:={Diagnostic(RudeEditKind.Move, "Shared Bar As Integer = 2", FeaturesResources.field)}) + {New SourceLineUpdate(2, 3), New SourceLineUpdate(3, 2)}, + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").SharedConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -576,8 +583,8 @@ End Class " Dim edits = GetTopEdits(src1, src2) edits.VerifyLineEdits( - Array.Empty(Of SequencePointUpdates), - diagnostics:={Diagnostic(RudeEditKind.Move, "Shared c As New C()", FeaturesResources.field)}) + {New SourceLineUpdate(2, 3), New SourceLineUpdate(3, 2)}, + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").SharedConstructors.Single(), preserveLocalVariables:=True)}) End Sub @@ -598,8 +605,8 @@ End Class Dim edits = GetTopEdits(src1, src2) edits.VerifyLineEdits( - Array.Empty(Of SequencePointUpdates), - diagnostics:={Diagnostic(RudeEditKind.Move, "Shared c, d As New C()", FeaturesResources.field)}) + {New SourceLineUpdate(2, 3), New SourceLineUpdate(3, 2)}, + {SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").SharedConstructors.Single(), preserveLocalVariables:=True)}) End Sub diff --git a/src/Features/VisualBasicTest/EditAndContinue/StatementEditingTests.vb b/src/Features/VisualBasicTest/EditAndContinue/StatementEditingTests.vb index a6550aca7c311..52579ee25b1e1 100644 --- a/src/Features/VisualBasicTest/EditAndContinue/StatementEditingTests.vb +++ b/src/Features/VisualBasicTest/EditAndContinue/StatementEditingTests.vb @@ -139,6 +139,90 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue.UnitTests "Update [Resume Next]@80 -> [Resume]@65") End Sub + + Public Sub XmlLiteral_Text() + Dim src1 = " +Dim a = Text1 +" + Dim src2 = " +Dim a = Text2 +" + Dim edits = GetMethodEdits(src1, src2) + + edits.VerifyEdits( + "Update [a = Text1]@14 -> [a = Text2]@14") + End Sub + + + Public Sub XmlLiteral_Node() + Dim src1 = " +Dim a = Text +" + Dim src2 = " +Dim a = Text +" + Dim edits = GetMethodEdits(src1, src2) + + edits.VerifyEdits( + "Update [a = Text]@14 -> [a = Text]@14") + End Sub + + + Public Sub XmlLiteral_AttributeValue() + Dim src1 = " +Dim a = Text +" + Dim src2 = " +Dim a = Text +" + Dim edits = GetMethodEdits(src1, src2) + + edits.VerifyEdits( + "Update [a = Text]@14 -> [a = Text]@14") + End Sub + + + Public Sub XmlLiteral_AttributeName() + Dim src1 = " +Dim a = Text +" + Dim src2 = " +Dim a = Text +" + Dim edits = GetMethodEdits(src1, src2) + + edits.VerifyEdits( + "Update [a = Text]@14 -> [a = Text]@14") + End Sub + + + Public Sub XmlLiteral_CDATA() + Dim src1 = " +Dim a = +" + Dim src2 = " +Dim a = +" + Dim edits = GetMethodEdits(src1, src2) + + edits.VerifyEdits( + "Update [a = ]@14 -> [a = ]@14") + End Sub + + + Public Sub XmlLiteral_Comment() + Dim src1 = " +Dim a = +" + Dim src2 = " +Dim a = +" + Dim edits = GetMethodEdits(src1, src2) + + edits.VerifyEdits( + "Update [a = ]@14 -> [a = ]@14") + End Sub + #End Region #Region "Select" diff --git a/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb b/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb index ca321cab826b5..b08162f35c135 100644 --- a/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb +++ b/src/Features/VisualBasicTest/EditAndContinue/TopLevelEditingTests.vb @@ -2,6 +2,7 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports Microsoft.CodeAnalysis.Differencing Imports Microsoft.CodeAnalysis.EditAndContinue Imports Microsoft.CodeAnalysis.EditAndContinue.UnitTests Imports Microsoft.CodeAnalysis.Emit @@ -120,18 +121,9 @@ Imports System.Collections.Generic Dim edits = GetTopEdits(src1, src2) - ' TODO: https://github.com/dotnet/roslyn/issues/51374 - ' Should be following: - 'edits.VerifyEdits( - ' "Update [Imports X1 = System.Collections]@30 -> [Imports X2 = System.Collections]@30", - ' "Update [Imports ]@28 -> [Imports ]@28") - ' - 'edits.VerifySemanticDiagnostics( - ' Diagnostic(RudeEditKind.Update, "Imports X2 = System.Collections", VBFeaturesResources.import), - ' Diagnostic(RudeEditKind.Update, "Imports ", VBFeaturesResources.import)) - edits.VerifyEdits( - "Update [Imports X1 = System.Collections]@30 -> [Imports X2 = System.Collections]@30") + "Update [Imports X1 = System.Collections]@30 -> [Imports X2 = System.Collections]@30", + "Update [Imports ]@63 -> [Imports ]@63") edits.VerifySemanticDiagnostics() End Sub @@ -5090,28 +5082,114 @@ Imports System.Runtime.InteropServices End Sub - Public Sub Method_Reorder1() - Dim src1 = "Class C : " & vbLf & "Sub f(a As Integer, b As Integer)" & vbLf & "a = b : End Sub : " & vbLf & "Sub g() : End Sub : End Class" - Dim src2 = "Class C : " & vbLf & "Sub g() : End Sub : " & vbLf & "Sub f(a As Integer, b As Integer)" & vbLf & "a = b : End Sub : End Class" + Public Sub Method_Reorder() + Dim src1 = " +Class C + + + Sub F() + End Sub + Sub G() + End Sub + Sub H() + End Sub +End Class +" + + Dim src2 = " +class C + Sub H() + End Sub + Sub F() + End Sub + Sub G() + End Sub + + +End Class +" + Dim edits = GetTopEdits(src1, src2) - edits.VerifyEdits( - "Reorder [Sub g() : End Sub]@64 -> @11") + edits.VerifyEdits(EditKind.Reorder) - edits.VerifySemantics(ActiveStatementsDescription.Empty, Array.Empty(Of SemanticEditDescription)()) + edits.VerifySemantics({SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("C.H"))}) End Sub - Public Sub InterfaceMethod_Reorder1() - Dim src1 = "Interface I : " & vbLf & "Sub f(a As Integer, b As Integer)" & vbLf & "Sub g() : End Interface" - Dim src2 = "Interface I : " & vbLf & "Sub g() : " & vbLf & "Sub f(a As Integer, b As Integer) : End Interface" + Public Sub Method_Reorder_Interface() + Dim src1 = " +Interface I + Sub F() + Sub G() + Sub H() +End Interface +" + Dim src2 = " +Interface I + Sub H() + Sub F() + Sub G() +End Interface +" Dim edits = GetTopEdits(src1, src2) + edits.VerifyEdits(EditKind.Reorder) + edits.VerifySemantics({SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember("I.H"))}) + End Sub - edits.VerifyEdits( - "Reorder [Sub g()]@49 -> @15") + + Public Sub Method_Reorder_Interface_ComImport() + Dim src1 = " +Imports System.Runtime.InteropServices + + +Interface I + Sub F() + Sub G() + Sub H() +End Interface +" + Dim src2 = " +Imports System.Runtime.InteropServices + + + +Interface I + Sub H() + Sub F() + Sub G() +End Interface +" + Dim edits = GetTopEdits(src1, src2) + edits.VerifyEdits(EditKind.Reorder) edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Move, "Sub g()", FeaturesResources.method)) + Diagnostic(RudeEditKind.InsertOrMoveComInterfaceMember, "Sub H()", GetResource("method"))) + End Sub + + + Public Sub Method_Insert_Interface_ComImport() + Dim src1 = " +Imports System.Runtime.InteropServices + + + +Interface I +End Interface +" + Dim src2 = " +Imports System.Runtime.InteropServices + + + +Interface I + Sub F() +End Interface +" + Dim edits = GetTopEdits(src1, src2) + edits.VerifySemanticDiagnostics( + Diagnostic(RudeEditKind.InsertVirtual, "Sub F()", GetResource("method")), + Diagnostic(RudeEditKind.InsertOrMoveComInterfaceMember, "Sub F()", GetResource("method"))) End Sub @@ -7605,7 +7683,30 @@ End Class End Sub - Public Sub Field_VariableMove6() + Public Sub Field_Reorder1() + Dim src1 = " +Class C + + Dim a = 0 + Dim b = 1 + Dim c +End Class" + Dim src2 = " +Class C + Dim c + Dim a = 0 + Dim b = 1 + +End Class" + Dim edits = GetTopEdits(src1, src2) + + edits.VerifyEdits(EditKind.Reorder) + + edits.VerifySemantics() + End Sub + + + Public Sub Field_Reorder2() Dim src1 = "Class C : Dim a As Object, b As Object : End Class" Dim src2 = "Class C : Dim b As Object, a As Object : End Class" Dim edits = GetTopEdits(src1, src2) @@ -7617,7 +7718,7 @@ End Class End Sub - Public Sub Field_VariableMove7() + Public Sub Field_Reorder3() Dim src1 = "Class C : Dim a As Object, b, c As Object : End Class" Dim src2 = "Class C : Dim b, c As Object, a As Object : End Class" Dim edits = GetTopEdits(src1, src2) @@ -7628,6 +7729,149 @@ End Class edits.VerifySemantics() End Sub + + Public Sub Field_Reorder_WithInitializer() + Dim src1 = " +Class C + + Dim a = 0 + Dim b = 1 + Dim c = 2 +End Class" + Dim src2 = " +Class C + Dim c = 2 + Dim a = 0 + Dim b = 1 + +End Class" + Dim edits = GetTopEdits(src1, src2) + + edits.VerifyEdits(EditKind.Reorder) + + edits.VerifySemantics( + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)) + End Sub + + + Public Sub Field_Reorder_WithEvents() + Dim src1 = " +Class C + + Dim a As Integer = 0 + Dim b As Integer = 1 + Dim WithEvents WE As Object +End Class" + Dim src2 = " +Class C + Dim WithEvents WE As Object + Dim a As Integer = 0 + Dim b As Integer = 1 + +End Class" + Dim edits = GetTopEdits(src1, src2) + + edits.VerifyEdits(EditKind.Reorder) + + edits.VerifySemantics() + End Sub + + + Friend Sub Field_Reorder_WithEvents_TypeLayout1() + Dim src1 = " +Imports System.Runtime.InteropServices + +Class C + Dim a As Integer + Dim WithEvents WE As Object +End Class" + + Dim src2 = " +Imports System.Runtime.InteropServices + +Class C + Dim WithEvents WE As Object + Dim a As Integer +End Class" + + Dim edits = GetTopEdits(src1, src2) + edits.VerifyEdits(EditKind.Reorder) + edits.VerifySemanticDiagnostics( + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "Dim WithEvents WE As Object", GetResource("WithEvents field"), GetResource("class"))) + End Sub + + + Friend Sub Field_Reorder_WithEvents_TypeLayout2() + Dim src1 = " +Imports System.Runtime.InteropServices + +Class C + Dim WithEvents WE1, WE2 As Object +End Class" + + Dim src2 = " +Imports System.Runtime.InteropServices + +Class C + Dim WithEvents WE2, WE1 As Object +End Class" + + Dim edits = GetTopEdits(src1, src2) + edits.VerifyEdits(EditKind.Reorder) + edits.VerifySemanticDiagnostics( + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "WE2", GetResource("WithEvents field"), GetResource("class"))) + End Sub + + + Public Sub Field_Reorder_Reloadable() + Dim src1 = ReloadableAttributeSrc & " + +Structure C + + Dim a = 0 + Dim b = 1 + Dim c +End Structure" + Dim src2 = ReloadableAttributeSrc & " + +Structure C + Dim c + Dim a = 0 + Dim b = 1 + +End Structure" + Dim edits = GetTopEdits(src1, src2) + + edits.VerifyEdits(EditKind.Reorder) + + edits.VerifySemantics( + {SemanticEdit(SemanticEditKind.Replace, Function(c) c.GetMember("C"))}, + capabilities:=EditAndContinueCapabilities.NewTypeDefinition) + End Sub + + + Public Sub EventField_Reorder() + Dim src1 = " +Class C + + Dim a As Integer = 0 + Dim b As Integer = 1 + Event c As Action +End Class" + Dim src2 = " +Class C + Event c As Action + Dim a As Integer = 0 + Dim b As Integer = 1 + +End Class" + Dim edits = GetTopEdits(src1, src2) + + edits.VerifyEdits(EditKind.Reorder) + + edits.VerifySemantics() + End Sub + Public Sub Field_VariableMove_TypeChange() Dim src1 = "Class C : Dim a As Object, b, c As Object : End Class" @@ -7824,29 +8068,6 @@ End Class Diagnostic(RudeEditKind.ModifiersUpdate, "Dim a As WE", GetResource("WithEvents field"))) End Sub - - Public Sub FieldReorder() - Dim src1 = "Class C : Dim a = 0 : Dim b = 1 : Dim c = 2 : End Class" - Dim src2 = "Class C : Dim c = 2 : Dim a = 0 : Dim b = 1 : End Class" - Dim edits = GetTopEdits(src1, src2) - - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Move, "Dim c = 2", FeaturesResources.field)) - End Sub - - - Public Sub EventFieldReorder() - Dim src1 = "Class C : Dim a As Integer = 0 : Dim b As Integer = 1 : Event c As Action : End Class" - Dim src2 = "Class C : Event c As Action : Dim a As Integer = 0 : Dim b As Integer = 1 : End Class" - Dim edits = GetTopEdits(src1, src2) - - edits.VerifyEdits( - "Reorder [Event c As Action]@56 -> @10") - - edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Move, "Event c", FeaturesResources.event_)) - End Sub - Public Sub EventField_Partial_InsertDelete() Dim srcA1 = "Partial Class C : End Class" @@ -7874,7 +8095,7 @@ End Class End Sub - Public Sub FieldInsert_WithEvents1() + Public Sub Field_Insert_WithEvents() Dim src1 = "Class C : End Class" Dim src2 = "Class C : WithEvents F As C : End Class" Dim edits = GetTopEdits(src1, src2) @@ -7884,7 +8105,7 @@ End Class End Sub - Public Sub FieldInsert_WithEvents2() + Public Sub Field_Insert_WithEvents2() Dim src1 = "Class C : WithEvents F As C : End Class" Dim src2 = "Class C : WithEvents F, G As C : End Class" Dim edits = GetTopEdits(src1, src2) @@ -7894,7 +8115,7 @@ End Class End Sub - Public Sub FieldInsert_WithEvents3() + Public Sub Field_Insert_WithEvents3() Dim src1 = "Class C : WithEvents F As C : End Class" Dim src2 = "Class C : WithEvents F As C, G As C : End Class" Dim edits = GetTopEdits(src1, src2) @@ -7904,25 +8125,23 @@ End Class End Sub - Public Sub FieldInsert_IntoStruct() + Public Sub Field_Insert_IntoStruct() Dim src1 = "Structure S : Private a As Integer : End Structure" Dim src2 = " Structure S Private a As Integer Private b As Integer - Private Shared c As Integer Private Event d As System.Action End Structure " Dim edits = GetTopEdits(src1, src2) edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoStruct, "Private Event d", GetResource("event"), GetResource("structure")), - Diagnostic(RudeEditKind.InsertIntoStruct, "b As Integer", GetResource("field"), GetResource("structure")), - Diagnostic(RudeEditKind.InsertIntoStruct, "c As Integer", GetResource("field"), GetResource("structure"))) + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "Private Event d", GetResource("event"), GetResource("structure")), + Diagnostic(RudeEditKind.InsertOrMoveStructMember, "b As Integer", GetResource("field"), GetResource("structure"))) End Sub - Public Sub FieldInsert_IntoLayoutClass_Auto() + Public Sub Field_Insert_IntoLayoutClass_Auto() Dim src1 = " Imports System.Runtime.InteropServices @@ -7983,9 +8202,9 @@ End Class Dim edits = GetTopEdits(src1, src2) edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "b As Integer", FeaturesResources.field, FeaturesResources.class_), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "c As Integer", FeaturesResources.field, FeaturesResources.class_), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "d As Integer", FeaturesResources.field, FeaturesResources.class_)) + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "b As Integer", GetResource("field"), GetResource("class")), + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "c As Integer", GetResource("field"), GetResource("class")), + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "d As Integer", GetResource("field"), GetResource("class"))) End Sub @@ -8013,9 +8232,9 @@ End Class Dim edits = GetTopEdits(src1, src2) edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "b As Integer", FeaturesResources.field, FeaturesResources.class_), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "c As Integer", FeaturesResources.field, FeaturesResources.class_), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "d As Integer", FeaturesResources.field, FeaturesResources.class_)) + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "b As Integer", GetResource("field"), GetResource("class")), + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "c As Integer", GetResource("field"), GetResource("class")), + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "d As Integer", GetResource("field"), GetResource("class"))) End Sub @@ -8047,7 +8266,7 @@ End Class ' TODO: We don't compare the ordering currently. We could allow this edit if the ordering is preserved. edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "b As Integer", FeaturesResources.field, FeaturesResources.class_)) + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "b As Integer", FeaturesResources.field, FeaturesResources.class_)) End Sub @@ -8077,7 +8296,7 @@ End Class Dim edits = GetTopEdits(src1, src2) edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "a As Integer", FeaturesResources.field, FeaturesResources.class_)) + Diagnostic(RudeEditKind.InsertOrMoveTypeWithLayoutMember, "a As Integer", FeaturesResources.field, FeaturesResources.class_)) End Sub @@ -8348,36 +8567,173 @@ End Class End Sub - Public Sub PropertyReorder1() - Dim src1 = "Class C : ReadOnly Property P" & vbLf & "Get" & vbLf & "Return 1 : End Get : End Property : " & - "ReadOnly Property Q" & vbLf & "Get" & vbLf & "Return 1 : End Get : End Property : End Class" - Dim src2 = "Class C : ReadOnly Property Q" & vbLf & "Get" & vbLf & "Return 1 : End Get : End Property : " & - "ReadOnly Property P" & vbLf & "Get" & vbLf & "Return 1 : End Get : End Property : End Class" + Public Sub Property_Reorder1() + Dim src1 = " +Class C + ReadOnly Property P + Get + Return 1 + End Get + End Property + ReadOnly Property Q + Get + Return 1 + End Get + End Property +End Class" + Dim src2 = " +Class C + ReadOnly Property Q + Get + Return 1 + End Get + End Property + ReadOnly Property P + Get + Return 1 + End Get + End Property +End Class" Dim edits = GetTopEdits(src1, src2) + edits.VerifyEdits(EditKind.Reorder) + edits.VerifySemantics() + End Sub - edits.VerifyEdits( - "Reorder [ReadOnly Property Q" & vbLf & "Get" & vbLf & "Return 1 : End Get : End Property]@70 -> @10") + + Public Sub Property_Reorder_Auto() + Dim src1 = " +Class C - edits.VerifySemanticDiagnostics() + Property P As Integer = 0 + Property Q As Integer = 1 + Property R As Integer +End Class" + Dim src2 = " +Class C + Property R As Integer + Property P As Integer = 0 + Property Q As Integer = 1 + +End Class" + + Dim edits = GetTopEdits(src1, src2) + edits.VerifyEdits(EditKind.Reorder) + edits.VerifySemantics() End Sub - Public Sub PropertyReorder2() - Dim src1 = "Class C : Property P As Integer : Property Q As Integer : End Class" - Dim src2 = "Class C : Property Q As Integer : Property P As Integer : End Class" + Public Sub Property_Reorder_Auto_WithInitializer() + Dim src1 = " +Class C + + Property P As Integer = 0 + Property Q As Integer = 1 + Property R As Integer = 2 +End Class" + Dim src2 = " +Class C + Property R As Integer = 2 + Property P As Integer = 0 + Property Q As Integer = 1 + +End Class" Dim edits = GetTopEdits(src1, src2) + edits.VerifyEdits(EditKind.Reorder) + edits.VerifySemantics( + SemanticEdit(SemanticEditKind.Update, Function(c) c.GetMember(Of NamedTypeSymbol)("C").InstanceConstructors.Single(), preserveLocalVariables:=True)) + End Sub - edits.VerifyEdits( - "Reorder [Property Q As Integer]@34 -> @10") + + + ", "Class")> + Public Sub Property_Reorder_TypeLayout(attribute As String, keyword As String) + Dim src1 = attribute & keyword & " C + ReadOnly Property Q + Get + Return 1 + End Get + End Property + ReadOnly Property P + Get + Return 1 + End Get + End Property +End " & keyword + + Dim src2 = attribute & keyword & " C + ReadOnly Property P + Get + Return 1 + End Get + End Property + ReadOnly Property Q + Get + Return 1 + End Get + End Property +End " & keyword + + Dim edits = GetTopEdits(src1, src2) + edits.VerifyEdits(EditKind.Reorder) + edits.VerifySemantics() + End Sub + + + + ", "Class", RudeEditKind.InsertOrMoveTypeWithLayoutMember)> + Friend Sub Property_Reorder_Auto_TypeLayout(attribute As String, keyword As String, rudeEditKind As RudeEditKind) + Dim src1 = attribute & keyword & " C + + Property P As Integer = 0 + Property Q As Integer = 1 + Property R As Integer = 2 +End " & keyword + + Dim src2 = attribute & keyword & " C + Property R As Integer = 2 + Property P As Integer = 0 + Property Q As Integer = 1 + +End " & keyword + + Dim edits = GetTopEdits(src1, src2) + edits.VerifyEdits(EditKind.Reorder) edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.Move, "Property Q", FeaturesResources.auto_property)) + Diagnostic(rudeEditKind, "Property R", GetResource("auto-property"), GetResource(keyword))) End Sub - Public Sub PropertyAccessorReorder() + Friend Sub Property_Reorder_Auto_Reloadable() + Dim src1 = ReloadableAttributeSrc & " + +Structure C + Property P As Integer = 0 + Property Q As Integer = 1 + Property R As Integer +End Structure" + + Dim src2 = ReloadableAttributeSrc & " + +Structure C + Property R As Integer + Property P As Integer = 0 + Property Q As Integer = 1 + +End Structure" + + Dim edits = GetTopEdits(src1, src2) + edits.VerifyEdits(EditKind.Reorder) + + edits.VerifySemantics( + {SemanticEdit(SemanticEditKind.Replace, Function(c) c.GetMember(Of NamedTypeSymbol)("C"))}, + capabilities:=EditAndContinueCapabilities.NewTypeDefinition) + End Sub + + + Public Sub PropertyAccessor_Reorder() Dim src1 = "Class C : Property P As Integer" & vbLf & "Get" & vbLf & "Return 1 : End Get" & vbLf & "Set : End Set : End Property : End Class" Dim src2 = "Class C : Property P As Integer" & vbLf & "Set : End Set" & vbLf & "Get" & vbLf & "Return 1 : End Get : End Property : End Class" Dim edits = GetTopEdits(src1, src2) @@ -8389,7 +8745,7 @@ End Class End Sub - Public Sub PropertyTypeUpdate() + Public Sub Property_Update_Type() Dim src1 = "Class C : Property P As Integer : End Class" Dim src2 = "Class C : Property P As Char : End Class" Dim edits = GetTopEdits(src1, src2) @@ -8411,7 +8767,7 @@ End Class End Sub - Public Sub PropertyInsert() + Public Sub Property_Insert() Dim src1 = "Class C : End Class" Dim src2 = " Class C @@ -8572,7 +8928,7 @@ End Class" End Sub - Public Sub PropertyRename1() + Public Sub Property_Rename1() Dim src1 = "Class C : ReadOnly Property P As Integer" & vbLf & "Get : End Get : End Property : End Class" Dim src2 = "Class C : ReadOnly Property Q As Integer" & vbLf & "Get : End Get : End Property : End Class" Dim edits = GetTopEdits(src1, src2) @@ -8592,7 +8948,7 @@ End Class" End Sub - Public Sub PropertyRename2() + Public Sub Property_Rename2() Dim src1 = "Class C : ReadOnly Property P As Integer : End Class" Dim src2 = "Class C : ReadOnly Property Q As Integer : End Class" Dim edits = GetTopEdits(src1, src2) @@ -8611,14 +8967,15 @@ End Class" capabilities:=EditAndContinueCapabilities.AddMethodToExistingType Or EditAndContinueCapabilities.AddInstanceFieldToExistingType) End Sub - - Public Sub PropertyInsert_IntoStruct() - Dim src1 = "Structure S : Private a As Integer : End Structure" - Dim src2 = " -Structure S - Private a As Integer + + + ", "Class", RudeEditKind.InsertOrMoveTypeWithLayoutMember)> + Friend Sub Property_Insert_TypeLayout(attribute As String, type As String, rudeEditKind As RudeEditKind) + Dim src1 = attribute & type & " S +End " & type + + Dim src2 = attribute & type & " S Private Property b As Integer - Private Shared Property c As Integer Private Property d As Integer Get @@ -8629,15 +8986,6 @@ Structure S End Set End Property - Private Shared Property e As Integer - Get - Return 0 - End Get - - Set - End Set - End Property - Private ReadOnly Property f As Integer Get Return 0 @@ -8648,46 +8996,24 @@ Structure S Set End Set End Property - - Private Shared ReadOnly Property h As Integer - Get - Return 0 - End Get - End Property - - Private Shared WriteOnly Property i As Integer - Set - End Set - End Property -End Structure" +End " & type Dim edits = GetTopEdits(src1, src2) edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoStruct, "Private Property b", GetResource("auto-property"), GetResource("structure")), - Diagnostic(RudeEditKind.InsertIntoStruct, "Private Shared Property c", GetResource("auto-property"), GetResource("structure"))) + Diagnostic(rudeEditKind, "Private Property b", GetResource("auto-property"), GetResource(type))) End Sub - - Public Sub PropertyInsert_IntoLayoutClass_Sequential() - Dim src1 = " -Imports System.Runtime.InteropServices - - -Class C - Private a As Integer -End Class -" - - Dim src2 = " -Imports System.Runtime.InteropServices + + + ", "Class", RudeEditKind.InsertOrMoveTypeWithLayoutMember)> + Friend Sub Property_Insert_TypeLayout_Shared(attribute As String, type As String, rudeEditKind As RudeEditKind) + Dim src1 = attribute & type & " S +End " & type - -Class C - Private a As Integer - Private Property b As Integer + Dim src2 = attribute & type & " S Private Shared Property c As Integer - Private Property d As Integer + Private Shared Property e As Integer Get Return 0 End Get @@ -8696,20 +9022,22 @@ Class C End Set End Property - Private Shared Property e As Integer + Private Shared ReadOnly Property h As Integer Get Return 0 End Get + End Property + Private Shared WriteOnly Property i As Integer Set End Set End Property -End Class -" +End " & type Dim edits = GetTopEdits(src1, src2) + edits.VerifySemanticDiagnostics( - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "Private Property b", GetResource("auto-property"), GetResource("class")), - Diagnostic(RudeEditKind.InsertIntoClassWithLayout, "Private Shared Property c", GetResource("auto-property"), GetResource("class"))) + {Diagnostic(rudeEditKind, "Private Shared Property c", GetResource("auto-property"), GetResource(type))}, + capabilities:=EditAndContinueCapabilities.AddMethodToExistingType Or EditAndContinueCapabilities.AddStaticFieldToExistingType) End Sub @@ -9637,7 +9965,7 @@ End Class - Public Sub Field_Insert(modifiers As String) + Public Sub Field_Insert_Accessibility(modifiers As String) Dim src1 = "Class C : End Class" Dim src2 = "Class C : " & modifiers & " a As Integer = 1 : End Class" Dim edits = GetTopEdits(src1, src2) @@ -9658,7 +9986,7 @@ End Class - Public Sub Property_Insert(accessibility As String) + Public Sub Property_Insert_Accessibility(accessibility As String) Dim src1 = "Class C : End Class" Dim src2 = "Class C : " & accessibility & " Property a As Integer = 1 : End Class" Dim edits = GetTopEdits(src1, src2) diff --git a/src/Interactive/Host/Microsoft.CodeAnalysis.InteractiveHost.csproj b/src/Interactive/Host/Microsoft.CodeAnalysis.InteractiveHost.csproj index 002cd61d995fe..d06fa7a7bee4a 100644 --- a/src/Interactive/Host/Microsoft.CodeAnalysis.InteractiveHost.csproj +++ b/src/Interactive/Host/Microsoft.CodeAnalysis.InteractiveHost.csproj @@ -11,7 +11,7 @@ true - true + true .NET Compiler Platform ("Roslyn") interactive host implementation. diff --git a/src/Interactive/HostProcess/x64/InteractiveHost64.csproj b/src/Interactive/HostProcess/x64/InteractiveHost64.csproj index 7bbf60b076672..f2e640e639115 100644 --- a/src/Interactive/HostProcess/x64/InteractiveHost64.csproj +++ b/src/Interactive/HostProcess/x64/InteractiveHost64.csproj @@ -8,7 +8,7 @@ net472;$(NetVS)-windows win-x64 true - true + true true @@ -23,34 +23,46 @@ - + + + + + + + <_IntermediateDepsFilePath Condition=" '$(PublishDepsFilePath)' != ''">$(PublishDepsFilePath) + <_IntermediateDepsFilePath Condition=" '$(PublishDepsFilePath)' == ''">$(IntermediateOutputPath)$(ProjectDepsFileName) + - - <_PublishedFiles Include="$(PublishDir)**\*.*" /> - <_PublishedFiles Remove="@(_PublishedFiles)" Condition="'%(Extension)' == '.pdb'" /> + <_VsixItem Include="@(PublishItemsOutputGroupOutputs->'%(OutputPath)')" /> + <_VsixItem Remove="@(_VsixItem)" Condition="'%(Extension)' == '.pdb'" /> + + + <_VsixItem Include="$(_IntermediateDepsFilePath)" Condition="'$(TargetFrameworkIdentifier)' != '.NETFramework'" /> - <_PublishedFiles Include="$(MSBuildProjectDirectory)\Desktop\CSharpInteractive.rsp" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" /> - <_PublishedFiles Include="$(MSBuildProjectDirectory)\Core\CSharpInteractive.rsp" Condition="'$(TargetFrameworkIdentifier)' != '.NETFramework'" /> + <_VsixItem Include="$(MSBuildProjectDirectory)\Desktop\CSharpInteractive.rsp" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" /> + <_VsixItem Include="$(MSBuildProjectDirectory)\Core\CSharpInteractive.rsp" Condition="'$(TargetFrameworkIdentifier)' != '.NETFramework'" /> - <_PublishedFiles Include="$(MSBuildProjectDirectory)\.editorconfig"/> + <_VsixItem Include="$(MSBuildProjectDirectory)\.editorconfig" /> - <_PublishedFiles Update="@(_PublishedFiles)" TargetPath="%(RecursiveDir)%(Filename)%(Extension)" /> + <_VsixItem Update="@(_VsixItem)" TargetPath="%(Filename)%(Extension)" Condition="'%(_VsixItem.TargetPath)' == ''" /> - <_PublishedFiles Update="@(_PublishedFiles)" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework' and ('%(Extension)' == '.dll' or '%(Extension)' == '.exe')"> + <_VsixItem Update="@(_VsixItem)" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework' and ('%(Extension)' == '.dll' or '%(Extension)' == '.exe')"> true 3 All X64 [installDir]\Common7\IDE\$(CommonExtensionInstallationRoot)\$(LanguageServicesExtensionInstallationFolder)\InteractiveHost\Desktop\InteractiveHost64.exe - + + + \ No newline at end of file diff --git a/src/Interactive/HostProcess/x86/InteractiveHost32.csproj b/src/Interactive/HostProcess/x86/InteractiveHost32.csproj index d32f4393c6225..70e32290b8987 100644 --- a/src/Interactive/HostProcess/x86/InteractiveHost32.csproj +++ b/src/Interactive/HostProcess/x86/InteractiveHost32.csproj @@ -7,7 +7,7 @@ Exe net472 true - true + true true @@ -22,22 +22,25 @@ - + - <_PublishProjectOutputGroup Include="$(TargetPath)"> + <_VsixItem Include="$(TargetPath)"> $(TargetFileName) true 3 X86 [installDir]\Common7\IDE\$(CommonExtensionInstallationRoot)\$(LanguageServicesExtensionInstallationFolder)\InteractiveHost\Desktop\InteractiveHost32.exe - - <_PublishProjectOutputGroup Include="$(TargetPath).config" TargetPath="$(TargetFileName).config"/> + + <_VsixItem Include="$(TargetPath).config" TargetPath="$(TargetFileName).config"/> + + + \ No newline at end of file diff --git a/src/Interactive/HostTest/InteractiveHost.UnitTests.csproj b/src/Interactive/HostTest/InteractiveHost.UnitTests.csproj index 146044986fcd9..e3306cfbb04d7 100644 --- a/src/Interactive/HostTest/InteractiveHost.UnitTests.csproj +++ b/src/Interactive/HostTest/InteractiveHost.UnitTests.csproj @@ -50,8 +50,7 @@ --> - - + diff --git a/src/Interactive/HostTest/InteractiveHostDesktopTests.cs b/src/Interactive/HostTest/InteractiveHostDesktopTests.cs index 848e841ecd142..eda6c32516ddf 100644 --- a/src/Interactive/HostTest/InteractiveHostDesktopTests.cs +++ b/src/Interactive/HostTest/InteractiveHostDesktopTests.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.UnitTests.Interactive { @@ -937,7 +936,7 @@ public class C var lib = CSharpCompilation.Create( "Lib", new[] { SyntaxFactory.ParseSyntaxTree(source) }, -new[] { Net451.mscorlib, Net451.System }, +new[] { NetFramework.mscorlib, NetFramework.System }, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); var libFile = Temp.CreateFile("lib").WriteAllBytes(lib.EmitToArray()); diff --git a/src/Interactive/csi/csi.csproj b/src/Interactive/csi/csi.csproj index 24f12e41615da..9ccdffbbfae79 100644 --- a/src/Interactive/csi/csi.csproj +++ b/src/Interactive/csi/csi.csproj @@ -6,7 +6,7 @@ Exe CSharpInteractive $(NetRoslynSourceBuild);net472 - false + false true diff --git a/src/Interactive/vbi/vbi.vbproj b/src/Interactive/vbi/vbi.vbproj index a3c0cda7f116e..2895249e32a81 100644 --- a/src/Interactive/vbi/vbi.vbproj +++ b/src/Interactive/vbi/vbi.vbproj @@ -6,7 +6,7 @@ Exe Sub Main $(NetRoslynSourceBuild);net472 - false + false false diff --git a/src/LanguageServer/BannedSymbols.txt b/src/LanguageServer/BannedSymbols.txt index 7cf931bd24c12..1bf0bca833137 100644 --- a/src/LanguageServer/BannedSymbols.txt +++ b/src/LanguageServer/BannedSymbols.txt @@ -11,13 +11,13 @@ T:System.ComponentModel.Composition.PartNotDiscoverableAttribute; Use types from T:System.ComponentModel.Composition.SharedAttribute; Use types from System.Composition instead T:System.ComponentModel.Composition.SharingBoundaryAttribute; Use types from System.Composition instead T:System.ComponentModel.Composition.Convention.AttributedModelProvider; Use types from System.Composition instead -M:System.Uri.#ctor(System.String); Use ProtocolConversions.CreateAbsoluteUri or ProtocolConversions.CreateUriFromSourceGeneratedFilePath -M:System.Uri.#ctor(System.String,System.Boolean); Use ProtocolConversions.CreateAbsoluteUri or ProtocolConversions.CreateUriFromSourceGeneratedFilePath -M:System.Uri.#ctor(System.String,System.UriCreationOptions); Use ProtocolConversions.CreateAbsoluteUri or ProtocolConversions.CreateUriFromSourceGeneratedFilePath -M:System.Uri.#ctor(System.String,System.UriKind); Use ProtocolConversions.CreateAbsoluteUri or ProtocolConversions.CreateUriFromSourceGeneratedFilePath -M:System.Uri.#ctor(System.Uri,System.String); Use ProtocolConversions.CreateAbsoluteUri or ProtocolConversions.CreateUriFromSourceGeneratedFilePath -M:System.Uri.#ctor(System.Uri,System.Uri); Use ProtocolConversions.CreateAbsoluteUri or ProtocolConversions.CreateUriFromSourceGeneratedFilePath -M:System.Uri.#ctor(System.Uri,System.String,System.Boolean); Use ProtocolConversions.CreateAbsoluteUri or ProtocolConversions.CreateUriFromSourceGeneratedFilePath -M:System.Uri.TryCreate(System.String,System.UriKind,System.Uri@); Use ProtocolConversions.CreateAbsoluteUri or ProtocolConversions.CreateUriFromSourceGeneratedFilePath -M:System.Uri.TryCreate(System.Uri,System.String,System.Uri@); Use ProtocolConversions.CreateAbsoluteUri or ProtocolConversions.CreateUriFromSourceGeneratedFilePath -M:System.Uri.TryCreate(System.Uri,System.Uri,System.Uri@); Use ProtocolConversions.CreateAbsoluteUri or ProtocolConversions.CreateUriFromSourceGeneratedFilePath +M:System.Uri.#ctor(System.String); Use Extensions.GetURI() if you have a document, or ProtocolConversions.CreateAbsoluteUri if you are sure the path is a real file path and not a generated file path +M:System.Uri.#ctor(System.String,System.Boolean); Use Extensions.GetURI() if you have a document, or ProtocolConversions.CreateAbsoluteUri if you are sure the path is a real file path and not a generated file path +M:System.Uri.#ctor(System.String,System.UriCreationOptions); Use Extensions.GetURI() if you have a document, or ProtocolConversions.CreateAbsoluteUri if you are sure the path is a real file path and not a generated file path +M:System.Uri.#ctor(System.String,System.UriKind); Use Extensions.GetURI() if you have a document, or ProtocolConversions.CreateAbsoluteUri if you are sure the path is a real file path and not a generated file path +M:System.Uri.#ctor(System.Uri,System.String); Use Extensions.GetURI() if you have a document, or ProtocolConversions.CreateAbsoluteUri if you are sure the path is a real file path and not a generated file path +M:System.Uri.#ctor(System.Uri,System.Uri); Use Extensions.GetURI() if you have a document, or ProtocolConversions.CreateAbsoluteUri if you are sure the path is a real file path and not a generated file path +M:System.Uri.#ctor(System.Uri,System.String,System.Boolean); Use Extensions.GetURI() if you have a document, or ProtocolConversions.CreateAbsoluteUri if you are sure the path is a real file path and not a generated file path +M:System.Uri.TryCreate(System.String,System.UriKind,System.Uri@); Use Extensions.GetURI() if you have a document, or ProtocolConversions.CreateAbsoluteUri if you are sure the path is a real file path and not a generated file path +M:System.Uri.TryCreate(System.Uri,System.String,System.Uri@); Use Extensions.GetURI() if you have a document, or ProtocolConversions.CreateAbsoluteUri if you are sure the path is a real file path and not a generated file path +M:System.Uri.TryCreate(System.Uri,System.Uri,System.Uri@); Use Extensions.GetURI() if you have a document, or ProtocolConversions.CreateAbsoluteUri if you are sure the path is a real file path and not a generated file path diff --git a/src/LanguageServer/Directory.Build.props b/src/LanguageServer/Directory.Build.props index 6eef643958f56..9dd0ddea9df26 100644 --- a/src/LanguageServer/Directory.Build.props +++ b/src/LanguageServer/Directory.Build.props @@ -1,6 +1,6 @@ - true + true diff --git a/src/LanguageServer/ExternalAccess/CompilerDeveloperSDK/Microsoft.CodeAnalysis.ExternalAccess.CompilerDeveloperSDK.csproj b/src/LanguageServer/ExternalAccess/CompilerDeveloperSDK/Microsoft.CodeAnalysis.ExternalAccess.CompilerDeveloperSDK.csproj index 6822a080a6076..f3cdaa4cdccf6 100644 --- a/src/LanguageServer/ExternalAccess/CompilerDeveloperSDK/Microsoft.CodeAnalysis.ExternalAccess.CompilerDeveloperSDK.csproj +++ b/src/LanguageServer/ExternalAccess/CompilerDeveloperSDK/Microsoft.CodeAnalysis.ExternalAccess.CompilerDeveloperSDK.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs index a87b6604e47f6..41fe21c197552 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs @@ -20,7 +20,7 @@ public class LspFileChangeWatcherTests : AbstractLanguageServerHostTests { Workspace = new WorkspaceClientCapabilities { - DidChangeWatchedFiles = new DynamicRegistrationSetting { DynamicRegistration = true } + DidChangeWatchedFiles = new DidChangeWatchedFilesClientCapabilities { DynamicRegistration = true } } }; @@ -61,13 +61,13 @@ public async Task CreatingDirectoryWatchRequestsDirectoryWatch() var tempDirectory = tempRoot.CreateDirectory(); // Try creating a context and ensure we created the registration - var context = lspFileChangeWatcher.CreateContext(new ProjectSystem.WatchedDirectory(tempDirectory.Path, extensionFilter: null)); + var context = lspFileChangeWatcher.CreateContext([new ProjectSystem.WatchedDirectory(tempDirectory.Path, extensionFilter: null)]); await WaitForFileWatcherAsync(testLspServer); var watcher = GetSingleFileWatcher(dynamicCapabilitiesRpcTarget); - Assert.Equal(tempDirectory.Path, watcher.GlobPattern.BaseUri.LocalPath); - Assert.Equal("**/*", watcher.GlobPattern.Pattern); + Assert.Equal(tempDirectory.Path, watcher.GlobPattern.Second.BaseUri.Second.LocalPath); + Assert.Equal("**/*", watcher.GlobPattern.Second.Pattern); // Get rid of the registration and it should be gone again context.Dispose(); @@ -92,14 +92,14 @@ public async Task CreatingFileWatchRequestsFileWatch() var tempDirectory = tempRoot.CreateDirectory(); // Try creating a single file watch and ensure we created the registration - var context = lspFileChangeWatcher.CreateContext(); + var context = lspFileChangeWatcher.CreateContext([]); var watchedFile = context.EnqueueWatchingFile("Z:\\SingleFile.txt"); await WaitForFileWatcherAsync(testLspServer); var watcher = GetSingleFileWatcher(dynamicCapabilitiesRpcTarget); - Assert.Equal("Z:\\", watcher.GlobPattern.BaseUri.LocalPath); - Assert.Equal("SingleFile.txt", watcher.GlobPattern.Pattern); + Assert.Equal("Z:\\", watcher.GlobPattern.Second.BaseUri.Second.LocalPath); + Assert.Equal("SingleFile.txt", watcher.GlobPattern.Second.Pattern); // Get rid of the registration and it should be gone again watchedFile.Dispose(); @@ -134,7 +134,7 @@ public Task RegisterCapabilityAsync(RegistrationParams registrationParams, Cance } [JsonRpcMethod("client/unregisterCapability", UseSingleObjectParameterDeserialization = true)] - public Task UnregisterCapabilityAsync(UnregistrationParamsWithMisspelling unregistrationParams, CancellationToken _) + public Task UnregisterCapabilityAsync(UnregistrationParams unregistrationParams, CancellationToken _) { foreach (var unregistration in unregistrationParams.Unregistrations) Assert.True(Registrations.TryRemove(unregistration.Id, out var _)); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Microsoft.CodeAnalysis.LanguageServer.UnitTests.csproj b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Microsoft.CodeAnalysis.LanguageServer.UnitTests.csproj index a596f3092dc3b..d76aa319a94d6 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Microsoft.CodeAnalysis.LanguageServer.UnitTests.csproj +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Microsoft.CodeAnalysis.LanguageServer.UnitTests.csproj @@ -38,3 +38,4 @@ + diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/TestOutputLogger.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/TestOutputLogger.cs index ed0a188850c3a..ea77589b3d0f7 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/TestOutputLogger.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/TestOutputLogger.cs @@ -15,7 +15,7 @@ public class TestOutputLogger : ILogger public TestOutputLogger(ITestOutputHelper testOutputHelper) { _testOutputHelper = testOutputHelper; - Factory = new LoggerFactory(new[] { new TestLoggerProvider(this) }); + Factory = new LoggerFactory([new TestLoggerProvider(this)]); } public IDisposable BeginScope(TState state) where TState : notnull diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs index b637a8ead14ff..1fb946820d563 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/BrokeredServices/Services/Descriptors.cs @@ -49,6 +49,8 @@ internal class Descriptors { BrokeredServiceDescriptors.HotReloadOptionService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, { BrokeredServiceDescriptors.HotReloadLoggerService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, { BrokeredServiceDescriptors.MauiLaunchCustomizerService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, + { BrokeredServiceDescriptors.DebuggerSymbolLocatorService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, + { BrokeredServiceDescriptors.DebuggerSourceLinkService.Moniker, new ServiceRegistration(ServiceAudience.Local, null, allowGuestClients: false) }, }.ToImmutableDictionary(); public static ServiceJsonRpcDescriptor CreateDescriptor(ServiceMoniker serviceMoniker) => new( diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ExportProviderBuilder.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ExportProviderBuilder.cs index 431ff203c59e7..47139da193da3 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ExportProviderBuilder.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ExportProviderBuilder.cs @@ -57,7 +57,7 @@ public static async Task CreateExportProviderAsync( var config = CompositionConfiguration.Create(catalog); // Verify we only have expected errors. - ThrowOnUnexpectedErrors(config, logger); + ThrowOnUnexpectedErrors(config, catalog, logger); // Prepare an ExportProvider factory based on this graph. var exportProviderFactory = config.CreateExportProviderFactory(); @@ -75,7 +75,7 @@ public static async Task CreateExportProviderAsync( return exportProvider; } - private static void ThrowOnUnexpectedErrors(CompositionConfiguration configuration, ILogger logger) + private static void ThrowOnUnexpectedErrors(CompositionConfiguration configuration, ComposableCatalog catalog, ILogger logger) { // Verify that we have exactly the MEF errors that we expect. If we have less or more this needs to be updated to assert the expected behavior. // Currently we are expecting the following: @@ -87,15 +87,18 @@ private static void ThrowOnUnexpectedErrors(CompositionConfiguration configurati // part definition Microsoft.CodeAnalysis.ExternalAccess.Pythia.PythiaSignatureHelpProvider var erroredParts = configuration.CompositionErrors.FirstOrDefault()?.SelectMany(error => error.Parts).Select(part => part.Definition.Type.Name) ?? Enumerable.Empty(); var expectedErroredParts = new string[] { "PythiaSignatureHelpProvider" }; - if (erroredParts.Count() != expectedErroredParts.Length || !erroredParts.All(part => expectedErroredParts.Contains(part))) + var hasUnexpectedErroredParts = erroredParts.Any(part => !expectedErroredParts.Contains(part)); + + if (hasUnexpectedErroredParts || !catalog.DiscoveredParts.DiscoveryErrors.IsEmpty) { try { + catalog.DiscoveredParts.ThrowOnErrors(); configuration.ThrowOnErrors(); } catch (CompositionFailedException ex) { - // The ToString for the composition failed exception doesn't output a nice set of errors by default, so log it separately here. + // The ToString for the composition failed exception doesn't output a nice set of errors by default, so log it separately logger.LogError($"Encountered errors in the MEF composition:{Environment.NewLine}{ex.ErrorsAsString}"); throw; } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/DelegatingFileChangeWatcher.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/DelegatingFileChangeWatcher.cs index d4535df2b7123..b32ec7ef66d3f 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/DelegatingFileChangeWatcher.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/DelegatingFileChangeWatcher.cs @@ -2,56 +2,45 @@ // 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.Composition; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.LanguageServer; using Microsoft.CodeAnalysis.ProjectSystem; -using Microsoft.Extensions.Logging; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.Extensions.Logging; namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.FileWatching; /// -/// A MEF export for . This checks if we're able to create an if the client supports -/// file watching. If we do, we create that and delegate to it. Otherwise we use a . +/// A MEF export for . This checks if we're able to create an if the client supports file watching. If we do, we create that and delegate to it. +/// Otherwise we use a . /// /// -/// LSP clients don't always support file watching; this allows us to be flexible and use it when we can, but fall back to something else if we can't. +/// LSP clients don't always support file watching; this allows us to be flexible and use it when we can, but fall back +/// to something else if we can't. /// [Export(typeof(IFileChangeWatcher)), Shared] -internal sealed class DelegatingFileChangeWatcher : IFileChangeWatcher +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class DelegatingFileChangeWatcher( + ILoggerFactory loggerFactory, + IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider) + : IFileChangeWatcher { - private readonly ILoggerFactory _loggerFactory; - private readonly IAsynchronousOperationListenerProvider _asynchronousOperationListenerProvider; - private readonly Lazy _underlyingFileWatcher; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public DelegatingFileChangeWatcher(ILoggerFactory loggerFactory, IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider) - { - _loggerFactory = loggerFactory; - _asynchronousOperationListenerProvider = asynchronousOperationListenerProvider; - _underlyingFileWatcher = new Lazy(CreateFileWatcher); - } + private readonly Lazy _underlyingFileWatcher = new(() => + { + // Do we already have an LSP client that we can confirm works for us? + var instance = LanguageServerHost.Instance; - private IFileChangeWatcher CreateFileWatcher() - { - // Do we already have an LSP client that we can confirm works for us? - var instance = LanguageServerHost.Instance; + if (instance != null && LspFileChangeWatcher.SupportsLanguageServerHost(instance)) + return new LspFileChangeWatcher(instance, asynchronousOperationListenerProvider); - if (instance != null && LspFileChangeWatcher.SupportsLanguageServerHost(instance)) - { - return new LspFileChangeWatcher(instance, _asynchronousOperationListenerProvider); - } - else - { - _loggerFactory.CreateLogger().LogWarning("We are unable to use LSP file watching; falling back to our in-process watcher."); + loggerFactory.CreateLogger().LogWarning("We are unable to use LSP file watching; falling back to our in-process watcher."); return new SimpleFileChangeWatcher(); - } - } + }); - public IFileChangeContext CreateContext(params WatchedDirectory[] watchedDirectories) - { - return _underlyingFileWatcher.Value.CreateContext(watchedDirectories); - } + public IFileChangeContext CreateContext(ImmutableArray watchedDirectories) + => _underlyingFileWatcher.Value.CreateContext(watchedDirectories); } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/LspContractTypes.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/LspContractTypes.cs deleted file mode 100644 index ba53553cc6b9a..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/LspContractTypes.cs +++ /dev/null @@ -1,48 +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.Text.Json.Serialization; - -namespace Roslyn.LanguageServer.Protocol; - -internal class DidChangeWatchedFilesRegistrationOptions -{ - [JsonPropertyName("watchers")] - public required FileSystemWatcher[] Watchers { get; set; } -} - -internal class FileSystemWatcher -{ - [JsonPropertyName("globPattern")] - public required RelativePattern GlobPattern { get; set; } - - [JsonPropertyName("kind")] - public WatchKind? Kind { get; set; } -} - -internal class RelativePattern -{ - [JsonPropertyName("baseUri")] - [JsonConverter(typeof(DocumentUriConverter))] - public required Uri BaseUri { get; set; } - - [JsonPropertyName("pattern")] - public required string Pattern { get; set; } -} - -// The LSP specification has a spelling error in the protocol, but Microsoft.VisualStudio.LanguageServer.Protocol -// didn't carry that error along. This corrects that. -internal class UnregistrationParamsWithMisspelling -{ - [JsonPropertyName("unregisterations")] - public required Unregistration[] Unregistrations { get; set; } -} - -[Flags] -internal enum WatchKind -{ - Create = 1, - Change = 2, - Delete = 4 -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/LspFileChangeWatcher.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/LspFileChangeWatcher.cs index 254707da542a7..06451af2acaa3 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/LspFileChangeWatcher.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/LspFileChangeWatcher.cs @@ -40,12 +40,10 @@ public static bool SupportsLanguageServerHost(LanguageServerHost languageServerH return clientCapabilitiesProvider.GetClientCapabilities().Workspace?.DidChangeWatchedFiles?.DynamicRegistration ?? false; } - public IFileChangeContext CreateContext(params WatchedDirectory[] watchedDirectories) - { - return new FileChangeContext([.. watchedDirectories], this); - } + public IFileChangeContext CreateContext(ImmutableArray watchedDirectories) + => new FileChangeContext(watchedDirectories, this); - private class FileChangeContext : IFileChangeContext + private sealed class FileChangeContext : IFileChangeContext { private readonly ImmutableArray _watchedDirectories; private readonly LspFileChangeWatcher _lspFileChangeWatcher; @@ -234,7 +232,7 @@ public void Dispose() _registrationTask.ContinueWith(async _ => { - var unregistrationParams = new UnregistrationParamsWithMisspelling() + var unregistrationParams = new UnregistrationParams() { Unregistrations = [ diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/SimpleFileChangeWatcher.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/SimpleFileChangeWatcher.cs index 3f901a8be52b8..9cc6048699756 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/SimpleFileChangeWatcher.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/SimpleFileChangeWatcher.cs @@ -17,12 +17,10 @@ namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.FileWatching; /// internal sealed class SimpleFileChangeWatcher : IFileChangeWatcher { - public IFileChangeContext CreateContext(params WatchedDirectory[] watchedDirectories) - { - return new FileChangeContext([.. watchedDirectories]); - } + public IFileChangeContext CreateContext(ImmutableArray watchedDirectories) + => new FileChangeContext(watchedDirectories); - private class FileChangeContext : IFileChangeContext + private sealed class FileChangeContext : IFileChangeContext { private readonly ImmutableArray _watchedDirectories; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs index b896d0b363112..781feabf5d46e 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs @@ -115,7 +115,7 @@ public async Task OpenSolutionAsync(string solutionFilePath) foreach (var project in await buildHost.GetProjectsInSolutionAsync(solutionFilePath, CancellationToken.None)) { - _projectsToLoadAndReload.AddWork(new ProjectToLoad(project.ProjectPath, project.ProjectGuid)); + _projectsToLoadAndReload.AddWork(new ProjectToLoad(project.ProjectPath, project.ProjectGuid, ReportTelemetry: true)); } // Wait for the in progress batch to complete and send a project initialized notification to the client. @@ -131,7 +131,7 @@ public async Task OpenProjectsAsync(ImmutableArray projectFilePaths) using (await _gate.DisposableWaitAsync()) { - _projectsToLoadAndReload.AddWork(projectFilePaths.Select(p => new ProjectToLoad(p, ProjectGuid: null))); + _projectsToLoadAndReload.AddWork(projectFilePaths.Select(p => new ProjectToLoad(p, ProjectGuid: null, ReportTelemetry: true))); // Wait for the in progress batch to complete and send a project initialized notification to the client. await _projectsToLoadAndReload.WaitUntilCurrentBatchCompletesAsync(); @@ -278,7 +278,7 @@ private async Task LoadOrReloadProjectAsync(ProjectToLoad projectToLoad, T _workspaceFactory.ProjectSystemHostInfo); var loadedProject = new LoadedProject(projectSystemProject, _workspaceFactory.Workspace.Services.SolutionServices, _fileChangeWatcher, _workspaceFactory.TargetFrameworkManager); - loadedProject.NeedsReload += (_, _) => _projectsToLoadAndReload.AddWork(projectToLoad); + loadedProject.NeedsReload += (_, _) => _projectsToLoadAndReload.AddWork(projectToLoad with { ReportTelemetry = false }); existingProjects.Add(loadedProject); (targetTelemetryInfo, targetNeedsRestore) = await loadedProject.UpdateWithNewProjectInfoAsync(loadedProjectInfo, _logger); @@ -288,7 +288,11 @@ private async Task LoadOrReloadProjectAsync(ProjectToLoad projectToLoad, T } } - await _projectLoadTelemetryReporter.ReportProjectLoadTelemetryAsync(telemetryInfos, projectToLoad, cancellationToken); + if (projectToLoad.ReportTelemetry) + { + await _projectLoadTelemetryReporter.ReportProjectLoadTelemetryAsync(telemetryInfos, projectToLoad, cancellationToken); + } + diagnosticLogItems = await loadedFile.GetDiagnosticLogItemsAsync(cancellationToken); if (diagnosticLogItems.Any()) { diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs index 1e33f50614121..c921e70de6d6b 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerWorkspaceFactory.cs @@ -8,8 +8,8 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler.DebugConfiguration; -using Microsoft.CodeAnalysis.LanguageServer.Services; using Microsoft.CodeAnalysis.ProjectSystem; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.Composition; @@ -26,7 +26,7 @@ internal sealed class LanguageServerWorkspaceFactory public LanguageServerWorkspaceFactory( HostServicesProvider hostServicesProvider, IFileChangeWatcher fileChangeWatcher, - [ImportMany] IEnumerable> dynamicFileInfoProviders, + [ImportMany] IEnumerable> dynamicFileInfoProviders, ProjectTargetFrameworkManager projectTargetFrameworkManager, ServerConfigurationFactory serverConfigurationFactory, ILoggerFactory loggerFactory) @@ -35,13 +35,14 @@ public LanguageServerWorkspaceFactory( var workspace = new LanguageServerWorkspace(hostServicesProvider.HostServices); Workspace = workspace; - ProjectSystemProjectFactory = new ProjectSystemProjectFactory(Workspace, fileChangeWatcher, static (_, _) => Task.CompletedTask, _ => { }); + ProjectSystemProjectFactory = new ProjectSystemProjectFactory( + Workspace, fileChangeWatcher, static (_, _) => Task.CompletedTask, _ => { }, + CancellationToken.None); // TODO: do we need to introduce a shutdown cancellation token for this? workspace.ProjectSystemProjectFactory = ProjectSystemProjectFactory; var razorSourceGenerator = serverConfigurationFactory?.ServerConfiguration?.RazorSourceGenerator; ProjectSystemHostInfo = new ProjectSystemHostInfo( DynamicFileInfoProviders: dynamicFileInfoProviders.ToImmutableArray(), - ProjectSystemDiagnosticSource.Instance, new HostDiagnosticAnalyzerProvider(razorSourceGenerator)); TargetFrameworkManager = projectTargetFrameworkManager; @@ -56,7 +57,7 @@ public LanguageServerWorkspaceFactory( public async Task InitializeSolutionLevelAnalyzersAsync(ImmutableArray analyzerPaths) { var references = new List(); - var analyzerLoader = Workspace.Services.GetRequiredService().GetLoader(shadowCopy: true); + var analyzerLoader = Workspace.Services.GetRequiredService().SharedShadowCopyLoader; foreach (var analyzerPath in analyzerPaths) { diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs index 0166dcf42ef43..c2e7f749d2367 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LoadedProject.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.MSBuild; using Microsoft.CodeAnalysis.ProjectSystem; using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; +using Microsoft.Extensions.FileSystemGlobbing; using Microsoft.Extensions.Logging; using Roslyn.Utilities; @@ -19,6 +20,9 @@ namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; /// internal sealed class LoadedProject : IDisposable { + private readonly string _projectFilePath; + private readonly string _projectDirectory; + private readonly ProjectSystemProject _projectSystemProject; private readonly ProjectSystemProjectOptionsProcessor _optionsProcessor; private readonly IFileChangeContext _fileChangeContext; @@ -28,6 +32,10 @@ internal sealed class LoadedProject : IDisposable /// The most recent version of the project design time build information; held onto so the next reload we can diff against this. /// private ProjectFileInfo? _mostRecentFileInfo; + /// + /// The most recent version of the file glob matcher. Held onto + /// + private Lazy>? _mostRecentFileMatchers; private IWatchedFile? _mostRecentProjectAssetsFileWatcher; private ImmutableArray _mostRecentMetadataReferences = ImmutableArray.Empty; private ImmutableArray _mostRecentAnalyzerReferences = ImmutableArray.Empty; @@ -35,6 +43,7 @@ internal sealed class LoadedProject : IDisposable public LoadedProject(ProjectSystemProject projectSystemProject, SolutionServices solutionServices, IFileChangeWatcher fileWatcher, ProjectTargetFrameworkManager targetFrameworkManager) { Contract.ThrowIfNull(projectSystemProject.FilePath); + _projectFilePath = projectSystemProject.FilePath; _projectSystemProject = projectSystemProject; _optionsProcessor = new ProjectSystemProjectOptionsProcessor(projectSystemProject, solutionServices); @@ -42,24 +51,49 @@ public LoadedProject(ProjectSystemProject projectSystemProject, SolutionServices // We'll watch the directory for all source file changes // TODO: we only should listen for add/removals here, but we can't specify such a filter now - var projectDirectory = Path.GetDirectoryName(projectSystemProject.FilePath)!; - var watchedDirectories = new WatchedDirectory[] - { - new(projectDirectory, ".cs"), - new(projectDirectory, ".cshtml"), - new(projectDirectory, ".razor") - }; + _projectDirectory = Path.GetDirectoryName(_projectFilePath)!; - _fileChangeContext = fileWatcher.CreateContext(watchedDirectories); + _fileChangeContext = fileWatcher.CreateContext([ + new(_projectDirectory, ".cs"), + new(_projectDirectory, ".cshtml"), + new(_projectDirectory, ".razor") + ]); _fileChangeContext.FileChanged += FileChangedContext_FileChanged; // Start watching for file changes for the project file as well - _fileChangeContext.EnqueueWatchingFile(projectSystemProject.FilePath); + _fileChangeContext.EnqueueWatchingFile(_projectFilePath); } private void FileChangedContext_FileChanged(object? sender, string filePath) { - NeedsReload?.Invoke(this, EventArgs.Empty); + // If the project file itself changed, we almost certainly need to reload the project. + if (string.Equals(filePath, _projectFilePath, StringComparison.OrdinalIgnoreCase)) + { + NeedsReload?.Invoke(this, EventArgs.Empty); + return; + } + + var matchers = _mostRecentFileMatchers?.Value; + if (matchers is null) + { + return; + } + + // Check if the file path matches any of the globs in the project file. + foreach (var matcher in matchers) + { + // CPS re-creates the msbuild globs from the includes/excludes/removes and the project XML directory and + // ignores the MSBuildGlob.FixedDirectoryPart. We'll do the same here and match using the project directory as the relative path. + // See https://devdiv.visualstudio.com/DevDiv/_git/CPS?path=/src/Microsoft.VisualStudio.ProjectSystem/Build/MsBuildGlobFactory.cs + var relativeDirectory = _projectDirectory; + + var matches = matcher.Match(relativeDirectory, filePath); + if (matches.HasMatches) + { + NeedsReload?.Invoke(this, EventArgs.Empty); + return; + } + } } public event EventHandler? NeedsReload; @@ -188,6 +222,17 @@ public void Dispose() var needsRestore = ProjectDependencyHelper.NeedsRestore(newProjectInfo, _mostRecentFileInfo, logger); + _mostRecentFileMatchers = new Lazy>(() => + { + return newProjectInfo.FileGlobs.Select(glob => + { + var matcher = new Matcher(); + matcher.AddIncludePatterns(glob.Includes); + matcher.AddExcludePatterns(glob.Excludes); + matcher.AddExcludePatterns(glob.Removes); + return matcher; + }).ToImmutableArray(); + }); _mostRecentFileInfo = newProjectInfo; Contract.ThrowIfNull(_projectSystemProject.CompilationOptions, "Compilation options cannot be null for C#/VB project"); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectSystemDiagnosticSource.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectSystemDiagnosticSource.cs deleted file mode 100644 index 5fc406f39698a..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectSystemDiagnosticSource.cs +++ /dev/null @@ -1,22 +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 Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; - -internal sealed class ProjectSystemDiagnosticSource : IProjectSystemDiagnosticSource -{ - public static readonly ProjectSystemDiagnosticSource Instance = new(); - - private ProjectSystemDiagnosticSource() - { - } - - public DiagnosticData CreateAnalyzerLoadFailureDiagnostic(AnalyzerLoadFailureEventArgs e, string fullPath, ProjectId projectId, string language) - { - return DocumentAnalysisExecutor.CreateAnalyzerLoadFailureDiagnostic(e, fullPath, projectId, language); - } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectToLoad.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectToLoad.cs index bacfa547fffd8..ae11154877798 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectToLoad.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/ProjectToLoad.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; /// /// The project path (and the guid if it game from a solution) of the project to load. /// -internal record ProjectToLoad(string Path, string? ProjectGuid) +internal record ProjectToLoad(string Path, string? ProjectGuid, bool ReportTelemetry) { public static IEqualityComparer Comparer = new ProjectToLoadComparer(); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorDynamicFileInfoProvider.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorDynamicFileInfoProvider.cs index beae910355125..4e3d57878fdb8 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorDynamicFileInfoProvider.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/RazorDynamicFileInfoProvider.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.LanguageServer; using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; @@ -20,22 +21,22 @@ internal class RazorDynamicFileInfoProvider : IDynamicFileInfoProvider private class ProvideDynamicFileParams { - [JsonPropertyName("razorFiles")] - public required Uri[] RazorFiles { get; set; } + [JsonPropertyName("razorDocument")] + public required TextDocumentIdentifier RazorDocument { get; set; } } private class ProvideDynamicFileResponse { - [JsonPropertyName("generatedFiles")] - public required Uri[] GeneratedFiles { get; set; } + [JsonPropertyName("csharpDocument")] + public required TextDocumentIdentifier CSharpDocument { get; set; } } private const string RemoveRazorDynamicFileInfoMethodName = "razor/removeDynamicFileInfo"; private class RemoveDynamicFileParams { - [JsonPropertyName("razorFiles")] - public required Uri[] RazorFiles { get; set; } + [JsonPropertyName("csharpDocument")] + public required TextDocumentIdentifier CSharpDocument { get; set; } } #pragma warning disable CS0067 // We won't fire the Updated event -- we expect Razor to send us textual changes via didChange instead @@ -55,7 +56,13 @@ public RazorDynamicFileInfoProvider(Lazy razo { _razorWorkspaceListenerInitializer.Value.NotifyDynamicFile(projectId); - var requestParams = new ProvideDynamicFileParams { RazorFiles = [ProtocolConversions.CreateAbsoluteUri(filePath)] }; + var requestParams = new ProvideDynamicFileParams + { + RazorDocument = new() + { + Uri = ProtocolConversions.CreateAbsoluteUri(filePath) + } + }; Contract.ThrowIfNull(LanguageServerHost.Instance, "We don't have an LSP channel yet to send this request through."); var clientLanguageServerManager = LanguageServerHost.Instance.GetRequiredLspService(); @@ -64,7 +71,7 @@ public RazorDynamicFileInfoProvider(Lazy razo ProvideRazorDynamicFileInfoMethodName, requestParams, cancellationToken); // Since we only sent one file over, we should get either zero or one URI back - var responseUri = response.GeneratedFiles.SingleOrDefault(); + var responseUri = response.CSharpDocument?.Uri; if (responseUri == null) { @@ -79,7 +86,13 @@ public RazorDynamicFileInfoProvider(Lazy razo public Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken) { - var notificationParams = new RemoveDynamicFileParams { RazorFiles = [ProtocolConversions.CreateAbsoluteUri(filePath)] }; + var notificationParams = new RemoveDynamicFileParams + { + CSharpDocument = new() + { + Uri = ProtocolConversions.CreateAbsoluteUri(filePath) + } + }; Contract.ThrowIfNull(LanguageServerHost.Instance, "We don't have an LSP channel yet to send this request through."); var clientLanguageServerManager = LanguageServerHost.Instance.GetRequiredLspService(); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/VSCodeAnalyzerLoader.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/VSCodeAnalyzerLoader.cs deleted file mode 100644 index 29fa134aafc25..0000000000000 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/VSCodeAnalyzerLoader.cs +++ /dev/null @@ -1,60 +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.Composition; -using System.Reflection; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServer.Services; -using Microsoft.Extensions.Logging; - -namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; - -[ExportWorkspaceService(typeof(IAnalyzerAssemblyLoaderProvider), [WorkspaceKind.Host]), Shared] -internal class VSCodeAnalyzerLoaderProvider : AbstractAnalyzerAssemblyLoaderProvider -{ - private readonly ExtensionAssemblyManager _extensionAssemblyManager; - private readonly ILoggerFactory _loggerFactory; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VSCodeAnalyzerLoaderProvider( - ExtensionAssemblyManager extensionAssemblyManager, - ILoggerFactory loggerFactory, - [ImportMany] IEnumerable externalResolvers) : base(externalResolvers) - { - _extensionAssemblyManager = extensionAssemblyManager; - _loggerFactory = loggerFactory; - } - - protected override IAnalyzerAssemblyLoader CreateShadowCopyLoader(ImmutableArray externalResolvers) - { - var baseLoader = base.CreateShadowCopyLoader(externalResolvers); - return new VSCodeExtensionAssemblyAnalyzerLoader(baseLoader, _extensionAssemblyManager, _loggerFactory.CreateLogger()); - } - - /// - /// Analyzer loader that will re-use already loaded assemblies from the extension load context. - /// - private class VSCodeExtensionAssemblyAnalyzerLoader(IAnalyzerAssemblyLoader defaultLoader, ExtensionAssemblyManager extensionAssemblyManager, ILogger logger) : IAnalyzerAssemblyLoader - { - public void AddDependencyLocation(string fullPath) - { - defaultLoader.AddDependencyLocation(fullPath); - } - - public Assembly LoadFromPath(string fullPath) - { - var assembly = extensionAssemblyManager.TryLoadAssemblyInExtensionContext(fullPath); - if (assembly is not null) - { - logger.LogTrace("Loaded analyzer {fullPath} from extension context", fullPath); - return assembly; - } - - return defaultLoader.LoadFromPath(fullPath); - } - } -} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/VSCodeAnalyzerLoaderProviderFactory.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/VSCodeAnalyzerLoaderProviderFactory.cs new file mode 100644 index 0000000000000..623c912837f21 --- /dev/null +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/VSCodeAnalyzerLoaderProviderFactory.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Composition; +using System.Reflection; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer.Services; +using Microsoft.Extensions.Logging; + +namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; + +[ExportWorkspaceService(typeof(IAnalyzerAssemblyLoaderProvider), [WorkspaceKind.Host]), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class VSCodeAnalyzerLoaderProviderFactory( + ExtensionAssemblyManager extensionAssemblyManager, + ILoggerFactory loggerFactory, + [ImportMany] IEnumerable externalResolvers) + : AbstractAnalyzerAssemblyLoaderProvider(externalResolvers) +{ + protected override IAnalyzerAssemblyLoaderInternal WrapLoader(IAnalyzerAssemblyLoaderInternal baseLoader) + => new VSCodeExtensionAssemblyAnalyzerLoader(baseLoader, extensionAssemblyManager, loggerFactory.CreateLogger()); + + /// + /// Analyzer loader that will re-use already loaded assemblies from the extension load context. + /// + private sealed class VSCodeExtensionAssemblyAnalyzerLoader( + IAnalyzerAssemblyLoaderInternal defaultLoader, + ExtensionAssemblyManager extensionAssemblyManager, + ILogger logger) : IAnalyzerAssemblyLoaderInternal + { + public void AddDependencyLocation(string fullPath) + => defaultLoader.AddDependencyLocation(fullPath); + + public string? GetOriginalDependencyLocation(AssemblyName assembly) + => defaultLoader.GetOriginalDependencyLocation(assembly); + + public bool IsHostAssembly(Assembly assembly) + => defaultLoader.IsHostAssembly(assembly); + + public Assembly LoadFromPath(string fullPath) + { + var assembly = extensionAssemblyManager.TryLoadAssemblyInExtensionContext(fullPath); + if (assembly is not null) + { + logger.LogTrace("Loaded analyzer {fullPath} from extension context", fullPath); + return assembly; + } + + return defaultLoader.LoadFromPath(fullPath); + } + + public void Dispose() + => defaultLoader.Dispose(); + } +} diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx index 890a0f135613b..404ee9daf58d7 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx @@ -240,4 +240,16 @@ Project {0} has unresolved dependencies + + Standard Output Messages + + + Standard Error Messages + + + Debug Trace Messages + + + Additional Info Messages + \ No newline at end of file diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj index 56ede6d5b150e..e4d766433e2d1 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Microsoft.CodeAnalysis.LanguageServer.csproj @@ -78,9 +78,11 @@ + + diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.TestRunHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.TestRunHandler.cs index 53344dbc24313..106f36090ad14 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.TestRunHandler.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.TestRunHandler.cs @@ -2,9 +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.Collections.Immutable; +using System.Collections.ObjectModel; using System.Text; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.LanguageServer.Handler.Testing; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; @@ -137,11 +140,7 @@ private static string CreateTestCaseReportMessage(TestRunChangedEventArgs? testR var results = testRunChangedEventArgs.NewTestResults.Select(result => { var messageBuilder = new StringBuilder(); - messageBuilder.Append($"[{result.Outcome}] {result.TestCase.DisplayName}"); - if (result.ErrorMessage != null || result.ErrorStackTrace != null) - { - messageBuilder.AppendLine(); - } + messageBuilder.AppendLine($"[{result.Outcome}] {result.TestCase.DisplayName}"); if (!string.IsNullOrWhiteSpace(result.ErrorMessage)) { @@ -155,14 +154,64 @@ private static string CreateTestCaseReportMessage(TestRunChangedEventArgs? testR messageBuilder.AppendLine(IndentString(result.ErrorStackTrace, 8)); } + var standardOutputMessages = GetTestMessages(result.Messages, TestResultMessage.StandardOutCategory); + if (standardOutputMessages.Length > 0) + { + messageBuilder.AppendLine(value: IndentString($"{LanguageServerResources.Standard_Output_Messages}:", 4)); + messageBuilder.AppendLine(FormatMessages(standardOutputMessages, 8)); + } + + var standardErrorMessages = GetTestMessages(result.Messages, TestResultMessage.StandardErrorCategory); + if (standardErrorMessages.Length > 0) + { + messageBuilder.AppendLine(value: IndentString($"{LanguageServerResources.Standard_Error_Messages}:", 4)); + messageBuilder.AppendLine(FormatMessages(standardErrorMessages, 8)); + } + + var debugTraceMessages = GetTestMessages(result.Messages, TestResultMessage.DebugTraceCategory); + if (debugTraceMessages.Length > 0) + { + messageBuilder.AppendLine(value: IndentString($"{LanguageServerResources.Debug_Trace_Messages}:", 4)); + messageBuilder.AppendLine(FormatMessages(debugTraceMessages, 8)); + } + + var additionalInfoMessages = GetTestMessages(result.Messages, TestResultMessage.AdditionalInfoCategory); + if (additionalInfoMessages.Length > 0) + { + messageBuilder.AppendLine(value: IndentString($"{LanguageServerResources.Additional_Info_Messages}:", 4)); + messageBuilder.AppendLine(FormatMessages(additionalInfoMessages, 8)); + } + return messageBuilder.ToString(); }); - return string.Join(Environment.NewLine, results); + return string.Join("", results); static string IndentString(string text, int count) { - return text.Replace(Environment.NewLine, $"{Environment.NewLine} ").TrimEnd().Insert(0, new string(' ', count)); + var indentation = new string(' ', count); + return text.Replace(Environment.NewLine, $"{Environment.NewLine}{indentation}").TrimEnd().Insert(0, indentation); + } + + static ImmutableArray GetTestMessages(Collection messages, string requiredCategory) + { + return messages.WhereAsArray(static (msg, category) => msg.Category.Equals(category, StringComparison.OrdinalIgnoreCase), requiredCategory); + } + + static string FormatMessages(ImmutableArray messages, int indentation) + { + var builder = new StringBuilder(); + foreach (var message in messages) + { + if (message.Text is null) + continue; + + var indentedMessage = IndentString(message.Text, indentation); + if (!string.IsNullOrWhiteSpace(indentedMessage)) + builder.Append(indentedMessage); + } + + return builder.ToString(); } } } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf index ca6673bf876c9..3f692c5accc7a 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf @@ -7,6 +7,11 @@ Přerušeno!
+ + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} Připojování ladicího programu k procesu {0} @@ -32,6 +37,11 @@ Dokončilo se (opětovné) načtení všech projektů v čase {0} The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... Ladí se testy… @@ -162,6 +172,16 @@ Trasování zásobníku + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery Spouštění zjišťování testů… diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.de.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.de.xlf index 57f3c43bdc6a3..886437ae4d6df 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.de.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.de.xlf @@ -7,6 +7,11 @@ Abgebrochen! + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} Debugger wird an Prozess "{0}" angefügt @@ -32,6 +37,11 @@ Abgeschlossenes (erneutes) Laden aller Projekte in {0} The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... Debugging von Tests wird ausgeführt... @@ -162,6 +172,16 @@ Stapelüberwachung + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery Testermittlung wird gestartet diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.es.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.es.xlf index ffbbb2b8bca28..04fa3a8aeb227 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.es.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.es.xlf @@ -7,6 +7,11 @@ ¡Anulado! + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} Asociación del depurador para procesar {0} @@ -32,6 +37,11 @@ (Re)carga completa de todos los proyectos en {0} The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... Depurando pruebas... @@ -162,6 +172,16 @@ Seguimiento de la pila + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery Iniciando detección de pruebas diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.fr.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.fr.xlf index 6941c95ef6fb4..a3a6efc871d65 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.fr.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.fr.xlf @@ -7,6 +7,11 @@ Abandonné ! + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} Attachement du débogueur au processus {0} @@ -32,6 +37,11 @@ Chargement ou rechargement terminé de tous les projets dans {0} The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... Débogage en cours des tests... @@ -162,6 +172,16 @@ Trace de la pile + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery Démarrage de la découverte de tests diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.it.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.it.xlf index 27e970862bbae..bc6c2f5fad0a4 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.it.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.it.xlf @@ -7,6 +7,11 @@ Interrotto! + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} Collegamento del debugger all'elaborazione di {0} @@ -32,6 +37,11 @@ Completato il (ri)caricamento di tutti i progetti in {0} The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... Debug dei test... @@ -162,6 +172,16 @@ Analisi dello stack + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery Avvio dell'individuazione dei test diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ja.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ja.xlf index c4940eb7c664d..8bfd7778dd809 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ja.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ja.xlf @@ -7,6 +7,11 @@ 中止されました! + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} プロセス {0} にデバッガーをアタッチしています @@ -32,6 +37,11 @@ {0} のすべてのプロジェクトの (再) 読み込みが完了しました The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... テストをデバッグしています... @@ -162,6 +172,16 @@ スタック トレース + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery テストの検出を開始します diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ko.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ko.xlf index 56ecb0074946d..1ca432945e8f9 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ko.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ko.xlf @@ -7,6 +7,11 @@ 중단됨! + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} 프로세스 {0}에 디버거를 연결하는 중 @@ -32,6 +37,11 @@ {0}에 있는 모든 프로젝트의 (재)로드가 완료됨 The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... 테스트를 디버그하는 중... @@ -162,6 +172,16 @@ 스택 추적 + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery 테스트 검색을 시작하는 중 diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pl.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pl.xlf index 6bb6fb61ba444..658b055b599b2 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pl.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pl.xlf @@ -7,6 +7,11 @@ Przerwane! + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} Dołączanie debugera do procesu {0} @@ -32,6 +37,11 @@ Ukończono (ponownie)ładowanie wszystkich projektów w usłudze {0} The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... Trwa debugowanie testów... @@ -162,6 +172,16 @@ Śledzenie stosu + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery Uruchamianie odnajdywania testów diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pt-BR.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pt-BR.xlf index 0be751a2cb52d..2bc8e705be376 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pt-BR.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pt-BR.xlf @@ -7,6 +7,11 @@ Anulado! + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} Anexar o depurador ao processo {0} @@ -32,6 +37,11 @@ (Re)carregamento concluído de todos os projetos em {0} The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... Depurando testes... @@ -162,6 +172,16 @@ Rastreamento de pilha + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery Iniciando a detecção de testes diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ru.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ru.xlf index 9f6ffe157bbd1..59437ba4e25a2 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ru.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ru.xlf @@ -7,6 +7,11 @@ Прервано + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} Подключение отладчика для обработки {0} @@ -32,6 +37,11 @@ Завершена (повторная) загрузка всех проектов в {0} The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... Идет отладка тестов... @@ -162,6 +172,16 @@ Трассировка стека + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery Запуск обнаружения тестов diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.tr.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.tr.xlf index 095b6ce4197ac..a21f0b3303281 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.tr.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.tr.xlf @@ -7,6 +7,11 @@ Durduruldu! + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} Hata ayıklayıcı, {0} işlemine ekleniyor @@ -32,6 +37,11 @@ Tüm projelerin (yeniden) yüklemesi {0} içinde tamamlandı The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... Test hataları ayıklanıyor... @@ -162,6 +172,16 @@ Yığın İzleme + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery Test bulma başlatılıyor diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hans.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hans.xlf index 9c0e452b77054..80c31b1ade404 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hans.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hans.xlf @@ -7,6 +7,11 @@ 已中止! + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} 正在将调试器附加到进程 {0} @@ -32,6 +37,11 @@ 已完成加载(重新加载) {0} 中的所有项目 The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... 正在调试测试... @@ -162,6 +172,16 @@ 堆栈跟踪 + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery 正在启动测试发现 diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hant.xlf b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hant.xlf index b3ce5e2fdaaec..02bcf5a74d0f1 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hant.xlf +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hant.xlf @@ -7,6 +7,11 @@ 已中止! + + Additional Info Messages + Additional Info Messages + + Attaching debugger to process {0} 正在將偵錯工具連結到處理序 {0} @@ -32,6 +37,11 @@ 已完成 {0} 中所有專案的(重新)載入 The placeholder is a time duration like 00:15 + + Debug Trace Messages + Debug Trace Messages + + Debugging tests... 正在偵錯測試... @@ -162,6 +172,16 @@ 堆疊追蹤 + + Standard Error Messages + Standard Error Messages + + + + Standard Output Messages + Standard Output Messages + + Starting test discovery 即將開始測試探索 diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/ExampleTests.cs b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/ExampleTests.cs index 844c1de5cd591..17e859f3a7049 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/ExampleTests.cs +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.UnitTests/ExampleTests.cs @@ -53,7 +53,7 @@ public async Task InitializeServer_SerializesCorrectly() var server = TestExampleLanguageServer.CreateLanguageServer(logger); var result = await server.InitializeServerAsync(); - Assert.True(result.Capabilities.SemanticTokensOptions!.Range!.Value.First); + Assert.True(result.Capabilities.SemanticTokensOptions!.Value.Unify().Range!.Value.First); } [Fact] diff --git a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/README.md b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/README.md index 01d75995ed2c5..517ddf22717ed 100644 --- a/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/README.md +++ b/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework/README.md @@ -15,30 +15,30 @@ To get started with CLaSP you may follow the following steps 1. Create a PackageReference to `Microsoft.CommonLanguageServerProtocol.Framework` in your LSP server project. 1. Implement the following classes: 1. `ILspLogger`. This allows CLaSP to log information however you would like. - 1. [`ILspServices`](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLspServices.cs). This interface will serve as a wrapper around whatever DI system you choose to use to make sure that your services implemented elsewhere are available to CLaSP. + 1. [`ILspServices`](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLspServices.cs). This interface will serve as a wrapper around whatever DI system you choose to use to make sure that your services implemented elsewhere are available to CLaSP. 1. We recommend making `SupportsGetRegisteredServices` return `false` and `GetRegisteredServices` throw `NotImplementedException`. - 1. [`AbstractLanguageServer`](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLanguageServer.cs). This is the core of your Language Server implementation, which will manage your lifecycle and host the rest of the components. - 1. [Ensure that `Initialize` is called](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLanguageServer.cs#:~:text=Initialize) (preferably from the constructor) to start the server. - 1. [`ConstructLspServices`](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLanguageServer.cs#:~:text=ConstructLspServices) will be called once to construct your implementation of `ILspServices`. When this exits all your services should be registerd, including your `IMethodHandlers`. The following Services are mandatory for proper function: + 1. [`AbstractLanguageServer`](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLanguageServer.cs). This is the core of your Language Server implementation, which will manage your lifecycle and host the rest of the components. + 1. [Ensure that `Initialize` is called](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLanguageServer.cs#:~:text=Initialize) (preferably from the constructor) to start the server. + 1. [`ConstructLspServices`](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLanguageServer.cs#:~:text=ConstructLspServices) will be called once to construct your implementation of `ILspServices`. When this exits all your services should be registerd, including your `IMethodHandlers`. The following Services are mandatory for proper function: - An `ILspLogger`. - An `IRequestContextFactory`. - An `InitializeHandler` and `InitializedHandler`, either the ones included in CLaSP or your own implementations. If you use the included handlers you will need an `IInitializeManager` (which handles your Client and Server Capabilities) too. - - [The `AbstractLanguageServer` itself](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLanguageServer.cs#L28). - 1. [`IRequestContextFactory`](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleRequestContextFactory.cs). Constructs the RequestContext for each request. To maintain good performance you need to minimize the work being done in `CreateRequestContextAsync` since it blocks the queue from receiving mutating requests. - 1. [A RequestContext type](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleRequestContext.cs). This is an object which will be passed in on every request your Handlers handle. It is a useful place to keep things like Loggers, Service providers, and most importantly DocumentSnapshots. -1. Now implement any Method handlers you need for your Language Server to properly function, such as [textDocument/didOpen](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_didOpen) using the `INotificationHandler` and `IRequestHandler` interfaces (and the `ITextDocumeentIdentifierhandler` interface if the request relates to a specific document), being sure to include them in your `ILspServices` object (as constructed by `ConstructLspServices`) [as `IMethodHandler` services](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLanguageServer.cs#:~:text=AddHandlers). This automatically registers them on the JsonRpc object. + - [The `AbstractLanguageServer` itself](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLanguageServer.cs#L28). + 1. [`IRequestContextFactory`](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleRequestContextFactory.cs). Constructs the RequestContext for each request. To maintain good performance you need to minimize the work being done in `CreateRequestContextAsync` since it blocks the queue from receiving mutating requests. + 1. [A RequestContext type](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleRequestContext.cs). This is an object which will be passed in on every request your Handlers handle. It is a useful place to keep things like Loggers, Service providers, and most importantly DocumentSnapshots. +1. Now implement any Method handlers you need for your Language Server to properly function, such as [textDocument/didOpen](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_didOpen) using the `INotificationHandler` and `IRequestHandler` interfaces (and the `ITextDocumeentIdentifierhandler` interface if the request relates to a specific document), being sure to include them in your `ILspServices` object (as constructed by `ConstructLspServices`) [as `IMethodHandler` services](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Microsoft.CommonLanguageServerProtocol.Framework.Example/ExampleLanguageServer.cs#:~:text=AddHandlers). This automatically registers them on the JsonRpc object. 1. `MutatesSolutionState` should be `true` for Handlers like `textDocument/didChange` which change solution state because this affects the queuing behavior required in order to ensure that the correct document version is being operated on. 1. `HandleNotificationAsync` and `HandleRequestAsync`. These implement your actual handler behavior but it's very important that if they require access to the current state of a TextDocument that this information be gathered by `IRequestContextFactory` and put on the `RequestContext` object rather than retrieved here. If you fail to follow this stipulation you may run into document sync issues because requests which mutate document state are not guaranteed to happen in a particular order. This means that document state might change while your `HandleRequestAsync` request is executing, but the `IRequestContextFactory` is guaranteed to operate in a thread-safe manner. ## More complex examples - [Roslyn](https://github.com/dotnet/roslyn/tree/main/src/Features/LanguageServer/Protocol) is the original implementor of CLaSP. - - [`AbstractLanguageServer`](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Protocol/RoslynLanguageServer.cs). Note that Roslyn overrides `ConstructRequestExecutionQueue`, allowing it to change the override some default behavior. + - [`AbstractLanguageServer`](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Protocol/RoslynLanguageServer.cs). Note that Roslyn overrides `ConstructRequestExecutionQueue`, allowing it to change the override some default behavior. - [`ILSPLogger`](https://github.com/dotnet/roslyn/blob/main/src/VisualStudio/Core/Def/LanguageClient/LogHubLspLogger.cs). Logs to LogHub. - - [`ILSPServices`](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Protocol/LspServices/LspServices.cs). Note: Roslyns `ILSPServices` implementation is a product of their specific history and needs and ends up being a combination of MEF and explicitly constructed services. We don't recommend using it to guide your creation of an `ILSPServices` implementation unless you have similarly complicated needs. - - [`IRequestContextFactory`](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Protocol/Handler/RequestContextFactory.cs). Provides a good example of how to get the TextDocumentIdentifier (URI) off of the `requestParam` object. - - [RequestContext](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Protocol/Handler/RequestContext.cs). Of particular interest here is the [retrieval of information about the document](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Protocol/Handler/RequestContext.cs#:~:text=GetLspDocumentInfoAsync) (if any). Since `RequestContext.CreateAsync` is called by `IRequestContextFactory.CreateRequestContextAsync` we maintain synchronization safety. - - [`IRequestHandler` or `INotificationHandler`](https://github.com/dotnet/roslyn/blob/main/src/Features/LanguageServer/Protocol/Handler/DocumentChanges/DidOpenHandler.cs). Note that this example mutates solution state and has document context. + - [`ILSPServices`](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Protocol/LspServices/LspServices.cs). Note: Roslyns `ILSPServices` implementation is a product of their specific history and needs and ends up being a combination of MEF and explicitly constructed services. We don't recommend using it to guide your creation of an `ILSPServices` implementation unless you have similarly complicated needs. + - [`IRequestContextFactory`](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Protocol/Handler/RequestContextFactory.cs). Provides a good example of how to get the TextDocumentIdentifier (URI) off of the `requestParam` object. + - [RequestContext](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Protocol/Handler/RequestContext.cs). Of particular interest here is the [retrieval of information about the document](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Protocol/Handler/RequestContext.cs#:~:text=GetLspDocumentInfoAsync) (if any). Since `RequestContext.CreateAsync` is called by `IRequestContextFactory.CreateRequestContextAsync` we maintain synchronization safety. + - [`IRequestHandler` or `INotificationHandler`](https://github.com/dotnet/roslyn/blob/main/src/LanguageServer/Protocol/Handler/DocumentChanges/DidOpenHandler.cs). Note that this example mutates solution state and has document context. - [Razor](https://github.com/dotnet/razor/tree/main/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer) has simpler requirements than Roslyn in some ways (such as `ILSPServices`) but relies on multiple other language servers (C#, HTML) for information on its contained languages. - [`AbstractLanguageServer`](https://github.com/dotnet/razor/blob/main/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs). - [`ConstructLspServices`](https://github.com/dotnet/razor/blob/main/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorLanguageServer.cs#:~:text=ConstructLspServices). Razor has a simple implementation of `ILSPServices` which wraps `Microsoft.Extensions.DependencyInjection` and explicitly adds each service that it depends on. diff --git a/src/LanguageServer/Protocol.TestUtilities/Microsoft.CodeAnalysis.LanguageServer.Protocol.Test.Utilities.csproj b/src/LanguageServer/Protocol.TestUtilities/Microsoft.CodeAnalysis.LanguageServer.Protocol.Test.Utilities.csproj index a613cf81260df..4de8104136f4c 100644 --- a/src/LanguageServer/Protocol.TestUtilities/Microsoft.CodeAnalysis.LanguageServer.Protocol.Test.Utilities.csproj +++ b/src/LanguageServer/Protocol.TestUtilities/Microsoft.CodeAnalysis.LanguageServer.Protocol.Test.Utilities.csproj @@ -8,7 +8,7 @@ true false true - true + true diff --git a/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs b/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs index 406ea9a4c2de0..2dffadeb45af7 100644 --- a/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs +++ b/src/LanguageServer/Protocol/DefaultCapabilitiesProvider.cs @@ -48,7 +48,7 @@ public ServerCapabilities GetCapabilities(ClientCapabilities clientCapabilities) var supportsVsExtensions = clientCapabilities.HasVisualStudioLspCapability(); var capabilities = supportsVsExtensions ? GetVSServerCapabilities() : new VSInternalServerCapabilities(); - var commitCharacters = AbstractLspCompletionResultCreationService.DefaultCommitCharactersArray; + var commitCharacters = CompletionResultFactory.DefaultCommitCharactersArray; var triggerCharacters = _completionProviders.SelectMany( lz => CommonCompletionUtilities.GetTriggerCharacters(lz.Value)).Distinct().Select(c => c.ToString()).ToArray(); diff --git a/src/LanguageServer/Protocol/Extensions/Extensions.KnownImageIds.cs b/src/LanguageServer/Protocol/Extensions/Extensions.KnownImageIds.cs new file mode 100644 index 0000000000000..f7273dd51630d --- /dev/null +++ b/src/LanguageServer/Protocol/Extensions/Extensions.KnownImageIds.cs @@ -0,0 +1,113 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.CodeAnalysis.LanguageServer +{ + internal static partial class Extensions + { + /// + /// This is the subset of values from Microsoft.VisualStudio.Imaging.KnownImageIds that we + /// care about. Copying them here avoids referencing Microsoft.VisualStudio.ImageCatalog.dll. + /// + private static class KnownImageIds + { + public static readonly Guid ImageCatalogGuid = Guid.Parse("ae27a6b0-e345-4288-96df-5eaf394ee369"); + + public const int Assembly = 196; + + public const int ClassInternal = 466; + public const int ClassPrivate = 471; + public const int ClassProtected = 472; + public const int ClassPublic = 473; + + public const int ConstantInternal = 617; + public const int ConstantPrivate = 618; + public const int ConstantProtected = 619; + public const int ConstantPublic = 620; + + public const int CSFileNode = 738; + public const int CSProjectNode = 758; + + public const int DelegateInternal = 910; + public const int DelegatePrivate = 911; + public const int DelegateProtected = 912; + public const int DelegatePublic = 913; + + public const int EnumerationInternal = 1121; + public const int EnumerationPrivate = 1129; + public const int EnumerationProtected = 1130; + public const int EnumerationPublic = 1131; + + public const int EnumerationItemPublic = 1125; + + public const int EventInternal = 1145; + public const int EventPrivate = 1150; + public const int EventProtected = 1151; + public const int EventPublic = 1152; + + public const int ExtensionMethod = 1204; + + public const int FieldInternal = 1218; + public const int FieldPrivate = 1220; + public const int FieldProtected = 1221; + public const int FieldPublic = 1222; + + public const int IntellisenseKeyword = 1589; + public const int IntellisenseWarning = 1591; + + public const int InterfaceInternal = 1605; + public const int InterfacePrivate = 1606; + public const int InterfaceProtected = 1607; + public const int InterfacePublic = 1608; + + public const int Label = 1661; + + public const int LocalVariable = 1747; + + public const int MatchType = 3790; + + public const int MethodInternal = 1876; + public const int MethodPrivate = 1878; + public const int MethodProtected = 1879; + public const int MethodPublic = 1880; + + public const int ModuleInternal = 1916; + public const int ModulePrivate = 1917; + public const int ModuleProtected = 1918; + public const int ModulePublic = 1919; + + public const int Namespace = 1951; + + public const int NuGet = 3150; + + public const int OpenFolder = 2162; + + public const int Operator = 2174; + + public const int PropertyInternal = 2431; + public const int PropertyPrivate = 2434; + public const int PropertyProtected = 2435; + public const int PropertyPublic = 2436; + + public const int Reference = 2521; + + public const int Snippet = 2852; + + public const int StatusInformation = 2933; + public const int StatusError = 2926; + + public const int Type = 3233; + + public const int ValueTypeInternal = 3332; + public const int ValueTypePrivate = 3333; + public const int ValueTypeProtected = 3334; + public const int ValueTypePublic = 3335; + + public const int VBFileNode = 3361; + public const int VBProjectNode = 3380; + } + } +} diff --git a/src/LanguageServer/Protocol/Extensions/Extensions.cs b/src/LanguageServer/Protocol/Extensions/Extensions.cs index d9b8e4078f89f..adc965d671f6f 100644 --- a/src/LanguageServer/Protocol/Extensions/Extensions.cs +++ b/src/LanguageServer/Protocol/Extensions/Extensions.cs @@ -10,22 +10,24 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindUsages; +using Microsoft.CodeAnalysis.QuickInfo.Presentation; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Roslyn.Core.Imaging; using Roslyn.LanguageServer.Protocol; using Roslyn.Text.Adornments; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer { - internal static class Extensions + internal static partial class Extensions { public static Uri GetURI(this TextDocument document) { Contract.ThrowIfNull(document.FilePath); - return document is SourceGeneratedDocument - ? ProtocolConversions.CreateUriFromSourceGeneratedFilePath(document.FilePath) + return document is SourceGeneratedDocument sourceGeneratedDocument + ? SourceGeneratedDocumentUri.Create(sourceGeneratedDocument.Identity) : ProtocolConversions.CreateAbsoluteUri(document.FilePath); } @@ -56,42 +58,63 @@ public static Uri CreateUriForDocumentWithoutFilePath(this TextDocument document return ProtocolConversions.CreateAbsoluteUri(path); } - public static ImmutableArray GetDocuments(this Solution solution, Uri documentUri) - => GetDocuments(solution, ProtocolConversions.GetDocumentFilePathFromUri(documentUri)); - - public static ImmutableArray GetDocuments(this Solution solution, string documentPath) - { - var documentIds = solution.GetDocumentIdsWithFilePath(documentPath); - - // We don't call GetRequiredDocument here as the id could be referring to an additional document. - var documents = documentIds.Select(solution.GetDocument).WhereNotNull().ToImmutableArray(); - return documents; - } - /// /// Get all regular and additional s for the given . + /// This will not return source generated documents. /// public static ImmutableArray GetTextDocuments(this Solution solution, Uri documentUri) { var documentIds = GetDocumentIds(solution, documentUri); var documents = documentIds - .Select(solution.GetDocument) - .Concat(documentIds.Select(solution.GetAdditionalDocument)) + .Select(solution.GetTextDocument) .WhereNotNull() .ToImmutableArray(); return documents; } public static ImmutableArray GetDocumentIds(this Solution solution, Uri documentUri) - => solution.GetDocumentIdsWithFilePath(ProtocolConversions.GetDocumentFilePathFromUri(documentUri)); + { + // If this is not our special scheme for generated documents, then we can just look for documents with that file path. + if (documentUri.Scheme != SourceGeneratedDocumentUri.Scheme) + return solution.GetDocumentIdsWithFilePath(ProtocolConversions.GetDocumentFilePathFromUri(documentUri)); + + // We can get a null documentId if we were unable to find the project associated with the + // generated document - this can happen if say a project is unloaded. There may be LSP requests + // already in-flight which may ask for a generated document from that project. So we return null + var documentId = SourceGeneratedDocumentUri.DeserializeIdentity(solution, documentUri)?.DocumentId; - public static Document? GetDocument(this Solution solution, TextDocumentIdentifier documentIdentifier) + return documentId is not null ? [documentId] : []; + } + + /// + /// Finds the document for a TextDocumentIdentifier, potentially returning a source-generated file. + /// + public static async ValueTask GetDocumentAsync(this Solution solution, TextDocumentIdentifier documentIdentifier, CancellationToken cancellationToken) + { + var textDocument = await solution.GetTextDocumentAsync(documentIdentifier, cancellationToken).ConfigureAwait(false); + Contract.ThrowIfTrue(textDocument is not null && textDocument is not Document, $"{textDocument!.Id} is not a Document"); + return textDocument as Document; + } + + /// + /// Finds the TextDocument for a TextDocumentIdentifier, potentially returning a source-generated file. + /// + public static async ValueTask GetTextDocumentAsync(this Solution solution, TextDocumentIdentifier documentIdentifier, CancellationToken cancellationToken) { - var documents = solution.GetDocuments(documentIdentifier.Uri); + // If it's the URI scheme for source generated files, delegate to our other helper, otherwise we can handle anything else here. + if (documentIdentifier.Uri.Scheme == SourceGeneratedDocumentUri.Scheme) + { + // In the case of a URI scheme for source generated files, we generate a different URI for each project, thus this URI cannot be linked into multiple projects; + // this means we can safely call .SingleOrDefault() and not worry about calling FindDocumentInProjectContext. + var documentId = solution.GetDocumentIds(documentIdentifier.Uri).SingleOrDefault(); + return await solution.GetDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + } + + var documents = solution.GetTextDocuments(documentIdentifier.Uri); return documents.Length == 0 ? null - : documents.FindDocumentInProjectContext(documentIdentifier, (sln, id) => sln.GetRequiredDocument(id)); + : documents.FindDocumentInProjectContext(documentIdentifier, (sln, id) => sln.GetRequiredTextDocument(id)); } private static T FindItemInProjectContext( @@ -243,5 +266,182 @@ private static bool TryGetVSCompletionListSetting(ClientCapabilities clientCapab return true; } + + public static int CompareTo(this Position p1, Position p2) + { + if (p1.Line > p2.Line) + return 1; + else if (p1.Line < p2.Line) + return -1; + + if (p1.Character > p2.Character) + return 1; + else if (p1.Character < p2.Character) + return -1; + + return 0; + } + + public static VSImageId ToVSImageId(this Glyph glyph) + { + var (guid, id) = glyph.GetVsImageData(); + + return new() { Guid = guid, Id = id }; + } + + public static ImageId ToLSPImageId(this Glyph glyph) + { + var (guid, id) = glyph.GetVsImageData(); + + return new(guid, id); + } + + public static ImageElement ToLSPElement(this QuickInfoGlyphElement element) + => new(element.Glyph.ToLSPImageId()); + + public static ClassifiedTextRun ToLSPRun(this QuickInfoClassifiedTextRun run) + => new(run.ClassificationTypeName, run.Text, (ClassifiedTextRunStyle)run.Style, markerTagType: null, run.NavigationAction, run.Tooltip); + + public static ClassifiedTextElement ToLSPElement(this QuickInfoClassifiedTextElement element) + => new(element.Runs.Select(ToLSPRun)); + + public static ContainerElement ToLSPElement(this QuickInfoContainerElement element) + => new((ContainerElementStyle)element.Style, element.Elements.Select(ToLSPElement)); + + private static object? ToLSPElement(QuickInfoElement value) + { + return value switch + { + QuickInfoGlyphElement element => element.ToLSPElement(), + QuickInfoContainerElement element => element.ToLSPElement(), + QuickInfoClassifiedTextElement element => element.ToLSPElement(), + + _ => value + }; + } + + /// + /// Retrieves the and id that can represent a particular + /// in the Visual Studio client. + /// + /// + /// + /// + public static (Guid guid, int id) GetVsImageData(this Glyph glyph) + { + return glyph switch + { + Glyph.None => default, + + Glyph.Assembly => (KnownImageIds.ImageCatalogGuid, KnownImageIds.Assembly), + + Glyph.BasicFile => (KnownImageIds.ImageCatalogGuid, KnownImageIds.VBFileNode), + Glyph.BasicProject => (KnownImageIds.ImageCatalogGuid, KnownImageIds.VBProjectNode), + + Glyph.ClassPublic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ClassPublic), + Glyph.ClassProtected => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ClassProtected), + Glyph.ClassPrivate => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ClassPrivate), + Glyph.ClassInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ClassInternal), + + Glyph.CSharpFile => (KnownImageIds.ImageCatalogGuid, KnownImageIds.CSFileNode), + Glyph.CSharpProject => (KnownImageIds.ImageCatalogGuid, KnownImageIds.CSProjectNode), + + Glyph.CompletionWarning => (KnownImageIds.ImageCatalogGuid, KnownImageIds.IntellisenseWarning), + + Glyph.ConstantPublic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ConstantPublic), + Glyph.ConstantProtected => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ConstantProtected), + Glyph.ConstantPrivate => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ConstantPrivate), + Glyph.ConstantInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ConstantInternal), + + Glyph.DelegatePublic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.DelegatePublic), + Glyph.DelegateProtected => (KnownImageIds.ImageCatalogGuid, KnownImageIds.DelegateProtected), + Glyph.DelegatePrivate => (KnownImageIds.ImageCatalogGuid, KnownImageIds.DelegatePrivate), + Glyph.DelegateInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.DelegateInternal), + + Glyph.EnumPublic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.EnumerationPublic), + Glyph.EnumProtected => (KnownImageIds.ImageCatalogGuid, KnownImageIds.EnumerationProtected), + Glyph.EnumPrivate => (KnownImageIds.ImageCatalogGuid, KnownImageIds.EnumerationPrivate), + Glyph.EnumInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.EnumerationInternal), + + Glyph.EnumMemberPublic or + Glyph.EnumMemberProtected or + Glyph.EnumMemberPrivate or + Glyph.EnumMemberInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.EnumerationItemPublic), + + Glyph.Error => (KnownImageIds.ImageCatalogGuid, KnownImageIds.StatusError), + + Glyph.EventPublic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.EventPublic), + Glyph.EventProtected => (KnownImageIds.ImageCatalogGuid, KnownImageIds.EventProtected), + Glyph.EventPrivate => (KnownImageIds.ImageCatalogGuid, KnownImageIds.EventPrivate), + Glyph.EventInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.EventInternal), + + // Extension methods have the same glyph regardless of accessibility. + Glyph.ExtensionMethodPublic or + Glyph.ExtensionMethodProtected or + Glyph.ExtensionMethodPrivate or + Glyph.ExtensionMethodInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ExtensionMethod), + + Glyph.FieldPublic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.FieldPublic), + Glyph.FieldProtected => (KnownImageIds.ImageCatalogGuid, KnownImageIds.FieldProtected), + Glyph.FieldPrivate => (KnownImageIds.ImageCatalogGuid, KnownImageIds.FieldPrivate), + Glyph.FieldInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.FieldInternal), + + Glyph.InterfacePublic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.InterfacePublic), + Glyph.InterfaceProtected => (KnownImageIds.ImageCatalogGuid, KnownImageIds.InterfaceProtected), + Glyph.InterfacePrivate => (KnownImageIds.ImageCatalogGuid, KnownImageIds.InterfacePrivate), + Glyph.InterfaceInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.InterfaceInternal), + + // TODO: Figure out the right thing to return here. + Glyph.Intrinsic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.Type), + + Glyph.Keyword => (KnownImageIds.ImageCatalogGuid, KnownImageIds.IntellisenseKeyword), + + Glyph.Label => (KnownImageIds.ImageCatalogGuid, KnownImageIds.Label), + + Glyph.MethodPublic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.MethodPublic), + Glyph.MethodProtected => (KnownImageIds.ImageCatalogGuid, KnownImageIds.MethodProtected), + Glyph.MethodPrivate => (KnownImageIds.ImageCatalogGuid, KnownImageIds.MethodPrivate), + Glyph.MethodInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.MethodInternal), + + Glyph.ModulePublic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ModulePublic), + Glyph.ModuleProtected => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ModuleProtected), + Glyph.ModulePrivate => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ModulePrivate), + Glyph.ModuleInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ModuleInternal), + + Glyph.Namespace => (KnownImageIds.ImageCatalogGuid, KnownImageIds.Namespace), + + Glyph.NuGet => (KnownImageIds.ImageCatalogGuid, KnownImageIds.NuGet), + + Glyph.OpenFolder => (KnownImageIds.ImageCatalogGuid, KnownImageIds.OpenFolder), + + Glyph.Operator => (KnownImageIds.ImageCatalogGuid, KnownImageIds.Operator), + + Glyph.Parameter or Glyph.Local => (KnownImageIds.ImageCatalogGuid, KnownImageIds.LocalVariable), + + Glyph.PropertyPublic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.PropertyPublic), + Glyph.PropertyProtected => (KnownImageIds.ImageCatalogGuid, KnownImageIds.PropertyProtected), + Glyph.PropertyPrivate => (KnownImageIds.ImageCatalogGuid, KnownImageIds.PropertyPrivate), + Glyph.PropertyInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.PropertyInternal), + + Glyph.RangeVariable => (KnownImageIds.ImageCatalogGuid, KnownImageIds.FieldPublic), + + Glyph.Reference => (KnownImageIds.ImageCatalogGuid, KnownImageIds.Reference), + + Glyph.Snippet => (KnownImageIds.ImageCatalogGuid, KnownImageIds.Snippet), + + Glyph.StatusInformation => (KnownImageIds.ImageCatalogGuid, KnownImageIds.StatusInformation), + + Glyph.StructurePublic => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ValueTypePublic), + Glyph.StructureProtected => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ValueTypeProtected), + Glyph.StructurePrivate => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ValueTypePrivate), + Glyph.StructureInternal => (KnownImageIds.ImageCatalogGuid, KnownImageIds.ValueTypeInternal), + + Glyph.TargetTypeMatch => (KnownImageIds.ImageCatalogGuid, KnownImageIds.MatchType), + + Glyph.TypeParameter => (KnownImageIds.ImageCatalogGuid, KnownImageIds.Type), + + _ => throw new ArgumentException($"Unknown glyph value: {glyph}", nameof(glyph)), + }; + } } } diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs new file mode 100644 index 0000000000000..9d084b8076d00 --- /dev/null +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs @@ -0,0 +1,275 @@ +// 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.Linq; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.LanguageServer.Features.Diagnostics; +using Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.LanguageServer.Protocol; +using Roslyn.Utilities; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer; + +internal static partial class ProtocolConversions +{ + /// + /// Converts from to + /// + /// The diagnostic to convert + /// Whether the client is Visual Studio + /// The project the diagnostic is relevant to + /// Whether the diagnostic is considered "live" and should supersede others + /// Whether the diagnostic is potentially a duplicate to a build diagnostic + /// The global options service + public static ImmutableArray ConvertDiagnostic(DiagnosticData diagnosticData, bool supportsVisualStudioExtensions, Project project, bool isLiveSource, bool potentialDuplicate, IGlobalOptionService globalOptionService) + { + if (!ShouldIncludeHiddenDiagnostic(diagnosticData, supportsVisualStudioExtensions)) + { + return []; + } + + var diagnostic = CreateLspDiagnostic(diagnosticData, project, isLiveSource, potentialDuplicate, supportsVisualStudioExtensions); + + // Check if we need to handle the unnecessary tag (fading). + if (!diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary)) + { + return [diagnostic]; + } + + // DiagnosticId supports fading, check if the corresponding VS option is turned on. + if (!SupportsFadingOption(diagnosticData, globalOptionService)) + { + return [diagnostic]; + } + + // Check to see if there are specific locations marked to fade. + if (!diagnosticData.TryGetUnnecessaryDataLocations(out var unnecessaryLocations)) + { + // There are no specific fading locations, just mark the whole diagnostic span as unnecessary. + // We should always have at least one tag (build or intellisense error). + Contract.ThrowIfNull(diagnostic.Tags, $"diagnostic {diagnostic.Identifier} was missing tags"); + diagnostic.Tags = diagnostic.Tags.Append(DiagnosticTag.Unnecessary); + return [diagnostic]; + } + + if (supportsVisualStudioExtensions) + { + // Roslyn produces unnecessary diagnostics by using additional locations, however LSP doesn't support tagging + // additional locations separately. Instead we just create multiple hidden diagnostics for unnecessary squiggling. + using var _ = ArrayBuilder.GetInstance(out var diagnosticsBuilder); + diagnosticsBuilder.Add(diagnostic); + foreach (var location in unnecessaryLocations) + { + var additionalDiagnostic = CreateLspDiagnostic(diagnosticData, project, isLiveSource, potentialDuplicate, supportsVisualStudioExtensions); + additionalDiagnostic.Severity = LSP.DiagnosticSeverity.Hint; + additionalDiagnostic.Range = GetRange(location); + additionalDiagnostic.Tags = [DiagnosticTag.Unnecessary, VSDiagnosticTags.HiddenInEditor, VSDiagnosticTags.HiddenInErrorList, VSDiagnosticTags.SuppressEditorToolTip]; + diagnosticsBuilder.Add(additionalDiagnostic); + } + + return diagnosticsBuilder.ToImmutableArray(); + } + else + { + diagnostic.Tags = diagnostic.Tags != null ? diagnostic.Tags.Append(DiagnosticTag.Unnecessary) : [DiagnosticTag.Unnecessary]; + var diagnosticRelatedInformation = unnecessaryLocations.Value.Select(l => new DiagnosticRelatedInformation + { + Location = new LSP.Location + { + Range = GetRange(l), + Uri = ProtocolConversions.CreateAbsoluteUri(l.UnmappedFileSpan.Path) + }, + Message = diagnostic.Message + }).ToArray(); + diagnostic.RelatedInformation = diagnosticRelatedInformation; + return [diagnostic]; + } + } + + private static LSP.VSDiagnostic CreateLspDiagnostic( + DiagnosticData diagnosticData, + Project project, + bool isLiveSource, + bool potentialDuplicate, + bool supportsVisualStudioExtensions) + { + Contract.ThrowIfNull(diagnosticData.Message, $"Got a document diagnostic that did not have a {nameof(diagnosticData.Message)}"); + + // We can just use VSDiagnostic as it doesn't have any default properties set that + // would get automatically serialized. + var diagnostic = new LSP.VSDiagnostic + { + Code = diagnosticData.Id, + CodeDescription = ProtocolConversions.HelpLinkToCodeDescription(diagnosticData.GetValidHelpLinkUri()), + Message = diagnosticData.Message, + Severity = ConvertDiagnosticSeverity(diagnosticData.Severity, supportsVisualStudioExtensions), + Tags = ConvertTags(diagnosticData, isLiveSource, potentialDuplicate), + DiagnosticRank = ConvertRank(diagnosticData), + Range = GetRange(diagnosticData.DataLocation) + }; + + if (supportsVisualStudioExtensions) + { + var expandedMessage = string.IsNullOrEmpty(diagnosticData.Description) ? null : diagnosticData.Description; + var informationService = project.Solution.Services.GetRequiredService(); + + diagnostic.DiagnosticType = diagnosticData.Category; + diagnostic.ExpandedMessage = expandedMessage; + diagnostic.Projects = [informationService.GetDiagnosticProjectInformation(project)]; + + // Defines an identifier used by the client for merging diagnostics across projects. We want diagnostics + // to be merged from separate projects if they have the same code, filepath, range, and message. + // + // Note: LSP pull diagnostics only operates on unmapped locations. + diagnostic.Identifier = (diagnostic.Code, diagnosticData.DataLocation.UnmappedFileSpan.Path, diagnostic.Range, diagnostic.Message) + .GetHashCode().ToString(); + } + + return diagnostic; + } + + private static LSP.Range GetRange(DiagnosticDataLocation dataLocation) + { + // We currently do not map diagnostics spans as + // 1. Razor handles span mapping for razor files on their side. + // 2. LSP does not allow us to report document pull diagnostics for a different file path. + // 3. The VS LSP client does not support document pull diagnostics for files outside our content type. + // 4. This matches classic behavior where we only squiggle the original location anyway. + + // We also do not adjust the diagnostic locations to ensure they are in bounds because we've + // explicitly requested up to date diagnostics as of the snapshot we were passed in. + return new LSP.Range + { + Start = new Position + { + Character = dataLocation.UnmappedFileSpan.StartLinePosition.Character, + Line = dataLocation.UnmappedFileSpan.StartLinePosition.Line, + }, + End = new Position + { + Character = dataLocation.UnmappedFileSpan.EndLinePosition.Character, + Line = dataLocation.UnmappedFileSpan.EndLinePosition.Line, + } + }; + } + + private static bool ShouldIncludeHiddenDiagnostic(DiagnosticData diagnosticData, bool supportsVisualStudioExtensions) + { + // VS can handle us reporting any kind of diagnostic using VS custom tags. + if (supportsVisualStudioExtensions == true) + { + return true; + } + + // Diagnostic isn't hidden - we should report this diagnostic in all scenarios. + if (diagnosticData.Severity != DiagnosticSeverity.Hidden) + { + return true; + } + + // Roslyn creates these for example in remove unnecessary imports, see RemoveUnnecessaryImportsConstants.DiagnosticFixableId. + // These aren't meant to be visible in anyway, so we can safely exclude them. + // TODO - We should probably not be creating these as separate diagnostics or have a 'really really' hidden tag. + if (string.IsNullOrEmpty(diagnosticData.Message)) + { + return false; + } + + // Hidden diagnostics that are unnecessary are visible to the user in the form of fading. + // We can report these diagnostics. + if (diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary)) + { + return true; + } + + // We have a hidden diagnostic that has no fading. This diagnostic can't be visible so don't send it to the client. + return false; + } + + 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, bool supportsVisualStudioExtensions) + => severity switch + { + // Hidden is translated in ConvertTags to pass along appropriate _ms tags + // that will hide the item in a client that knows about those tags. + DiagnosticSeverity.Hidden => LSP.DiagnosticSeverity.Hint, + // VSCode shows information diagnostics as blue squiggles, and hint diagnostics as 3 dots. We prefer the latter rendering so we return hint diagnostics in vscode. + DiagnosticSeverity.Info => supportsVisualStudioExtensions ? LSP.DiagnosticSeverity.Information : LSP.DiagnosticSeverity.Hint, + DiagnosticSeverity.Warning => LSP.DiagnosticSeverity.Warning, + DiagnosticSeverity.Error => LSP.DiagnosticSeverity.Error, + _ => throw ExceptionUtilities.UnexpectedValue(severity), + }; + + /// + /// If you make change in this method, please also update the corresponding file in + /// src\VisualStudio\Xaml\Impl\Implementation\LanguageServer\Handler\Diagnostics\AbstractPullDiagnosticHandler.cs + /// + private static DiagnosticTag[] ConvertTags(DiagnosticData diagnosticData, bool isLiveSource, bool potentialDuplicate) + { + using var _ = ArrayBuilder.GetInstance(out var result); + + if (diagnosticData.Severity == DiagnosticSeverity.Hidden) + { + result.Add(VSDiagnosticTags.HiddenInEditor); + result.Add(VSDiagnosticTags.HiddenInErrorList); + result.Add(VSDiagnosticTags.SuppressEditorToolTip); + } + else + { + result.Add(VSDiagnosticTags.VisibleInErrorList); + } + + if (diagnosticData.CustomTags.Contains(PullDiagnosticConstants.TaskItemCustomTag)) + result.Add(VSDiagnosticTags.TaskItem); + + // Let the host know that these errors represent potentially stale information from the past that should + // be superseded by fresher info. + if (potentialDuplicate) + result.Add(VSDiagnosticTags.PotentialDuplicate); + + // Mark this also as a build error. That way an explicitly kicked off build from a source like CPS can + // override it. + if (!isLiveSource) + result.Add(VSDiagnosticTags.BuildError); + + result.Add(diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.Build) + ? VSDiagnosticTags.BuildError + : VSDiagnosticTags.IntellisenseError); + + if (diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.EditAndContinue)) + result.Add(VSDiagnosticTags.EditAndContinueError); + + return result.ToArray(); + } + + private static bool SupportsFadingOption(DiagnosticData diagnosticData, IGlobalOptionService globalOptionService) + { + if (IDEDiagnosticIdToOptionMappingHelper.TryGetMappedFadingOption(diagnosticData.Id, out var fadingOption)) + { + Contract.ThrowIfNull(diagnosticData.Language, $"diagnostic {diagnosticData.Id} is missing a language"); + return globalOptionService.GetOption(fadingOption, diagnosticData.Language); + } + + return true; + } +} diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index 8a160dc30d3fc..f88adb94801c7 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -19,8 +19,8 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.NavigateTo; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.SpellCheck; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; using Roslyn.Text.Adornments; @@ -34,14 +34,9 @@ internal static partial class ProtocolConversions { private const string CSharpMarkdownLanguageName = "csharp"; private const string VisualBasicMarkdownLanguageName = "vb"; - private const string SourceGeneratedDocumentBaseUri = "source-generated:///"; private const string BlockCodeFence = "```"; private const string InlineCodeFence = "`"; -#pragma warning disable RS0030 // Do not use banned APIs - private static readonly Uri s_sourceGeneratedDocumentBaseUri = new(SourceGeneratedDocumentBaseUri, UriKind.Absolute); -#pragma warning restore - private static readonly char[] s_dirSeparators = [PathUtilities.DirectorySeparatorChar, PathUtilities.AltDirectorySeparatorChar]; private static readonly Regex s_markdownEscapeRegex = new(@"([\\`\*_\{\}\[\]\(\)#+\-\.!])", RegexOptions.Compiled); @@ -187,7 +182,9 @@ static async Task GetInsertionCharacterAsync(Document document, int positi } public static string GetDocumentFilePathFromUri(Uri uri) - => uri.IsFile ? uri.LocalPath : uri.AbsoluteUri; + { + return uri.IsFile ? uri.LocalPath : uri.AbsoluteUri; + } /// /// Converts an absolute local file path or an absolute URL string to . @@ -261,28 +258,6 @@ static string EscapeUriPart(string stringToEscape) #pragma warning restore } - public static Uri CreateUriFromSourceGeneratedFilePath(string filePath) - { - Debug.Assert(!PathUtilities.IsAbsolute(filePath)); - - // Fast path for common cases: - if (IsAscii(filePath)) - { -#pragma warning disable RS0030 // Do not use banned APIs - return new Uri(s_sourceGeneratedDocumentBaseUri, filePath); -#pragma warning restore - } - - // Workaround for https://github.com/dotnet/runtime/issues/89538: - - var parts = filePath.Split(s_dirSeparators); - var url = SourceGeneratedDocumentBaseUri + string.Join("/", parts.Select(Uri.EscapeDataString)); - -#pragma warning disable RS0030 // Do not use banned APIs - return new Uri(url, UriKind.Absolute); -#pragma warning restore - } - private static bool IsAscii(char c) => (uint)c <= '\x007f'; @@ -309,13 +284,14 @@ public static LSP.TextDocumentPositionParams PositionToTextDocumentPositionParam } public static LSP.TextDocumentIdentifier DocumentToTextDocumentIdentifier(TextDocument document) - => new LSP.TextDocumentIdentifier { Uri = document.GetURI() }; + => new() { Uri = document.GetURI() }; public static LSP.VersionedTextDocumentIdentifier DocumentToVersionedTextDocumentIdentifier(Document document) - => new LSP.VersionedTextDocumentIdentifier { Uri = document.GetURI() }; + => new() { Uri = document.GetURI() }; public static LinePosition PositionToLinePosition(LSP.Position position) - => new LinePosition(position.Line, position.Character); + => new(position.Line, position.Character); + public static LinePositionSpan RangeToLinePositionSpan(LSP.Range range) => new(PositionToLinePosition(range.Start), PositionToLinePosition(range.End)); @@ -453,7 +429,7 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) } } - var documentEdits = uriToTextEdits.GroupBy(uriAndEdit => uriAndEdit.Uri, uriAndEdit => uriAndEdit.TextEdit, (uri, edits) => new LSP.TextDocumentEdit + var documentEdits = uriToTextEdits.GroupBy(uriAndEdit => uriAndEdit.Uri, uriAndEdit => new LSP.SumType(uriAndEdit.TextEdit), (uri, edits) => new LSP.TextDocumentEdit { TextDocument = new LSP.OptionalVersionedTextDocumentIdentifier { Uri = uri }, Edits = edits.ToArray(), @@ -510,13 +486,12 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) Range = MappedSpanResultToRange(mappedSpan) }; - static async Task ConvertTextSpanToLocationAsync( + static async Task ConvertTextSpanToLocationAsync( TextDocument document, TextSpan span, bool isStale, CancellationToken cancellationToken) { - Debug.Assert(document.FilePath != null); var uri = document.GetURI(); var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); @@ -582,6 +557,15 @@ public static LSP.DocumentHighlightKind HighlightSpanKindToDocumentHighlightKind } } + public static LSP.VSInternalSpellCheckableRangeKind SpellCheckSpanKindToSpellCheckableRangeKind(SpellCheckKind kind) + => kind switch + { + SpellCheckKind.Identifier => LSP.VSInternalSpellCheckableRangeKind.Identifier, + SpellCheckKind.Comment => LSP.VSInternalSpellCheckableRangeKind.Comment, + SpellCheckKind.String => LSP.VSInternalSpellCheckableRangeKind.String, + _ => throw ExceptionUtilities.UnexpectedValue(kind), + }; + public static Glyph SymbolKindToGlyph(LSP.SymbolKind kind) { switch (kind) @@ -925,12 +909,23 @@ public static LSP.MarkupContent GetDocumentationMarkupContent(ImmutableArray`) in doc comments. + // Since code elements optionally support a `lang` attribute and we do not have access to the + // language which was specified at this point, we tell the client to render it as plain text. + + if (!markdownBuilder.IsLineEmpty()) + AppendLineBreak(markdownBuilder); + + // The current line is empty, we can append a code block. + markdownBuilder.AppendLine($"{BlockCodeFence}text"); + markdownBuilder.AppendLine(taggedText.Text); + markdownBuilder.AppendLine(BlockCodeFence); + break; case TextTags.LineBreak: - // A line ending with double space and a new line indicates to markdown - // to render a single-spaced line break. - markdownBuilder.Append(" "); - markdownBuilder.AppendLine(); + AppendLineBreak(markdownBuilder); break; default: var styledText = GetStyledText(taggedText, codeFence != null); @@ -947,6 +942,14 @@ public static LSP.MarkupContent GetDocumentationMarkupContent(ImmutableArray(); + var spanMappingService = document.DocumentServiceProvider.GetService(); if (spanMappingService == null) { return null; diff --git a/src/LanguageServer/Protocol/Extensions/SourceGeneratedDocumentUri.cs b/src/LanguageServer/Protocol/Extensions/SourceGeneratedDocumentUri.cs new file mode 100644 index 0000000000000..c42bc1002eae8 --- /dev/null +++ b/src/LanguageServer/Protocol/Extensions/SourceGeneratedDocumentUri.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.Specialized; +using System.Linq; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.LanguageServer; + +// For source generated documents, we'll produce a URI specifically for LSP that has a scheme the client can register for; the "host" portion will +// just be the project ID of the document, and the path will be the hint text for the document. This recognizes that VS Code shows just the local +// path portion in the UI and thus embedding more into the path will appear and we don't want that. The rest of the stuff to serialize, namely the DocumentId, and any information +// for the SourceGeneratedDocumentIdentity are put in as query string arguments +// +// For example, the URI can look like: +// +// roslyn-source-generated://E7D5BCFA-E345-4029-9D12-3EDCD0FB0F6B/Generated.cs?documentId=8E4C0B71-4044-4247-BDD0-04AF4C9E1677&assembly=Generator... +// +// where the first GUID is the project ID, the second GUID is the document ID. +internal static class SourceGeneratedDocumentUri +{ + public const string Scheme = "roslyn-source-generated"; + private const string GuidFormat = "D"; + private const string DocumentIdParam = "documentId"; + private const string HintNameParam = "hintName"; + private const string AssemblyNameParam = "assemblyName"; + private const string AssemblyVersionParam = "assemblyVersion"; + private const string AssemblyPathParam = "assemblyPath"; + private const string TypeNameParam = "typeName"; + + public static Uri Create(SourceGeneratedDocumentIdentity identity) + { + var hintPath = Uri.EscapeDataString(identity.HintName); + var projectId = identity.DocumentId.ProjectId.Id.ToString(GuidFormat); + var documentId = identity.DocumentId.Id.ToString(GuidFormat); + var hintName = Uri.EscapeDataString(identity.HintName); + var assemblyName = Uri.EscapeDataString(identity.Generator.AssemblyName); + var assemblyVersion = Uri.EscapeDataString(identity.Generator.AssemblyVersion.ToString()); + var typeName = Uri.EscapeDataString(identity.Generator.TypeName); + + var uri = $"{Scheme}://{projectId}/{hintPath}?{DocumentIdParam}={documentId}&{HintNameParam}={hintName}&{AssemblyNameParam}={assemblyName}&{AssemblyVersionParam}={assemblyVersion}&{TypeNameParam}={typeName}"; + + // If we have a path (which is technically optional) also append it + if (identity.Generator.AssemblyPath != null) + uri += $"&{AssemblyPathParam}={Uri.EscapeDataString(identity.Generator.AssemblyPath)}"; + + return ProtocolConversions.CreateAbsoluteUri(uri); + } + + public static SourceGeneratedDocumentIdentity? DeserializeIdentity(Solution solution, Uri documentUri) + { + // This is a generated document, so the "host" portion is just the GUID of the project ID; we'll parse that into an ID and then + // look up the project in the Solution. This relies on the fact that technically the only part of the ID that matters for equality + // is the GUID; looking up the project again means we can then recover the ProjectId with the debug name, so anybody looking at a crash + // dump sees a "normal" ID. It also means if the project is gone we can trivially say there are no usable IDs anymore. + var projectIdGuidOnly = ProjectId.CreateFromSerialized(Guid.ParseExact(documentUri.Host, GuidFormat)); + var projectId = solution.GetProject(projectIdGuidOnly)?.Id; + + if (projectId == null) + return null; + + var query = System.Web.HttpUtility.ParseQueryString(documentUri.Query); + var documentIdGuid = Guid.ParseExact(GetRequiredQueryValue(DocumentIdParam, query, documentUri.Query), GuidFormat); + var hintName = GetRequiredQueryValue(HintNameParam, query, documentUri.Query); + var assemblyName = GetRequiredQueryValue(AssemblyNameParam, query, documentUri.Query); + // this one is actually OK if it's null, since it's optional + var assemblyPath = query[AssemblyPathParam]; + var assemblyVersion = Version.Parse(GetRequiredQueryValue(AssemblyVersionParam, query, documentUri.Query)); + var typeName = GetRequiredQueryValue(TypeNameParam, query, documentUri.Query); + + var documentId = DocumentId.CreateFromSerialized(projectId, documentIdGuid, isSourceGenerated: true, hintName); + + return new SourceGeneratedDocumentIdentity( + documentId, + hintName, + new SourceGeneratorIdentity( + assemblyName, + assemblyPath, + assemblyVersion, + typeName), + hintName); + + static string GetRequiredQueryValue(string keyName, NameValueCollection nameValueCollection, string query) + { + var value = nameValueCollection[keyName]; + Contract.ThrowIfNull(value, $"Could not get {keyName} from {query}"); + return value; + } + } +} diff --git a/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs b/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs index ecb2e80929404..1036b6cafa5dc 100644 --- a/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs +++ b/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs @@ -73,7 +73,7 @@ public FormatNewFileHandler(IGlobalOptionService globalOptions) var removeImportsService = document.GetLanguageService(); if (removeImportsService is not null) { - document = await removeImportsService.RemoveUnnecessaryImportsAsync(document, syntaxFormattingOptions, cancellationToken).ConfigureAwait(false); + document = await removeImportsService.RemoveUnnecessaryImportsAsync(document, cancellationToken).ConfigureAwait(false); } // Now format the document so indentation etc. is correct diff --git a/src/LanguageServer/Protocol/Features/AbstractAnalyzerAssemblyLoaderProvider.cs b/src/LanguageServer/Protocol/Features/AbstractAnalyzerAssemblyLoaderProvider.cs deleted file mode 100644 index 2c57d8288463c..0000000000000 --- a/src/LanguageServer/Protocol/Features/AbstractAnalyzerAssemblyLoaderProvider.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. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Composition; -using System.IO; - -namespace Microsoft.CodeAnalysis.Host; - -/// -/// Abstract implementation of an anlyzer assembly loader that can be used by VS/VSCode to provide a -/// with an appropriate path. -/// -internal abstract class AbstractAnalyzerAssemblyLoaderProvider : IAnalyzerAssemblyLoaderProvider -{ - private readonly DefaultAnalyzerAssemblyLoader _loader; - private readonly Lazy _shadowCopyLoader; - - public AbstractAnalyzerAssemblyLoaderProvider([ImportMany] IEnumerable externalResolvers) - { - var resolvers = externalResolvers.ToImmutableArray(); - _loader = new(resolvers); - - // We use a lazy here in case creating the loader requires MEF imports in the derived constructor. - _shadowCopyLoader = new Lazy(() => CreateShadowCopyLoader(resolvers)); - } - - public IAnalyzerAssemblyLoader GetLoader(bool shadowCopy) - => shadowCopy ? _shadowCopyLoader.Value : _loader; - - protected virtual IAnalyzerAssemblyLoader CreateShadowCopyLoader(ImmutableArray externalResolvers) - { - return DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader( - Path.Combine(Path.GetTempPath(), "VS", "AnalyzerAssemblyLoader"), - externalResolvers: externalResolvers); - } -} diff --git a/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs b/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs index 20adf787ac759..0c3b268d504a4 100644 --- a/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs +++ b/src/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs @@ -39,7 +39,6 @@ public async Task CleanupAsync( Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgress progressTracker, - CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { // add one item for the code fixers we get from nuget, we'll do last @@ -70,12 +69,12 @@ public async Task CleanupAsync( } document = await ApplyCodeFixesAsync( - document, enabledDiagnostics.Diagnostics, progressTracker, fallbackOptions, cancellationToken).ConfigureAwait(false); + document, enabledDiagnostics.Diagnostics, progressTracker, cancellationToken).ConfigureAwait(false); if (enabledDiagnostics.RunThirdPartyFixers) { document = await ApplyThirdPartyCodeFixesAsync( - document, thirdPartyDiagnosticIdsAndTitles, progressTracker, fallbackOptions, cancellationToken).ConfigureAwait(false); + document, thirdPartyDiagnosticIdsAndTitles, progressTracker, cancellationToken).ConfigureAwait(false); } // do the remove usings after code fix, as code fix might remove some code which can results in unused usings. @@ -102,7 +101,7 @@ public async Task CleanupAsync( if (enabledDiagnostics.RunThirdPartyFixers) { document = await ApplyThirdPartyCodeFixesAsync( - document, thirdPartyDiagnosticIdsAndTitles, progressTracker, fallbackOptions, cancellationToken).ConfigureAwait(false); + document, thirdPartyDiagnosticIdsAndTitles, progressTracker, cancellationToken).ConfigureAwait(false); } return document; @@ -117,7 +116,7 @@ private static async Task RemoveSortUsingsAsync( using (Logger.LogBlock(FunctionId.CodeCleanup_RemoveUnusedImports, cancellationToken)) { var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); - document = await removeUsingsService.RemoveUnnecessaryImportsAsync(document, formattingOptions, cancellationToken).ConfigureAwait(false); + document = await removeUsingsService.RemoveUnnecessaryImportsAsync(document, cancellationToken).ConfigureAwait(false); } } @@ -136,7 +135,7 @@ private static async Task RemoveSortUsingsAsync( private async Task ApplyCodeFixesAsync( Document document, ImmutableArray enabledDiagnosticSets, - IProgress progressTracker, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) + IProgress progressTracker, CancellationToken cancellationToken) { // Add a progressTracker item for each enabled option we're going to fixup. foreach (var diagnosticSet in enabledDiagnosticSets) @@ -145,7 +144,7 @@ private async Task ApplyCodeFixesAsync( progressTracker.Report(CodeAnalysisProgress.Description(diagnosticSet.Description)); document = await ApplyCodeFixesForSpecificDiagnosticIdsAsync( - document, diagnosticSet.DiagnosticIds, diagnosticSet.IsAnyDiagnosticIdExplicitlyEnabled, progressTracker, fallbackOptions, cancellationToken).ConfigureAwait(false); + document, diagnosticSet.DiagnosticIds, diagnosticSet.IsAnyDiagnosticIdExplicitlyEnabled, progressTracker, cancellationToken).ConfigureAwait(false); // Mark this option as being completed. progressTracker.ItemCompleted(); @@ -155,7 +154,7 @@ private async Task ApplyCodeFixesAsync( } private async Task ApplyCodeFixesForSpecificDiagnosticIdsAsync( - Document document, ImmutableArray diagnosticIds, bool isAnyDiagnosticIdExplicitlyEnabled, IProgress progressTracker, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) + Document document, ImmutableArray diagnosticIds, bool isAnyDiagnosticIdExplicitlyEnabled, IProgress progressTracker, CancellationToken cancellationToken) { // Enable fixes for all diagnostic severities if any of the diagnostic IDs has been explicitly enabled in Code Cleanup. // Otherwise, only enable fixes for Warning and Error severity diagnostics. @@ -166,7 +165,7 @@ private async Task ApplyCodeFixesForSpecificDiagnosticIdsAsync( using (Logger.LogBlock(FunctionId.CodeCleanup_ApplyCodeFixesAsync, diagnosticId, cancellationToken)) { document = await ApplyCodeFixesForSpecificDiagnosticIdAsync( - document, diagnosticId, minimumSeverity, progressTracker, fallbackOptions, cancellationToken).ConfigureAwait(false); + document, diagnosticId, minimumSeverity, progressTracker, cancellationToken).ConfigureAwait(false); } } @@ -174,13 +173,13 @@ private async Task ApplyCodeFixesForSpecificDiagnosticIdsAsync( } private async Task ApplyCodeFixesForSpecificDiagnosticIdAsync( - Document document, string diagnosticId, DiagnosticSeverity minimumSeverity, IProgress progressTracker, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) + Document document, string diagnosticId, DiagnosticSeverity minimumSeverity, IProgress progressTracker, CancellationToken cancellationToken) { var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var textSpan = new TextSpan(0, tree.Length); var fixCollection = await _codeFixService.GetDocumentFixAllForIdInSpanAsync( - document, textSpan, diagnosticId, minimumSeverity, fallbackOptions, cancellationToken).ConfigureAwait(false); + document, textSpan, diagnosticId, minimumSeverity, cancellationToken).ConfigureAwait(false); if (fixCollection == null) { return document; @@ -221,7 +220,6 @@ private async Task ApplyThirdPartyCodeFixesAsync( Document document, ImmutableArray<(string diagnosticId, string? title)> diagnosticIds, IProgress progressTracker, - CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { foreach (var (diagnosticId, title) in diagnosticIds) @@ -231,7 +229,7 @@ private async Task ApplyThirdPartyCodeFixesAsync( progressTracker.Report(CodeAnalysisProgress.Description(string.Format(FeaturesResources.Fixing_0, title ?? diagnosticId))); // Apply codefixes for diagnostics with a severity of warning or higher var updatedDocument = await _codeFixService.ApplyCodeFixesForSpecificDiagnosticIdAsync( - document, diagnosticId, DiagnosticSeverity.Warning, progressTracker, fallbackOptions, cancellationToken).ConfigureAwait(false); + document, diagnosticId, DiagnosticSeverity.Warning, progressTracker, cancellationToken).ConfigureAwait(false); // If changes were made to the solution snap shot outside the current document discard the changes. // The assumption here is that if we are applying a third party code fix to a document it only affects the document. diff --git a/src/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs b/src/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs index 4da7f236a1211..64ac9a965739c 100644 --- a/src/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs +++ b/src/LanguageServer/Protocol/Features/CodeCleanup/ICodeCleanupService.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CodeCleanup { internal interface ICodeCleanupService : ILanguageService { - Task CleanupAsync(Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgress progressTracker, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken); + Task CleanupAsync(Document document, EnabledDiagnosticOptions enabledDiagnostics, IProgress progressTracker, CancellationToken cancellationToken); EnabledDiagnosticOptions GetAllDiagnostics(); } } diff --git a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs b/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs index 7ad0124d5fb6b..b76abcf95ec86 100644 --- a/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs +++ b/src/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs @@ -99,7 +99,7 @@ public CodeFixService( } public async Task GetMostSevereFixAsync( - TextDocument document, TextSpan range, ICodeActionRequestPriorityProvider priorityProvider, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) + TextDocument document, TextSpan range, ICodeActionRequestPriorityProvider priorityProvider, CancellationToken cancellationToken) { using var _ = TelemetryLogging.LogBlockTimeAggregated(FunctionId.CodeFix_Summary, $"Pri{priorityProvider.Priority.GetPriorityInt()}.{nameof(GetMostSevereFixAsync)}"); @@ -156,7 +156,7 @@ public CodeFixService( await foreach (var collection in StreamFixesAsync( document, spanToDiagnostics, fixAllForInSpan: false, - priorityProvider, fallbackOptions, cancellationToken).ConfigureAwait(false)) + priorityProvider, cancellationToken).ConfigureAwait(false)) { // Stop at the result error we see. return collection; @@ -170,7 +170,6 @@ public async IAsyncEnumerable StreamFixesAsync( TextDocument document, TextSpan range, ICodeActionRequestPriorityProvider priorityProvider, - CodeActionOptionsProvider fallbackOptions, [EnumeratorCancellation] CancellationToken cancellationToken) { using var _ = TelemetryLogging.LogBlockTimeAggregated(FunctionId.CodeFix_Summary, $"Pri{priorityProvider.Priority.GetPriorityInt()}"); @@ -215,7 +214,7 @@ public async IAsyncEnumerable StreamFixesAsync( { await foreach (var collection in StreamFixesAsync( document, spanToDiagnostics, fixAllForInSpan: false, - priorityProvider, fallbackOptions, cancellationToken).ConfigureAwait(false)) + priorityProvider, cancellationToken).ConfigureAwait(false)) { yield return collection; } @@ -234,7 +233,7 @@ public async IAsyncEnumerable StreamFixesAsync( foreach (var (span, diagnosticList) in spanToDiagnostics) { await foreach (var codeFixCollection in StreamConfigurationFixesAsync( - document, span, diagnosticList, registeredConfigurationFixTitles, fallbackOptions, cancellationToken).ConfigureAwait(false)) + document, span, diagnosticList, registeredConfigurationFixTitles, cancellationToken).ConfigureAwait(false)) { yield return codeFixCollection; } @@ -279,11 +278,11 @@ private static SortedDictionary> ConvertToMap( } public Task GetDocumentFixAllForIdInSpanAsync( - TextDocument document, TextSpan range, string diagnosticId, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) - => GetDocumentFixAllForIdInSpanAsync(document, range, diagnosticId, DiagnosticSeverity.Hidden, fallbackOptions, cancellationToken); + TextDocument document, TextSpan range, string diagnosticId, CancellationToken cancellationToken) + => GetDocumentFixAllForIdInSpanAsync(document, range, diagnosticId, DiagnosticSeverity.Hidden, cancellationToken); public async Task GetDocumentFixAllForIdInSpanAsync( - TextDocument document, TextSpan range, string diagnosticId, DiagnosticSeverity minimumSeverity, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) + TextDocument document, TextSpan range, string diagnosticId, DiagnosticSeverity minimumSeverity, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -309,7 +308,7 @@ private static SortedDictionary> ConvertToMap( await foreach (var collection in StreamFixesAsync( document, spanToDiagnostics, fixAllForInSpan: true, new DefaultCodeActionRequestPriorityProvider(), - fallbackOptions, cancellationToken).ConfigureAwait(false)) + cancellationToken).ConfigureAwait(false)) { if (collection.FixAllState is not null && collection.SupportedScopes.Contains(FixAllScope.Document)) { @@ -322,15 +321,14 @@ private static SortedDictionary> ConvertToMap( return null; } - public Task ApplyCodeFixesForSpecificDiagnosticIdAsync(TDocument document, string diagnosticId, IProgress progressTracker, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) where TDocument : TextDocument - => ApplyCodeFixesForSpecificDiagnosticIdAsync(document, diagnosticId, DiagnosticSeverity.Hidden, progressTracker, fallbackOptions, cancellationToken); + public Task ApplyCodeFixesForSpecificDiagnosticIdAsync(TDocument document, string diagnosticId, IProgress progressTracker, CancellationToken cancellationToken) where TDocument : TextDocument + => ApplyCodeFixesForSpecificDiagnosticIdAsync(document, diagnosticId, DiagnosticSeverity.Hidden, progressTracker, cancellationToken); public async Task ApplyCodeFixesForSpecificDiagnosticIdAsync( TDocument document, string diagnosticId, DiagnosticSeverity severity, IProgress progressTracker, - CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) where TDocument : TextDocument { @@ -340,7 +338,7 @@ public async Task ApplyCodeFixesForSpecificDiagnosticIdAsync StreamFixesAsync( SortedDictionary> spanToDiagnostics, bool fixAllForInSpan, ICodeActionRequestPriorityProvider priorityProvider, - CodeActionOptionsProvider fallbackOptions, [EnumeratorCancellation] CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -547,18 +544,17 @@ private async IAsyncEnumerable StreamFixesAsync( if (fixAllForInSpan) { var primaryDiagnostic = dxs.First(); - return GetCodeFixesAsync(document, primaryDiagnostic.Location.SourceSpan, fixer, fixerMetadata, fallbackOptions, + return GetCodeFixesAsync(document, primaryDiagnostic.Location.SourceSpan, fixer, fixerMetadata, [primaryDiagnostic], uniqueDiagosticToEquivalenceKeysMap, diagnosticAndEquivalenceKeyToFixersMap, cancellationToken); } else { - return GetCodeFixesAsync(document, span, fixer, fixerMetadata, fallbackOptions, dxs, + return GetCodeFixesAsync(document, span, fixer, fixerMetadata, dxs, uniqueDiagosticToEquivalenceKeysMap, diagnosticAndEquivalenceKeyToFixersMap, cancellationToken); } } }, - fallbackOptions, cancellationToken).ConfigureAwait(false); if (codeFixCollection != null) @@ -619,7 +615,7 @@ static void AddAllFixers( } private static async Task> GetCodeFixesAsync( - TextDocument document, TextSpan span, CodeFixProvider fixer, CodeChangeProviderMetadata? fixerMetadata, CodeActionOptionsProvider fallbackOptions, + TextDocument document, TextSpan span, CodeFixProvider fixer, CodeChangeProviderMetadata? fixerMetadata, ImmutableArray diagnostics, Dictionary> uniqueDiagosticToEquivalenceKeysMap, Dictionary<(Diagnostic diagnostic, string? equivalenceKey), CodeFixProvider> diagnosticAndEquivalenceKeyToFixersMap, @@ -650,7 +646,6 @@ private static async Task> GetCodeFixesAsync( } } }, - fallbackOptions, cancellationToken); var task = fixer.RegisterCodeFixesAsync(context) ?? Task.CompletedTask; @@ -704,7 +699,6 @@ private async IAsyncEnumerable StreamConfigurationFixesAsync( TextSpan diagnosticsSpan, IEnumerable diagnostics, PooledHashSet registeredConfigurationFixTitles, - CodeActionOptionsProvider fallbackOptions, [EnumeratorCancellation] CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -728,7 +722,6 @@ private async IAsyncEnumerable StreamConfigurationFixesAsync( var fixes = await provider.GetFixesAsync(document, diagnosticsSpan, dxs, cancellationToken).ConfigureAwait(false); return fixes.WhereAsArray(f => registeredConfigurationFixTitles.Add(f.Action.Title)); }, - fallbackOptions, cancellationToken).ConfigureAwait(false); if (codeFixCollection != null) yield return codeFixCollection; @@ -744,7 +737,6 @@ private async IAsyncEnumerable StreamConfigurationFixesAsync( TCodeFixProvider fixer, Func hasFix, Func, Task>> getFixes, - CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) where TCodeFixProvider : notnull { @@ -795,8 +787,7 @@ await diagnosticsWithSameSpan.OrderByDescending(d => d.Severity) FixAllScope.Document, fixes[0].Action.EquivalenceKey, diagnosticIds, - diagnosticProvider, - fallbackOptions); + diagnosticProvider); supportedScopes = fixAllProviderInfo.SupportedScopes; } diff --git a/src/LanguageServer/Protocol/Features/CodeFixes/ICodeFixService.cs b/src/LanguageServer/Protocol/Features/CodeFixes/ICodeFixService.cs index 30bbcb2d73e8b..5ad72d5bf0095 100644 --- a/src/LanguageServer/Protocol/Features/CodeFixes/ICodeFixService.cs +++ b/src/LanguageServer/Protocol/Features/CodeFixes/ICodeFixService.cs @@ -15,33 +15,33 @@ namespace Microsoft.CodeAnalysis.CodeFixes { internal interface ICodeFixService { - IAsyncEnumerable StreamFixesAsync(TextDocument document, TextSpan textSpan, ICodeActionRequestPriorityProvider priorityProvider, CodeActionOptionsProvider options, CancellationToken cancellationToken); + IAsyncEnumerable StreamFixesAsync(TextDocument document, TextSpan textSpan, ICodeActionRequestPriorityProvider priorityProvider, CancellationToken cancellationToken); /// /// Similar to except that instead of streaming all results, this ends with the /// first. This will also attempt to return a fix for an error first, but will fall back to any fix if that /// does not succeed. /// - Task GetMostSevereFixAsync(TextDocument document, TextSpan range, ICodeActionRequestPriorityProvider priorityProvider, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken); + Task GetMostSevereFixAsync(TextDocument document, TextSpan range, ICodeActionRequestPriorityProvider priorityProvider, CancellationToken cancellationToken); - Task GetDocumentFixAllForIdInSpanAsync(TextDocument document, TextSpan textSpan, string diagnosticId, DiagnosticSeverity severity, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken); - Task ApplyCodeFixesForSpecificDiagnosticIdAsync(TDocument document, string diagnosticId, DiagnosticSeverity severity, IProgress progressTracker, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) + Task GetDocumentFixAllForIdInSpanAsync(TextDocument document, TextSpan textSpan, string diagnosticId, DiagnosticSeverity severity, CancellationToken cancellationToken); + Task ApplyCodeFixesForSpecificDiagnosticIdAsync(TDocument document, string diagnosticId, DiagnosticSeverity severity, IProgress progressTracker, CancellationToken cancellationToken) where TDocument : TextDocument; CodeFixProvider? GetSuppressionFixer(string language, IEnumerable diagnosticIds); } internal static class ICodeFixServiceExtensions { - public static IAsyncEnumerable StreamFixesAsync(this ICodeFixService service, TextDocument document, TextSpan range, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) - => service.StreamFixesAsync(document, range, new DefaultCodeActionRequestPriorityProvider(), fallbackOptions, cancellationToken); + public static IAsyncEnumerable StreamFixesAsync(this ICodeFixService service, TextDocument document, TextSpan range, CancellationToken cancellationToken) + => service.StreamFixesAsync(document, range, new DefaultCodeActionRequestPriorityProvider(), cancellationToken); - public static Task> GetFixesAsync(this ICodeFixService service, TextDocument document, TextSpan range, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) - => service.StreamFixesAsync(document, range, fallbackOptions, cancellationToken).ToImmutableArrayAsync(cancellationToken); + public static Task> GetFixesAsync(this ICodeFixService service, TextDocument document, TextSpan range, CancellationToken cancellationToken) + => service.StreamFixesAsync(document, range, cancellationToken).ToImmutableArrayAsync(cancellationToken); - public static Task> GetFixesAsync(this ICodeFixService service, TextDocument document, TextSpan textSpan, ICodeActionRequestPriorityProvider priorityProvider, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) - => service.StreamFixesAsync(document, textSpan, priorityProvider, fallbackOptions, cancellationToken).ToImmutableArrayAsync(cancellationToken); + public static Task> GetFixesAsync(this ICodeFixService service, TextDocument document, TextSpan textSpan, ICodeActionRequestPriorityProvider priorityProvider, CancellationToken cancellationToken) + => service.StreamFixesAsync(document, textSpan, priorityProvider, cancellationToken).ToImmutableArrayAsync(cancellationToken); - public static Task ApplyCodeFixesForSpecificDiagnosticIdAsync(this ICodeFixService service, TDocument document, string diagnosticId, IProgress progressTracker, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) where TDocument : TextDocument - => service.ApplyCodeFixesForSpecificDiagnosticIdAsync(document, diagnosticId, DiagnosticSeverity.Hidden, progressTracker, fallbackOptions, cancellationToken); + public static Task ApplyCodeFixesForSpecificDiagnosticIdAsync(this ICodeFixService service, TDocument document, string diagnosticId, IProgress progressTracker, CancellationToken cancellationToken) where TDocument : TextDocument + => service.ApplyCodeFixesForSpecificDiagnosticIdAsync(document, diagnosticId, DiagnosticSeverity.Hidden, progressTracker, cancellationToken); } } diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs b/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs index dffb6ed4419e8..2ec8ee686304b 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs @@ -20,6 +20,7 @@ using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Threading; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Diagnostics { diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs index 4abe7eb44d1e0..98e0dc4c68628 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer.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.Diagnostics; using System.Linq; @@ -216,7 +217,9 @@ async Task ExecuteAnalyzersAsync( } var syntaxFacts = document.GetRequiredLanguageService(); - var members = syntaxFacts.GetMethodLevelMembers(root); + using var pooledMembers = syntaxFacts.GetMethodLevelMembers(root); + var members = pooledMembers.Object; + var memberSpans = members.SelectAsArray(member => member.FullSpan); var changedMemberId = members.IndexOf(changedMember); diff --git a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs index 0cf8570ac3410..c76750e900a4c 100644 --- a/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs +++ b/src/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.IncrementalMemberEditAnalyzer_MemberSpans.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -45,7 +46,10 @@ static async Task> CreateMemberSpansAsync(Document docu { var service = document.GetRequiredLanguageService(); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var members = service.GetMethodLevelMembers(root); + + using var pooledMembers = service.GetMethodLevelMembers(root); + var members = pooledMembers.Object; + return members.SelectAsArray(m => m.FullSpan); } } diff --git a/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_OpenDocument.cs b/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_OpenDocument.cs index deb7877c1b234..be5413ebdeffc 100644 --- a/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_OpenDocument.cs +++ b/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_OpenDocument.cs @@ -27,14 +27,16 @@ public override async Task> GetDiagnosticsAsync(R var designTimeSolution = designTimeDocument.Project.Solution; var services = designTimeSolution.Services; - // avoid creating and synchronizing compile-time solution if Hot Reload/EnC session is not active - if (services.GetRequiredService().SessionTracker is not { IsSessionActive: true } sessionStateTracker) + // Do not report EnC diagnostics for a non-host workspace, or if Hot Reload/EnC session is not active. + if (designTimeSolution.WorkspaceKind != WorkspaceKind.Host || + services.GetService()?.SessionTracker is not { IsSessionActive: true } sessionStateTracker) { return []; } var applyDiagnostics = sessionStateTracker.ApplyChangesDiagnostics.WhereAsArray(static (data, id) => data.DocumentId == id, designTimeDocument.Id); + // Only create and synchronize compile-time solution if we need it. var compileTimeSolution = services.GetRequiredService().GetCompileTimeSolution(designTimeSolution); var compileTimeDocument = await CompileTimeSolutionProvider.TryGetCompileTimeDocumentAsync(designTimeDocument, compileTimeSolution, cancellationToken).ConfigureAwait(false); diff --git a/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs b/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs index b84fee77d2030..8906835b732ae 100644 --- a/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs +++ b/src/LanguageServer/Protocol/Features/EditAndContinue/EditAndContinueDiagnosticSource_Workspace.cs @@ -37,7 +37,9 @@ public override Task> GetDiagnosticsAsync(Request public static async ValueTask> CreateWorkspaceDiagnosticSourcesAsync(Solution solution, Func isDocumentOpen, CancellationToken cancellationToken) { - if (solution.Services.GetRequiredService().SessionTracker is not { IsSessionActive: true } sessionStateTracker) + // Do not report EnC diagnostics for a non-host workspace, or if Hot Reload/EnC session is not active. + if (solution.WorkspaceKind != WorkspaceKind.Host || + solution.Services.GetService()?.SessionTracker is not { IsSessionActive: true } sessionStateTracker) { return []; } diff --git a/src/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs b/src/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs deleted file mode 100644 index 50e7ac0609b1b..0000000000000 --- a/src/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.CodeCleanup; -using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.ImplementType; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.SymbolSearch; - -namespace Microsoft.CodeAnalysis.CodeActions -{ - internal static class CodeActionOptionsStorage - { - public static CodeActionOptions GetCodeActionOptions(this IGlobalOptionService globalOptions, LanguageServices languageServices) - => new() - { - SearchOptions = globalOptions.GetSymbolSearchOptions(languageServices.Language), - ImplementTypeOptions = globalOptions.GetImplementTypeOptions(languageServices.Language), - }; - - internal static CodeActionOptionsProvider GetCodeActionOptionsProvider(this IGlobalOptionService globalOptions) - { - var cache = ImmutableDictionary.Empty; - return new DelegatingCodeActionOptionsProvider(languageService => ImmutableInterlocked.GetOrAdd(ref cache, languageService.Language, (_, options) => GetCodeActionOptions(options, languageService), globalOptions)); - } - } -} diff --git a/src/LanguageServer/Protocol/Features/Options/GlobalCodeActionOptionsProvider.cs b/src/LanguageServer/Protocol/Features/Options/GlobalCodeActionOptionsProvider.cs deleted file mode 100644 index a9b5000a69e25..0000000000000 --- a/src/LanguageServer/Protocol/Features/Options/GlobalCodeActionOptionsProvider.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 Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Host; - -namespace Microsoft.CodeAnalysis.Options; - -internal static class CodeActionOptionsStorage -{ - public static Provider CreateProvider(this IGlobalOptionService globalOptions) - => new(globalOptions); - - // TODO: we can implement providers directly on IGlobalOptionService once it moves to LSP layer - public sealed class Provider : - CodeActionOptionsProvider - { - private readonly IGlobalOptionService _globalOptions; - - public Provider(IGlobalOptionService globalOptions) - => _globalOptions = globalOptions; - - CodeActionOptions CodeActionOptionsProvider.GetOptions(LanguageServices languageServices) - => _globalOptions.GetCodeActionOptions(languageServices); - } -} diff --git a/src/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs b/src/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs deleted file mode 100644 index 4fd63975954af..0000000000000 --- a/src/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.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 Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.ImplementType -{ - internal static class ImplementTypeOptionsStorage - { - public static ImplementTypeOptions GetImplementTypeOptions(this IGlobalOptionService globalOptions, string language) - => new() - { - InsertionBehavior = globalOptions.GetOption(InsertionBehavior, language), - PropertyGenerationBehavior = globalOptions.GetOption(PropertyGenerationBehavior, language) - }; - - private static readonly OptionGroup s_implementTypeGroup = new(name: "implement_type", description: ""); - - public static readonly PerLanguageOption2 InsertionBehavior = - new("dotnet_insertion_behavior", - defaultValue: ImplementTypeOptions.Default.InsertionBehavior, group: s_implementTypeGroup, serializer: EditorConfigValueSerializer.CreateSerializerForEnum()); - - public static readonly PerLanguageOption2 PropertyGenerationBehavior = - new("dotnet_property_generation_behavior", - defaultValue: ImplementTypeOptions.Default.PropertyGenerationBehavior, group: s_implementTypeGroup, serializer: EditorConfigValueSerializer.CreateSerializerForEnum()); - } -} diff --git a/src/LanguageServer/Protocol/Features/Options/SymbolSearchOptionsStorage.cs b/src/LanguageServer/Protocol/Features/Options/SymbolSearchOptionsStorage.cs deleted file mode 100644 index 4e4bb0d4d62cc..0000000000000 --- a/src/LanguageServer/Protocol/Features/Options/SymbolSearchOptionsStorage.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 Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.SymbolSearch -{ - internal static class SymbolSearchOptionsStorage - { - internal static SymbolSearchOptions GetSymbolSearchOptions(this IGlobalOptionService globalOptions, string language) - => new() - { - SearchReferenceAssemblies = globalOptions.GetOption(SearchReferenceAssemblies, language), - SearchNuGetPackages = globalOptions.GetOption(SearchNuGetPackages, language) - }; - - private static readonly OptionGroup s_optionGroup = new(name: "symbol_search", description: ""); - - public static PerLanguageOption2 SearchReferenceAssemblies = - new("dotnet_search_reference_assemblies", - SymbolSearchOptions.Default.SearchReferenceAssemblies, - group: s_optionGroup); - - public static PerLanguageOption2 SearchNuGetPackages = - new("dotnet_search_nuget_packages", SymbolSearchOptions.Default.SearchNuGetPackages, group: s_optionGroup); - } -} diff --git a/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index 233808fd063d1..323323d041cd9 100644 --- a/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -38,7 +38,6 @@ public static async ValueTask> GetFilt TextDocument document, TextSpan selection, ICodeActionRequestPriorityProvider priorityProvider, - CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var originalSolution = document.Project.Solution; @@ -50,7 +49,6 @@ public static async ValueTask> GetFilt document, selection, priorityProvider, - fallbackOptions, cancellationToken).ConfigureAwait(false); var filteredFixes = fixes.WhereAsArray(c => c.Fixes.Length > 0); @@ -438,7 +436,6 @@ public static async Task> GetFilterAnd TextDocument document, TextSpan selection, CodeActionRequestPriority? priority, - CodeActionOptionsProvider options, bool filterOutsideSelection, CancellationToken cancellationToken) { @@ -446,7 +443,7 @@ public static async Task> GetFilterAnd // this on the UI thread and potentially allow any code to take a dependency on that. await TaskScheduler.Default; var refactorings = await codeRefactoringService.GetRefactoringsAsync( - document, selection, priority, options, + document, selection, priority, cancellationToken).ConfigureAwait(false); var filteredRefactorings = FilterOnAnyThread(refactorings, selection, filterOutsideSelection); @@ -477,7 +474,7 @@ private static ImmutableArray FilterOnAnyThread( ? null : actions.Length == refactoring.CodeActions.Length ? refactoring - : new CodeRefactoring(refactoring.Provider, actions, refactoring.FixAllProviderInfo, refactoring.CodeActionOptionsProvider); + : new CodeRefactoring(refactoring.Provider, actions, refactoring.FixAllProviderInfo); bool IsActionAndSpanApplicable((CodeAction action, TextSpan? applicableSpan) actionAndSpan) { @@ -565,7 +562,7 @@ async Task GetUnifiedSuggestedActionSetAsync(CodeAction { var fixAllSuggestedActionSet = await GetUnifiedFixAllSuggestedActionSetAsync(codeAction, refactoring.CodeActions.Length, document as Document, selection, refactoring.Provider, - refactoring.FixAllProviderInfo, refactoring.CodeActionOptionsProvider, + refactoring.FixAllProviderInfo, workspace, cancellationToken).ConfigureAwait(false); return new UnifiedCodeRefactoringSuggestedAction( @@ -584,7 +581,6 @@ async Task GetUnifiedSuggestedActionSetAsync(CodeAction TextSpan selection, CodeRefactoringProvider provider, FixAllProviderInfo? fixAllProviderInfo, - CodeActionOptionsProvider optionsProvider, Workspace workspace, CancellationToken cancellationToken) { @@ -608,7 +604,7 @@ async Task GetUnifiedSuggestedActionSetAsync(CodeAction { var fixAllState = new CodeRefactorings.FixAllState( (CodeRefactorings.FixAllProvider)fixAllProviderInfo.FixAllProvider, - document, selection, provider, optionsProvider, scope, action); + document, selection, provider, scope, action); if (scope is FixAllScope.ContainingMember or FixAllScope.ContainingType) { diff --git a/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs b/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs index 4d988ebd887a8..5eec735c049bd 100644 --- a/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs +++ b/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Shared.TestHooks; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; +using StreamJsonRpc; namespace Microsoft.CodeAnalysis.LanguageServer.Handler { @@ -49,6 +50,12 @@ public AbstractRefreshQueue( } public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) + { + Initialize(clientCapabilities); + return Task.CompletedTask; + } + + public void Initialize(ClientCapabilities clientCapabilities) { if (_refreshQueue is null && GetRefreshSupport(clientCapabilities) is true) { @@ -66,11 +73,9 @@ public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestCon _isQueueCreated = true; _lspWorkspaceRegistrationService.LspSolutionChanged += OnLspSolutionChanged; } - - return Task.CompletedTask; } - private void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e) + protected virtual void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e) { if (e.DocumentId is not null && e.Kind is WorkspaceChangeKind.DocumentChanged) { @@ -109,7 +114,15 @@ private ValueTask FilterLspTrackedDocumentsAsync( { if (documentUri is null || !trackedDocuments.ContainsKey(documentUri)) { - return notificationManager.SendRequestAsync(GetWorkspaceRefreshName(), cancellationToken); + try + { + return notificationManager.SendRequestAsync(GetWorkspaceRefreshName(), cancellationToken); + } + catch (Exception ex) when (ex is ObjectDisposedException or ConnectionLostException) + { + // It is entirely possible that we're shutting down and the connection is lost while we're trying to send a notification + // as this runs outside of the guaranteed ordering in the queue. We can safely ignore this exception. + } } } diff --git a/src/LanguageServer/Protocol/Handler/BufferedProgress.cs b/src/LanguageServer/Protocol/Handler/BufferedProgress.cs index efd622a17c73c..2b13dfbae3c75 100644 --- a/src/LanguageServer/Protocol/Handler/BufferedProgress.cs +++ b/src/LanguageServer/Protocol/Handler/BufferedProgress.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler @@ -69,6 +70,12 @@ internal static class BufferedProgress public static BufferedProgress Create(IProgress? progress) => new BufferedProgress(progress); + public static BufferedProgress Create(IProgress? progress, Func transform) + => Create(progress?.Transform(transform)); + + static IProgress Transform(this IProgress progress, Func transform) + => new ProgressTransformer(progress, transform); + public static void Report(this BufferedProgress progress, T item) { progress.Report([item]); @@ -78,5 +85,10 @@ public static void Report(this BufferedProgress progress, T item) { return progress.GetValues()?.Flatten().ToArray(); } + + class ProgressTransformer(IProgress inner, Func transform) : IProgress + { + public void Report(TIn value) => inner.Report(transform(value)); + } } } diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionFixAllResolveHandler.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionFixAllResolveHandler.cs index 103dd05fba686..2677137bf9096 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionFixAllResolveHandler.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionFixAllResolveHandler.cs @@ -44,11 +44,9 @@ public async Task HandleRequestAsync(RoslynFixAllCodeAct var data = GetCodeActionResolveData(request); Assumes.Present(data); - var options = _globalOptions.GetCodeActionOptionsProvider(); var codeActions = await CodeActionHelpers.GetCodeActionsAsync( document, data.Range, - options, _codeFixService, _codeRefactoringService, request.Scope, diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs index 9395fe55c338b..cbfd9f869d226 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs @@ -31,14 +31,13 @@ internal static class CodeActionHelpers public static async Task GetVSCodeActionsAsync( CodeActionParams request, TextDocument document, - CodeActionOptionsProvider fallbackOptions, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, bool hasVsLspCapability, CancellationToken cancellationToken) { var actionSets = await GetActionSetsAsync( - document, fallbackOptions, codeFixService, codeRefactoringService, request.Range, cancellationToken).ConfigureAwait(false); + document, codeFixService, codeRefactoringService, request.Range, cancellationToken).ConfigureAwait(false); if (actionSets.IsDefaultOrEmpty) return []; @@ -305,14 +304,13 @@ static VSInternalCodeAction[] GenerateNestedVSCodeActions( public static async Task> GetCodeActionsAsync( TextDocument document, LSP.Range selection, - CodeActionOptionsProvider fallbackOptions, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, string? fixAllScope, CancellationToken cancellationToken) { var actionSets = await GetActionSetsAsync( - document, fallbackOptions, codeFixService, codeRefactoringService, selection, cancellationToken).ConfigureAwait(false); + document, codeFixService, codeRefactoringService, selection, cancellationToken).ConfigureAwait(false); if (actionSets.IsDefaultOrEmpty) return []; @@ -383,7 +381,6 @@ private static void GetFixAllActionsFromActionSet(IUnifiedSuggestedAction sugges private static async ValueTask> GetActionSetsAsync( TextDocument document, - CodeActionOptionsProvider fallbackOptions, ICodeFixService codeFixService, ICodeRefactoringService codeRefactoringService, LSP.Range selection, @@ -395,10 +392,10 @@ private static async ValueTask> GetAct var codeFixes = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeFixesAsync( document.Project.Solution.Workspace, codeFixService, document, textSpan, new DefaultCodeActionRequestPriorityProvider(), - fallbackOptions, cancellationToken).ConfigureAwait(false); + cancellationToken).ConfigureAwait(false); var codeRefactorings = await UnifiedSuggestedActionsSource.GetFilterAndOrderCodeRefactoringsAsync( - document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, priority: null, fallbackOptions, + document.Project.Solution.Workspace, codeRefactoringService, document, textSpan, priority: null, filterOutsideSelection: false, cancellationToken).ConfigureAwait(false); var actionSets = UnifiedSuggestedActionsSource.FilterAndOrderActionSets( diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs index 154fb50d1ef60..be6077f5ed3b7 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs @@ -76,11 +76,9 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.CodeAction request) var document = context.GetRequiredTextDocument(); var solution = document.Project.Solution; - var options = _globalOptions.GetCodeActionOptionsProvider(); var codeActions = await CodeActionHelpers.GetCodeActionsAsync( document, data.Range, - options, _codeFixService, _codeRefactoringService, fixAllScope: null, diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs index 937ceb3901ab8..cec1f54f679ab 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs @@ -278,7 +278,7 @@ async Task AddTextDocumentEditsAsync( textChanges = newText.GetTextChanges(oldText); } - var edits = textChanges.Select(tc => ProtocolConversions.TextChangeToTextEdit(tc, oldText)).ToArray(); + var edits = textChanges.Select(tc => new LSP.SumType(ProtocolConversions.TextChangeToTextEdit(tc, oldText))).ToArray(); if (edits.Length > 0) { diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs index c13a4e7e1d649..87ef08b73bbcb 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs @@ -54,10 +54,9 @@ public CodeActionsHandler( public async Task HandleRequestAsync(LSP.CodeActionParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.GetRequiredTextDocument(); - var options = _globalOptions.GetCodeActionOptionsProvider(); var clientCapability = context.GetRequiredClientCapabilities(); var codeActions = await CodeActionHelpers.GetVSCodeActionsAsync( - request, document, options, _codeFixService, _codeRefactoringService, hasVsLspCapability: clientCapability.HasVisualStudioLspCapability(), cancellationToken).ConfigureAwait(false); + request, document, _codeFixService, _codeRefactoringService, hasVsLspCapability: clientCapability.HasVisualStudioLspCapability(), cancellationToken).ConfigureAwait(false); return codeActions; } diff --git a/src/LanguageServer/Protocol/Handler/Completion/CompletionCapabilityHelper.cs b/src/LanguageServer/Protocol/Handler/Completion/CompletionCapabilityHelper.cs index 7bf5905039f3d..6ed2dfe1ef6f1 100644 --- a/src/LanguageServer/Protocol/Handler/Completion/CompletionCapabilityHelper.cs +++ b/src/LanguageServer/Protocol/Handler/Completion/CompletionCapabilityHelper.cs @@ -18,9 +18,6 @@ internal sealed class CompletionCapabilityHelper public const string DataPropertyName = "data"; public const string EditRangePropertyName = "editRange"; - private readonly CompletionSetting? _completionSetting; - private readonly VSInternalCompletionSetting? _vsCompletionSetting; - public bool SupportVSInternalClientCapabilities { get; } public bool SupportDefaultEditRange { get; } public bool SupportCompletionListData { get; } @@ -33,32 +30,31 @@ internal sealed class CompletionCapabilityHelper public ISet SupportedItemTags { get; } public CompletionCapabilityHelper(ClientCapabilities clientCapabilities) + : this(supportsVSExtensions: clientCapabilities.HasVisualStudioLspCapability(), + completionSetting: clientCapabilities.TextDocument?.Completion) { - // public LSP - _completionSetting = clientCapabilities.TextDocument?.Completion; + } - SupportSnippets = _completionSetting?.CompletionItem?.SnippetSupport ?? false; - SupportDefaultEditRange = _completionSetting?.CompletionListSetting?.ItemDefaults?.Contains(EditRangePropertyName) == true; - SupportsMarkdownDocumentation = _completionSetting?.CompletionItem?.DocumentationFormat?.Contains(MarkupKind.Markdown) == true; - SupportCompletionListData = _completionSetting?.CompletionListSetting?.ItemDefaults?.Contains(DataPropertyName) == true; - SupportDefaultCommitCharacters = _completionSetting?.CompletionListSetting?.ItemDefaults?.Contains(CommitCharactersPropertyName) == true; - SupportedItemKinds = _completionSetting?.CompletionItemKind?.ValueSet?.ToSet() ?? SpecializedCollections.EmptySet(); - SupportedItemTags = _completionSetting?.CompletionItem?.TagSupport?.ValueSet?.ToSet() ?? SpecializedCollections.EmptySet(); + public CompletionCapabilityHelper(bool supportsVSExtensions, CompletionSetting? completionSetting) + { + // public LSP + SupportSnippets = completionSetting?.CompletionItem?.SnippetSupport ?? false; + SupportDefaultEditRange = completionSetting?.CompletionListSetting?.ItemDefaults?.Contains(EditRangePropertyName) == true; + SupportsMarkdownDocumentation = completionSetting?.CompletionItem?.DocumentationFormat?.Contains(MarkupKind.Markdown) == true; + SupportCompletionListData = completionSetting?.CompletionListSetting?.ItemDefaults?.Contains(DataPropertyName) == true; + SupportDefaultCommitCharacters = completionSetting?.CompletionListSetting?.ItemDefaults?.Contains(CommitCharactersPropertyName) == true; + SupportedItemKinds = completionSetting?.CompletionItemKind?.ValueSet?.ToSet() ?? SpecializedCollections.EmptySet(); + SupportedItemTags = completionSetting?.CompletionItem?.TagSupport?.ValueSet?.ToSet() ?? SpecializedCollections.EmptySet(); // internal VS LSP - if (clientCapabilities.HasVisualStudioLspCapability()) + if (supportsVSExtensions) { SupportVSInternalClientCapabilities = true; - _vsCompletionSetting = ((VSInternalClientCapabilities)clientCapabilities).TextDocument?.Completion as VSInternalCompletionSetting; - } - else - { - SupportVSInternalClientCapabilities = false; - _vsCompletionSetting = null; - } - SupportVSInternalCompletionListData = SupportVSInternalClientCapabilities && _vsCompletionSetting?.CompletionList?.Data == true; - SupportVSInternalDefaultCommitCharacters = SupportVSInternalClientCapabilities && _vsCompletionSetting?.CompletionList?.CommitCharacters == true; + var vsCompletionSetting = completionSetting as VSInternalCompletionSetting; + SupportVSInternalCompletionListData = vsCompletionSetting?.CompletionList?.Data == true; + SupportVSInternalDefaultCommitCharacters = vsCompletionSetting?.CompletionList?.CommitCharacters == true; + } } } } diff --git a/src/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs b/src/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs index 5a17d02cd577f..9ad91dcbe6864 100644 --- a/src/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Completion/CompletionHandler.cs @@ -49,49 +49,79 @@ public CompletionHandler( Contract.ThrowIfNull(context.Solution); var document = context.Document; - var documentText = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); + var position = await document + .GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken) + .ConfigureAwait(false); + var capabilityHelper = new CompletionCapabilityHelper(context.GetRequiredClientCapabilities()); + var completionListCache = context.GetRequiredLspService(); + + return await GetCompletionListAsync( + document, + position, + request.Context, + _globalOptions, + capabilityHelper, + completionListCache, + cancellationToken).ConfigureAwait(false); + } + + public static async Task GetCompletionListAsync( + Document document, + int position, + LSP.CompletionContext? completionContext, + IGlobalOptionService globalOptions, + CompletionCapabilityHelper capabilityHelper, + CompletionListCache completionListCache, + CancellationToken cancellationToken) + { + var completionOptions = globalOptions.GetCompletionOptionsForLsp(document.Project.Language, capabilityHelper); + var completionListMaxSize = globalOptions.GetOption(LspOptionsStorage.MaxCompletionListSize); - var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); - var completionTrigger = await ProtocolConversions.LSPToRoslynCompletionTriggerAsync(request.Context, document, position, cancellationToken).ConfigureAwait(false); - var completionOptions = GetCompletionOptions(document, capabilityHelper); + var documentText = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); + var completionTrigger = await ProtocolConversions + .LSPToRoslynCompletionTriggerAsync(completionContext, document, position, cancellationToken) + .ConfigureAwait(false); var completionService = document.GetRequiredLanguageService(); + var project = document.Project; + // Let CompletionService decide if we should trigger completion, unless the request is for incomplete results, in which case we always trigger. - if (request.Context?.TriggerKind is not LSP.CompletionTriggerKind.TriggerForIncompleteCompletions - && !completionService.ShouldTriggerCompletion(document.Project, document.Project.Services, documentText, position, completionTrigger, completionOptions, document.Project.Solution.Options, roles: null)) + if (completionContext?.TriggerKind is not LSP.CompletionTriggerKind.TriggerForIncompleteCompletions + && !completionService.ShouldTriggerCompletion(project, project.Services, documentText, position, completionTrigger, completionOptions, project.Solution.Options, roles: null)) { return null; } var completionListResult = await GetFilteredCompletionListAsync( - request, context, documentText, document, completionOptions, completionService, capabilityHelper, cancellationToken).ConfigureAwait(false); + completionContext, document, documentText, position, completionOptions, capabilityHelper, completionService, completionListCache, completionListMaxSize, cancellationToken).ConfigureAwait(false); if (completionListResult == null) return null; var (list, isIncomplete, resultId) = completionListResult.Value; - var creationService = document.Project.Solution.Services.GetRequiredService(); - var result = await creationService.ConvertToLspCompletionListAsync(document, position, capabilityHelper, list, isIncomplete, resultId, cancellationToken) + var result = await CompletionResultFactory + .ConvertToLspCompletionListAsync(document, capabilityHelper, list, isIncomplete, resultId, cancellationToken) .ConfigureAwait(false); + return result; } - private async Task<(CompletionList CompletionList, bool IsIncomplete, long ResultId)?> GetFilteredCompletionListAsync( - LSP.CompletionParams request, - RequestContext context, - SourceText sourceText, + private static async Task<(CompletionList CompletionList, bool IsIncomplete, long ResultId)?> GetFilteredCompletionListAsync( + LSP.CompletionContext? context, Document document, + SourceText sourceText, + int position, CompletionOptions completionOptions, - CompletionService completionService, CompletionCapabilityHelper capabilityHelper, + CompletionService completionService, + CompletionListCache completionListCache, + int completionListMaxSize, CancellationToken cancellationToken) { - var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); - var completionTrigger = await ProtocolConversions.LSPToRoslynCompletionTriggerAsync(request.Context, document, position, cancellationToken).ConfigureAwait(false); - var isTriggerForIncompleteCompletions = request.Context?.TriggerKind == LSP.CompletionTriggerKind.TriggerForIncompleteCompletions; - var completionListCache = context.GetRequiredLspService(); + var completionTrigger = await ProtocolConversions.LSPToRoslynCompletionTriggerAsync(context, document, position, cancellationToken).ConfigureAwait(false); + var isTriggerForIncompleteCompletions = context?.TriggerKind == LSP.CompletionTriggerKind.TriggerForIncompleteCompletions; (CompletionList List, long ResultId)? result; if (isTriggerForIncompleteCompletions) @@ -127,7 +157,6 @@ public CompletionHandler( completionList = completionList.WithSpan(defaultSpan); } - var completionListMaxSize = _globalOptions.GetOption(LspOptionsStorage.MaxCompletionListSize); var (filteredCompletionList, isIncomplete) = FilterCompletionList(completionList, completionListMaxSize, completionTrigger, sourceText); return (filteredCompletionList, isIncomplete, resultId); @@ -224,37 +253,5 @@ static CompletionFilterReason GetFilterReason(CompletionTrigger trigger) }; } } - - private CompletionOptions GetCompletionOptions(Document document, CompletionCapabilityHelper capabilityHelper) - { - var options = _globalOptions.GetCompletionOptions(document.Project.Language); - - if (capabilityHelper.SupportVSInternalClientCapabilities) - { - // Filter out unimported types for now as there are two issues with providing them: - // 1. LSP client does not currently provide a way to provide detail text on the completion item to show the namespace. - // https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1076759 - // 2. We need to figure out how to provide the text edits along with the completion item or provide them in the resolve request. - // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/985860/ - // 3. LSP client should support completion filters / expanders - options = options with - { - ShowItemsFromUnimportedNamespaces = false, - ExpandedCompletionBehavior = ExpandedCompletionMode.NonExpandedItemsOnly, - UpdateImportCompletionCacheInBackground = false, - }; - } - else - { - var updateImportCompletionCacheInBackground = options.ShowItemsFromUnimportedNamespaces is true; - options = options with - { - ShowNewSnippetExperienceUserOption = false, - UpdateImportCompletionCacheInBackground = updateImportCompletionCacheInBackground - }; - } - - return options; - } } } diff --git a/src/LanguageServer/Protocol/Handler/Completion/CompletionResolveHandler.cs b/src/LanguageServer/Protocol/Handler/Completion/CompletionResolveHandler.cs index 31f932e9d66e7..2148954e0acda 100644 --- a/src/LanguageServer/Protocol/Handler/Completion/CompletionResolveHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Completion/CompletionResolveHandler.cs @@ -2,12 +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. +using System; +using System.Composition; using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler.Completion; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; @@ -23,59 +25,92 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler /// /// This isn't a because it could return null. /// + [ExportCSharpVisualBasicStatelessLspService(typeof(CompletionResolveHandler)), Shared] [Method(LSP.Methods.TextDocumentCompletionResolveName)] internal sealed class CompletionResolveHandler : ILspServiceRequestHandler, ITextDocumentIdentifierHandler { - private readonly CompletionListCache _completionListCache; private readonly IGlobalOptionService _globalOptions; public bool MutatesSolutionState => false; public bool RequiresLSPSolution => true; - public CompletionResolveHandler(IGlobalOptionService globalOptions, CompletionListCache completionListCache) + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CompletionResolveHandler(IGlobalOptionService globalOptions) { _globalOptions = globalOptions; - _completionListCache = completionListCache; } public LSP.TextDocumentIdentifier? GetTextDocumentIdentifier(LSP.CompletionItem request) - => CompletionResolveHandler.GetTextDocumentCacheEntry(request); + => GetTextDocumentCacheEntry(request); - public async Task HandleRequestAsync(LSP.CompletionItem completionItem, RequestContext context, CancellationToken cancellationToken) + public Task HandleRequestAsync(LSP.CompletionItem completionItem, RequestContext context, CancellationToken cancellationToken) { - var cacheEntry = GetCompletionListCacheEntry(completionItem); - if (cacheEntry == null) + var completionListCache = context.GetRequiredLspService(); + + if (!completionListCache.TryGetCompletionListCacheEntry(completionItem, out var cacheEntry)) { // Don't have a cache associated with this completion item, cannot resolve. context.TraceInformation("No cache entry found for the provided completion item at resolve time."); - return completionItem; + return Task.FromResult(completionItem); } var document = context.GetRequiredDocument(); - var completionService = document.Project.Services.GetRequiredService(); + var capabilityHelper = new CompletionCapabilityHelper(context.GetRequiredClientCapabilities()); - // Find the matching completion item in the completion list - var selectedItem = cacheEntry.CompletionList.ItemsList.FirstOrDefault(cachedCompletionItem => MatchesLSPCompletionItem(completionItem, cachedCompletionItem)); + return ResolveCompletionItemAsync( + completionItem, cacheEntry.CompletionList, document, _globalOptions, capabilityHelper, cancellationToken); + } + + public static Task ResolveCompletionItemAsync( + LSP.CompletionItem completionItem, + Document document, + IGlobalOptionService globalOptions, + CompletionCapabilityHelper capabilityHelper, + CompletionListCache completionListCache, + CancellationToken cancellationToken) + { + if (!completionListCache.TryGetCompletionListCacheEntry(completionItem, out var cacheEntry)) + { + // Don't have a cache associated with this completion item, cannot resolve. + return Task.FromResult(completionItem); + } - var completionOptions = _globalOptions.GetCompletionOptions(document.Project.Language); - var symbolDescriptionOptions = _globalOptions.GetSymbolDescriptionOptions(document.Project.Language); + return ResolveCompletionItemAsync( + completionItem, cacheEntry.CompletionList, document, globalOptions, capabilityHelper, cancellationToken); + } + + private static async Task ResolveCompletionItemAsync( + LSP.CompletionItem completionItem, + CompletionList cachedCompletionList, + Document document, + IGlobalOptionService globalOptions, + CompletionCapabilityHelper capabilityHelper, + CancellationToken cancellationToken) + { + // Find the matching completion item in the completion list + var roslynItem = cachedCompletionList.ItemsList + .FirstOrDefault(cachedCompletionItem => MatchesLSPCompletionItem(completionItem, cachedCompletionItem)); - if (selectedItem is not null) + if (roslynItem is null) { - var creationService = document.Project.Solution.Services.GetRequiredService(); - await creationService.ResolveAsync( - completionItem, - selectedItem, - ProtocolConversions.DocumentToTextDocumentIdentifier(document), - document, - new CompletionCapabilityHelper(context.GetRequiredClientCapabilities()), - completionService, - completionOptions, - symbolDescriptionOptions, - cancellationToken).ConfigureAwait(false); + return completionItem; } - return completionItem; + var completionOptions = globalOptions.GetCompletionOptions(document.Project.Language); + var symbolDescriptionOptions = globalOptions.GetSymbolDescriptionOptions(document.Project.Language); + var completionService = document.Project.Services.GetRequiredService(); + + return await CompletionResultFactory.ResolveAsync( + completionItem, + roslynItem, + ProtocolConversions.DocumentToTextDocumentIdentifier(document), + document, + capabilityHelper, + completionService, + completionOptions, + symbolDescriptionOptions, + cancellationToken).ConfigureAwait(false); } private static bool MatchesLSPCompletionItem(LSP.CompletionItem lspCompletionItem, CompletionItem completionItem) @@ -99,25 +134,5 @@ private static bool MatchesLSPCompletionItem(LSP.CompletionItem lspCompletionIte return resolveData.TextDocument; } - - private CompletionListCache.CacheEntry? GetCompletionListCacheEntry(LSP.CompletionItem request) - { - Contract.ThrowIfNull(request.Data); - var resolveData = JsonSerializer.Deserialize((JsonElement)request.Data, ProtocolConversions.LspJsonSerializerOptions); - if (resolveData?.ResultId == null) - { - Contract.Fail("Result id should always be provided when resolving a completion item we returned."); - return null; - } - - var cacheEntry = _completionListCache.GetCachedEntry(resolveData.ResultId); - if (cacheEntry == null) - { - // No cache for associated completion item. Log some telemetry so we can understand how frequently this actually happens. - Logger.Log(FunctionId.LSP_CompletionListCacheMiss, KeyValueLogMessage.NoProperty); - } - - return cacheEntry; - } } } diff --git a/src/LanguageServer/Protocol/Handler/Completion/CompletionResolveHandlerFactory.cs b/src/LanguageServer/Protocol/Handler/Completion/CompletionResolveHandlerFactory.cs deleted file mode 100644 index ad55e53dc391d..0000000000000 --- a/src/LanguageServer/Protocol/Handler/Completion/CompletionResolveHandlerFactory.cs +++ /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. - -using System; -using System.Composition; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServer.Handler.Completion; -using Microsoft.CodeAnalysis.Options; - -namespace Microsoft.CodeAnalysis.LanguageServer.Handler -{ - [ExportCSharpVisualBasicLspServiceFactory(typeof(CompletionResolveHandler)), Shared] - internal sealed class CompletionResolveHandlerFactory : ILspServiceFactory - { - private readonly IGlobalOptionService _globalOptions; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CompletionResolveHandlerFactory(IGlobalOptionService globalOptions) - { - _globalOptions = globalOptions; - } - - public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) - { - var completionListCache = lspServices.GetRequiredService(); - return new CompletionResolveHandler(_globalOptions, completionListCache); - } - } -} diff --git a/src/LanguageServer/Protocol/Handler/Completion/AbstractLspCompletionResultCreationService.cs b/src/LanguageServer/Protocol/Handler/Completion/CompletionResultFactory.cs similarity index 67% rename from src/LanguageServer/Protocol/Handler/Completion/AbstractLspCompletionResultCreationService.cs rename to src/LanguageServer/Protocol/Handler/Completion/CompletionResultFactory.cs index 7f3ceaa0a5795..a74e297641ab0 100644 --- a/src/LanguageServer/Protocol/Handler/Completion/AbstractLspCompletionResultCreationService.cs +++ b/src/LanguageServer/Protocol/Handler/Completion/CompletionResultFactory.cs @@ -18,23 +18,27 @@ using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Roslyn.Text.Adornments; using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Completion { - internal abstract class AbstractLspCompletionResultCreationService : ILspCompletionResultCreationService + internal static class CompletionResultFactory { - protected abstract Task CreateItemAndPopulateTextEditAsync(Document document, SourceText documentText, bool snippetsSupported, bool itemDefaultsSupported, TextSpan defaultSpan, string typedText, CompletionItem item, CompletionService completionService, CancellationToken cancellationToken); - public abstract Task ResolveAsync(LSP.CompletionItem lspItem, CompletionItem roslynItem, LSP.TextDocumentIdentifier textDocumentIdentifier, Document document, CompletionCapabilityHelper capabilityHelper, CompletionService completionService, CompletionOptions completionOptions, SymbolDescriptionOptions symbolDescriptionOptions, CancellationToken cancellationToken); + /// + /// Command name implemented by the client and invoked when an item with complex edit is committed. + /// + public const string CompleteComplexEditCommand = "roslyn.client.completionComplexEdit"; public static string[] DefaultCommitCharactersArray { get; } = CreateCommitCharacterArrayFromRules(CompletionItemRules.Default); - public async Task ConvertToLspCompletionListAsync( + public static async Task ConvertToLspCompletionListAsync( Document document, - int position, CompletionCapabilityHelper capabilityHelper, - CompletionList list, bool isIncomplete, long resultId, + CompletionList list, + bool isIncomplete, + long resultId, CancellationToken cancellationToken) { var isSuggestionMode = list.SuggestionModeItem is not null; @@ -63,14 +67,13 @@ internal abstract class AbstractLspCompletionResultCreationService : ILspComplet using var _ = ArrayBuilder.GetInstance(out var lspCompletionItems); var commitCharactersRuleCache = new Dictionary, string[]>(CommitCharacterArrayComparer.Instance); - var creationService = document.Project.Solution.Services.GetRequiredService(); var completionService = document.GetRequiredLanguageService(); var defaultSpan = list.Span; var typedText = documentText.GetSubText(defaultSpan).ToString(); foreach (var item in list.ItemsList) { - item.Span = defaultSpan; // item.Span will be used to generate change, adjust it if needed + item.Span = defaultSpan; // item.Span will be used to generate change, adjust it if needed lspCompletionItems.Add(await CreateLSPCompletionItemAsync(item, typedText).ConfigureAwait(false)); } @@ -95,7 +98,7 @@ internal abstract class AbstractLspCompletionResultCreationService : ILspComplet PromoteCommonCommitCharactersOntoList(); - if (completionList.ItemDefaults.EditRange is null && completionList.ItemDefaults.CommitCharacters is null && completionList.ItemDefaults.Data is null) + if (completionList.ItemDefaults is { EditRange: null, CommitCharacters: null, Data: null }) completionList.ItemDefaults = null; return capabilityHelper.SupportVSInternalClientCapabilities @@ -104,10 +107,19 @@ internal abstract class AbstractLspCompletionResultCreationService : ILspComplet async Task CreateLSPCompletionItemAsync(CompletionItem item, string typedText) { - // Defer to host to create the actual completion item (including potential subclasses), and add any - // custom information. + // Defer to host to create the actual completion item (including potential subclasses), + // and add any custom information. var lspItem = await CreateItemAndPopulateTextEditAsync( - document, documentText, capabilityHelper.SupportSnippets, defaultEditRangeSupported, defaultSpan, typedText, item, completionService, cancellationToken).ConfigureAwait(false); + document, + documentText, + lspVSClientCapability, + capabilityHelper.SupportSnippets, + defaultEditRangeSupported, + defaultSpan, + typedText, + item, + completionService, + cancellationToken).ConfigureAwait(false); if (!item.InlineDescription.IsEmpty()) lspItem.LabelDetails = new() { Description = item.InlineDescription }; @@ -293,6 +305,99 @@ void PromoteCommonCommitCharactersOntoList() } } + private static async Task CreateItemAndPopulateTextEditAsync( + Document document, + SourceText documentText, + bool supportsVSExtensions, + bool snippetsSupported, + bool itemDefaultsSupported, + TextSpan defaultSpan, + string typedText, + CompletionItem item, + CompletionService completionService, + CancellationToken cancellationToken) + { + if (supportsVSExtensions) + { + return await CreateVsItemAndPopulateTextEditAsync( + document, + documentText, + snippetsSupported, + itemDefaultsSupported, + defaultSpan, + item, + completionService, + cancellationToken).ConfigureAwait(false); + } + + var lspItem = new LSP.CompletionItem() { Label = item.GetEntireDisplayText() }; + + if (item.IsComplexTextEdit) + { + // For unimported item, we use display text (type or method name) as the text edit text, and rely on resolve handler to add missing import as additional edit. + // For other complex edit item, we return a no-op edit and rely on resolve handler to compute the actual change and provide the command to apply it. + var completionChangeNewText = item.Flags.IsExpanded() ? item.DisplayText : typedText; + PopulateTextEdit(lspItem, completionChangeSpan: defaultSpan, completionChangeNewText, documentText, itemDefaultsSupported, defaultSpan: defaultSpan); + } + else + { + await GetChangeAndPopulateSimpleTextEditAsync( + document, + documentText, + itemDefaultsSupported, + defaultSpan, + item, + lspItem, + completionService, + cancellationToken).ConfigureAwait(false); + } + + return lspItem; + } + + private static async Task CreateVsItemAndPopulateTextEditAsync( + Document document, + SourceText documentText, + bool snippetsSupported, + bool itemDefaultsSupported, + TextSpan defaultSpan, + CompletionItem item, + CompletionService completionService, + CancellationToken cancellationToken) + { + var lspItem = new LSP.VSInternalCompletionItem + { + Label = item.GetEntireDisplayText(), + Icon = new ImageElement(item.Tags.GetFirstGlyph().ToLSPImageId()), + }; + + // Complex text edits (e.g. override and partial method completions) are always populated in the + // resolve handler, so we leave both TextEdit and InsertText unpopulated in these cases. + if (item.IsComplexTextEdit) + { + lspItem.VsResolveTextEditOnCommit = true; + + // Razor C# is currently the only language client that supports LSP.InsertTextFormat.Snippet. + // We can enable it for regular C# once LSP is used for local completion. + if (snippetsSupported) + lspItem.InsertTextFormat = LSP.InsertTextFormat.Snippet; + } + else + { + await GetChangeAndPopulateSimpleTextEditAsync( + document, + documentText, + itemDefaultsSupported, + defaultSpan, + item, + lspItem, + completionService, + cancellationToken).ConfigureAwait(false); + } + + return lspItem; + } + public static string[] CreateCommitCharacterArrayFromRules(CompletionItemRules rules) { using var _ = PooledHashSet.GetInstance(out var commitCharacters); @@ -365,7 +470,7 @@ public int GetHashCode([DisallowNull] ImmutableArray GetCompletionChangeOrDisplayNameInCa } } + public static Task ResolveAsync( + LSP.CompletionItem lspItem, + CompletionItem roslynItem, + LSP.TextDocumentIdentifier textDocumentIdentifier, + Document document, + CompletionCapabilityHelper capabilityHelper, + CompletionService completionService, + CompletionOptions completionOptions, + SymbolDescriptionOptions symbolDescriptionOptions, + CancellationToken cancellationToken) + { + return capabilityHelper.SupportVSInternalClientCapabilities + ? VsResolveAsync(lspItem, roslynItem, document, capabilityHelper, completionService, completionOptions, symbolDescriptionOptions, cancellationToken) + : DefaultResolveAsync(lspItem, roslynItem, textDocumentIdentifier, document, capabilityHelper, completionService, completionOptions, symbolDescriptionOptions, cancellationToken); + } + + private static async Task DefaultResolveAsync( + LSP.CompletionItem lspItem, + CompletionItem roslynItem, + LSP.TextDocumentIdentifier textDocumentIdentifier, + Document document, + CompletionCapabilityHelper capabilityHelper, + CompletionService completionService, + CompletionOptions completionOptions, + SymbolDescriptionOptions symbolDescriptionOptions, + CancellationToken cancellationToken) + { + var description = await completionService.GetDescriptionAsync( + document, roslynItem, completionOptions, symbolDescriptionOptions, cancellationToken).ConfigureAwait(false); + + if (description != null) + { + lspItem.Documentation = ProtocolConversions.GetDocumentationMarkupContent( + description.TaggedParts, document, capabilityHelper.SupportsMarkdownDocumentation); + } + + if (roslynItem.IsComplexTextEdit) + { + if (roslynItem.Flags.IsExpanded()) + { + var additionalEdits = await GenerateAdditionalTextEditForImportCompletionAsync( + roslynItem, document, completionService, cancellationToken).ConfigureAwait(false); + lspItem.AdditionalTextEdits = additionalEdits; + } + else + { + var (textEdit, isSnippetString, newPosition) = await GenerateComplexTextEditAsync( + document, completionService, roslynItem, capabilityHelper.SupportSnippets, insertNewPositionPlaceholder: false, cancellationToken).ConfigureAwait(false); + + var lspOffset = newPosition is null ? -1 : newPosition.Value; + + lspItem.Command = lspItem.Command = new LSP.Command() + { + CommandIdentifier = CompleteComplexEditCommand, + Title = nameof(CompleteComplexEditCommand), + Arguments = [textDocumentIdentifier, textEdit, isSnippetString, lspOffset] + }; + } + } + + if (!roslynItem.InlineDescription.IsEmpty()) + lspItem.LabelDetails = new() { Description = roslynItem.InlineDescription }; + + return lspItem; + } + + private static async Task VsResolveAsync( + LSP.CompletionItem lspItem, + CompletionItem roslynItem, + Document document, + CompletionCapabilityHelper capabilityHelper, + CompletionService completionService, + CompletionOptions completionOptions, + SymbolDescriptionOptions symbolDescriptionOptions, + CancellationToken cancellationToken) + { + var description = await completionService.GetDescriptionAsync( + document, roslynItem, completionOptions, symbolDescriptionOptions, cancellationToken).ConfigureAwait(false); + + if (description != null) + { + var vsCompletionItem = (LSP.VSInternalCompletionItem)lspItem; + vsCompletionItem.Description = new ClassifiedTextElement(description.TaggedParts + .Select(tp => new ClassifiedTextRun(tp.Tag.ToClassificationTypeName(), tp.Text))); + } + + // We compute the TextEdit resolves for complex text edits (e.g. override and partial + // method completions) here. Lazily resolving TextEdits is technically a violation of + // the LSP spec, but is currently supported by the VS client anyway. Once the VS client + // adheres to the spec, this logic will need to change and VS will need to provide + // official support for TextEdit resolution in some form. + if (roslynItem.IsComplexTextEdit) + { + Contract.ThrowIfTrue(lspItem.InsertText != null); + Contract.ThrowIfTrue(lspItem.TextEdit != null); + + var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var (edit, _, _) = await GenerateComplexTextEditAsync( + document, completionService, roslynItem, capabilityHelper.SupportSnippets, insertNewPositionPlaceholder: true, cancellationToken).ConfigureAwait(false); + + lspItem.TextEdit = edit; + } + + return lspItem; + } + public static async Task<(LSP.TextEdit edit, bool isSnippetString, int? newPosition)> GenerateComplexTextEditAsync( Document document, CompletionService completionService, diff --git a/src/LanguageServer/Protocol/Handler/Completion/DefaultLspCompletionResultCreationService.cs b/src/LanguageServer/Protocol/Handler/Completion/DefaultLspCompletionResultCreationService.cs deleted file mode 100644 index c09f3806d9ef0..0000000000000 --- a/src/LanguageServer/Protocol/Handler/Completion/DefaultLspCompletionResultCreationService.cs +++ /dev/null @@ -1,114 +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 System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; -using LSP = Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Completion -{ - [ExportWorkspaceService(typeof(ILspCompletionResultCreationService), ServiceLayer.Default), Shared] - internal sealed class DefaultLspCompletionResultCreationService : AbstractLspCompletionResultCreationService - { - /// - /// Command name implemented by the client and invoked when an item with complex edit is committed. - /// - public const string CompleteComplexEditCommand = "roslyn.client.completionComplexEdit"; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public DefaultLspCompletionResultCreationService() - { - } - - protected override async Task CreateItemAndPopulateTextEditAsync(Document document, - SourceText documentText, - bool snippetsSupported, - bool itemDefaultsSupported, - TextSpan defaultSpan, - string typedText, - CompletionItem item, - CompletionService completionService, - CancellationToken cancellationToken) - { - var lspItem = new LSP.CompletionItem() { Label = item.GetEntireDisplayText() }; - - if (item.IsComplexTextEdit) - { - //await completionService.GetChangeAsync(document, item, cancellationToken: cancellationToken).ConfigureAwait(false); - // For unimported item, we use display text (type or method name) as the text edit text, and rely on resolve handler to add missing import as additional edit. - // For other complex edit item, we return a no-op edit and rely on resolve handler to compute the actual change and provide the command to apply it. - var completionChangeNewText = item.Flags.IsExpanded() ? item.DisplayText : typedText; - PopulateTextEdit(lspItem, completionChangeSpan: defaultSpan, completionChangeNewText, documentText, itemDefaultsSupported, defaultSpan: defaultSpan); - } - else - { - await GetChangeAndPopulateSimpleTextEditAsync( - document, - documentText, - itemDefaultsSupported, - defaultSpan, - item, - lspItem, - completionService, - cancellationToken).ConfigureAwait(false); - } - - return lspItem; - } - - public override async Task ResolveAsync( - LSP.CompletionItem lspItem, - CompletionItem roslynItem, - LSP.TextDocumentIdentifier textDocumentIdentifier, - Document document, - CompletionCapabilityHelper capabilityHelper, - CompletionService completionService, - CompletionOptions completionOptions, - SymbolDescriptionOptions symbolDescriptionOptions, - CancellationToken cancellationToken) - { - var description = await completionService.GetDescriptionAsync(document, roslynItem, completionOptions, symbolDescriptionOptions, cancellationToken).ConfigureAwait(false)!; - if (description != null) - { - lspItem.Documentation = ProtocolConversions.GetDocumentationMarkupContent(description.TaggedParts, document, capabilityHelper.SupportsMarkdownDocumentation); - } - - if (roslynItem.IsComplexTextEdit) - { - if (roslynItem.Flags.IsExpanded()) - { - var additionalEdits = await GenerateAdditionalTextEditForImportCompletionAsync(roslynItem, document, completionService, cancellationToken).ConfigureAwait(false); - lspItem.AdditionalTextEdits = additionalEdits; - } - else - { - var (textEdit, isSnippetString, newPosition) = await GenerateComplexTextEditAsync( - document, completionService, roslynItem, capabilityHelper.SupportSnippets, insertNewPositionPlaceholder: false, cancellationToken).ConfigureAwait(false); - - var lspOffset = newPosition is null ? -1 : newPosition.Value; - - lspItem.Command = lspItem.Command = new LSP.Command() - { - CommandIdentifier = CompleteComplexEditCommand, - Title = nameof(CompleteComplexEditCommand), - Arguments = [textDocumentIdentifier, textEdit, isSnippetString, lspOffset] - }; - } - } - - if (!roslynItem.InlineDescription.IsEmpty()) - lspItem.LabelDetails = new() { Description = roslynItem.InlineDescription }; - - return lspItem; - } - } -} diff --git a/src/LanguageServer/Protocol/Handler/Completion/Extensions.cs b/src/LanguageServer/Protocol/Handler/Completion/Extensions.cs new file mode 100644 index 0000000000000..c0763139f9b96 --- /dev/null +++ b/src/LanguageServer/Protocol/Handler/Completion/Extensions.cs @@ -0,0 +1,72 @@ +// 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.Text.Json; +using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Options; +using Roslyn.Utilities; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Completion; + +internal static class Extensions +{ + public static CompletionOptions GetCompletionOptionsForLsp(this IGlobalOptionService globalOptionService, string language, CompletionCapabilityHelper capabilityHelper) + { + var options = globalOptionService.GetCompletionOptions(language); + + if (capabilityHelper.SupportVSInternalClientCapabilities) + { + // Filter out unimported types for now as there are two issues with providing them: + // 1. LSP client does not currently provide a way to provide detail text on the completion item to show the namespace. + // https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1076759 + // 2. We need to figure out how to provide the text edits along with the completion item or provide them in the resolve request. + // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/985860/ + // 3. LSP client should support completion filters / expanders + options = options with + { + ShowItemsFromUnimportedNamespaces = false, + ExpandedCompletionBehavior = ExpandedCompletionMode.NonExpandedItemsOnly, + UpdateImportCompletionCacheInBackground = false, + }; + } + else + { + var updateImportCompletionCacheInBackground = options.ShowItemsFromUnimportedNamespaces is true; + options = options with + { + ShowNewSnippetExperienceUserOption = false, + UpdateImportCompletionCacheInBackground = updateImportCompletionCacheInBackground + }; + } + + return options; + } + + public static bool TryGetCompletionListCacheEntry( + this CompletionListCache completionListCache, + LSP.CompletionItem request, + [NotNullWhen(true)] out CompletionListCache.CacheEntry? cacheEntry) + { + Contract.ThrowIfNull(request.Data); + var resolveData = JsonSerializer.Deserialize((JsonElement)request.Data, ProtocolConversions.LspJsonSerializerOptions); + if (resolveData?.ResultId is null) + { + Contract.Fail("Result id should always be provided when resolving a completion item we returned."); + cacheEntry = null; + return false; + } + + cacheEntry = completionListCache.GetCachedEntry(resolveData.ResultId); + if (cacheEntry is null) + { + // No cache for associated completion item. Log some telemetry so we can understand how frequently this actually happens. + Logger.Log(FunctionId.LSP_CompletionListCacheMiss, KeyValueLogMessage.NoProperty); + } + + return cacheEntry is not null; + } +} diff --git a/src/LanguageServer/Protocol/Handler/Completion/ILspCompletionResultCreationService.cs b/src/LanguageServer/Protocol/Handler/Completion/ILspCompletionResultCreationService.cs deleted file mode 100644 index 5fec8b6b20c28..0000000000000 --- a/src/LanguageServer/Protocol/Handler/Completion/ILspCompletionResultCreationService.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.LanguageService; -using LSP = Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Completion -{ - internal interface ILspCompletionResultCreationService : IWorkspaceService - { - Task ConvertToLspCompletionListAsync( - Document document, - int position, - CompletionCapabilityHelper capabilityHelper, - CompletionList list, bool isIncomplete, long resultId, - CancellationToken cancellationToken); - - Task ResolveAsync( - LSP.CompletionItem lspItem, - CompletionItem roslynItem, - LSP.TextDocumentIdentifier textDocumentIdentifier, - Document document, - CompletionCapabilityHelper capabilityHelper, - CompletionService completionService, - CompletionOptions completionOptions, - SymbolDescriptionOptions symbolDescriptionOptions, - CancellationToken cancellationToken); - } -} diff --git a/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler.cs b/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler.cs index 60137a3e1ac92..ba4ed447b8d6a 100644 --- a/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler.cs @@ -85,7 +85,7 @@ private async Task RefreshOptionsAsync(CancellationToken cancellationToken) RoslynDebug.Assert(configurationsFromClient.Length == SupportedOptions.Sum(option => option is IPerLanguageValuedOption ? 2 : 1)); // LSP ensures the order of result from client should match the order we sent from server. - var optionsToUpdate = new ArrayBuilder>(); + using var _ = ArrayBuilder>.GetInstance(out var optionsToUpdate); for (var i = 0; i < configurationsFromClient.Length; i++) { @@ -111,23 +111,15 @@ private async Task RefreshOptionsAsync(CancellationToken cancellationToken) private async Task> GetConfigurationsAsync(CancellationToken cancellationToken) { - try - { - var configurationParams = new ConfigurationParams() { Items = _configurationItems.AsArray() }; - var options = await _clientLanguageServerManager.SendRequestAsync( - Methods.WorkspaceConfigurationName, configurationParams, cancellationToken).ConfigureAwait(false); - - // Failed to get result from client. - Contract.ThrowIfNull(options); - var converted = options.SelectAsArray(token => token?.ToString()); - return converted; - } - catch (Exception e) - { - _lspLogger.LogException(e, $"Exception occurs when make {Methods.WorkspaceConfigurationName}."); - } - - return []; + // Attempt to get configurations from the client. If this throws we'll get NFW reports. + var configurationParams = new ConfigurationParams() { Items = _configurationItems.AsArray() }; + var options = await _clientLanguageServerManager.SendRequestAsync( + Methods.WorkspaceConfigurationName, configurationParams, cancellationToken).ConfigureAwait(false); + + // Failed to get result from client. + Contract.ThrowIfNull(options); + var converted = options.SelectAsArray(token => token?.ToString()); + return converted; } private static ImmutableArray<(IOption2 option, string? langaugeName)> GenerateOptionsNeedsToRefresh() @@ -190,7 +182,7 @@ private static ImmutableArray GenerateGlobalConfigurationItem /// /// /// Example:Full name of would be: - /// implement_type.dotnet_insertion_behavior + /// implement_type.dotnet_member_insertion_location /// internal static string GenerateFullNameForOption(IOption2 option) { diff --git a/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OptionList.cs b/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OptionList.cs index b5e15a8ebe982..a6402a1305666 100644 --- a/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OptionList.cs +++ b/src/LanguageServer/Protocol/Handler/Configuration/DidChangeConfigurationNotificationHandler_OptionList.cs @@ -27,6 +27,7 @@ internal partial class DidChangeConfigurationNotificationHandler CompletionOptionsStorage.ShowNameSuggestions, CompletionOptionsStorage.ProvideRegexCompletions, CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, + CompletionOptionsStorage.TriggerInArgumentLists, QuickInfoOptionsStorage.ShowRemarksInQuickInfo, MetadataAsSourceOptionsStorage.NavigateToDecompiledSources, HighlightingOptionsStorage.HighlightRelatedJsonComponentsUnderCursor, @@ -55,6 +56,7 @@ internal partial class DidChangeConfigurationNotificationHandler LspOptionsStorage.LspEnableTestsCodeLens, LanguageServerProjectSystemOptionsStorage.BinaryLogPath, LanguageServerProjectSystemOptionsStorage.EnableAutomaticRestore, + MetadataAsSourceOptionsStorage.NavigateToSourceLinkAndEmbeddedSources, ]; } } diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs index 5c35c9063208b..6336c64247162 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs @@ -6,11 +6,9 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.LanguageServer.Features.Diagnostics; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.SolutionCrawler; @@ -55,6 +53,8 @@ internal abstract partial class AbstractPullDiagnosticHandler private readonly ConcurrentDictionary> _categoryToVersionedCache = []; + protected virtual bool PotentialDuplicate => false; + public bool MutatesSolutionState => false; public bool RequiresLSPSolution => true; @@ -89,11 +89,6 @@ protected abstract ValueTask> GetOrderedDiagno protected abstract TReturn? CreateReturn(BufferedProgress progress); - /// - /// Generate the right diagnostic tags for a particular diagnostic. - /// - protected abstract DiagnosticTag[] ConvertTags(DiagnosticData diagnosticData, bool isLiveSource); - protected abstract string? GetRequestDiagnosticCategory(TDiagnosticsParams diagnosticsParams); /// @@ -138,7 +133,7 @@ protected virtual Task WaitForChangesAsync(string? category, RequestContext cont // the updated diagnostics are. using var _1 = PooledDictionary.GetInstance(out var documentIdToPreviousDiagnosticParams); using var _2 = PooledHashSet.GetInstance(out var removedDocuments); - ProcessPreviousResults(context.Solution, previousResults, documentIdToPreviousDiagnosticParams, removedDocuments); + await ProcessPreviousResultsAsync(context.Solution, previousResults, documentIdToPreviousDiagnosticParams, removedDocuments, cancellationToken).ConfigureAwait(false); // First, let the client know if any workspace documents have gone away. That way it can remove those for // the user from squiggles or error-list. @@ -224,17 +219,18 @@ await ComputeAndReportCurrentDiagnosticsAsync( return CreateReturn(progress); - static void ProcessPreviousResults( + static async Task ProcessPreviousResultsAsync( Solution solution, ImmutableArray previousResults, Dictionary idToPreviousDiagnosticParams, - HashSet removedResults) + HashSet removedResults, + CancellationToken cancellationToken) { foreach (var diagnosticParams in previousResults) { if (diagnosticParams.TextDocument != null) { - var id = GetIdForPreviousResult(diagnosticParams.TextDocument, solution); + var id = await GetIdForPreviousResultAsync(diagnosticParams.TextDocument, solution, cancellationToken).ConfigureAwait(false); if (id != null) { idToPreviousDiagnosticParams[id.Value] = diagnosticParams; @@ -249,9 +245,9 @@ static void ProcessPreviousResults( } } - static ProjectOrDocumentId? GetIdForPreviousResult(TextDocumentIdentifier textDocumentIdentifier, Solution solution) + static async Task GetIdForPreviousResultAsync(TextDocumentIdentifier textDocumentIdentifier, Solution solution, CancellationToken cancellationToken) { - var document = solution.GetDocument(textDocumentIdentifier); + var document = await solution.GetTextDocumentAsync(textDocumentIdentifier, cancellationToken).ConfigureAwait(false); if (document != null) { return new ProjectOrDocumentId(document.Id); @@ -319,247 +315,12 @@ private void HandleRemovedDocuments(RequestContext context, HashSet ConvertDiagnostic(IDiagnosticSource diagnosticSource, DiagnosticData diagnosticData, ClientCapabilities capabilities) { - if (!ShouldIncludeHiddenDiagnostic(diagnosticData, capabilities)) - { - return []; - } - - var project = diagnosticSource.GetProject(); - var diagnostic = CreateLspDiagnostic(diagnosticData, project, capabilities); - - // Check if we need to handle the unnecessary tag (fading). - if (!diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary)) - { - return [diagnostic]; - } - - // DiagnosticId supports fading, check if the corresponding VS option is turned on. - if (!SupportsFadingOption(diagnosticData)) - { - return [diagnostic]; - } - - // Check to see if there are specific locations marked to fade. - if (!diagnosticData.TryGetUnnecessaryDataLocations(out var unnecessaryLocations)) - { - // There are no specific fading locations, just mark the whole diagnostic span as unnecessary. - // We should always have at least one tag (build or intellisense error). - Contract.ThrowIfNull(diagnostic.Tags, $"diagnostic {diagnostic.Identifier} was missing tags"); - diagnostic.Tags = diagnostic.Tags.Append(DiagnosticTag.Unnecessary); - return [diagnostic]; - } - - if (capabilities.HasVisualStudioLspCapability()) - { - // Roslyn produces unnecessary diagnostics by using additional locations, however LSP doesn't support tagging - // additional locations separately. Instead we just create multiple hidden diagnostics for unnecessary squiggling. - using var _ = ArrayBuilder.GetInstance(out var diagnosticsBuilder); - diagnosticsBuilder.Add(diagnostic); - foreach (var location in unnecessaryLocations) - { - var additionalDiagnostic = CreateLspDiagnostic(diagnosticData, project, capabilities); - additionalDiagnostic.Severity = LSP.DiagnosticSeverity.Hint; - additionalDiagnostic.Range = GetRange(location); - additionalDiagnostic.Tags = [DiagnosticTag.Unnecessary, VSDiagnosticTags.HiddenInEditor, VSDiagnosticTags.HiddenInErrorList, VSDiagnosticTags.SuppressEditorToolTip]; - diagnosticsBuilder.Add(additionalDiagnostic); - } - - return diagnosticsBuilder.ToImmutableArray(); - } - else - { - diagnostic.Tags = diagnostic.Tags != null ? diagnostic.Tags.Append(DiagnosticTag.Unnecessary) : [DiagnosticTag.Unnecessary]; - var diagnosticRelatedInformation = unnecessaryLocations.Value.Select(l => new DiagnosticRelatedInformation - { - Location = new LSP.Location - { - Range = GetRange(l), - Uri = ProtocolConversions.CreateAbsoluteUri(l.UnmappedFileSpan.Path) - }, - Message = diagnostic.Message - }).ToArray(); - diagnostic.RelatedInformation = diagnosticRelatedInformation; - return [diagnostic]; - } - - LSP.VSDiagnostic CreateLspDiagnostic( - DiagnosticData diagnosticData, - Project project, - ClientCapabilities capabilities) - { - Contract.ThrowIfNull(diagnosticData.Message, $"Got a document diagnostic that did not have a {nameof(diagnosticData.Message)}"); - - // We can just use VSDiagnostic as it doesn't have any default properties set that - // would get automatically serialized. - var diagnostic = new LSP.VSDiagnostic - { - Code = diagnosticData.Id, - CodeDescription = ProtocolConversions.HelpLinkToCodeDescription(diagnosticData.GetValidHelpLinkUri()), - Message = diagnosticData.Message, - Severity = ConvertDiagnosticSeverity(diagnosticData.Severity, capabilities), - Tags = ConvertTags(diagnosticData, diagnosticSource.IsLiveSource()), - DiagnosticRank = ConvertRank(diagnosticData), - Range = GetRange(diagnosticData.DataLocation) - }; - - if (capabilities.HasVisualStudioLspCapability()) - { - var expandedMessage = string.IsNullOrEmpty(diagnosticData.Description) ? null : diagnosticData.Description; - var informationService = project.Solution.Services.GetRequiredService(); - - diagnostic.DiagnosticType = diagnosticData.Category; - diagnostic.ExpandedMessage = expandedMessage; - diagnostic.Projects = [informationService.GetDiagnosticProjectInformation(project)]; - - // Defines an identifier used by the client for merging diagnostics across projects. We want diagnostics - // to be merged from separate projects if they have the same code, filepath, range, and message. - // - // Note: LSP pull diagnostics only operates on unmapped locations. - diagnostic.Identifier = (diagnostic.Code, diagnosticData.DataLocation.UnmappedFileSpan.Path, diagnostic.Range, diagnostic.Message) - .GetHashCode().ToString(); - } - - return diagnostic; - } - - static LSP.Range GetRange(DiagnosticDataLocation dataLocation) - { - // We currently do not map diagnostics spans as - // 1. Razor handles span mapping for razor files on their side. - // 2. LSP does not allow us to report document pull diagnostics for a different file path. - // 3. The VS LSP client does not support document pull diagnostics for files outside our content type. - // 4. This matches classic behavior where we only squiggle the original location anyway. - - // We also do not adjust the diagnostic locations to ensure they are in bounds because we've - // explicitly requested up to date diagnostics as of the snapshot we were passed in. - return new LSP.Range - { - Start = new Position - { - Character = dataLocation.UnmappedFileSpan.StartLinePosition.Character, - Line = dataLocation.UnmappedFileSpan.StartLinePosition.Line, - }, - End = new Position - { - Character = dataLocation.UnmappedFileSpan.EndLinePosition.Character, - Line = dataLocation.UnmappedFileSpan.EndLinePosition.Line, - } - }; - } - - static bool ShouldIncludeHiddenDiagnostic(DiagnosticData diagnosticData, ClientCapabilities capabilities) - { - // VS can handle us reporting any kind of diagnostic using VS custom tags. - if (capabilities.HasVisualStudioLspCapability() == true) - { - return true; - } - - // Diagnostic isn't hidden - we should report this diagnostic in all scenarios. - if (diagnosticData.Severity != DiagnosticSeverity.Hidden) - { - return true; - } - - // Roslyn creates these for example in remove unnecessary imports, see RemoveUnnecessaryImportsConstants.DiagnosticFixableId. - // These aren't meant to be visible in anyway, so we can safely exclude them. - // TODO - We should probably not be creating these as separate diagnostics or have a 'really really' hidden tag. - if (string.IsNullOrEmpty(diagnosticData.Message)) - { - return false; - } - - // Hidden diagnostics that are unnecessary are visible to the user in the form of fading. - // We can report these diagnostics. - if (diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary)) - { - return true; - } - - // We have a hidden diagnostic that has no fading. This diagnostic can't be visible so don't send it to the client. - return false; - } - } - - 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, ClientCapabilities clientCapabilities) - => severity switch - { - // Hidden is translated in ConvertTags to pass along appropriate _ms tags - // that will hide the item in a client that knows about those tags. - DiagnosticSeverity.Hidden => LSP.DiagnosticSeverity.Hint, - // VSCode shows information diagnostics as blue squiggles, and hint diagnostics as 3 dots. We prefer the latter rendering so we return hint diagnostics in vscode. - DiagnosticSeverity.Info => clientCapabilities.HasVisualStudioLspCapability() ? LSP.DiagnosticSeverity.Information : LSP.DiagnosticSeverity.Hint, - DiagnosticSeverity.Warning => LSP.DiagnosticSeverity.Warning, - DiagnosticSeverity.Error => LSP.DiagnosticSeverity.Error, - _ => throw ExceptionUtilities.UnexpectedValue(severity), - }; - - /// - /// If you make change in this method, please also update the corresponding file in - /// src\VisualStudio\Xaml\Impl\Implementation\LanguageServer\Handler\Diagnostics\AbstractPullDiagnosticHandler.cs - /// - protected static DiagnosticTag[] ConvertTags(DiagnosticData diagnosticData, bool isLiveSource, bool potentialDuplicate) - { - using var _ = ArrayBuilder.GetInstance(out var result); - - if (diagnosticData.Severity == DiagnosticSeverity.Hidden) - { - result.Add(VSDiagnosticTags.HiddenInEditor); - result.Add(VSDiagnosticTags.HiddenInErrorList); - result.Add(VSDiagnosticTags.SuppressEditorToolTip); - } - else - { - result.Add(VSDiagnosticTags.VisibleInErrorList); - } - - if (diagnosticData.CustomTags.Contains(PullDiagnosticConstants.TaskItemCustomTag)) - result.Add(VSDiagnosticTags.TaskItem); - - // Let the host know that these errors represent potentially stale information from the past that should - // be superseded by fresher info. - if (potentialDuplicate) - result.Add(VSDiagnosticTags.PotentialDuplicate); - - // Mark this also as a build error. That way an explicitly kicked off build from a source like CPS can - // override it. - if (!isLiveSource) - result.Add(VSDiagnosticTags.BuildError); - - result.Add(diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.Build) - ? VSDiagnosticTags.BuildError - : VSDiagnosticTags.IntellisenseError); - - if (diagnosticData.CustomTags.Contains(WellKnownDiagnosticTags.EditAndContinue)) - result.Add(VSDiagnosticTags.EditAndContinueError); - - return result.ToArray(); - } - - private bool SupportsFadingOption(DiagnosticData diagnosticData) - { - if (IDEDiagnosticIdToOptionMappingHelper.TryGetMappedFadingOption(diagnosticData.Id, out var fadingOption)) - { - Contract.ThrowIfNull(diagnosticData.Language, $"diagnostic {diagnosticData.Id} is missing a language"); - return GlobalOptions.GetOption(fadingOption, diagnosticData.Language); - } - - return true; + return ProtocolConversions.ConvertDiagnostic( + diagnosticData, + capabilities.HasVisualStudioLspCapability(), + diagnosticSource.GetProject(), + diagnosticSource.IsLiveSource(), + PotentialDuplicate, + GlobalOptions); } } diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs index a739454e9db9f..dd00913897084 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractWorkspacePullDiagnosticsHandler.cs @@ -106,7 +106,7 @@ protected override async Task WaitForChangesAsync(string? category, RequestConte } // We've hit a change, so we close the current request to allow the client to open a new one. - context.TraceInformation("Closing workspace/diagnostics request"); + context.TraceInformation($"Closing workspace/diagnostics request for {category}"); return; bool HasChanged() diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs index 16ee2f87d2bf2..0578f40c43090 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs @@ -64,9 +64,6 @@ protected override bool TryCreateUnchangedReport(TextDocumentIdentifier identifi return null; } - protected override DiagnosticTag[] ConvertTags(DiagnosticData diagnosticData, bool isLiveSource) - => ConvertTags(diagnosticData, isLiveSource, potentialDuplicate: false); - protected override VSInternalDiagnosticReport[]? CreateReturn(BufferedProgress progress) { return progress.GetFlattenedValues(); diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicDocumentPullDiagnosticsHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicDocumentPullDiagnosticsHandler.cs index 426148bed2f11..877ecb816e1a0 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicDocumentPullDiagnosticsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicDocumentPullDiagnosticsHandler.cs @@ -39,9 +39,6 @@ public PublicDocumentPullDiagnosticsHandler( public override TextDocumentIdentifier GetTextDocumentIdentifier(DocumentDiagnosticParams diagnosticsParams) => diagnosticsParams.TextDocument; - protected override DiagnosticTag[] ConvertTags(DiagnosticData diagnosticData, bool isLiveSource) - => ConvertTags(diagnosticData, isLiveSource, potentialDuplicate: false); - protected override DocumentDiagnosticPartialReport CreateReport(TextDocumentIdentifier identifier, Roslyn.LanguageServer.Protocol.Diagnostic[] diagnostics, string resultId) => new(new RelatedFullDocumentDiagnosticReport { diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs index 71f78c36902a0..abd295573170c 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs @@ -36,9 +36,6 @@ public PublicWorkspacePullDiagnosticsHandler( protected override string? GetRequestDiagnosticCategory(WorkspaceDiagnosticParams diagnosticsParams) => diagnosticsParams.Identifier; - protected override DiagnosticTag[] ConvertTags(DiagnosticData diagnosticData, bool isLiveSource) - => ConvertTags(diagnosticData, isLiveSource, potentialDuplicate: false); - protected override WorkspaceDiagnosticPartialReport CreateReport(TextDocumentIdentifier identifier, Roslyn.LanguageServer.Protocol.Diagnostic[] diagnostics, string resultId) => new(new WorkspaceDiagnosticReport { diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs index 62f6e9b5b8332..05b60afae44a9 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs @@ -24,6 +24,10 @@ internal sealed partial class WorkspacePullDiagnosticHandler( : AbstractWorkspacePullDiagnosticsHandler( workspaceManager, registrationService, analyzerService, diagnosticSourceManager, diagnosticsRefresher, globalOptions) { + // All workspace diagnostics are potential duplicates given that they can be overridden by the diagnostics + // produced by document diagnostics. + protected override bool PotentialDuplicate => true; + protected override string? GetRequestDiagnosticCategory(VSInternalWorkspaceDiagnosticsParams diagnosticsParams) => diagnosticsParams.QueryingDiagnosticKind?.Value; @@ -54,13 +58,6 @@ protected override bool TryCreateUnchangedReport(TextDocumentIdentifier identifi protected override ImmutableArray? GetPreviousResults(VSInternalWorkspaceDiagnosticsParams diagnosticsParams) => diagnosticsParams.PreviousResults?.Where(d => d.PreviousResultId != null).Select(d => new PreviousPullResult(d.PreviousResultId!, d.TextDocument!)).ToImmutableArray(); - protected override DiagnosticTag[] ConvertTags(DiagnosticData diagnosticData, bool isLiveSource) - { - // All workspace diagnostics are potential duplicates given that they can be overridden by the diagnostics - // produced by document diagnostics. - return ConvertTags(diagnosticData, isLiveSource, potentialDuplicate: true); - } - protected override VSInternalWorkspaceDiagnosticReport[]? CreateReturn(BufferedProgress progress) { return progress.GetFlattenedValues(); diff --git a/src/LanguageServer/Protocol/Handler/DocumentChanges/DidChangeHandler.cs b/src/LanguageServer/Protocol/Handler/DocumentChanges/DidChangeHandler.cs index e4586f2f83a01..b13b4ae983006 100644 --- a/src/LanguageServer/Protocol/Handler/DocumentChanges/DidChangeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/DocumentChanges/DidChangeHandler.cs @@ -4,9 +4,11 @@ using System; using System.Composition; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Text; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; @@ -28,15 +30,53 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DidChangeTextDocumentPar { var text = context.GetTrackedDocumentSourceText(request.TextDocument.Uri); - // Per the LSP spec, each text change builds upon the previous, so we don't need to translate any text - // positions between changes, which makes this quite easy. See - // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#didChangeTextDocumentParams - // for more details. - foreach (var change in request.ContentChanges) - text = text.WithChanges(ProtocolConversions.ContentChangeEventToTextChange(change, text)); + text = GetUpdatedSourceText(request.ContentChanges, text); context.UpdateTrackedDocument(request.TextDocument.Uri, text); return SpecializedTasks.Default(); } + + internal static bool AreChangesInReverseOrder(TextDocumentContentChangeEvent[] contentChanges) + { + for (var i = 1; i < contentChanges.Length; i++) + { + var prevChange = contentChanges[i - 1]; + var curChange = contentChanges[i]; + + if (prevChange.Range.Start.CompareTo(curChange.Range.End) < 0) + { + return false; + } + } + + return true; + } + + private static SourceText GetUpdatedSourceText(TextDocumentContentChangeEvent[] contentChanges, SourceText text) + { + // Per the LSP spec, each text change builds upon the previous, so we don't need to translate any text + // positions between changes. See + // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#didChangeTextDocumentParams + // for more details. + // + // If the host sends us changes in a way such that no earlier change can affect the position of a later change, + // then we can merge the changes into a single TextChange, allowing creation of only a single new + // source text. + if (AreChangesInReverseOrder(contentChanges)) + { + // The changes were in reverse document order, so we can merge them into a single operation on the source text. + // Note that the WithChanges implementation works more efficiently with it's input in forward document order. + var newChanges = contentChanges.Reverse().SelectAsArray(change => ProtocolConversions.ContentChangeEventToTextChange(change, text)); + text = text.WithChanges(newChanges); + } + else + { + // The host didn't send us the items ordered, so we'll apply each one independently. + foreach (var change in contentChanges) + text = text.WithChanges(ProtocolConversions.ContentChangeEventToTextChange(change, text)); + } + + return text; + } } diff --git a/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs b/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs index 45f13c67d6d03..331c3971595bf 100644 --- a/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs +++ b/src/LanguageServer/Protocol/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs @@ -42,9 +42,9 @@ internal abstract class AbstractFormatDocumentHandlerBase(); + using var _ = ArrayBuilder.GetInstance(out var edits); edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text))); - return edits.ToArrayAndFree(); + return edits.ToArray(); } public abstract LSP.TextDocumentIdentifier GetTextDocumentIdentifier(RequestType request); diff --git a/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs b/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs index f15993645ca9c..87efbd4a7a72c 100644 --- a/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Formatting/FormatDocumentOnTypeHandler.cs @@ -72,9 +72,9 @@ public FormatDocumentOnTypeHandler(IGlobalOptionService globalOptions) return []; } - var edits = new ArrayBuilder(); + using var _ = ArrayBuilder.GetInstance(out var edits); edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, documentSyntax.Text))); - return edits.ToArrayAndFree(); + return edits.ToArray(); } } } diff --git a/src/LanguageServer/Protocol/Handler/Hover/HoverHandler.cs b/src/LanguageServer/Protocol/Handler/Hover/HoverHandler.cs index 5d8a617908b4c..a0582bb21547b 100644 --- a/src/LanguageServer/Protocol/Handler/Hover/HoverHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Hover/HoverHandler.cs @@ -3,24 +3,24 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Immutable; using System.Composition; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.QuickInfo; +using Microsoft.CodeAnalysis.QuickInfo.Presentation; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler { - /// - /// TODO - This must be moved to the MS.CA.LanguageServer.Protocol project once it - /// no longer references VS icon or classified text run types. - /// See https://github.com/dotnet/roslyn/issues/55142 - /// [ExportCSharpVisualBasicStatelessLspService(typeof(HoverHandler)), Shared] [Method(Methods.TextDocumentHoverName)] internal sealed class HoverHandler : ILspServiceDocumentRequestHandler @@ -39,22 +39,57 @@ public HoverHandler(IGlobalOptionService globalOptions) public TextDocumentIdentifier GetTextDocumentIdentifier(TextDocumentPositionParams request) => request.TextDocument; - public async Task HandleRequestAsync(TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken) + public Task HandleRequestAsync(TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.GetRequiredDocument(); var clientCapabilities = context.GetRequiredClientCapabilities(); - var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); - var options = _globalOptions.GetSymbolDescriptionOptions(document.Project.Language); - return await GetHoverAsync(document, position, options, clientCapabilities, cancellationToken).ConfigureAwait(false); + var linePosition = ProtocolConversions.PositionToLinePosition(request.Position); + var supportsVSExtensions = clientCapabilities.HasVisualStudioLspCapability(); + var supportsMarkdown = clientCapabilities?.TextDocument?.Hover?.ContentFormat?.Contains(MarkupKind.Markdown) == true; + + return GetHoverAsync(document, linePosition, _globalOptions, supportsVSExtensions, supportsMarkdown, cancellationToken); } - internal static async Task GetHoverAsync( + // Used by the LSIF Generator + internal static Task GetHoverAsync( Document document, int position, SymbolDescriptionOptions options, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) + { + var supportsVSExtensions = clientCapabilities.HasVisualStudioLspCapability(); + var supportsMarkdown = clientCapabilities?.TextDocument?.Hover?.ContentFormat?.Contains(MarkupKind.Markdown) == true; + + return GetHoverAsync(document, position, options, supportsVSExtensions, supportsMarkdown, cancellationToken); + } + + internal static async Task GetHoverAsync( + Document document, + LinePosition linePosition, + IGlobalOptionService globalOptions, + bool supportsVSExtensions, + bool supportsMarkdown, + CancellationToken cancellationToken) + { + var position = await document + .GetPositionFromLinePositionAsync(linePosition, cancellationToken) + .ConfigureAwait(false); + + var options = globalOptions.GetSymbolDescriptionOptions(document.Project.Language); + + return await GetHoverAsync( + document, position, options, supportsVSExtensions, supportsMarkdown, cancellationToken).ConfigureAwait(false); + } + + private static async Task GetHoverAsync( + Document document, + int position, + SymbolDescriptionOptions options, + bool supportsVSExtensions, + bool supportsMarkdown, + CancellationToken cancellationToken) { // Get the quick info service to compute quick info. // This code path is only invoked for C# and VB, so we can directly cast to QuickInfoServiceWithProviders. @@ -63,8 +98,53 @@ public HoverHandler(IGlobalOptionService globalOptions) if (info == null) return null; - var hoverService = document.Project.Solution.Services.GetRequiredService(); - return await hoverService.CreateHoverAsync(document, info, clientCapabilities, cancellationToken).ConfigureAwait(false); + return supportsVSExtensions + ? await CreateVsHoverAsync(document, info, options, cancellationToken).ConfigureAwait(false) + : await CreateDefaultHoverAsync(document, info, supportsMarkdown, cancellationToken).ConfigureAwait(false); + } + + private static async Task CreateVsHoverAsync( + Document document, QuickInfoItem info, SymbolDescriptionOptions options, CancellationToken cancellationToken) + { + var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); + var formattingOptions = await document.GetLineFormattingOptionsAsync(cancellationToken).ConfigureAwait(false); + + var context = new QuickInfoContentBuilderContext( + document, + options.ClassificationOptions, + formattingOptions, + // Build the classified text without navigation actions - they are not serializable. + navigationActionFactory: null); + + var content = await QuickInfoContentBuilder.BuildInteractiveContentAsync(info, context, cancellationToken).ConfigureAwait(false); + + return new VSInternalHover + { + Range = ProtocolConversions.TextSpanToRange(info.Span, text), + Contents = new SumType[], MarkupContent>(string.Empty), + + // TODO - Switch to markup content once it supports classifications. + // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/918138 + RawContent = content.ToLSPElement(), + }; + } + + private static async Task CreateDefaultHoverAsync( + TextDocument document, QuickInfoItem info, bool supportsMarkdown, CancellationToken cancellationToken) + { + // Insert line breaks in between sections to ensure we get double spacing between sections. + ImmutableArray tags = [ + .. info.Sections.SelectMany(static s => s.TaggedParts.Add(new TaggedText(TextTags.LineBreak, Environment.NewLine))) + ]; + + var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); + var language = document.Project.Language; + + return new Hover + { + Range = ProtocolConversions.TextSpanToRange(info.Span, text), + Contents = ProtocolConversions.GetDocumentationMarkupContent(tags, language, supportsMarkdown), + }; } } } diff --git a/src/LanguageServer/Protocol/Handler/Hover/ILspHoverResultCreationService.cs b/src/LanguageServer/Protocol/Handler/Hover/ILspHoverResultCreationService.cs deleted file mode 100644 index 10e0d8e5c2726..0000000000000 --- a/src/LanguageServer/Protocol/Handler/Hover/ILspHoverResultCreationService.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.Immutable; -using System.Composition; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.QuickInfo; -using Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.Handler -{ - internal interface ILspHoverResultCreationService : IWorkspaceService - { - Task CreateHoverAsync( - Document document, QuickInfoItem info, ClientCapabilities clientCapabilities, CancellationToken cancellationToken); - } - - [ExportWorkspaceService(typeof(ILspHoverResultCreationService)), Shared] - internal sealed class DefaultLspHoverResultCreationService : ILspHoverResultCreationService - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public DefaultLspHoverResultCreationService() - { - } - - public Task CreateHoverAsync(Document document, QuickInfoItem info, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) - => CreateDefaultHoverAsync(document, info, clientCapabilities, cancellationToken); - - public static async Task CreateDefaultHoverAsync(TextDocument document, QuickInfoItem info, ClientCapabilities clientCapabilities, CancellationToken cancellationToken) - { - var clientSupportsMarkdown = clientCapabilities?.TextDocument?.Hover?.ContentFormat?.Contains(MarkupKind.Markdown) == true; - - // Insert line breaks in between sections to ensure we get double spacing between sections. - var tags = info.Sections - .SelectMany(section => section.TaggedParts.Add(new TaggedText(TextTags.LineBreak, Environment.NewLine))) - .ToImmutableArray(); - - var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); - var language = document.Project.Language; - - return new Hover - { - Range = ProtocolConversions.TextSpanToRange(info.Span, text), - Contents = ProtocolConversions.GetDocumentationMarkupContent(tags, language, clientSupportsMarkdown), - }; - } - } -} diff --git a/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintHandler.cs b/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintHandler.cs index 08025830a4bca..8ce98a031b551 100644 --- a/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintHandler.cs +++ b/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintHandler.cs @@ -38,18 +38,24 @@ public InlayHintHandler(IGlobalOptionService optionsService) public TextDocumentIdentifier GetTextDocumentIdentifier(InlayHintParams request) => request.TextDocument; - public async Task HandleRequestAsync(InlayHintParams request, RequestContext context, CancellationToken cancellationToken) + public Task HandleRequestAsync(InlayHintParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.GetRequiredDocument(); + var inlayHintCache = context.GetRequiredLspService(); + var options = _optionsService.GetInlineHintsOptions(document.Project.Language); + + return GetInlayHintsAsync(document, request.TextDocument, request.Range, options, displayAllOverride: false, inlayHintCache, cancellationToken); + } + + internal static async Task GetInlayHintsAsync(Document document, TextDocumentIdentifier textDocumentIdentifier, LSP.Range range, InlineHintsOptions options, bool displayAllOverride, InlayHintCache inlayHintCache, CancellationToken cancellationToken) + { var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); - var textSpan = ProtocolConversions.RangeToTextSpan(request.Range, text); + var textSpan = ProtocolConversions.RangeToTextSpan(range, text); var inlineHintService = document.GetRequiredLanguageService(); - var options = _optionsService.GetInlineHintsOptions(document.Project.Language); - var hints = await inlineHintService.GetInlineHintsAsync(document, textSpan, options, displayAllOverride: false, cancellationToken).ConfigureAwait(false); + var hints = await inlineHintService.GetInlineHintsAsync(document, textSpan, options, displayAllOverride, cancellationToken).ConfigureAwait(false); var syntaxVersion = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false); - var inlayHintCache = context.GetRequiredLspService(); // Store the members in the resolve cache so that when we get a resolve request for a particular // member we can re-use the inline hint. @@ -83,7 +89,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(InlayHintParams request) ToolTip = null, PaddingLeft = leftPadding, PaddingRight = rightPadding, - Data = new InlayHintResolveData(resultId, i, request.TextDocument) + Data = new InlayHintResolveData(resultId, i, textDocumentIdentifier) }; inlayHints[i] = inlayHint; diff --git a/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveHandler.cs b/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveHandler.cs index 122bdcc25e622..468e908a507e6 100644 --- a/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveHandler.cs +++ b/src/LanguageServer/Protocol/Handler/InlayHint/InlayHintResolveHandler.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.Text.Json; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.InlineHints; @@ -9,7 +10,6 @@ using Roslyn.Utilities; using StreamJsonRpc; using LSP = Roslyn.LanguageServer.Protocol; -using System.Text.Json; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.InlayHint { @@ -30,11 +30,16 @@ public InlayHintResolveHandler(InlayHintCache inlayHintCache) public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.InlayHint request) => GetInlayHintResolveData(request).TextDocument; - public async Task HandleRequestAsync(LSP.InlayHint request, RequestContext context, CancellationToken cancellationToken) + public Task HandleRequestAsync(LSP.InlayHint request, RequestContext context, CancellationToken cancellationToken) { var document = context.GetRequiredDocument(); + return ResolveInlayHintAsync(document, request, _inlayHintCache, cancellationToken); + } + + internal static async Task ResolveInlayHintAsync(Document document, LSP.InlayHint request, InlayHintCache inlayHintCache, CancellationToken cancellationToken) + { var resolveData = GetInlayHintResolveData(request); - var (cacheEntry, inlineHintToResolve) = GetCacheEntry(resolveData); + var (cacheEntry, inlineHintToResolve) = GetCacheEntry(resolveData, inlayHintCache); var currentSyntaxVersion = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false); var cachedSyntaxVersion = cacheEntry.SyntaxVersion; @@ -53,9 +58,9 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.InlayHint request) return request; } - private (InlayHintCache.InlayHintCacheEntry CacheEntry, InlineHint InlineHintToResolve) GetCacheEntry(InlayHintResolveData resolveData) + private static (InlayHintCache.InlayHintCacheEntry CacheEntry, InlineHint InlineHintToResolve) GetCacheEntry(InlayHintResolveData resolveData, InlayHintCache inlayHintCache) { - var cacheEntry = _inlayHintCache.GetCachedEntry(resolveData.ResultId); + var cacheEntry = inlayHintCache.GetCachedEntry(resolveData.ResultId); Contract.ThrowIfNull(cacheEntry, "Missing cache entry for inlay hint resolve request"); return (cacheEntry, cacheEntry.InlayHintMembers[resolveData.ListIndex]); } diff --git a/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs b/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs index 3967261f2131d..59279fcf4a48a 100644 --- a/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs @@ -42,12 +42,12 @@ public MapCodeHandler() throw new NotImplementedException("mapCode Request failed: additional workspace 'Update' is currently not supported"); } - using var _ = PooledDictionary.GetInstance(out var uriToEditsMap); + using var _ = PooledDictionary.GetInstance(out var uriToEditsMap); foreach (var codeMapping in request.Mappings) { var mappingResult = await MapCodeAsync(codeMapping).ConfigureAwait(false); - if (mappingResult is not (Uri uri, TextEdit[] textEdits)) + if (mappingResult is not (Uri uri, LSP.TextEdit[] textEdits)) { // Failed the entire request if any of the sub-requests failed return null; @@ -65,7 +65,7 @@ public MapCodeHandler() DocumentChanges = uriToEditsMap.Select(kvp => new TextDocumentEdit { TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = kvp.Key }, - Edits = kvp.Value, + Edits = kvp.Value.Select(v => new SumType(v)).ToArray(), }).ToArray() }; } @@ -77,12 +77,13 @@ public MapCodeHandler() }; } - async Task<(Uri, TextEdit[])?> MapCodeAsync(LSP.VSInternalMapCodeMapping codeMapping) + async Task<(Uri, LSP.TextEdit[])?> MapCodeAsync(LSP.VSInternalMapCodeMapping codeMapping) { var textDocument = codeMapping.TextDocument ?? throw new ArgumentException($"mapCode sub-request failed: MapCodeMapping.TextDocument not expected to be null."); - if (context.Solution.GetDocument(textDocument) is not Document document) + var document = await context.Solution.GetDocumentAsync(textDocument, cancellationToken).ConfigureAwait(false); + if (document is null) throw new ArgumentException($"mapCode sub-request for {textDocument.Uri} failed: can't find this document in the workspace."); var codeMapper = document.GetRequiredLanguageService(); diff --git a/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs b/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs index bdfdaf086746d..c97d512ca5a42 100644 --- a/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs +++ b/src/LanguageServer/Protocol/Handler/References/FindAllReferencesHandler.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler { [ExportCSharpVisualBasicStatelessLspService(typeof(FindAllReferencesHandler)), Shared] [Method(LSP.Methods.TextDocumentReferencesName)] - internal sealed class FindAllReferencesHandler : ILspServiceDocumentRequestHandler[]?> + internal sealed class FindAllReferencesHandler : ILspServiceDocumentRequestHandler[]?> { private readonly IMetadataAsSourceFileService _metadataAsSourceFileService; private readonly IAsynchronousOperationListener _asyncListener; @@ -43,10 +43,10 @@ public FindAllReferencesHandler( public bool MutatesSolutionState => false; public bool RequiresLSPSolution => true; - public TextDocumentIdentifier GetTextDocumentIdentifier(ReferenceParams request) => request.TextDocument; + public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalReferenceParams request) => request.TextDocument; - public async Task[]?> HandleRequestAsync( - ReferenceParams referenceParams, + public async Task[]?> HandleRequestAsync( + VSInternalReferenceParams referenceParams, RequestContext context, CancellationToken cancellationToken) { @@ -55,14 +55,16 @@ public FindAllReferencesHandler( Contract.ThrowIfNull(document); Contract.ThrowIfNull(workspace); - using var progress = BufferedProgress.Create[]>(referenceParams.PartialResultToken); + using var progress = BufferedProgress.Create(referenceParams.PartialResultToken); var findUsagesService = document.GetRequiredLanguageService(); var position = await document.GetPositionFromLinePositionAsync( ProtocolConversions.PositionToLinePosition(referenceParams.Position), cancellationToken).ConfigureAwait(false); + var clientCapabilities = context.GetRequiredClientCapabilities(); + var findUsagesContext = new FindUsagesLSPContext( - progress, workspace, document, position, _metadataAsSourceFileService, _asyncListener, _globalOptions, cancellationToken); + progress, workspace, document, position, _metadataAsSourceFileService, _asyncListener, _globalOptions, clientCapabilities, cancellationToken); // Finds the references for the symbol at the specific position in the document, reporting them via streaming to the LSP client. var classificationOptions = _globalOptions.GetClassificationOptionsProvider(); diff --git a/src/LanguageServer/Protocol/Handler/References/FindImplementationsHandler.cs b/src/LanguageServer/Protocol/Handler/References/FindImplementationsHandler.cs index 343299bec39e4..edc18420b5433 100644 --- a/src/LanguageServer/Protocol/Handler/References/FindImplementationsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/References/FindImplementationsHandler.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler @@ -33,18 +34,24 @@ public FindImplementationsHandler(IGlobalOptionService globalOptions) public LSP.TextDocumentIdentifier GetTextDocumentIdentifier(LSP.TextDocumentPositionParams request) => request.TextDocument; - public async Task HandleRequestAsync(LSP.TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken) + public Task HandleRequestAsync(LSP.TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.GetRequiredDocument(); - var clientCapabilities = context.GetRequiredClientCapabilities(); + var supportsVisualStudioExtensions = context.GetRequiredClientCapabilities().HasVisualStudioLspCapability(); + var linePosition = ProtocolConversions.PositionToLinePosition(request.Position); + var classificationOptions = _globalOptions.GetClassificationOptionsProvider(); + + return FindImplementationsAsync(document, linePosition, classificationOptions, supportsVisualStudioExtensions, cancellationToken); + } + internal static async Task FindImplementationsAsync(Document document, LinePosition linePosition, OptionsProvider classificationOptions, bool supportsVisualStudioExtensions, CancellationToken cancellationToken) + { var locations = ArrayBuilder.GetInstance(); var findUsagesService = document.GetRequiredLanguageService(); - var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); + var position = await document.GetPositionFromLinePositionAsync(linePosition, cancellationToken).ConfigureAwait(false); var findUsagesContext = new SimpleFindUsagesContext(); - var classificationOptions = _globalOptions.GetClassificationOptionsProvider(); await findUsagesService.FindImplementationsAsync(findUsagesContext, document, position, classificationOptions, cancellationToken).ConfigureAwait(false); foreach (var definition in findUsagesContext.GetDefinitions()) @@ -52,7 +59,7 @@ public FindImplementationsHandler(IGlobalOptionService globalOptions) var text = definition.GetClassifiedText(); foreach (var sourceSpan in definition.SourceSpans) { - if (clientCapabilities.HasVisualStudioLspCapability() == true) + if (supportsVisualStudioExtensions) { locations.AddIfNotNull(await ProtocolConversions.DocumentSpanToLocationWithTextAsync(sourceSpan, text, cancellationToken).ConfigureAwait(false)); } diff --git a/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs b/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs index 92c7cec421960..9328c140b3804 100644 --- a/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs +++ b/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.FindSymbols.Finders; using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Options; @@ -35,6 +36,7 @@ internal sealed class FindUsagesLSPContext : FindUsagesContext private readonly int _position; private readonly IMetadataAsSourceFileService _metadataAsSourceFileService; private readonly IGlobalOptionService _globalOptions; + private readonly bool _supportsVSExtensions; /// /// Methods in FindUsagesLSPContext can be called by multiple threads concurrently. We need this semaphore to @@ -78,6 +80,7 @@ public FindUsagesLSPContext( IMetadataAsSourceFileService metadataAsSourceFileService, IAsynchronousOperationListener asyncListener, IGlobalOptionService globalOptions, + ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { _progress = progress; @@ -86,6 +89,7 @@ public FindUsagesLSPContext( _position = position; _metadataAsSourceFileService = metadataAsSourceFileService; _globalOptions = globalOptions; + _supportsVSExtensions = clientCapabilities.HasVisualStudioLspCapability(); _workQueue = new AsyncBatchingWorkQueue>( DelayTimeSpan.Medium, ReportReferencesAsync, asyncListener, cancellationToken); } @@ -138,7 +142,7 @@ public override async ValueTask OnReferencesFoundAsync(IAsyncEnumerable(); - return service.CreateReference( - definitionId, id, text, documentSpan, properties, definitionText, definitionGlyph, symbolUsageInfo, location); + return _supportsVSExtensions + ? CreateVsReference(definitionId, id, text, documentSpan, properties, definitionText, definitionGlyph, symbolUsageInfo, location) + : location; + } + + private static SumType? CreateVsReference( + int definitionId, + int id, + ClassifiedTextElement text, + DocumentSpan? documentSpan, + ImmutableArray<(string key, string value)> properties, + ClassifiedTextElement? definitionText, + Glyph definitionGlyph, + SymbolUsageInfo? symbolUsageInfo, + LSP.Location? location) + { + // TO-DO: The Origin property should be added once Rich-Nav is completed. + // https://github.com/dotnet/roslyn/issues/42847 + var result = new VSInternalReferenceItem + { + DefinitionId = definitionId, + DefinitionText = definitionText, // Only definitions should have a non-null DefinitionText + DefinitionIcon = new ImageElement(definitionGlyph.ToLSPImageId()), + DisplayPath = location?.Uri.LocalPath, + Id = id, + Kind = symbolUsageInfo.HasValue ? ProtocolConversions.SymbolUsageInfoToReferenceKinds(symbolUsageInfo.Value) : [], + ResolutionStatus = VSInternalResolutionStatusKind.ConfirmedAsReference, + Text = text, + }; + + // There are certain items that may not have locations, such as namespace definitions. + if (location != null) + result.Location = location; + + if (documentSpan is var (document, _)) + { + result.DocumentName = document.Name; + result.ProjectName = document.Project.Name; + } + + foreach (var (key, value) in properties) + { + if (key == AbstractReferenceFinder.ContainingMemberInfoPropertyName) + result.ContainingMember = value; + else if (key == AbstractReferenceFinder.ContainingTypeInfoPropertyName) + result.ContainingType = value; + } + + return result; } private async Task ComputeLocationAsync(DocumentSpan? documentSpan, CancellationToken cancellationToken) diff --git a/src/LanguageServer/Protocol/Handler/References/ILspReferencesResultCreationService.cs b/src/LanguageServer/Protocol/Handler/References/ILspReferencesResultCreationService.cs deleted file mode 100644 index 37505b5a78b87..0000000000000 --- a/src/LanguageServer/Protocol/Handler/References/ILspReferencesResultCreationService.cs +++ /dev/null @@ -1,51 +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; -using Microsoft.CodeAnalysis.Host.Mef; -using Roslyn.LanguageServer.Protocol; -using Roslyn.Text.Adornments; -using LSP = Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.Handler; - -internal interface ILspReferencesResultCreationService : IWorkspaceService -{ - SumType? CreateReference( - int definitionId, - int id, - ClassifiedTextElement text, - DocumentSpan? documentSpan, - ImmutableArray<(string key, string value)> properties, - ClassifiedTextElement? definitionText, - Glyph definitionGlyph, - SymbolUsageInfo? symbolUsageInfo, - LSP.Location? location); -} - -[ExportWorkspaceService(typeof(ILspReferencesResultCreationService)), Shared] -[method: ImportingConstructor] -[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal sealed class DefaultLspReferencesResultCreationService() : ILspReferencesResultCreationService -{ - public SumType? CreateReference( - int definitionId, - int id, - ClassifiedTextElement text, - DocumentSpan? documentSpan, - ImmutableArray<(string key, string value)> properties, - ClassifiedTextElement? definitionText, - Glyph definitionGlyph, - SymbolUsageInfo? symbolUsageInfo, - LSP.Location? location) - { - if (location is null) - return null; - - return location; - } -} diff --git a/src/LanguageServer/Protocol/Handler/RelatedDocuments/RelatedDocumentsHandler.cs b/src/LanguageServer/Protocol/Handler/RelatedDocuments/RelatedDocumentsHandler.cs new file mode 100644 index 0000000000000..f30fe7ad72219 --- /dev/null +++ b/src/LanguageServer/Protocol/Handler/RelatedDocuments/RelatedDocumentsHandler.cs @@ -0,0 +1,91 @@ +// 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.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.RelatedDocuments; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CommonLanguageServerProtocol.Framework; +using Roslyn.LanguageServer.Protocol; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler.RelatedDocuments; + +[ExportCSharpVisualBasicLspServiceFactory(typeof(RelatedDocumentsHandler)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class RelatedDocumentsHandlerFactory() : ILspServiceFactory +{ + public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) + => new RelatedDocumentsHandler(); +} + +[Method(VSInternalMethods.CopilotRelatedDocumentsName)] +internal sealed class RelatedDocumentsHandler + : ILspServiceRequestHandler, + ITextDocumentIdentifierHandler +{ + + public bool MutatesSolutionState => false; + public bool RequiresLSPSolution => true; + + public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalRelatedDocumentParams requestParams) + => requestParams.TextDocument; + + public async Task HandleRequestAsync( + VSInternalRelatedDocumentParams requestParams, RequestContext context, CancellationToken cancellationToken) + { + context.TraceInformation($"{this.GetType()} started getting related documents"); + + var solution = context.Solution; + var document = context.Document; + Contract.ThrowIfNull(solution); + Contract.ThrowIfNull(document); + + context.TraceInformation($"Processing: {document.FilePath}"); + + var relatedDocumentsService = document.GetLanguageService(); + if (relatedDocumentsService == null) + { + context.TraceInformation($"Ignoring document '{document.FilePath}' because it does not support related documents"); + return []; + } + + // The progress object we will stream reports to. + using var progress = BufferedProgress.Create(requestParams.PartialResultToken); + + var linePosition = requestParams.Position is null + ? new LinePosition(0, 0) + : ProtocolConversions.PositionToLinePosition(requestParams.Position); + + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var position = text.Lines.GetPosition(linePosition); + + await relatedDocumentsService.GetRelatedDocumentIdsAsync( + document, + position, + (relatedDocumentIds, cancellationToken) => + { + // As the related docs services reports document ids to us, stream those immediately through our + // progress reporter. + progress.Report(new VSInternalRelatedDocumentReport + { + FilePaths = relatedDocumentIds.Select(id => solution.GetRequiredDocument(id).FilePath).WhereNotNull().ToArray(), + }); + + return ValueTaskFactory.CompletedTask; + }, + cancellationToken).ConfigureAwait(false); + + // If we had a progress object, then we will have been reporting to that. Otherwise, take what we've been + // collecting and return that. + context.TraceInformation($"{this.GetType()} finished getting related documents"); + return progress.GetFlattenedValues(); + } +} diff --git a/src/LanguageServer/Protocol/Handler/RequestTelemetryLogger.cs b/src/LanguageServer/Protocol/Handler/RequestTelemetryLogger.cs index 4a2be60dae256..68e6ed6b8cd5d 100644 --- a/src/LanguageServer/Protocol/Handler/RequestTelemetryLogger.cs +++ b/src/LanguageServer/Protocol/Handler/RequestTelemetryLogger.cs @@ -66,7 +66,7 @@ public void UpdateTelemetryData( TelemetryLogging.LogAggregated(FunctionId.LSP_TimeInQueue, KeyValueLogMessage.Create(m => { m[TelemetryLogging.KeyName] = _serverTypeName; - m[TelemetryLogging.KeyValue] = queuedDuration.Milliseconds; + m[TelemetryLogging.KeyValue] = (int)queuedDuration.TotalMilliseconds; m[TelemetryLogging.KeyMetricName] = "TimeInQueue"; m["server"] = _serverTypeName; m["method"] = methodName; @@ -76,7 +76,7 @@ public void UpdateTelemetryData( TelemetryLogging.LogAggregated(FunctionId.LSP_RequestDuration, KeyValueLogMessage.Create(m => { m[TelemetryLogging.KeyName] = _serverTypeName + "." + methodName; - m[TelemetryLogging.KeyValue] = requestDuration.Milliseconds; + m[TelemetryLogging.KeyValue] = (int)requestDuration.TotalMilliseconds; m[TelemetryLogging.KeyMetricName] = "RequestDuration"; m["server"] = _serverTypeName; m["method"] = methodName; diff --git a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs index 15c3acda9213e..c843c239128ee 100644 --- a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs +++ b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs @@ -91,7 +91,7 @@ public static async Task ComputeSemanticTokensDataAsync( using var _1 = Classifier.GetPooledList(out var classifiedSpans); using var _2 = Classifier.GetPooledList(out var updatedClassifiedSpans); - // We either calculate the tokens for the full document span, or the user + // We either calculate the tokens for the full document span, or the user // can pass in a range from the full document if they wish. ImmutableArray textSpans; if (spans.Length == 0) @@ -338,6 +338,10 @@ private static int ComputeNextToken( // 6. Token modifiers - each set bit will be looked up in SemanticTokensLegend.tokenModifiers modifierBits |= TokenModifiers.Deprecated; } + else if (classificationType == ClassificationTypeNames.TestCode) + { + // Skip additive types that are not being converted to token modifiers. + } else { // 7. Token type - looked up in SemanticTokensLegend.tokenTypes (language server defined mapping diff --git a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueue.cs b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueue.cs index a512ea1d5857d..af4f7fe83d7a5 100644 --- a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueue.cs +++ b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueue.cs @@ -7,23 +7,16 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; using Roslyn.LanguageServer.Protocol; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens; /// /// Batches requests to refresh the semantic tokens to optimize user experience. /// -/// This implements to avoid race conditions related to creating the queue on the -/// first request. -internal class SemanticTokensRefreshQueue : - IOnInitialized, - ILspService, - IDisposable +internal class SemanticTokensRefreshQueue : AbstractRefreshQueue { /// /// Lock over the mutable state that follows. @@ -36,108 +29,38 @@ internal class SemanticTokensRefreshQueue : /// private readonly Dictionary _projectIdToLastComputedChecksum = []; - private readonly LspWorkspaceManager _lspWorkspaceManager; - private readonly IClientLanguageServerManager _notificationManager; - private readonly ICapabilitiesProvider _capabilitiesProvider; - - private readonly IAsynchronousOperationListener _asyncListener; - private readonly CancellationTokenSource _disposalTokenSource = new(); - - /// - /// Debouncing queue so that we don't attempt to issue a semantic tokens refresh notification too often. - /// - /// when the client does not support sending refresh notifications. - /// - private AsyncBatchingWorkQueue? _semanticTokenRefreshQueue; - - private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; - public SemanticTokensRefreshQueue( IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, LspWorkspaceManager lspWorkspaceManager, - IClientLanguageServerManager notificationManager, - ICapabilitiesProvider capabilitiesProvider) + IClientLanguageServerManager notificationManager) : base(asynchronousOperationListenerProvider, lspWorkspaceRegistrationService, lspWorkspaceManager, notificationManager) { - _asyncListener = asynchronousOperationListenerProvider.GetListener(FeatureAttribute.Classification); - - _lspWorkspaceRegistrationService = lspWorkspaceRegistrationService; - _lspWorkspaceManager = lspWorkspaceManager; - _notificationManager = notificationManager; - _capabilitiesProvider = capabilitiesProvider; - } - - public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestContext context, CancellationToken _) - { - if (_capabilitiesProvider.GetCapabilities(clientCapabilities).SemanticTokensOptions is not null) - { - Initialize(clientCapabilities); - } - - return Task.CompletedTask; - } - - public void Initialize(ClientCapabilities clientCapabilities) - { - if (_semanticTokenRefreshQueue is null - && clientCapabilities.Workspace?.SemanticTokens?.RefreshSupport is true) - { - // Only send a refresh notification to the client every 2s (if needed) in order to avoid sending too many - // notifications at once. This ensures we batch up workspace notifications, but also means we send soon - // enough after a compilation-computation to not make the user wait an enormous amount of time. - _semanticTokenRefreshQueue = new AsyncBatchingWorkQueue( - delay: TimeSpan.FromMilliseconds(2000), - processBatchAsync: FilterLspTrackedDocumentsAsync, - equalityComparer: EqualityComparer.Default, - asyncListener: _asyncListener, - _disposalTokenSource.Token); - - _lspWorkspaceRegistrationService.LspSolutionChanged += OnLspSolutionChanged; - } } public async Task TryEnqueueRefreshComputationAsync(Project project, CancellationToken cancellationToken) { - if (_semanticTokenRefreshQueue is not null) - { - // Determine the checksum for this project cone. Note: this should be fast in practice because this is the - // same project-cone-checksum we used to even call into OOP above when we computed semantic tokens. - var projectChecksum = await project.Solution.CompilationState.GetChecksumAsync(project.Id, cancellationToken).ConfigureAwait(false); + // Determine the checksum for this project cone. Note: this should be fast in practice because this is the + // same project-cone-checksum we used to even call into OOP above when we computed semantic tokens. + var projectChecksum = await project.Solution.CompilationState.GetChecksumAsync(project.Id, cancellationToken).ConfigureAwait(false); - lock (_gate) - { - // If this checksum is the same as the last computed result, no need to continue, we would not produce a - // different compilation. - if (_projectIdToLastComputedChecksum.TryGetValue(project.Id, out var lastChecksum) && lastChecksum == projectChecksum) - return; - - // keep track of this checksum. That way we don't get into a loop where we send a refresh notification, - // then we get called back into, causing us to compute the compilation, causing us to send the refresh - // notification, etc. etc. - _projectIdToLastComputedChecksum[project.Id] = projectChecksum; - - } + lock (_gate) + { + // If this checksum is the same as the last computed result, no need to continue, we would not produce a + // different compilation. + if (_projectIdToLastComputedChecksum.TryGetValue(project.Id, out var lastChecksum) && lastChecksum == projectChecksum) + return; - EnqueueSemanticTokenRefreshNotification(documentUri: null); - } - } + // keep track of this checksum. That way we don't get into a loop where we send a refresh notification, + // then we get called back into, causing us to compute the compilation, causing us to send the refresh + // notification, etc. etc. + _projectIdToLastComputedChecksum[project.Id] = projectChecksum; - private ValueTask FilterLspTrackedDocumentsAsync( - ImmutableSegmentedList documentUris, - CancellationToken cancellationToken) - { - var trackedDocuments = _lspWorkspaceManager.GetTrackedLspText(); - foreach (var documentUri in documentUris) - { - if (documentUri is null || !trackedDocuments.ContainsKey(documentUri)) - return _notificationManager.SendRequestAsync(Methods.WorkspaceSemanticTokensRefreshName, cancellationToken); } - // LSP is already tracking all changed documents so we don't need to send a refresh request. - return ValueTaskFactory.CompletedTask; + EnqueueRefreshNotification(documentUri: null); } - private void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e) + protected override void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e) { Uri? documentUri = null; @@ -173,7 +96,7 @@ private void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e) } } - EnqueueSemanticTokenRefreshNotification(documentUri); + EnqueueRefreshNotification(documentUri); } // Duplicated from Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.LoadedProject.TreatAsIsDynamicFile @@ -183,21 +106,9 @@ private static bool DisallowsAdditionalDocumentChangedRefreshes(string? filePath return extension is ".cshtml" or ".razor"; } - private void EnqueueSemanticTokenRefreshNotification(Uri? documentUri) - { - // We should have only gotten here if semantic tokens refresh is supported and initialized. - Contract.ThrowIfNull(_semanticTokenRefreshQueue); - _semanticTokenRefreshQueue.AddWork(documentUri); - } + protected override string GetFeatureAttribute() => FeatureAttribute.Classification; - public void Dispose() - { - lock (_gate) - { - _lspWorkspaceRegistrationService.LspSolutionChanged -= OnLspSolutionChanged; - } + protected override bool? GetRefreshSupport(ClientCapabilities clientCapabilities) => clientCapabilities.Workspace?.SemanticTokens?.RefreshSupport; - _disposalTokenSource.Cancel(); - _disposalTokenSource.Dispose(); - } + protected override string GetWorkspaceRefreshName() => Methods.WorkspaceSemanticTokensRefreshName; } diff --git a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueueFactory.cs b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueueFactory.cs index e798d7a3cbfc8..803d0a5e0f7d2 100644 --- a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueueFactory.cs +++ b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueueFactory.cs @@ -29,9 +29,8 @@ public ILspService CreateILspService(LspServices lspServices, WellKnownLspServer { var notificationManager = lspServices.GetRequiredService(); var lspWorkspaceManager = lspServices.GetRequiredService(); - var capabilitiesProvider = lspServices.GetRequiredService(); - return new SemanticTokensRefreshQueue(_asyncListenerProvider, _lspWorkspaceRegistrationService, lspWorkspaceManager, notificationManager, capabilitiesProvider); + return new SemanticTokensRefreshQueue(_asyncListenerProvider, _lspWorkspaceRegistrationService, lspWorkspaceManager, notificationManager); } } } diff --git a/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs b/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs index a9a782fe910a7..055fba092cd05 100644 --- a/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs +++ b/src/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs @@ -80,7 +80,7 @@ internal class SignatureHelpHandler(SignatureHelpService signatureHelpService) : var sigHelp = new LSP.SignatureHelp { ActiveSignature = GetActiveSignature(sigItems), - ActiveParameter = sigItems.ArgumentIndex, + ActiveParameter = sigItems.SemanticParameterIndex, Signatures = sigInfos.ToArray() }; @@ -100,7 +100,8 @@ private static int GetActiveSignature(SignatureHelpItems items) // However, the LSP spec expects the language server to make this decision. // So implement the logic of picking a signature that has enough arguments here. - var matchingSignature = items.Items.FirstOrDefault(sig => sig.Parameters.Length > items.ArgumentIndex); + var matchingSignature = items.Items.FirstOrDefault( + sig => sig.Parameters.Length > items.SemanticParameterIndex); return matchingSignature != null ? items.Items.IndexOf(matchingSignature) : 0; } @@ -135,9 +136,10 @@ private static string GetSignatureText(SignatureHelpItem item) return sb.ToString(); } + private static ClassifiedTextElement GetSignatureClassifiedText(SignatureHelpItem item) { - var taggedTexts = new ArrayBuilder(); + using var _ = ArrayBuilder.GetInstance(out var taggedTexts); taggedTexts.AddRange(item.PrefixDisplayParts); @@ -159,7 +161,7 @@ private static ClassifiedTextElement GetSignatureClassifiedText(SignatureHelpIte taggedTexts.AddRange(item.SuffixDisplayParts); taggedTexts.AddRange(item.DescriptionParts); - return new ClassifiedTextElement(taggedTexts.ToArrayAndFree().Select(part => new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text))); + return new ClassifiedTextElement(taggedTexts.ToArray().Select(part => new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text))); } } } diff --git a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentGetTextHandler.cs b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentGetTextHandler.cs new file mode 100644 index 0000000000000..31402aaa61f25 --- /dev/null +++ b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentGetTextHandler.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Roslyn.Utilities; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler; + +[ExportCSharpVisualBasicStatelessLspService(typeof(SourceGeneratedDocumentGetTextHandler)), Shared] +[Method(MethodName)] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class SourceGeneratedDocumentGetTextHandler() : ILspServiceDocumentRequestHandler +{ + public const string MethodName = "sourceGeneratedDocument/_roslyn_getText"; + + public bool MutatesSolutionState => false; + public bool RequiresLSPSolution => true; + + public LSP.TextDocumentIdentifier GetTextDocumentIdentifier(SourceGeneratorGetTextParams request) => request.TextDocument; + + public async Task HandleRequestAsync(SourceGeneratorGetTextParams request, RequestContext context, CancellationToken cancellationToken) + { + var document = context.Document; + + // Nothing here strictly prevents this from working on any other document, but we'll assert we got a source-generated file, since + // it wouldn't really make sense for the server to be asked for the contents of a regular file. Since this endpoint is intended for + // source-generated files only, this would indicate that something else has gone wrong. + Contract.ThrowIfFalse(document is SourceGeneratedDocument); + + // When a user has a open source-generated file, we ensure that the contents in the LSP snapshot match the contents that we + // get through didOpen/didChanges, like any other file. That way operations in LSP file are in sync with the + // contents the user has. However in this case, we don't want to look at that frozen text, but look at what the + // generator would generate if we ran it again. Otherwise, we'll get "stuck" and never update the file with something new. + document = await document.Project.Solution.WithoutFrozenSourceGeneratedDocuments().GetDocumentAsync(document.Id, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + + var text = document != null ? await document.GetTextAsync(cancellationToken).ConfigureAwait(false) : null; + return new SourceGeneratedDocumentText(text?.ToString()); + } +} diff --git a/src/Compilers/RealParserTests/CLibraryShim/CLibraryShim.h b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentText.cs similarity index 50% rename from src/Compilers/RealParserTests/CLibraryShim/CLibraryShim.h rename to src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentText.cs index 7070918a7de6f..17c1105a0870e 100644 --- a/src/Compilers/RealParserTests/CLibraryShim/CLibraryShim.h +++ b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratedDocumentText.cs @@ -2,16 +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. -#pragma once +using System.Text.Json.Serialization; -using namespace System; +namespace Microsoft.CodeAnalysis.LanguageServer.Handler; -namespace CLibraryShim { - - public ref class RealConversions - { - public: - static double atod(String^ s); - static float atof(String^ s); - }; -} +internal sealed record SourceGeneratedDocumentText([property: JsonPropertyName("text")] string? Text); \ No newline at end of file diff --git a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorGetTextParams.cs b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorGetTextParams.cs new file mode 100644 index 0000000000000..f930f1cc438c0 --- /dev/null +++ b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorGetTextParams.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler; + +internal sealed record SourceGeneratorGetTextParams([property: JsonPropertyName("textDocument")] TextDocumentIdentifier TextDocument) : ITextDocumentParams; \ No newline at end of file diff --git a/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs b/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs index f63aed313296e..927be98a4b8c7 100644 --- a/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs +++ b/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs @@ -74,12 +74,12 @@ protected AbstractSpellCheckHandler() // First, let the client know if any workspace documents have gone away. That way it can remove those for // the user from squiggles or error-list. - HandleRemovedDocuments(context, previousResults, progress); + await HandleRemovedDocumentsAsync(context, previousResults, progress, cancellationToken).ConfigureAwait(false); // Create a mapping from documents to the previous results the client says it has for them. That way as we // process documents we know if we should tell the client it should stay the same, or we can tell it what // the updated spans are. - var documentToPreviousParams = GetDocumentToPreviousParams(context, previousResults); + var documentToPreviousParams = await GetDocumentToPreviousParamsAsync(context, previousResults, cancellationToken).ConfigureAwait(false); // Next process each file in priority order. Determine if spans are changed or unchanged since the // last time we notified the client. Report back either to the client so they can update accordingly. @@ -129,8 +129,8 @@ protected AbstractSpellCheckHandler() return progress.GetFlattenedValues(); } - private static Dictionary GetDocumentToPreviousParams( - RequestContext context, ImmutableArray previousResults) + private static async Task> GetDocumentToPreviousParamsAsync( + RequestContext context, ImmutableArray previousResults, CancellationToken cancellationToken) { Contract.ThrowIfNull(context.Solution); @@ -139,7 +139,7 @@ private static Dictionary GetDocumentToPreviousPar { if (requestParams.TextDocument != null) { - var document = context.Solution.GetDocument(requestParams.TextDocument); + var document = await context.Solution.GetDocumentAsync(requestParams.TextDocument, cancellationToken).ConfigureAwait(false); if (document != null) result[document] = requestParams; } @@ -156,7 +156,6 @@ private async IAsyncEnumerable ComputeAndReportCurrentSpansAsync( { var textDocumentIdentifier = ProtocolConversions.DocumentToTextDocumentIdentifier(document); - var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); var spans = await service.GetSpansAsync(document, cancellationToken).ConfigureAwait(false); // protocol requires the results be in sorted order @@ -186,13 +185,7 @@ private async IAsyncEnumerable ComputeAndReportCurrentSpansAsync( { var span = spans[i]; - var kind = span.Kind switch - { - SpellCheckKind.Identifier => VSInternalSpellCheckableRangeKind.Identifier, - SpellCheckKind.Comment => VSInternalSpellCheckableRangeKind.Comment, - SpellCheckKind.String => VSInternalSpellCheckableRangeKind.String, - _ => throw ExceptionUtilities.UnexpectedValue(span.Kind), - }; + var kind = ProtocolConversions.SpellCheckSpanKindToSpellCheckableRangeKind(span.Kind); triples[triplesIndex++] = (int)kind; triples[triplesIndex++] = span.TextSpan.Start - lastSpanEnd; @@ -206,8 +199,8 @@ private async IAsyncEnumerable ComputeAndReportCurrentSpansAsync( } } - private void HandleRemovedDocuments( - RequestContext context, ImmutableArray previousResults, BufferedProgress progress) + private async Task HandleRemovedDocumentsAsync( + RequestContext context, ImmutableArray previousResults, BufferedProgress progress, CancellationToken cancellationToken) { Contract.ThrowIfNull(context.Solution); @@ -216,7 +209,7 @@ private void HandleRemovedDocuments( var textDocument = previousResult.TextDocument; if (textDocument != null) { - var document = context.Solution.GetDocument(textDocument); + var document = await context.Solution.GetTextDocumentAsync(textDocument, cancellationToken).ConfigureAwait(false); if (document == null) { context.TraceInformation($"Clearing spans for removed document: {textDocument.Uri}"); diff --git a/src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs b/src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs index d9cd5fa1a5768..30bc2e6e620e3 100644 --- a/src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs @@ -25,7 +25,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler /// [ExportCSharpVisualBasicStatelessLspService(typeof(DocumentSymbolsHandler)), Shared] [Method(Methods.TextDocumentDocumentSymbolName)] - internal sealed class DocumentSymbolsHandler : ILspServiceDocumentRequestHandler + internal sealed class DocumentSymbolsHandler : ILspServiceDocumentRequestHandler> { public bool MutatesSolutionState => false; public bool RequiresLSPSolution => true; @@ -38,62 +38,68 @@ public DocumentSymbolsHandler() public TextDocumentIdentifier GetTextDocumentIdentifier(RoslynDocumentSymbolParams request) => request.TextDocument; - public async Task HandleRequestAsync(RoslynDocumentSymbolParams request, RequestContext context, CancellationToken cancellationToken) + public Task> HandleRequestAsync( + RoslynDocumentSymbolParams request, RequestContext context, CancellationToken cancellationToken) { var document = context.GetRequiredDocument(); var clientCapabilities = context.GetRequiredClientCapabilities(); + var useHierarchicalSymbols = clientCapabilities.TextDocument?.DocumentSymbol?.HierarchicalDocumentSymbolSupport == true || request.UseHierarchicalSymbols; + var supportsVSExtensions = clientCapabilities.HasVisualStudioLspCapability(); + return GetDocumentSymbolsAsync(document, useHierarchicalSymbols, supportsVSExtensions, cancellationToken); + } + + internal static async Task> GetDocumentSymbolsAsync( + Document document, bool useHierarchicalSymbols, bool supportsVSExtensions, CancellationToken cancellationToken) + { var navBarService = document.Project.Services.GetRequiredService(); var navBarItems = await navBarService.GetItemsAsync(document, supportsCodeGeneration: false, frozenPartialSemantics: false, cancellationToken).ConfigureAwait(false); if (navBarItems.IsEmpty) - return []; + return Array.Empty(); var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); - - // TODO - Return more than 2 levels of symbols. - // https://github.com/dotnet/roslyn/projects/45#card-20033869 - using var _ = ArrayBuilder.GetInstance(out var symbols); - if (clientCapabilities.TextDocument?.DocumentSymbol?.HierarchicalDocumentSymbolSupport == true || request.UseHierarchicalSymbols) + if (useHierarchicalSymbols) { + using var _ = ArrayBuilder.GetInstance(out var symbols); // only top level ones foreach (var item in navBarItems) symbols.AddIfNotNull(GetDocumentSymbol(item, text, cancellationToken)); + + return symbols.ToArray(); } else { + using var _ = ArrayBuilder.GetInstance(out var symbols); foreach (var item in navBarItems) { - symbols.AddIfNotNull(GetSymbolInformation(item, document, text, containerName: null)); + symbols.AddIfNotNull(GetSymbolInformation(item, document, text, containerName: null, supportsVSExtensions)); foreach (var childItem in item.ChildItems) - symbols.AddIfNotNull(GetSymbolInformation(childItem, document, text, item.Text)); + symbols.AddIfNotNull(GetSymbolInformation(childItem, document, text, item.Text, supportsVSExtensions)); } - } - var result = symbols.ToArray(); - return result; + return symbols.ToArray(); + } } /// /// Get a symbol information from a specified nav bar item. /// private static SymbolInformation? GetSymbolInformation( - RoslynNavigationBarItem item, Document document, SourceText text, string? containerName = null) + RoslynNavigationBarItem item, Document document, SourceText text, string? containerName, bool supportsVSExtensions) { if (item is not RoslynNavigationBarItem.SymbolItem symbolItem || symbolItem.Location.InDocumentInfo == null) return null; - var service = document.Project.Solution.Services.GetRequiredService(); - return service.Create( - GetDocumentSymbolName(item.Text), - containerName, - ProtocolConversions.GlyphToSymbolKind(item.Glyph), - new LSP.Location - { - Uri = document.GetURI(), - Range = ProtocolConversions.TextSpanToRange(symbolItem.Location.InDocumentInfo.Value.navigationSpan, text), - }, - item.Glyph); + var name = GetDocumentSymbolName(item.Text); + var kind = ProtocolConversions.GlyphToSymbolKind(item.Glyph); + var location = new LSP.Location() + { + Uri = document.GetURI(), + Range = ProtocolConversions.TextSpanToRange(symbolItem.Location.InDocumentInfo.Value.navigationSpan, text), + }; + + return SymbolInformationFactory.Create(name, containerName, kind, location, item.Glyph, supportsVSExtensions); } /// @@ -118,7 +124,9 @@ public async Task HandleRequestAsync(RoslynDocumentSymbolParams reques Detail = item.Text, Kind = ProtocolConversions.GlyphToSymbolKind(item.Glyph), Glyph = (int)item.Glyph, +#pragma warning disable CS0618 // SymbolInformation.Deprecated is obsolete, use Tags Deprecated = symbolItem.IsObsolete, +#pragma warning restore CS0618 Range = ProtocolConversions.TextSpanToRange(spans.First(), text), SelectionRange = ProtocolConversions.TextSpanToRange(navigationSpan, text), Children = GetChildren(item.ChildItems, text, cancellationToken), diff --git a/src/LanguageServer/Protocol/Handler/Symbols/ILspSymbolInformationCreationService.cs b/src/LanguageServer/Protocol/Handler/Symbols/ILspSymbolInformationCreationService.cs deleted file mode 100644 index ebc72add98679..0000000000000 --- a/src/LanguageServer/Protocol/Handler/Symbols/ILspSymbolInformationCreationService.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.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using Roslyn.LanguageServer.Protocol; -using LSP = Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.Handler -{ - internal interface ILspSymbolInformationCreationService : IWorkspaceService - { - SymbolInformation Create( - string name, string? containerName, LSP.SymbolKind kind, LSP.Location location, Glyph glyph); - } - - [ExportWorkspaceService(typeof(ILspSymbolInformationCreationService)), Shared] - internal sealed class DefaultLspSymbolInformationCreationService : ILspSymbolInformationCreationService - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public DefaultLspSymbolInformationCreationService() - { - } - - public SymbolInformation Create(string name, string? containerName, LSP.SymbolKind kind, LSP.Location location, Glyph glyph) - => new() - { - Name = name, - ContainerName = containerName, - Kind = kind, - Location = location, - }; - } -} diff --git a/src/LanguageServer/Protocol/Handler/Symbols/SymbolInformationFactory.cs b/src/LanguageServer/Protocol/Handler/Symbols/SymbolInformationFactory.cs new file mode 100644 index 0000000000000..ac9290bf64c4d --- /dev/null +++ b/src/LanguageServer/Protocol/Handler/Symbols/SymbolInformationFactory.cs @@ -0,0 +1,41 @@ +// 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.LanguageServer.Protocol; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler +{ + internal static class SymbolInformationFactory + { + public static SymbolInformation Create(string name, string? containerName, LSP.SymbolKind kind, LSP.Location location, Glyph glyph, bool supportsVSExtensions) + { + if (supportsVSExtensions) + { +#pragma warning disable CS0618 // SymbolInformation is obsolete, need to switch to DocumentSymbol/WorkspaceSymbol + return new VSSymbolInformation + { + Name = name, + ContainerName = containerName, + Kind = kind, + Location = location, + Icon = glyph.ToVSImageId(), + }; +#pragma warning restore CS0618 + } + else + { +#pragma warning disable CS0618 // SymbolInformation is obsolete, need to switch to DocumentSymbol/WorkspaceSymbol + return new SymbolInformation() + { + Name = name, + ContainerName = containerName, + Kind = kind, + Location = location + }; +#pragma warning restore CS0618 + } + } + } +} diff --git a/src/LanguageServer/Protocol/Handler/Symbols/WorkspaceSymbolsHandler.cs b/src/LanguageServer/Protocol/Handler/Symbols/WorkspaceSymbolsHandler.cs index f0ff5255f831b..196d9078ce86d 100644 --- a/src/LanguageServer/Protocol/Handler/Symbols/WorkspaceSymbolsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Symbols/WorkspaceSymbolsHandler.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Immutable; using System.Composition; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; @@ -24,7 +25,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] internal sealed class WorkspaceSymbolsHandler(IAsynchronousOperationListenerProvider listenerProvider) - : ILspServiceRequestHandler + : ILspServiceRequestHandler?> { private static readonly IImmutableSet s_supportedKinds = [ NavigateToItemKind.Class, @@ -46,13 +47,16 @@ internal sealed class WorkspaceSymbolsHandler(IAsynchronousOperationListenerProv public bool MutatesSolutionState => false; public bool RequiresLSPSolution => true; - public async Task HandleRequestAsync(WorkspaceSymbolParams request, RequestContext context, CancellationToken cancellationToken) + public async Task?> HandleRequestAsync(WorkspaceSymbolParams request, RequestContext context, CancellationToken cancellationToken) { Contract.ThrowIfNull(context.Solution); var solution = context.Solution; - using var progress = BufferedProgress.Create(request.PartialResultToken); + using var progress = BufferedProgress.Create( + request.PartialResultToken, + (SymbolInformation[] t) => new SumType(t)); + var searcher = NavigateToSearcher.Create( solution, _asyncListener, @@ -62,7 +66,7 @@ internal sealed class WorkspaceSymbolsHandler(IAsynchronousOperationListenerProv cancellationToken); await searcher.SearchAsync(NavigateToSearchScope.Solution, cancellationToken).ConfigureAwait(false); - return progress.GetFlattenedValues(); + return progress.GetValues()?.Flatten().ToArray(); } private sealed class LSPNavigateToCallback( @@ -75,6 +79,9 @@ public async Task AddResultsAsync(ImmutableArray result Contract.ThrowIfNull(context.Solution); var solution = context.Solution; + var clientCapabilities = context.GetRequiredClientCapabilities(); + var supportsVSExtensions = clientCapabilities.HasVisualStudioLspCapability(); + foreach (var result in results) { var document = await result.NavigableItem.Document.GetRequiredDocumentAsync(solution, cancellationToken).ConfigureAwait(false); @@ -84,9 +91,13 @@ public async Task AddResultsAsync(ImmutableArray result if (location == null) return; - var service = solution.Services.GetRequiredService(); - var symbolInfo = service.Create( - result.Name, result.AdditionalInformation, ProtocolConversions.NavigateToKindToSymbolKind(result.Kind), location, result.NavigableItem.Glyph); + var symbolInfo = SymbolInformationFactory.Create( + result.Name, + result.AdditionalInformation, + ProtocolConversions.NavigateToKindToSymbolKind(result.Kind), + location, + result.NavigableItem.Glyph, + supportsVSExtensions); progress.Report(symbolInfo); } diff --git a/src/LanguageServer/Protocol/ILanguageInfoProvider.cs b/src/LanguageServer/Protocol/ILanguageInfoProvider.cs index e6b81cbba6926..9673195278cdd 100644 --- a/src/LanguageServer/Protocol/ILanguageInfoProvider.cs +++ b/src/LanguageServer/Protocol/ILanguageInfoProvider.cs @@ -20,6 +20,6 @@ internal interface ILanguageInfoProvider : ILspService /// In that case, we use the language Id that the LSP client gave us. /// /// Thrown when the language information cannot be determined. - LanguageInformation GetLanguageInformation(string documentPath, string? lspLanguageId); + LanguageInformation GetLanguageInformation(Uri documentUri, string? lspLanguageId); } } diff --git a/src/LanguageServer/Protocol/LanguageInfoProvider.cs b/src/LanguageServer/Protocol/LanguageInfoProvider.cs index 6b5fbe623f777..0758584cad42f 100644 --- a/src/LanguageServer/Protocol/LanguageInfoProvider.cs +++ b/src/LanguageServer/Protocol/LanguageInfoProvider.cs @@ -43,24 +43,31 @@ internal class LanguageInfoProvider : ILanguageInfoProvider { ".mts", s_typeScriptLanguageInformation }, }; - public LanguageInformation GetLanguageInformation(string documentPath, string? lspLanguageId) + public LanguageInformation GetLanguageInformation(Uri uri, string? lspLanguageId) { - var extension = Path.GetExtension(documentPath); - if (s_extensionToLanguageInformation.TryGetValue(extension, out var languageInformation)) + // First try to get language information from the URI path. + // We can do this for File uris and absolute uris. We use local path to get the value without any query parameters. + if (uri.IsFile || uri.IsAbsoluteUri) { - return languageInformation; + var localPath = uri.LocalPath; + var extension = Path.GetExtension(localPath); + if (s_extensionToLanguageInformation.TryGetValue(extension, out var languageInformation)) + { + return languageInformation; + } } + // If the URI file path mapping failed, use the languageId from the LSP client (if any). return lspLanguageId switch { "csharp" => s_csharpLanguageInformation, - "fsharp" => s_csharpLanguageInformation, + "fsharp" => s_fsharpLanguageInformation, "vb" => s_vbLanguageInformation, "razor" => s_razorLanguageInformation, "xaml" => s_xamlLanguageInformation, "typescript" => s_typeScriptLanguageInformation, "javascript" => s_typeScriptLanguageInformation, - _ => throw new InvalidOperationException($"Unsupported extension '{extension}' and LSP language id '{lspLanguageId}'") + _ => throw new InvalidOperationException($"Unable to determine language for '{uri}' with LSP language id '{lspLanguageId}'") }; } } diff --git a/src/LanguageServer/Protocol/LanguageServerProtocolResources.Designer.cs b/src/LanguageServer/Protocol/LanguageServerProtocolResources.Designer.cs index 3497173ee3129..43d11a5dc023f 100644 --- a/src/LanguageServer/Protocol/LanguageServerProtocolResources.Designer.cs +++ b/src/LanguageServer/Protocol/LanguageServerProtocolResources.Designer.cs @@ -122,5 +122,38 @@ internal static string TextDocumentSyncSerializationError { return ResourceManager.GetString("TextDocumentSyncSerializationError", resourceCulture); } } + + /// + /// Looks up a localized string similar to Unable to deserialize FormattingOptions. Invalid token: {0}. + /// + internal static string FormattingOptionsEncounteredInvalidToken + { + get + { + return ResourceManager.GetString("FormattingOptionsEncounteredInvalidToken", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to deserialize FormattingOptions as it ended unexpectedly. + /// + internal static string FormattingOptionsEndedUnexpectedly + { + get + { + return ResourceManager.GetString("FormattingOptionsEndedUnexpectedly", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to deserialize FormattingOptions. Missing required property: {0}. + /// + internal static string FormattingOptionsMissingRequiredProperty + { + get + { + return ResourceManager.GetString("FormattingOptionsMissingRequiredProperty", resourceCulture); + } + } } } diff --git a/src/LanguageServer/Protocol/LanguageServerProtocolResources.resx b/src/LanguageServer/Protocol/LanguageServerProtocolResources.resx index 7dc4d9c00c182..b644ddb0186f8 100644 --- a/src/LanguageServer/Protocol/LanguageServerProtocolResources.resx +++ b/src/LanguageServer/Protocol/LanguageServerProtocolResources.resx @@ -101,6 +101,15 @@ Unable to deserialize Uri. Unexpected value encountered: {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + + + Unable to deserialize FormattingOptions as it ended unexpectedly + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Unable to deserialize MarkupContent. Unexpected value encountered: {0} diff --git a/src/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj b/src/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj index c85748a90fe20..73945f4ec700e 100644 --- a/src/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj +++ b/src/LanguageServer/Protocol/Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj @@ -37,9 +37,12 @@ - + + + + diff --git a/src/LanguageServer/Protocol/Protocol/AnnotatedTextEdit.cs b/src/LanguageServer/Protocol/Protocol/AnnotatedTextEdit.cs new file mode 100644 index 0000000000000..d24e1a5554dfd --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/AnnotatedTextEdit.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Class which represents a text edit with a change annotation +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class AnnotatedTextEdit : TextEdit +{ + /// + /// The annotation identifier. + /// + [JsonPropertyName("annotationId")] + [JsonRequired] + public ChangeAnnotationIdentifier AnnotationId { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/ApplyWorkspaceEditParams.cs b/src/LanguageServer/Protocol/Protocol/ApplyWorkspaceEditParams.cs index 2ede34011caaf..92f63f409781b 100644 --- a/src/LanguageServer/Protocol/Protocol/ApplyWorkspaceEditParams.cs +++ b/src/LanguageServer/Protocol/Protocol/ApplyWorkspaceEditParams.cs @@ -14,7 +14,9 @@ namespace Roslyn.LanguageServer.Protocol internal class ApplyWorkspaceEditParams { /// - /// Gets or sets the label associated with this edit. + /// An optional label of the workspace edit. This label is + /// presented in the user interface for example on an undo + /// stack to undo the workspace edit. /// [JsonPropertyName("label")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -25,9 +27,10 @@ public string? Label } /// - /// Gets or sets the edit to be applied to the workspace. + /// The edits to apply. /// [JsonPropertyName("edit")] + [JsonRequired] public WorkspaceEdit Edit { get; diff --git a/src/LanguageServer/Protocol/Protocol/ApplyWorkspaceEditResponse.cs b/src/LanguageServer/Protocol/Protocol/ApplyWorkspaceEditResponse.cs index 0fb22929337ba..98a99cba03de6 100644 --- a/src/LanguageServer/Protocol/Protocol/ApplyWorkspaceEditResponse.cs +++ b/src/LanguageServer/Protocol/Protocol/ApplyWorkspaceEditResponse.cs @@ -7,32 +7,40 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the response sent for a workspace/applyEdit request. - /// + /// Class representing the response sent for a workspace/applyEdit request. + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class ApplyWorkspaceEditResponse { /// - /// Gets or sets a value indicating whether edits were applied or not. + /// Indicates whether the edit was applied or not. /// [JsonPropertyName("applied")] - public bool Applied - { - get; - set; - } + [JsonRequired] + public bool Applied { get; set; } /// - /// Gets or sets a string with textual description for why the edit was not applied. + /// An optional textual description for why the edit was not applied. + /// + /// This may be used by the server for diagnostic logging or to provide + /// a suitable error for a request that triggered the edit. + /// /// [JsonPropertyName("failureReason")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? FailureReason - { - get; - set; - } + public string? FailureReason { get; set; } + + /// + /// Depending on the client's failure handling strategy this + /// might contain the index of the change that failed. + /// + /// This property is only available if the client signals a strategy in its client capabilities. + /// + /// + [JsonPropertyName("failedChange")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? FailedChange { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/ChangeAnnotation.cs b/src/LanguageServer/Protocol/Protocol/ChangeAnnotation.cs new file mode 100644 index 0000000000000..1004a68e0193e --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ChangeAnnotation.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Additional information that describes document changes +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// +/// Since LSP 3.16 +/// +internal class ChangeAnnotation +{ + /// + /// Human-readable string describing the change, rendered in the UI. + /// + [JsonPropertyName("label")] + [JsonRequired] + public string Label { get; init; } + + /// + /// Indicates whether user confirmation is needed before applying the change. + /// + [JsonPropertyName("needsConfirmation")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? NeedsConfirmation { get; init; } + + /// + /// Human-readable string describing the change, rendered in the UI less prominently than the . + /// + [JsonPropertyName("description")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Description { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/ChangeAnnotationIdentifier.cs b/src/LanguageServer/Protocol/Protocol/ChangeAnnotationIdentifier.cs new file mode 100644 index 0000000000000..f522f0bb6405b --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ChangeAnnotationIdentifier.cs @@ -0,0 +1,23 @@ +// 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.ComponentModel; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// An identifier referring to a change annotation managed by a workspace edit +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// +/// Since LSP 3.16 +/// +[JsonConverter(typeof(StringEnumConverter))] +[TypeConverter(typeof(StringEnumConverter.TypeConverter))] +internal readonly record struct ChangeAnnotationIdentifier(string Value) : IStringEnum +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/ChangeAnnotationSupport.cs b/src/LanguageServer/Protocol/Protocol/ChangeAnnotationSupport.cs new file mode 100644 index 0000000000000..8fa9d84712d5c --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ChangeAnnotationSupport.cs @@ -0,0 +1,23 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Describes how the client handles change annotations on workspace edits. +/// +/// Since LSP 3.16 +internal class ChangeAnnotationSupport +{ + /// + /// Whether the client groups edits with equal labels into tree nodes, + /// for instance all edits labelled with "Changes in Strings" would + /// be a tree node.. + /// + [JsonPropertyName("groupsOnLabel")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? GroupsOnLabel { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/ClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/ClientCapabilities.cs index ba9367aea66dd..1658f039aa594 100644 --- a/src/LanguageServer/Protocol/Protocol/ClientCapabilities.cs +++ b/src/LanguageServer/Protocol/Protocol/ClientCapabilities.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents client capabilities. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class ClientCapabilities { @@ -35,6 +36,29 @@ public TextDocumentClientCapabilities? TextDocument set; } + /// + /// Capabilities specific to the notebook document support. + /// + /// Since LSP 3.17 + [JsonPropertyName("notebook")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public NotebookDocumentClientCapabilities? Notebook { get; init; } + + /// + /// Window specific client capabilities. + /// + [JsonPropertyName("window")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public WindowClientCapabilities? Window { get; init; } + + /// + /// Capabilities specific to the notebook document support. + /// + /// Since LSP 3.17 + [JsonPropertyName("general")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public GeneralClientCapabilities? General { get; init; } + /// /// Gets or sets the experimental capabilities. /// diff --git a/src/LanguageServer/Protocol/Protocol/ClientInfo.cs b/src/LanguageServer/Protocol/Protocol/ClientInfo.cs new file mode 100644 index 0000000000000..6a79e0e0c72f4 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ClientInfo.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Information about the client +/// +/// Since LSP 3.16 +internal class ClientInfo +{ + /// + /// The client's name as defined by the client + /// + [JsonPropertyName("name")] + [JsonRequired] + public string Name { get; set; } + + /// + /// The client's version as defined by the client + /// + [JsonPropertyName("version")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Version { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/CodeAction.cs b/src/LanguageServer/Protocol/Protocol/CodeAction.cs index 9ac8ab11410e9..30a9e29ba7720 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeAction.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeAction.cs @@ -10,15 +10,17 @@ namespace Roslyn.LanguageServer.Protocol /// A class representing a change that can be performed in code. A CodeAction must either set /// or . If both are supplied, /// the edit will be applied first, then the command will be executed. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CodeAction { /// - /// Gets or sets the human readable title for this code action. + /// A short human readable title for this code action. /// [JsonPropertyName("title")] + [JsonRequired] public string Title { get; @@ -26,7 +28,7 @@ public string Title } /// - /// Gets or sets the kind of code action this instance represents. + /// The kind of the code action, used to filter code actions. /// [JsonPropertyName("kind")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -37,7 +39,7 @@ public CodeActionKind? Kind } /// - /// Gets or sets the diagnostics that this code action resolves. + /// The diagnostics that this code action resolves. /// [JsonPropertyName("diagnostics")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -47,6 +49,48 @@ public Diagnostic[]? Diagnostics set; } + /// + /// Marks this as a preferred action. Preferred actions are used by the + /// Auto Fix command and can be targeted by keybindings. + /// + /// A quick fix should be marked preferred if it properly addresses the + /// underlying error. A refactoring should be marked preferred if it is the + /// most reasonable choice of actions to take. + /// + /// + /// Since LSP 3.15 + [JsonPropertyName("preferred")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool IsPreferred { get; init; } + + /// + /// Marks that the code action cannot currently be applied. + /// + /// Clients should follow the following guidelines regarding disabled code + /// actions: + /// + /// + /// Disabled code actions are not shown in automatic lightbulbs code + /// action menus. + /// + /// + /// Disabled actions are shown as faded out in the code action menu when + /// the user request a more specific type of code action, such as + /// refactorings. + /// + /// + /// If the user has a keybinding that auto applies a code action and only + /// a disabled code actions are returned, the client should show the user + /// an error message with in the editor. + /// + /// + /// + /// + /// Since LSP 3.16 + [JsonPropertyName("disabled")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public CodeActionDisabledReason? Disabled { get; init; } + /// /// Gets or sets the workspace edit that this code action performs. /// @@ -59,7 +103,9 @@ public WorkspaceEdit? Edit } /// - /// Gets or sets the command that this code action executes. + /// A command this code action executes. If a code action + /// provides an edit and a command, first the edit is + /// executed and then the command. /// [JsonPropertyName("command")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -70,8 +116,10 @@ public Command? Command } /// - /// Gets or sets the data that will be resend to the server if the code action is selected to be resolved. + /// Data field that is preserved on a code action between a textDocument/codeAction request + /// and a codeAction/resolve request. /// + /// Since LSP 3.16 [JsonPropertyName("data")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public object? Data diff --git a/src/LanguageServer/Protocol/Protocol/CodeActionContext.cs b/src/LanguageServer/Protocol/Protocol/CodeActionContext.cs index e40c24c7a3bd6..f5a142522b6ca 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeActionContext.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeActionContext.cs @@ -8,15 +8,24 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing diagnostic information about the context of a code action - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CodeActionContext { /// - /// Gets or sets an array of diagnostics relevant to a code action. + /// An array of diagnostics known on the client side overlapping the range + /// provided to the textDocument/codeAction request. + /// + /// They are provided so that the server knows which errors are currently + /// presented to the user for the given range. There is no guarantee that + /// these accurately reflect the error state of the resource. The primary + /// parameter to compute code actions is the provided range. + /// /// [JsonPropertyName("diagnostics")] + [JsonRequired] public Diagnostic[] Diagnostics { get; @@ -24,7 +33,11 @@ public Diagnostic[] Diagnostics } /// - /// Gets or sets an array of code action kinds to filter for. + /// Requested kinds of actions to return. + /// + /// Actions not of this kind are filtered out by the client before being + /// shown, so servers can omit computing them. + /// /// [JsonPropertyName("only")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -37,6 +50,7 @@ public CodeActionKind[]? Only /// /// Gets or sets the indicating how the code action was triggered.. /// + /// Since LSP 3.17 [JsonPropertyName("triggerKind")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public CodeActionTriggerKind? TriggerKind diff --git a/src/LanguageServer/Protocol/Protocol/CodeActionDisabledReason.cs b/src/LanguageServer/Protocol/Protocol/CodeActionDisabledReason.cs new file mode 100644 index 0000000000000..7ae88a629cb98 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/CodeActionDisabledReason.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Indicates why a code action is disabled +/// +class CodeActionDisabledReason +{ + + /// + /// Human readable description of why the code action is currently + /// disabled. + /// + /// This is displayed in the code actions UI. + /// + /// + [JsonPropertyName("reason")] + [JsonRequired] + public string Reason { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/CodeActionKind.cs b/src/LanguageServer/Protocol/Protocol/CodeActionKind.cs index c6c8663e284b2..30b31542d4c09 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeActionKind.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeActionKind.cs @@ -9,8 +9,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Value representing the kind of a code action. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// [JsonConverter(typeof(StringEnumConverter))] [TypeConverter(typeof(StringEnumConverter.TypeConverter))] @@ -62,10 +63,13 @@ internal readonly record struct CodeActionKind(string Value) : IStringEnum /// /// Base kind for a fix all source action, which automatically fixes errors that have a clear /// fix that do not require user input. - /// - /// + /// /// They should not suppress errors or perform unsafe fixes such as generating new /// types or classes. + /// + /// + /// + /// Since LSP 3.17 /// public static readonly CodeActionKind SourceFixAll = new("source.fixAll"); } diff --git a/src/LanguageServer/Protocol/Protocol/CodeActionKindSetting.cs b/src/LanguageServer/Protocol/Protocol/CodeActionKindSetting.cs index 03806a7c4c696..fc4bdf623f4cf 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeActionKindSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeActionKindSetting.cs @@ -7,16 +7,19 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class containing the set of code action kinds that are supported. - /// + /// Represents the code action kinds that are supported by the client. + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.8 internal class CodeActionKindSetting { /// /// Gets or sets the code actions kinds the client supports. /// [JsonPropertyName("valueSet")] + [JsonRequired] public CodeActionKind[] ValueSet { get; diff --git a/src/LanguageServer/Protocol/Protocol/CodeActionLiteralSetting.cs b/src/LanguageServer/Protocol/Protocol/CodeActionLiteralSetting.cs index adc2cf397db90..9926693d1efc5 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeActionLiteralSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeActionLiteralSetting.cs @@ -7,16 +7,19 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing support for code action literals. - /// + /// Represents the client's support for code action literals in the response of the textDocument/codeAction request + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.8 internal class CodeActionLiteralSetting { /// /// Gets or sets a value indicating what code action kinds are supported. /// [JsonPropertyName("codeActionKind")] + [JsonRequired] public CodeActionKindSetting CodeActionKind { get; diff --git a/src/LanguageServer/Protocol/Protocol/CodeActionOptions.cs b/src/LanguageServer/Protocol/Protocol/CodeActionOptions.cs index e63a4852b80e8..7c1a6fda7106e 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeActionOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeActionOptions.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the registration options for code actions support. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CodeActionOptions : IWorkDoneProgressOptions { @@ -17,7 +18,7 @@ internal class CodeActionOptions : IWorkDoneProgressOptions /// Gets or sets the kinds of code action that this server may return. /// /// - /// The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server + /// The list of kinds may be generic, such as , or the server /// may list out every specific kind they provide. /// [JsonPropertyName("codeActionKinds")] @@ -28,17 +29,11 @@ public CodeActionKind[]? CodeActionKinds set; } - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// - [JsonPropertyName("workDoneProgress")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool WorkDoneProgress { get; init; } - /// /// Gets or sets a value indicating whether the server provides support to resolve /// additional information for a code action. /// + /// Since LSP 3.16 [JsonPropertyName("resolveProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool ResolveProvider @@ -46,5 +41,12 @@ public bool ResolveProvider get; set; } + + /// + /// Gets or sets a value indicating whether work done progress is supported. + /// + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/CodeActionParams.cs b/src/LanguageServer/Protocol/Protocol/CodeActionParams.cs index 70e9f70d93c4a..dbdd86bf00a2f 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeActionParams.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeActionParams.cs @@ -4,19 +4,22 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// /// Class representing the parameters sent from the client to the server for the textDocument/codeAction request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class CodeActionParams : ITextDocumentParams + internal class CodeActionParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams[]> { /// /// Gets or sets the document identifier indicating where the command was invoked. /// [JsonPropertyName("textDocument")] + [JsonRequired] public TextDocumentIdentifier TextDocument { get; @@ -27,6 +30,7 @@ public TextDocumentIdentifier TextDocument /// Gets or sets the range in the document for which the command was invoked. /// [JsonPropertyName("range")] + [JsonRequired] public Range Range { get; @@ -37,10 +41,21 @@ public Range Range /// Gets or sets the additional diagnostic information about the code action context. /// [JsonPropertyName("context")] + [JsonRequired] public CodeActionContext Context { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress[]>? PartialResultToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/CodeActionRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/CodeActionRegistrationOptions.cs index 42fa86ac528f5..39c26e4b66c20 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeActionRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeActionRegistrationOptions.cs @@ -7,19 +7,15 @@ namespace Roslyn.LanguageServer.Protocol; /// -/// Class representing the registration options for code action support. -/// +/// Subclass of that allows scoping the registration. +/// /// See the Language Server Protocol specification for additional information. +/// /// internal class CodeActionRegistrationOptions : CodeActionOptions, ITextDocumentRegistrationOptions { - /// - /// Gets or sets the document filters for this registration option. - /// + /// [JsonPropertyName("documentSelector")] - public DocumentFilter[]? DocumentSelector - { - get; - set; - } -} \ No newline at end of file + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/CodeActionResolveSupportSetting.cs b/src/LanguageServer/Protocol/Protocol/CodeActionResolveSupportSetting.cs index 1d1280be4d074..40c9f18014529 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeActionResolveSupportSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeActionResolveSupportSetting.cs @@ -7,9 +7,10 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing settings for codeAction/resolve support. - /// + /// Client capabilities specific to the codeAction/resolve request. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CodeActionResolveSupportSetting { @@ -17,6 +18,7 @@ internal class CodeActionResolveSupportSetting /// Gets or sets a value indicating the properties that a client can resolve lazily. /// [JsonPropertyName("properties")] + [JsonRequired] public string[] Properties { get; diff --git a/src/LanguageServer/Protocol/Protocol/CodeActionSetting.cs b/src/LanguageServer/Protocol/Protocol/CodeActionSetting.cs index eba4e7a023559..a57146027e17b 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeActionSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeActionSetting.cs @@ -7,15 +7,18 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing settings for code action support. - /// + /// Client capabilities specific to code actions. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CodeActionSetting : DynamicRegistrationSetting { /// - /// Gets or sets a value indicating the client supports code action literals. + /// The client supports code action literals as a valid response of + /// the textDocument/codeAction request. /// + /// Since LSP 3.8 [JsonPropertyName("codeActionLiteralSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public CodeActionLiteralSetting? CodeActionLiteralSupport @@ -24,11 +27,42 @@ public CodeActionLiteralSetting? CodeActionLiteralSupport set; } + /// + /// Whether code action supports the property. + /// + /// Since LSP 3.15 + [JsonPropertyName("isPreferredSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool IsPreferredSupport { get; init; } + + /// + /// Whether code action supports the property. + /// + /// Since LSP 3.16 + [JsonPropertyName("disabledSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DisabledSupport { get; init; } + + /// + /// Gets or sets a value indicating whether code action supports the + /// property which is preserved between a `textDocument/codeAction` request and a + /// `codeAction/resolve` request. + /// + /// Since LSP 3.16 + [JsonPropertyName("dataSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DataSupport + { + get; + set; + } + /// /// Gets or sets a value indicating whether the client supports resolving - /// additional code action properties via a separate `codeAction/resolve` + /// additional code action properties via a separate codeAction/resolve /// request. /// + /// Since LSP 3.16 [JsonPropertyName("resolveSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public CodeActionResolveSupportSetting? ResolveSupport @@ -38,16 +72,14 @@ public CodeActionResolveSupportSetting? ResolveSupport } /// - /// Gets or sets a value indicating whether code action supports the `data` - /// property which is preserved between a `textDocument/codeAction` and a - /// `codeAction/resolve` request. + /// Whether the client honors the change annotations in text edits and + /// resource operations returned via the property by + /// for example presenting the workspace edit in the user interface and asking + /// for confirmation. /// - [JsonPropertyName("dataSupport")] + /// Since LSP 3.16 + [JsonPropertyName("honorsChangeAnnotations")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool DataSupport - { - get; - set; - } + public bool HonorsChangeAnnotations { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/CodeActionTriggerKind.cs b/src/LanguageServer/Protocol/Protocol/CodeActionTriggerKind.cs index ed48b55932d33..b1fb8c8276036 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeActionTriggerKind.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeActionTriggerKind.cs @@ -6,9 +6,11 @@ namespace Roslyn.LanguageServer.Protocol { /// /// Enum which represents the various reason why code actions were requested. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal enum CodeActionTriggerKind { /// @@ -18,8 +20,10 @@ internal enum CodeActionTriggerKind /// /// Code actions were requested automatically. + /// /// This typically happens when current selection in a file changes, but can also be triggered when file content changes. + /// /// Automatic = 2, } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/CodeDescription.cs b/src/LanguageServer/Protocol/Protocol/CodeDescription.cs index d7c414285753e..4ff525a766ad9 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeDescription.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeDescription.cs @@ -8,10 +8,12 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing a description for an error code. - /// + /// Class representing a description for an error code in a . + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class CodeDescription : IEquatable { /// diff --git a/src/LanguageServer/Protocol/Protocol/CodeLens.cs b/src/LanguageServer/Protocol/Protocol/CodeLens.cs index 4bec557ca0a10..0eed0ebdb61ac 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeLens.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeLens.cs @@ -7,16 +7,24 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// A class representing a code lens command that should be shown alongside source code. - /// + /// A code lens represents a command that should be shown along with + /// source text, like the number of references, a way to run tests, etc. + /// + /// A code lens is _unresolved_ when no command is associated to it. For + /// performance reasons the creation of a code lens and resolving should be done + /// in two stages. + /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CodeLens { /// - /// Gets or sets the range that the code lens applies to. + /// The range in which this code lens is valid. Should only span a single line. /// [JsonPropertyName("range")] + [JsonRequired] public Range Range { get; diff --git a/src/LanguageServer/Protocol/Protocol/CodeLensClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/CodeLensClientCapabilities.cs new file mode 100644 index 0000000000000..44155ed3ecb03 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/CodeLensClientCapabilities.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/codeLens` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class CodeLensClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/CodeLensOptions.cs b/src/LanguageServer/Protocol/Protocol/CodeLensOptions.cs index 22ac4b4cbfb1c..828344451bcb2 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeLensOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeLensOptions.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the options for code lens support. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CodeLensOptions : IWorkDoneProgressOptions { diff --git a/src/LanguageServer/Protocol/Protocol/CodeLensParams.cs b/src/LanguageServer/Protocol/Protocol/CodeLensParams.cs index a2ee3f149fbc2..0ae8e41263b34 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeLensParams.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeLensParams.cs @@ -4,14 +4,16 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// /// Class representing the parameters sent from the client to the server for a textDocument/codeLens request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class CodeLensParams : ITextDocumentParams + internal class CodeLensParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams { /// /// Gets or sets the document identifier to fetch code lens results for. @@ -22,5 +24,15 @@ public TextDocumentIdentifier TextDocument get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/CodeLensRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/CodeLensRegistrationOptions.cs new file mode 100644 index 0000000000000..e3c824ff2708d --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/CodeLensRegistrationOptions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class CodeLensRegistrationOptions : CodeLensOptions, ITextDocumentRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/CodeLensWorkspaceSetting.cs b/src/LanguageServer/Protocol/Protocol/CodeLensWorkspaceSetting.cs index 444bf3390dabe..2a2c6ab47cdbe 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeLensWorkspaceSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeLensWorkspaceSetting.cs @@ -7,14 +7,22 @@ namespace Roslyn.LanguageServer.Protocol { /// - /// Class representing the workspace code lens client capabilities. - /// - /// See the Language Server Protocol specification for additional information. + /// Client capabilities specific to the code lens requests scoped to the workspace. + /// + /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class CodeLensWorkspaceSetting { /// - /// Gets or sets a value indicating whether the client supports a refresh request sent from the server to the client. + /// Whether the client implementation supports a refresh request sent from the + /// server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// code lenses currently shown. It should be used with absolute care and is + /// useful for situation where a server for example detect a project wide + /// change that requires such a calculation. /// [JsonPropertyName("refreshSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] diff --git a/src/LanguageServer/Protocol/Protocol/Color.cs b/src/LanguageServer/Protocol/Protocol/Color.cs index 319d60cf17462..e6773cc7fa16a 100644 --- a/src/LanguageServer/Protocol/Protocol/Color.cs +++ b/src/LanguageServer/Protocol/Protocol/Color.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents a color. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.6 internal class Color { /// diff --git a/src/LanguageServer/Protocol/Protocol/ColorInformation.cs b/src/LanguageServer/Protocol/Protocol/ColorInformation.cs index a55e45f655455..3a9bca5c7ec44 100644 --- a/src/LanguageServer/Protocol/Protocol/ColorInformation.cs +++ b/src/LanguageServer/Protocol/Protocol/ColorInformation.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents color information. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.6 internal class ColorInformation { /// diff --git a/src/LanguageServer/Protocol/Protocol/ColorPresentation.cs b/src/LanguageServer/Protocol/Protocol/ColorPresentation.cs new file mode 100644 index 0000000000000..9e25164639dfd --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ColorPresentation.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A color presentation for a textDocument/colorPresentation response. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.6 +internal class ColorPresentation +{ + /// + /// The label of this color presentation. It will be shown on the color picker header. + /// + /// By default this is also the text that is inserted when selecting this color presentation. + /// + /// + [JsonPropertyName("label")] + [JsonRequired] + public string Label { get; init; } + + /// + /// A which is applied to a document when selecting this presentation for the color. + /// + /// When omitted the [label](#ColorPresentation.label) is used. + /// + /// + [JsonPropertyName("textEdit")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public TextEdit? TextEdit { get; init; } + + /// + /// An optional array of additional that are applied + /// when selecting this color presentation. + /// + /// Edits must not overlap with the main nor with themselves. + /// + /// + [JsonPropertyName("additionalTextEdits")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public TextEdit[]? AdditionalTextEdits { get; init; } + +} diff --git a/src/LanguageServer/Protocol/Protocol/ColorPresentationParams.cs b/src/LanguageServer/Protocol/Protocol/ColorPresentationParams.cs new file mode 100644 index 0000000000000..995bb06e90a56 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ColorPresentationParams.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Class representing the parameters sent for a textDocument/colorPresentation request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.6 +internal class ColorPresentationParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams +{ + /// + /// The text document. + /// + [JsonPropertyName("textDocument")] + [JsonRequired] + public TextDocumentIdentifier TextDocument { get; set; } + + /// + /// The color information to request presentations for. + /// + [JsonPropertyName("color")] + [JsonRequired] + public Color Color { get; init; } + + /// + /// The range where the color would be inserted. Serves as a context. + /// + [JsonPropertyName("range")] + [JsonRequired] + public Range Range { get; init; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/CompletionContext.cs b/src/LanguageServer/Protocol/Protocol/CompletionContext.cs index 6c674e6b35b65..912477d1aa16b 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionContext.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionContext.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing additional information about the content in which a completion request is triggered. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CompletionContext { @@ -17,6 +18,7 @@ internal class CompletionContext /// Gets or sets the indicating how the completion was triggered. /// [JsonPropertyName("triggerKind")] + [JsonRequired] public CompletionTriggerKind TriggerKind { get; @@ -24,7 +26,8 @@ public CompletionTriggerKind TriggerKind } /// - /// Gets or sets the character that triggered code completion. + /// The trigger character (a single character) that has triggered code completion. + /// Undefined when is not /// [JsonPropertyName("triggerCharacter")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -34,4 +37,4 @@ public string? TriggerCharacter set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/CompletionItem.cs b/src/LanguageServer/Protocol/Protocol/CompletionItem.cs index d795c27940feb..44c5b6e04bf3d 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionItem.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionItem.cs @@ -4,19 +4,29 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; /// /// Class which represents an IntelliSense completion item. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CompletionItem { /// - /// Gets or sets the label value, i.e. display text to users. + /// The label of this completion item. + /// + /// The label property is also by default the text that + /// is inserted when selecting this completion. + /// + /// + /// If label details are provided the label itself should + /// be an unqualified name of the completion item. + /// /// [JsonPropertyName("label")] [JsonRequired] @@ -27,8 +37,9 @@ public string Label } /// - /// Gets or sets additional details for the label. + /// Additional details for the label. /// + /// Since LSP 3.17 [JsonPropertyName("labelDetails")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public CompletionItemLabelDetails? LabelDetails @@ -38,7 +49,8 @@ public CompletionItemLabelDetails? LabelDetails } /// - /// Gets or sets the completion kind. + /// The kind of this completion item. Based on the kind + /// an icon is chosen by the editor. /// [JsonPropertyName("kind")] [SuppressMessage("Microsoft.StyleCop.CSharp.LayoutRules", "SA1513:ClosingCurlyBracketMustBeFollowedByBlankLine", Justification = "There are no issues with this code")] @@ -52,8 +64,9 @@ public CompletionItemKind Kind } = CompletionItemKind.None; /// - /// Tags for this completion item. + /// Tags for this completion item, which tweak the rendering of the item. /// + /// Since LSP 3.15 [JsonPropertyName("tags")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public CompletionItemTag[]? Tags @@ -63,7 +76,8 @@ public CompletionItemTag[]? Tags } /// - /// Gets or sets the completion detail. + /// A human-readable string with additional information + /// about this item, like type or symbol information /// [JsonPropertyName("detail")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -74,7 +88,7 @@ public string? Detail } /// - /// Gets or sets the documentation comment. + /// A human-readable string that represents a documentation comment /// [JsonPropertyName("documentation")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -85,7 +99,20 @@ public SumType? Documentation } /// - /// Gets or sets a value indicating whether this should be the selected item when showing. + /// Indicates whether this item is deprecated. + /// + [Obsolete("Use Tags instead if supported")] + [JsonPropertyName("deprecated")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool? Deprecated { get; set; } + + /// + /// Select this item when showing. + /// + /// Note that only one completion item can be selected and that the + /// tool / client decides which item that is. The rule is that the *first* + /// item of those that match best is selected + /// /// [JsonPropertyName("preselect")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -96,7 +123,9 @@ public bool Preselect } /// - /// Gets or sets the custom sort text. + /// A string that should be used when comparing this item + /// with other items. When omitted the label is used + /// as the sort text for this item. /// [JsonPropertyName("sortText")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -107,7 +136,9 @@ public string? SortText } /// - /// Gets or sets the custom filter text. + /// A string that should be used when filtering a set of + /// completion items. When omitted the label is used as the + /// filter text for this item. /// [JsonPropertyName("filterText")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -118,7 +149,19 @@ public string? FilterText } /// - /// Gets or sets the insert text. + /// A string that should be inserted into a document when selecting + /// this completion. When omitted the label is used as the insert text + /// for this item. + /// + /// The is subject to interpretation by the client side, + /// so it is recommended to use instead which avoids + /// client side interpretation. + /// + /// + /// For example in VS Code when code complete is requested for + /// con<cursor position> and an item with + /// console is selected, it will only insert sole. + /// /// [JsonPropertyName("insertText")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -129,7 +172,14 @@ public string? InsertText } /// - /// Gets or sets the insert text format. + /// The format of the insert text. If omitted, defaults to + /// + /// The format applies to both and the + /// property on . + /// + /// + /// Note that this does not apply to + /// /// [JsonPropertyName("insertTextFormat")] [SuppressMessage("Microsoft.StyleCop.CSharp.LayoutRules", "SA1513:ClosingCurlyBracketMustBeFollowedByBlankLine", Justification = "There are no issues with this code")] @@ -143,7 +193,34 @@ public InsertTextFormat InsertTextFormat } = InsertTextFormat.Plaintext; /// - /// Gets or sets the text edit. + /// How whitespace and indentation is handled during completion + /// item insertion. If not provided the client's default value depends on + /// the client capability. + /// + /// Since LSP 3.16 + [JsonPropertyName("insertTextMode")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public InsertTextMode? InsertTextMode { get; init; } + + /// + /// An edit which is applied to a document when selecting this completion. + /// When an edit is provided the value of is ignored. + /// + /// The must be single-line and must contain the position at which completion was requested. + /// + /// + /// Most editors support two different commit operations: insert completion text, + /// or replace existing text with completion text. This cannot usually be predetermined + /// by a server, so it can report both ranges using + /// if the client signals support via the + /// capability. + /// + /// + /// The + /// must be a prefix of the i.e. same start + /// position and contained within it. They must be single-line and must contain the + /// position at which completion was requested. + /// /// [JsonPropertyName("textEdit")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -154,8 +231,17 @@ public SumType? TextEdit } /// - /// Gets or sets the text edit text. + /// The edit text used if the completion item is part of a + /// that defines a default . + /// + /// Clients will only honor this property if they opt into completion list + /// item defaults using the capability . + /// + /// + /// If not provided, the is used. + /// /// + /// Since LSP 3.17 [JsonPropertyName("textEditText")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? TextEditText @@ -165,11 +251,18 @@ public string? TextEditText } /// - /// Gets or sets any additional text edits. + /// An optional array of additional text edits that are applied when + /// selecting this completion. + /// + /// Edits must not overlap (including the same + /// insert position) with the main edit nor with themselves. + /// + /// + /// Additional text edits should be used to change text unrelated to the + /// current cursor position (for example adding an import statement at the + /// top of the file). + /// /// - /// - /// Additional text edits must not interfere with the main text edit. - /// [JsonPropertyName("additionalTextEdits")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public TextEdit[]? AdditionalTextEdits @@ -179,7 +272,10 @@ public TextEdit[]? AdditionalTextEdits } /// - /// Gets or sets the set of characters that will commit completion when this is selected + /// An optional set of characters that will commit this item if typed while this completion is active. + /// The completion will be committed before inserting the typed character. + /// + /// /// If present, this will override . /// If absent, will be used instead. /// @@ -192,7 +288,11 @@ public string[]? CommitCharacters } /// - /// Gets or sets any optional command that will be executed after completion item insertion. + /// An optional command that is executed after inserting this completion. + /// + /// Note that additional modifications to the current document should instead be + /// described with . + /// /// /// /// This feature is not supported in VS. @@ -206,7 +306,8 @@ public Command? Command } /// - /// Gets or sets any additional data that links the unresolve completion item and the resolved completion item. + /// A data field that is preserved on a completion item between a completion + /// request and and a completion resolve request. /// [JsonPropertyName("data")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/CompletionItemKind.cs b/src/LanguageServer/Protocol/Protocol/CompletionItemKind.cs index 24a46531e3b3c..7fc57e37de689 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionItemKind.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionItemKind.cs @@ -6,8 +6,9 @@ namespace Roslyn.LanguageServer.Protocol { /// /// Enum values for completion item kinds. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal enum CompletionItemKind { @@ -148,26 +149,31 @@ internal enum CompletionItemKind /// /// Macro. /// + /// Specific to VS Macro = 118115 + 0, /// /// Namespace. /// + /// Specific to VS Namespace = 118115 + 1, /// /// Template. /// + /// Specific to VS Template = 118115 + 2, /// /// TypeDefinition. /// + /// Specific to VS TypeDefinition = 118115 + 3, /// /// Union. /// + /// Specific to VS Union = 118115 + 4, /// @@ -178,31 +184,37 @@ internal enum CompletionItemKind /// /// TagHelper. /// + /// Specific to VS TagHelper = 118115 + 6, /// /// ExtensionMethod. /// + /// Specific to VS ExtensionMethod = 118115 + 7, /// /// Element. /// + /// Specific to VS Element = 118115 + 8, /// /// LocalResource. /// + /// Specific to VS LocalResource = 118115 + 9, /// /// SystemResource. /// + /// Specific to VS SystemResource = 118115 + 10, /// /// CloseElement. /// + /// Specific to VS CloseElement = 118115 + 11, } } diff --git a/src/LanguageServer/Protocol/Protocol/CompletionItemKindSetting.cs b/src/LanguageServer/Protocol/Protocol/CompletionItemKindSetting.cs index b80c3219ce3fa..3c8992c63905d 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionItemKindSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionItemKindSetting.cs @@ -7,14 +7,26 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents the initialization setting for completion item kind - /// + /// Describes the values supported by the client + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CompletionItemKindSetting { /// /// Gets or sets the values that the client supports. + /// + /// The completion item kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + /// + /// + /// If this property is not present the client only supports the completion item + /// kinds from to + /// as defined in the initial version of the protocol. + /// /// [JsonPropertyName("valueSet")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -24,4 +36,4 @@ public CompletionItemKind[]? ValueSet set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/CompletionItemLabelDetails.cs b/src/LanguageServer/Protocol/Protocol/CompletionItemLabelDetails.cs index 9bac8f809f335..a14e8b8fc4463 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionItemLabelDetails.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionItemLabelDetails.cs @@ -8,13 +8,17 @@ namespace Roslyn.LanguageServer.Protocol /// /// Additional details for a completion item label. - /// - /// See the Language Server Protocol specification for additional information. + /// + /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal class CompletionItemLabelDetails { /// - /// Gets or sets an optional string which is rendered less prominently directly after label, without any spacing. + /// An optional string which is rendered less prominently directly after + /// , without any spacing. Should be + /// used for function signatures or type annotations. /// [JsonPropertyName("detail")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -25,7 +29,9 @@ public string? Detail } /// - /// Gets or sets an optional string which is rendered less prominently after detail. + /// Gets or sets an optional string which is rendered less prominently after + /// . Should be used for fully qualified + /// names or file path. /// [JsonPropertyName("description")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/CompletionItemOptions.cs b/src/LanguageServer/Protocol/Protocol/CompletionItemOptions.cs index 11d0c8cd77ad1..82f32140a15a8 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionItemOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionItemOptions.cs @@ -7,10 +7,12 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents completion item capabilities. - /// + /// Class which represents completion item server capabilities. + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal class CompletionItemOptions { /// diff --git a/src/LanguageServer/Protocol/Protocol/CompletionItemSetting.cs b/src/LanguageServer/Protocol/Protocol/CompletionItemSetting.cs index e5ca68bae6da4..4d2b552bd2f08 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionItemSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionItemSetting.cs @@ -4,17 +4,26 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// - /// Class which represents initialization setting for completion item. - /// + /// Client capabilities specific to . + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CompletionItemSetting { /// - /// Gets or sets a value indicating whether completion items can contain snippets. + /// The client supports treating as a snippet + /// when is set to . + /// + /// A snippet can define tab stops and placeholders with $1, $2 + /// and ${3:foo}. $0 defines the final tab stop and defaults to + /// the end of the snippet. Placeholders with equal identifiers are + /// linked, such that typing in one will update others too. + /// /// [JsonPropertyName("snippetSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -25,7 +34,7 @@ public bool SnippetSupport } /// - /// Gets or sets a value indicating whether the client supports commit characters. + /// The client supports the property. /// [JsonPropertyName("commitCharactersSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -36,7 +45,8 @@ public bool CommitCharactersSupport } /// - /// Gets or sets the content formats supported for documentation. + /// The client supports the following content formats for the + /// property. The order describes the preferred format of the client. /// [JsonPropertyName("documentationFormat")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -47,8 +57,9 @@ public MarkupKind[]? DocumentationFormat } /// - /// Gets or sets the a value indicating whether the client supports the deprecated property on a completion item. + /// The client supports the property on a completion item. /// + [Obsolete("Use Tags instead if supported")] [JsonPropertyName("deprecatedSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool DeprecatedSupport @@ -58,7 +69,7 @@ public bool DeprecatedSupport } /// - /// Gets or sets the a value indicating whether the client supports the preselect property on a completion item. + /// The client supports the property. /// [JsonPropertyName("preselectSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -69,8 +80,14 @@ public bool PreselectSupport } /// - /// Gets or sets the a value indicating whether the client supports the tag property on a completion item. + /// The tags that the client supports on the property. + /// + /// Clients supporting tags have to handle unknown tags gracefully. Clients + /// especially need to preserve unknown tags when sending a completion + /// item back to the server in a resolve call. + /// /// + /// Since LSP 3.15 [JsonPropertyName("tagSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public CompletionItemTagSupportSetting? TagSupport @@ -80,8 +97,10 @@ public CompletionItemTagSupportSetting? TagSupport } /// - /// Gets or sets the a value indicating whether the client supports insert replace edit. + /// Whether the client supports values on the + /// property. /// + /// Since 3.16 [JsonPropertyName("insertReplaceSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool InsertReplaceSupport @@ -91,8 +110,13 @@ public bool InsertReplaceSupport } /// - /// Gets or sets the a value indicating which properties a client can resolve lazily on a completion item. + /// Indicates which properties a client can resolve lazily on a completion item. + /// + /// Before version 3.16 only the predefined properties + /// and could be resolved lazily. + /// /// + /// Since 3.16 [JsonPropertyName("resolveSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public ResolveSupportSetting? ResolveSupport @@ -102,8 +126,10 @@ public ResolveSupportSetting? ResolveSupport } /// - /// Gets or sets the a value indicating whether the client supports the `insertTextMode` property on a completion item to override the whitespace handling mode as defined by the client. + /// Indicates whether the client supports the + /// property and which values it supports. /// + /// Since 3.16 [JsonPropertyName("insertTextModeSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public InsertTextModeSupportSetting? InsertTextModeSupport @@ -113,8 +139,9 @@ public InsertTextModeSupportSetting? InsertTextModeSupport } /// - /// Gets or sets the a value indicating whether the client supports completion item label details. + /// Indicates whether the client supports the property. /// + /// Since 3.17 [JsonPropertyName("labelDetailsSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool LabelDetailsSupport diff --git a/src/LanguageServer/Protocol/Protocol/CompletionItemTag.cs b/src/LanguageServer/Protocol/Protocol/CompletionItemTag.cs index 349e188ce5087..95fb411bf5e77 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionItemTag.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionItemTag.cs @@ -6,9 +6,11 @@ namespace Roslyn.LanguageServer.Protocol { /// /// Completion item tags are extra annotations that tweak the rendering of a completion item. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.15 internal enum CompletionItemTag { /// diff --git a/src/LanguageServer/Protocol/Protocol/CompletionItemTagSupportSetting.cs b/src/LanguageServer/Protocol/Protocol/CompletionItemTagSupportSetting.cs index 0b79975a7393a..538dd72ce6d3b 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionItemTagSupportSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionItemTagSupportSetting.cs @@ -7,10 +7,12 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents initialization setting for the tag property on a completion item. - /// + /// Represents the tags supported by the client on the property. + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.15 internal class CompletionItemTagSupportSetting { /// diff --git a/src/LanguageServer/Protocol/Protocol/CompletionList.cs b/src/LanguageServer/Protocol/Protocol/CompletionList.cs index 122fcb04d4e64..4eaa0af430204 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionList.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionList.cs @@ -8,16 +8,20 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents a completion list. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CompletionList { /// - /// Gets or sets a value indicating whether Items is the complete list of items or not. If incomplete is true, then - /// filtering should ask the server again for completion item. + /// This list is not complete. Further typing should result in recomputing this list. + /// + /// Recomputed lists have all their items replaced (not appended) in the incomplete completion sessions. + /// /// [JsonPropertyName("isIncomplete")] + [JsonRequired] public bool IsIncomplete { get; @@ -25,24 +29,36 @@ public bool IsIncomplete } /// - /// Gets or sets the list of completion items. + /// Default values of properties for items + /// that do not provide a value for those properties. + /// + /// If a completion list specifies a default value and a completion item + /// also specifies a corresponding value the one from the item is used. + /// + /// + /// Servers are only allowed to return default values if the client + /// signals support for this via the + /// capability. + /// /// - [JsonPropertyName("items")] - public CompletionItem[] Items + /// Since LSP 3.17 + [JsonPropertyName("itemDefaults")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public CompletionListItemDefaults? ItemDefaults { get; set; } /// - /// Gets or sets the completion list item defaults. + /// The completion items. /// - [JsonPropertyName("itemDefaults")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public CompletionListItemDefaults? ItemDefaults + [JsonPropertyName("items")] + [JsonRequired] + public CompletionItem[] Items { get; set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/CompletionListItemDefaults.cs b/src/LanguageServer/Protocol/Protocol/CompletionListItemDefaults.cs index 4487a31a0f843..2d9ec548a6a6a 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionListItemDefaults.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionListItemDefaults.cs @@ -7,12 +7,14 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents default properties associated with the entire completion list. + /// Represents default values of properties for items + /// is the completion list that do not provide a value for those properties. /// + /// Since LSP 3.17 internal class CompletionListItemDefaults { /// - /// Gets or sets the default commit character set. + /// A default commit character set. /// [JsonPropertyName("commitCharacters")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -23,7 +25,7 @@ public string[]? CommitCharacters } /// - /// Gets or sets the default edit range. + /// A default edit range. /// [JsonPropertyName("editRange")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -34,7 +36,7 @@ public SumType? EditRange } /// - /// Gets or sets the default . + /// A default . /// [JsonPropertyName("insertTextFormat")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -45,7 +47,7 @@ public InsertTextFormat? InsertTextFormat } /// - /// Gets or sets the default . + /// A default . /// [JsonPropertyName("insertTextMode")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -56,7 +58,7 @@ public InsertTextMode? InsertTextMode } /// - /// Gets or sets the default completion item data. + /// A completion item data value. /// [JsonPropertyName("data")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/CompletionListSetting.cs b/src/LanguageServer/Protocol/Protocol/CompletionListSetting.cs index ee4a5d56d6e8e..6939dcfffe9b9 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionListSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionListSetting.cs @@ -7,12 +7,13 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents capabilites for the completion list type. + /// Client capabilities specific to /// + /// Since 3.17 internal class CompletionListSetting { /// - /// Gets or sets a value containing the supported property names of the object. + /// The supported property names of the object. /// If omitted, no properties are supported. /// [JsonPropertyName("itemDefaults")] diff --git a/src/LanguageServer/Protocol/Protocol/CompletionOptions.cs b/src/LanguageServer/Protocol/Protocol/CompletionOptions.cs index bdfa14e9507da..5d3ef67a729e7 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionOptions.cs @@ -8,13 +8,29 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents completion capabilities. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CompletionOptions : IWorkDoneProgressOptions { /// - /// Gets or sets the trigger characters. + /// The additional characters, beyond the defaults provided by the client (typically + /// [a-zA-Z]), that should automatically trigger a completion request. + /// + /// For example . JavaScript represents the beginning of an object property + /// or method and is thus a good candidate for triggering a completion request. + /// + /// + /// Most tools trigger a completion request automatically without explicitly + /// requesting it using a keyboard shortcut (e.g.Ctrl+Space). Typically they + /// do so when the user starts to type an identifier. + /// + /// + /// For example if the user types c in a JavaScript file code complete will + /// automatically pop up present console besides others as a completion item. + /// Characters that make up identifiers don't need to be listed here. + /// /// [JsonPropertyName("triggerCharacters")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -25,8 +41,17 @@ public string[]? TriggerCharacters } /// - /// Gets or sets a value indicating all the possible commit characters associated with the language server. + /// The list of all possible characters that commit a completion. + /// + /// This field can be used if clients don't support individual commit characters per + /// completion item. See client capability . + /// + /// + /// If a server provides both and commit characters on + /// an individual completion item the ones on the completion item win. + /// /// + /// Since LSP 3.2 [JsonPropertyName("allCommitCharacters")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string[]? AllCommitCharacters @@ -36,7 +61,7 @@ public string[]? AllCommitCharacters } /// - /// Gets or sets a value indicating whether server provides completion item resolve capabilities. + /// The server provides support to resolve additional information for a completion item. /// [JsonPropertyName("resolveProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -46,16 +71,10 @@ public bool ResolveProvider set; } - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// - [JsonPropertyName("workDoneProgress")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool WorkDoneProgress { get; init; } - /// /// Gets or sets completion item setting. /// + /// Since LSP 3.17 [JsonPropertyName("completionItem")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public CompletionItemOptions? CompletionItemOptions @@ -63,5 +82,12 @@ public CompletionItemOptions? CompletionItemOptions get; set; } + + /// + /// Gets or sets a value indicating whether work done progress is supported. + /// + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/CompletionParams.cs b/src/LanguageServer/Protocol/Protocol/CompletionParams.cs index 0c1626b6c3395..52aaf932c6f2f 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionParams.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionParams.cs @@ -9,13 +9,15 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the parameters for the textDocument/completion request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class CompletionParams : TextDocumentPositionParams, IPartialResultParams?> + internal class CompletionParams : TextDocumentPositionParams, IPartialResultParams?>, IWorkDoneProgressOptions { /// - /// Gets or sets the completion context. + /// The completion context. This is only available if the client specifies the + /// client capability . /// [JsonPropertyName("context")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -25,9 +27,7 @@ public CompletionContext? Context set; } - /// - /// Gets or sets the value of the PartialResultToken instance. - /// + /// [JsonPropertyName(Methods.PartialResultTokenName)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public IProgress?>? PartialResultToken @@ -35,5 +35,10 @@ public IProgress?>? PartialResultToken get; set; } + + /// + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/CompletionRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/CompletionRegistrationOptions.cs index af4bfbd32ee30..1e136762a8a95 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionRegistrationOptions.cs @@ -2,24 +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.Text.Json.Serialization; - namespace Roslyn.LanguageServer.Protocol; +using System.Text.Json.Serialization; + /// -/// Class representing the registration options for completion support. -/// +/// Subclass of that allows scoping the registration. +/// /// See the Language Server Protocol specification for additional information. +/// /// internal class CompletionRegistrationOptions : CompletionOptions, ITextDocumentRegistrationOptions { - /// - /// Gets or sets the document filters for this registration option. - /// + /// [JsonPropertyName("documentSelector")] - public DocumentFilter[]? DocumentSelector - { - get; - set; - } -} \ No newline at end of file + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/CompletionSetting.cs b/src/LanguageServer/Protocol/Protocol/CompletionSetting.cs index 30a5228668a92..3888b8d997de0 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionSetting.cs @@ -7,14 +7,15 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents initialization setting for completion. - /// + /// Client capabilities specific to completion. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class CompletionSetting : DynamicRegistrationSetting { /// - /// Gets or sets completion item setting. + /// The client supports the following specific capabilities. /// [JsonPropertyName("completionItem")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -25,7 +26,7 @@ public CompletionItemSetting? CompletionItem } /// - /// Gets or sets specific settings. + /// The client supports the following values. /// [JsonPropertyName("completionItemKind")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -36,7 +37,8 @@ public CompletionItemKindSetting? CompletionItemKind } /// - /// Gets or sets a value indicating whether the client supports sending additional context. + /// The client supports sending additional context information for + /// a textDocument/completion request. /// [JsonPropertyName("contextSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -47,8 +49,10 @@ public bool ContextSupport } /// - /// Gets or sets a value indicating client's default when the completion item doesn't provide an `insertTextMode` property. + /// The client's default insertion behavior when a completion item doesn't + /// provide a value for the property. /// + /// Since 3.17 [JsonPropertyName("insertTextMode")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public InsertTextMode? InsertTextMode @@ -58,8 +62,9 @@ public InsertTextMode? InsertTextMode } /// - /// Gets or sets a value indicating whether the client supports capabilities on the completion list. + /// The client supports the following specific capabilities. /// + /// Since 3.17 [JsonPropertyName("completionList")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public CompletionListSetting? CompletionListSetting diff --git a/src/LanguageServer/Protocol/Protocol/CompletionTriggerKind.cs b/src/LanguageServer/Protocol/Protocol/CompletionTriggerKind.cs index 4154beeb6fa7f..de988596cd333 100644 --- a/src/LanguageServer/Protocol/Protocol/CompletionTriggerKind.cs +++ b/src/LanguageServer/Protocol/Protocol/CompletionTriggerKind.cs @@ -6,18 +6,19 @@ namespace Roslyn.LanguageServer.Protocol { /// /// Enum which represents the various ways in which completion can be triggered. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal enum CompletionTriggerKind { /// - /// Completion was triggered by typing an identifier. + /// Completion was triggered by typing an identifier, manual invocation (e.g Ctrl+Space) or via API. /// Invoked = 1, /// - /// Completion was triggered by typing a trigger character. + /// Completion was triggered by a trigger character specified in /// TriggerCharacter = 2, @@ -26,4 +27,4 @@ internal enum CompletionTriggerKind /// TriggerForIncompleteCompletions = 3, } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/ConfigurationItem.cs b/src/LanguageServer/Protocol/Protocol/ConfigurationItem.cs index 51c7596a161c8..f97fcd9a3652c 100644 --- a/src/LanguageServer/Protocol/Protocol/ConfigurationItem.cs +++ b/src/LanguageServer/Protocol/Protocol/ConfigurationItem.cs @@ -9,8 +9,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents an configuration item. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class ConfigurationItem { @@ -37,4 +38,4 @@ public string? Section set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/ConfigurationParams.cs b/src/LanguageServer/Protocol/Protocol/ConfigurationParams.cs index 3cfc4fd4a19cf..0420f8b2f1ecd 100644 --- a/src/LanguageServer/Protocol/Protocol/ConfigurationParams.cs +++ b/src/LanguageServer/Protocol/Protocol/ConfigurationParams.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the parameters for the workspace/configuration request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class ConfigurationParams { @@ -17,10 +18,11 @@ internal class ConfigurationParams /// Gets or sets the ConfigurationItems being requested. /// [JsonPropertyName("items")] + [JsonRequired] public ConfigurationItem[] Items { get; set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/Converters/FormattingOptionsConverter.cs b/src/LanguageServer/Protocol/Protocol/Converters/FormattingOptionsConverter.cs new file mode 100644 index 0000000000000..63439d0ae5b64 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Converters/FormattingOptionsConverter.cs @@ -0,0 +1,147 @@ +// 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.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.LanguageServer; + +namespace Roslyn.LanguageServer.Protocol; + +/// Enables the FormattingOptions.OtherOptions JsonExtensionData to be strongly typed +internal class FormattingOptionsConverter : JsonConverter +{ + public override FormattingOptions? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var result = new FormattingOptions(); + + Debug.Assert(reader.TokenType == JsonTokenType.StartObject); + + static void ReadSkippingComments(ref Utf8JsonReader reader) + { + do + { + if (!reader.Read()) + { + throw new JsonException(LanguageServerProtocolResources.FormattingOptionsEndedUnexpectedly); + } + } + while (reader.TokenType == JsonTokenType.Comment); + } + + [DoesNotReturn] + static T ThrowMissingRequiredProperty(string propertyName) + { + throw new JsonException(string.Format(CultureInfo.InvariantCulture, LanguageServerProtocolResources.FormattingOptionsMissingRequiredProperty, propertyName)); + } + + int? tabSize = null; + bool? insertSpaces = null; + bool trimTrailingWhitespace = false; + bool insertFinalNewline = false; + bool trimFinalNewlines = false; + Dictionary>? otherOptions = null; + + while (true) + { + ReadSkippingComments(ref reader); + + if (reader.TokenType == JsonTokenType.EndObject) + { + return new FormattingOptions + { + TabSize = tabSize ?? ThrowMissingRequiredProperty(nameof(tabSize)), + InsertSpaces = insertSpaces ?? ThrowMissingRequiredProperty(nameof(insertSpaces)), + TrimTrailingWhitespace = trimTrailingWhitespace, + InsertFinalNewline = insertFinalNewline, + TrimFinalNewlines = trimFinalNewlines, + OtherOptions = otherOptions + }; + } + + if (reader.TokenType == JsonTokenType.Comment) + { + continue; + } + + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException(string.Format(CultureInfo.InvariantCulture, LanguageServerProtocolResources.FormattingOptionsEncounteredInvalidToken, reader.TokenType)); + } + + var propertyName = reader.GetString(); + + ReadSkippingComments(ref reader); + + switch (propertyName) + { + case nameof(tabSize): + tabSize = reader.GetInt32(); + continue; + case nameof(insertSpaces): + insertSpaces = reader.GetBoolean(); + continue; + case nameof(trimTrailingWhitespace): + trimTrailingWhitespace = reader.GetBoolean(); + continue; + case nameof(insertFinalNewline): + insertFinalNewline = reader.GetBoolean(); + continue; + case nameof(trimFinalNewlines): + trimFinalNewlines = reader.GetBoolean(); + continue; + default: + break; + } + + SumType value = reader.TokenType switch + { + JsonTokenType.Number => reader.GetInt32(), + JsonTokenType.String => reader.GetString(), + JsonTokenType.True => reader.GetBoolean(), + JsonTokenType.False => reader.GetBoolean(), + _ => throw new JsonException(string.Format(CultureInfo.InvariantCulture, LanguageServerProtocolResources.FormattingOptionsEncounteredInvalidToken, reader.TokenType)) + }; + + (otherOptions ??= []).Add(propertyName, value); + } + } + + public override void Write(Utf8JsonWriter writer, FormattingOptions value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + writer.WriteNumber("tabSize", value.TabSize); + writer.WriteBoolean("insertSpaces", value.InsertSpaces); + + if (value.TrimTrailingWhitespace != default) + { + writer.WriteBoolean("trimTrailingWhitespace", value.TrimTrailingWhitespace); + } + + if (value.InsertFinalNewline != default) + { + writer.WriteBoolean("insertFinalNewline", value.InsertFinalNewline); + } + + if (value.TrimFinalNewlines != default) + { + writer.WriteBoolean("trimFinalNewlines", value.TrimFinalNewlines); + } + + if (value.OtherOptions is not null) + { + foreach (var item in value.OtherOptions) + { + writer.WritePropertyName(item.Key); + JsonSerializer.Serialize(writer, item.Value, options); + } + } + + writer.WriteEndObject(); + } +} diff --git a/src/LanguageServer/Protocol/Protocol/Converters/InitializeParamsWorkspaceFoldersConverter.cs b/src/LanguageServer/Protocol/Protocol/Converters/InitializeParamsWorkspaceFoldersConverter.cs new file mode 100644 index 0000000000000..b9fbf0fe107b4 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Converters/InitializeParamsWorkspaceFoldersConverter.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.Text.Json; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// This is used to surface the distinction between "not supported" and "none open" for +/// +/// Per the LSP Spec: +/// +/// +/// If the property is NOT present, the client does not support workspace folders. +/// +/// +/// If the property is present but null, or an empty array, the client supports workspace folders but none are open. +/// +/// +/// +/// To represent this on , we use +/// to represent that the client does not support workspace folders, and use an empty array to represent that none are open. +/// +internal class InitializeParamsWorkspaceFoldersConverter : JsonConverter +{ + public override WorkspaceFolder[]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return JsonSerializer.Deserialize(ref reader, options) ?? []; + } + + public override void Write(Utf8JsonWriter writer, WorkspaceFolder[]? value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value, options); + } +} diff --git a/src/LanguageServer/Protocol/Protocol/Converters/SumConverter.cs b/src/LanguageServer/Protocol/Protocol/Converters/SumConverter.cs index d8fb1d10670a9..a3879a6b50449 100644 --- a/src/LanguageServer/Protocol/Protocol/Converters/SumConverter.cs +++ b/src/LanguageServer/Protocol/Protocol/Converters/SumConverter.cs @@ -56,7 +56,7 @@ public SumTypeInfoCache(Type sumTypeType) foreach (var parameterType in parameterTypes) { var parameterTypeInfo = NormalizeToNonNullable(parameterType).GetTypeInfo(); - var declaredConstructor = typeInfo.GetConstructor(new Type[] { parameterType }) ?? + var declaredConstructor = typeInfo.GetConstructor([parameterType]) ?? throw new ArgumentException(nameof(sumTypeType), "All constructor parameter types must be represented in the generic type arguments of the SumType"); var kindAttribute = parameterType.GetCustomAttribute(); @@ -65,6 +65,7 @@ public SumTypeInfoCache(Type sumTypeType) if (parameterTypeInfo.IsPrimitive || parameterTypeInfo == typeof(string) || + parameterTypeInfo == typeof(Uri) || typeof(IStringEnum).IsAssignableFrom(parameterTypeInfo)) { primitiveUnionTypeInfosSet ??= new List(); @@ -124,7 +125,7 @@ public class UnionTypeInfo // System.Text.Json can pre-compile the generic SumType<> constructor call so we don't need to do it through reflection every time. internal delegate T StjReader(ref Utf8JsonReader reader, JsonSerializerOptions options); - private static readonly Type[] expressionLambdaMethodTypes = new[] { typeof(Type), typeof(Expression), typeof(ParameterExpression[]) }; + private static readonly Type[] expressionLambdaMethodTypes = [typeof(Type), typeof(Expression), typeof(ParameterExpression[])]; private static readonly MethodInfo expressionLambdaMethod = typeof(Expression) .GetMethods() .Where(mi => @@ -135,7 +136,7 @@ public class UnionTypeInfo .SequenceEqual(expressionLambdaMethodTypes)) .Single(); - private static readonly Type[] jsonSerializerDeserializeMethodTypes = new[] { typeof(Utf8JsonReader).MakeByRefType(), typeof(JsonSerializerOptions) }; + private static readonly Type[] jsonSerializerDeserializeMethodTypes = [typeof(Utf8JsonReader).MakeByRefType(), typeof(JsonSerializerOptions)]; private static readonly MethodInfo jsonSerializerDeserializeMethod = typeof(JsonSerializer) .GetMethods() .Where(mi => @@ -160,7 +161,7 @@ public UnionTypeInfo(Type type, ConstructorInfo constructor, KindAttribute? kind jsonSerializerDeserializeMethod.MakeGenericMethod(type), param1, param2)); - var expression = (LambdaExpression)expressionLambdaMethod.Invoke(null, new object[] { typeof(StjReader<>).MakeGenericType(constructor.DeclaringType), body, new[] { param1, param2 } })!; + var expression = (LambdaExpression)expressionLambdaMethod.Invoke(null, [typeof(StjReader<>).MakeGenericType(constructor.DeclaringType), body, new[] { param1, param2 }])!; StjReaderFunction = expression.Compile(); } @@ -249,7 +250,7 @@ public override T Read(ref Utf8JsonReader reader, Type objectType, JsonSerialize } } - throw new JsonException(LanguageServerProtocolResources.NoSumTypeMatch); + throw new JsonException($"No sum type match for {objectType}"); } /// @@ -259,6 +260,13 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions var sumValue = value.Value; + // behavior from DocumentUriConverter + if (sumValue is Uri) + { + writer.WriteStringValue(sumValue.ToString()); + return; + } + if (sumValue != null) { JsonSerializer.Serialize(writer, sumValue, options); @@ -288,6 +296,7 @@ private static bool IsTokenCompatibleWithType(ref Utf8JsonReader reader, SumConv break; case JsonTokenType.String: isCompatible = unionTypeInfo.Type == typeof(string) || + unionTypeInfo.Type == typeof(Uri) || typeof(IStringEnum).IsAssignableFrom(unionTypeInfo.Type); break; } diff --git a/src/LanguageServer/Protocol/Protocol/CreateFile.cs b/src/LanguageServer/Protocol/Protocol/CreateFile.cs index 723850708e18b..2ca8e1a7e3a8c 100644 --- a/src/LanguageServer/Protocol/Protocol/CreateFile.cs +++ b/src/LanguageServer/Protocol/Protocol/CreateFile.cs @@ -9,11 +9,13 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing a create file operation. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.13 [Kind("create")] - internal class CreateFile + internal class CreateFile : IAnnotatedChange { /// /// Gets the kind value. @@ -44,5 +46,10 @@ public CreateFileOptions? Options get; set; } + + /// + [JsonPropertyName("annotationId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ChangeAnnotationIdentifier? AnnotationId { get; init; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/CreateFileOptions.cs b/src/LanguageServer/Protocol/Protocol/CreateFileOptions.cs index c8215d3a14223..3e47c186b70e7 100644 --- a/src/LanguageServer/Protocol/Protocol/CreateFileOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/CreateFileOptions.cs @@ -8,14 +8,19 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the options for a create file operation. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.13 internal class CreateFileOptions { /// - /// Gets or sets a value indicating whether the creation should overwrite the file if it already exists. (Overwrite wins over ignoreIfExists). + /// Gets or sets a value indicating whether the creation should overwrite the file if it already exists. /// + /// + /// wins over . + /// [JsonPropertyName("overwrite")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool Overwrite @@ -27,6 +32,9 @@ public bool Overwrite /// /// Gets or sets a value indicating whether the action should be ignored if the file already exists. /// + /// + /// wins over . + /// [JsonPropertyName("ignoreIfExists")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool IgnoreIfExists diff --git a/src/LanguageServer/Protocol/Protocol/DefaultBehaviorPrepareRename.cs b/src/LanguageServer/Protocol/Protocol/DefaultBehaviorPrepareRename.cs index d221861d3f169..6623df023bc13 100644 --- a/src/LanguageServer/Protocol/Protocol/DefaultBehaviorPrepareRename.cs +++ b/src/LanguageServer/Protocol/Protocol/DefaultBehaviorPrepareRename.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents a possible result value of the 'textDocument/prepareRename' request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class DefaultBehaviorPrepareRename { /// diff --git a/src/LanguageServer/Protocol/Protocol/DefinitionOptions.cs b/src/LanguageServer/Protocol/Protocol/DefinitionOptions.cs deleted file mode 100644 index b906658d84875..0000000000000 --- a/src/LanguageServer/Protocol/Protocol/DefinitionOptions.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. - -namespace Roslyn.LanguageServer.Protocol -{ - using System.Text.Json.Serialization; - - /// - /// Class which represents workspace symbols capabilities. - /// - /// See the Language Server Protocol specification for additional information. - /// - internal class DefinitionOptions : IWorkDoneProgressOptions - { - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// - [JsonPropertyName("workDoneProgress")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool WorkDoneProgress { get; init; } - } -} diff --git a/src/LanguageServer/Protocol/Protocol/DeleteFile.cs b/src/LanguageServer/Protocol/Protocol/DeleteFile.cs index 919093f482981..72cae2338387d 100644 --- a/src/LanguageServer/Protocol/Protocol/DeleteFile.cs +++ b/src/LanguageServer/Protocol/Protocol/DeleteFile.cs @@ -9,11 +9,13 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing a delete file operation. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.13 [Kind("delete")] - internal class DeleteFile + internal class DeleteFile : IAnnotatedChange { /// /// Gets the kind value. @@ -44,5 +46,10 @@ public DeleteFileOptions? Options get; set; } + + /// + [JsonPropertyName("annotationId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ChangeAnnotationIdentifier? AnnotationId { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/Diagnostic.cs b/src/LanguageServer/Protocol/Protocol/Diagnostic.cs index 57def31e7cee4..466142ba4b5b3 100644 --- a/src/LanguageServer/Protocol/Protocol/Diagnostic.cs +++ b/src/LanguageServer/Protocol/Protocol/Diagnostic.cs @@ -7,6 +7,7 @@ namespace Roslyn.LanguageServer.Protocol using System; using System.Linq; using System.Text.Json.Serialization; + using Roslyn.Utilities; /// /// Class which represents a source code diagnostic message. @@ -53,6 +54,7 @@ public SumType? Code /// /// Gets or sets an optional value that describes the error code. /// + /// Since LSP 3.16 [JsonPropertyName("codeDescription")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public CodeDescription? CodeDescription @@ -84,8 +86,9 @@ public string Message } /// - /// Gets or sets the diagnostic's tags. + /// Additional metadata about the diagnostic. /// + /// Since 3.16 [JsonPropertyName("tags")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public DiagnosticTag[]? Tags @@ -105,6 +108,14 @@ public DiagnosticRelatedInformation[]? RelatedInformation set; } + /// + /// Data that is preserved for a textDocument/codeAction request + /// + /// Since 3.16 + [JsonPropertyName("data")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public object? Data { get; init; } + public static bool operator ==(Diagnostic? value1, Diagnostic? value2) { if (ReferenceEquals(value1, value2)) @@ -138,7 +149,10 @@ public bool Equals(Diagnostic other) && string.Equals(this.Message, other.Message, StringComparison.Ordinal) && (this.Tags == null ? other.Tags == null - : this.Tags.Equals(other.Tags) || this.Tags.SequenceEqual(other.Tags)); + : this.Tags.Equals(other.Tags) || this.Tags.SequenceEqual(other.Tags)) + && (this.Data is null + ? other.Data is null + : this.Data.Equals(other.Data)); } /// @@ -155,15 +169,17 @@ public override bool Equals(object obj) } /// - public override int GetHashCode() - { - return (this.Range == null ? 53 : this.Range.GetHashCode() * 13) - ^ (this.Severity.GetHashCode() * 17) - ^ (this.Code == null ? 47 : this.Code.GetHashCode() * 19) - ^ (this.Source == null ? 61 : this.Source.GetHashCode() * 79) - ^ (this.Message == null ? 83 : this.Message.GetHashCode() * 23) - ^ (this.Tags == null ? 89 : this.Tags.Sum(t => (int)t) * 73) - ^ (this.CodeDescription == null ? 23 : this.CodeDescription.GetHashCode() * 29); - } + public override int GetHashCode() => +#if NET + HashCode.Combine(Range, Severity, Code, Source, Message, Hash.CombineValues(Tags), CodeDescription, Data); +#else + Hash.Combine(Range, + Hash.Combine((int)(Severity ?? 0), + Hash.Combine(Code?.GetHashCode() ?? 0, + Hash.Combine(Source, + Hash.Combine(Message, + Hash.Combine(Hash.CombineValues(Tags), + Hash.Combine(CodeDescription?.GetHashCode() ?? 0, Data?.GetHashCode() ?? 0))))))); +#endif } } diff --git a/src/LanguageServer/Protocol/Protocol/DiagnosticOptions.cs b/src/LanguageServer/Protocol/Protocol/DiagnosticOptions.cs index 4d51c1b96d201..62fdf966dce4c 100644 --- a/src/LanguageServer/Protocol/Protocol/DiagnosticOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DiagnosticOptions.cs @@ -8,14 +8,14 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Server capabilities for pull diagnostics. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 internal class DiagnosticOptions : IWorkDoneProgressOptions { - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// + /// [JsonPropertyName("workDoneProgress")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool WorkDoneProgress { get; init; } @@ -32,7 +32,13 @@ public string? Identifier } /// - /// Gets or sets a value indicating whether the language has inter file dependencies. + /// Whether the language has inter-file dependencies meaning that + /// editing code in one file can result in a different diagnostic + /// set in another file. + /// + /// Inter file dependencies are common for most programming + /// languages and typically uncommon for linters. + /// /// [JsonPropertyName("interFileDependencies")] public bool InterFileDependencies diff --git a/src/LanguageServer/Protocol/Protocol/DiagnosticRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/DiagnosticRegistrationOptions.cs index f41e6490d1766..30364dab17779 100644 --- a/src/LanguageServer/Protocol/Protocol/DiagnosticRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DiagnosticRegistrationOptions.cs @@ -8,29 +8,20 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Diagnostic registration options. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 internal class DiagnosticRegistrationOptions : DiagnosticOptions, IStaticRegistrationOptions, ITextDocumentRegistrationOptions { - /// - /// Gets or sets the document filters for this registration option. - /// + /// [JsonPropertyName("documentSelector")] - public DocumentFilter[]? DocumentSelector - { - get; - set; - } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// + /// [JsonPropertyName("id")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? Id - { - get; - set; - } + public string? Id { get; set; } } diff --git a/src/LanguageServer/Protocol/Protocol/DiagnosticRelatedInformation.cs b/src/LanguageServer/Protocol/Protocol/DiagnosticRelatedInformation.cs index cc3099afe6976..4a0866a073658 100644 --- a/src/LanguageServer/Protocol/Protocol/DiagnosticRelatedInformation.cs +++ b/src/LanguageServer/Protocol/Protocol/DiagnosticRelatedInformation.cs @@ -11,7 +11,7 @@ namespace Roslyn.LanguageServer.Protocol /// This should be used to point to code locations that cause or are related to /// a diagnostics, e.g when duplicating a symbol in a scope. /// - /// See the Language Server Protocol specification for additional information. + /// See the Language Server Protocol specification for additional information. /// internal class DiagnosticRelatedInformation { diff --git a/src/LanguageServer/Protocol/Protocol/DiagnosticServerCancellationData.cs b/src/LanguageServer/Protocol/Protocol/DiagnosticServerCancellationData.cs index 0ee406d772ae8..efff6f7331cb9 100644 --- a/src/LanguageServer/Protocol/Protocol/DiagnosticServerCancellationData.cs +++ b/src/LanguageServer/Protocol/Protocol/DiagnosticServerCancellationData.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Class representing the cancellation data returned from a diagnostic request. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 internal class DiagnosticServerCancellationData { /// @@ -22,4 +24,4 @@ public bool RetriggerRequest get; set; } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/DiagnosticSetting.cs b/src/LanguageServer/Protocol/Protocol/DiagnosticSetting.cs index b5d623d11f2c9..e416751dd382a 100644 --- a/src/LanguageServer/Protocol/Protocol/DiagnosticSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/DiagnosticSetting.cs @@ -7,10 +7,12 @@ namespace Roslyn.LanguageServer.Protocol; using System.Text.Json.Serialization; /// -/// Client settings for pull diagnostics. -/// -/// See the Language Server Protocol specification for additional information. +/// Client capabilities specific to pull diagnostics. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 internal class DiagnosticSetting : DynamicRegistrationSetting { /// @@ -19,4 +21,4 @@ internal class DiagnosticSetting : DynamicRegistrationSetting [JsonPropertyName("relatedDocumentSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool RelatedDocumentSupport { get; set; } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/DiagnosticTag.cs b/src/LanguageServer/Protocol/Protocol/DiagnosticTag.cs index 1b2662066ffea..6c648f8b3b29c 100644 --- a/src/LanguageServer/Protocol/Protocol/DiagnosticTag.cs +++ b/src/LanguageServer/Protocol/Protocol/DiagnosticTag.cs @@ -14,13 +14,13 @@ internal enum DiagnosticTag { /// /// Unused or unnecessary code. - /// Diagnostics with this tag are rendered faded out. + /// Clients are allowed to render diagnostics with this tag faded out. /// Unnecessary = 1, /// /// Deprecated or obsolete code. - /// Clients are allowed to rendered diagnostics with this tag strike through. + /// Clients are allowed to render diagnostics with this tag strike through. /// Deprecated = 2, } diff --git a/src/LanguageServer/Protocol/Protocol/DiagnosticTagSupport.cs b/src/LanguageServer/Protocol/Protocol/DiagnosticTagSupport.cs new file mode 100644 index 0000000000000..e8c631ab0505d --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/DiagnosticTagSupport.cs @@ -0,0 +1,23 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Represent the client's support for the property to provide metadata about a diagnostic. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.15 +internal class DiagnosticTagSupport +{ + /// + /// Gets or sets a value indicating the tags supported by the client. + /// + [JsonPropertyName("valueSet")] + public DiagnosticTag[] ValueSet { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/DiagnosticWorkspaceSetting.cs b/src/LanguageServer/Protocol/Protocol/DiagnosticWorkspaceSetting.cs index 5aee040d2afc3..cda41f08b7950 100644 --- a/src/LanguageServer/Protocol/Protocol/DiagnosticWorkspaceSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/DiagnosticWorkspaceSetting.cs @@ -8,15 +8,23 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Class representing the workspace diagnostic client capabilities. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 internal class DiagnosticWorkspaceSetting { /// - /// Gets or sets a value indicating whether the client supports a refresh request sent from the server to the client. + /// Whether the client supports a refresh request sent from the server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// pulled diagnostics currently shown. It should be used with absolute care + /// and is useful for situation where a server for example detects a project + /// wide change that requires such a calculation. + /// /// [JsonPropertyName("refreshSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool RefreshSupport { get; set; } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/DidChangeConfigurationClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/DidChangeConfigurationClientCapabilities.cs new file mode 100644 index 0000000000000..36a00a7cbc617 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/DidChangeConfigurationClientCapabilities.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `workspace/didChangeConfiguration` notification. +/// +/// +/// See the Language Server Protocol specification for additional information. +/// +internal class DidChangeConfigurationClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/DidChangeConfigurationParams.cs b/src/LanguageServer/Protocol/Protocol/DidChangeConfigurationParams.cs index 102c94551b080..dd846d1a242a7 100644 --- a/src/LanguageServer/Protocol/Protocol/DidChangeConfigurationParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DidChangeConfigurationParams.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents the parameter sent with workspace/didChangeConfiguration requests. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DidChangeConfigurationParams { diff --git a/src/LanguageServer/Protocol/Protocol/DidChangeTextDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/DidChangeTextDocumentParams.cs index 78ac42a0491d8..24f6c768af88b 100644 --- a/src/LanguageServer/Protocol/Protocol/DidChangeTextDocumentParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DidChangeTextDocumentParams.cs @@ -8,15 +8,19 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents the parameter that is sent with textDocument/didChange message. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DidChangeTextDocumentParams : ITextDocumentParams { /// - /// Gets or sets the document that changed. + /// The document that did change. The version number points + /// to the version after all provided content changes have + /// been applied. /// [JsonPropertyName("textDocument")] + [JsonRequired] public VersionedTextDocumentIdentifier TextDocument { get; @@ -24,9 +28,23 @@ public VersionedTextDocumentIdentifier TextDocument } /// - /// Gets or sets the content changes. + /// The actual content changes. The content changes describe single state + /// changes to the document. So if there are two content changes c1 (at + /// array index 0) and c2(at array index 1) for a document in state S then + /// c1 moves the document from S to S' and c2 from S' to S''. So c1 is + /// computed on the state S and c2 is computed on the state S'. + /// + /// To mirror the content of a document using change events use the following + /// approach: + /// + /// Start with the same initial content + /// Apply the 'textDocument/didChange' notifications in the order you receive them. + /// Apply the `TextDocumentContentChangeEvent`s in a single notification in the order you receive them. + /// + /// /// [JsonPropertyName("contentChanges")] + [JsonRequired] public TextDocumentContentChangeEvent[] ContentChanges { get; diff --git a/src/LanguageServer/Protocol/Protocol/DidCloseTextDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/DidCloseTextDocumentParams.cs index 15a1ccb176d6e..2cfcefc153255 100644 --- a/src/LanguageServer/Protocol/Protocol/DidCloseTextDocumentParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DidCloseTextDocumentParams.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents the parameter that is sent with textDocument/didClose message. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DidCloseTextDocumentParams : ITextDocumentParams { @@ -17,6 +18,7 @@ internal class DidCloseTextDocumentParams : ITextDocumentParams /// Gets or sets the text document identifier. /// [JsonPropertyName("textDocument")] + [JsonRequired] public TextDocumentIdentifier TextDocument { get; diff --git a/src/LanguageServer/Protocol/Protocol/DidOpenTextDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/DidOpenTextDocumentParams.cs index ff6ecfacc3ccb..812f72c8bdd24 100644 --- a/src/LanguageServer/Protocol/Protocol/DidOpenTextDocumentParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DidOpenTextDocumentParams.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents the parameter that is sent with textDocument/didOpen message. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DidOpenTextDocumentParams { @@ -17,6 +18,7 @@ internal class DidOpenTextDocumentParams /// Gets or sets the which represents the text document that was opened. /// [JsonPropertyName("textDocument")] + [JsonRequired] public TextDocumentItem TextDocument { get; diff --git a/src/LanguageServer/Protocol/Protocol/DidSaveTextDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/DidSaveTextDocumentParams.cs index b0c24f6e168c2..2c05d40d38946 100644 --- a/src/LanguageServer/Protocol/Protocol/DidSaveTextDocumentParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DidSaveTextDocumentParams.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents the parameter that is sent with a textDocument/didSave message. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DidSaveTextDocumentParams : ITextDocumentParams { @@ -17,6 +18,7 @@ internal class DidSaveTextDocumentParams : ITextDocumentParams /// Gets or sets the which represents the text document that was saved. /// [JsonPropertyName("textDocument")] + [JsonRequired] public TextDocumentIdentifier TextDocument { get; @@ -24,7 +26,9 @@ public TextDocumentIdentifier TextDocument } /// - /// Gets or sets the which represents the content of the text document when it was saved. + /// Optional the content when saved. Depends on the value + /// or the when the save + /// notification was requested. /// [JsonPropertyName("text")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/DocumentColorClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/DocumentColorClientCapabilities.cs new file mode 100644 index 0000000000000..c04b402eeb054 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/DocumentColorClientCapabilities.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. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/documentColor` and the `textDocument/colorPresentation` requests. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.6 +internal class DocumentColorClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentColorOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentColorOptions.cs index 96cf410caca2e..499e3d070c5e6 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentColorOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentColorOptions.cs @@ -7,10 +7,12 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents workspace symbols capabilities. - /// + /// Server capabilities specific to DocumentColor. + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.6 internal class DocumentColorOptions : IWorkDoneProgressOptions { /// diff --git a/src/LanguageServer/Protocol/Protocol/DocumentColorParams.cs b/src/LanguageServer/Protocol/Protocol/DocumentColorParams.cs index 6e5b7506a718b..5e2c738acca9e 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentColorParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentColorParams.cs @@ -4,23 +4,32 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// /// Class representing the parameters sent for a textDocument/documentColor request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class DocumentColorParams : ITextDocumentParams + /// Since LSP 3.6 + internal class DocumentColorParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams { /// - /// Gets or sets the to provide links for. + /// The to provide color information for. /// [JsonPropertyName("textDocument")] - public TextDocumentIdentifier TextDocument - { - get; - set; - } + public TextDocumentIdentifier TextDocument { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/DocumentColorRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentColorRegistrationOptions.cs new file mode 100644 index 0000000000000..645ffd2b647fc --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/DocumentColorRegistrationOptions.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.6 +internal class DocumentColorRegistrationOptions : DocumentColorOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions +{ + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticParams.cs b/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticParams.cs index 348274675e055..3ba3b8dcc7a6e 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticParams.cs @@ -9,14 +9,14 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Class representing the document diagnostic request parameters -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// -internal class DocumentDiagnosticParams : ITextDocumentParams, IPartialResultParams> +/// Since LSP 3.17 +internal class DocumentDiagnosticParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams> { - /// - /// Gets or sets the value of the Progress instance. - /// + /// /// /// Note that the first literal send needs to be either the or /// followed by n literals. @@ -25,10 +25,14 @@ internal class DocumentDiagnosticParams : ITextDocumentParams, IPartialResultPar [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public IProgress>? PartialResultToken { - get; - set; + get; set; } + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + /// /// Gets or sets the to provide diagnostics for. /// @@ -40,7 +44,7 @@ public TextDocumentIdentifier TextDocument } /// - /// Gets or sets the identifier for which the client is requesting diagnostics for. + /// The additional identifier provided during registration /// [JsonPropertyName("identifier")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticReportKind.cs b/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticReportKind.cs index 30efcc8483aa7..ce76ef7d9db2c 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticReportKind.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticReportKind.cs @@ -6,8 +6,10 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Value representing the kind of the document diagnostic report. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since LSP 3.17 /// internal static class DocumentDiagnosticReportKind { diff --git a/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticReportPartialResult.cs b/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticReportPartialResult.cs index 9e2c17cb63aef..65f92997293a2 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticReportPartialResult.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentDiagnosticReportPartialResult.cs @@ -10,9 +10,11 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Class representing a partial document diagnostic report for a set of related documents. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 internal class DocumentDiagnosticReportPartialResult { /// @@ -24,4 +26,4 @@ public Dictionary +/// Capabilities specific to the `textDocument/formatting` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DocumentFormattingClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentFormattingOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentFormattingOptions.cs index 144e53f17087c..5304dc376759e 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentFormattingOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentFormattingOptions.cs @@ -13,9 +13,7 @@ namespace Roslyn.LanguageServer.Protocol /// internal class DocumentFormattingOptions : IWorkDoneProgressOptions { - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// + /// [JsonPropertyName("workDoneProgress")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool WorkDoneProgress { get; init; } diff --git a/src/LanguageServer/Protocol/Protocol/DocumentFormattingParams.cs b/src/LanguageServer/Protocol/Protocol/DocumentFormattingParams.cs index 35f814d3ff9b9..478b3405479ae 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentFormattingParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentFormattingParams.cs @@ -4,19 +4,22 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// - /// Class which represents the parameter that is sent with textDocument/formatting message. - /// + /// Parameter for the 'textDocument/formatting' request. + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class DocumentFormattingParams : ITextDocumentParams + internal class DocumentFormattingParams : ITextDocumentParams, IWorkDoneProgressParams { /// /// Gets or sets the identifier for the text document to be formatted. /// [JsonPropertyName("textDocument")] + [JsonRequired] public TextDocumentIdentifier TextDocument { get; @@ -27,10 +30,16 @@ public TextDocumentIdentifier TextDocument /// Gets or sets the formatting options. /// [JsonPropertyName("options")] + [JsonRequired] public FormattingOptions Options { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/DocumentFormattingRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentFormattingRegistrationOptions.cs index bd8ebeea9458d..5a757d5e30e70 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentFormattingRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentFormattingRegistrationOptions.cs @@ -7,19 +7,15 @@ namespace Roslyn.LanguageServer.Protocol; /// -/// Class representing the registration options for document formatting support. -/// +/// Subclass of that allows scoping the registration. +/// /// See the Language Server Protocol specification for additional information. +/// /// internal class DocumentFormattingRegistrationOptions : DocumentFormattingOptions, ITextDocumentRegistrationOptions { - /// - /// Gets or sets the document filters for this registration option. - /// + /// [JsonPropertyName("documentSelector")] - public DocumentFilter[]? DocumentSelector - { - get; - set; - } -} \ No newline at end of file + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentHighlight.cs b/src/LanguageServer/Protocol/Protocol/DocumentHighlight.cs index ee7ab022fea0f..c90c401795fdb 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentHighlight.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentHighlight.cs @@ -9,9 +9,12 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the response from a textDocument/documentHighlight request. - /// + /// A document highlight is a range inside a text document which deserves + /// special attention.Usually a document highlight is visualized by changing + /// the background color of its range. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DocumentHighlight { diff --git a/src/LanguageServer/Protocol/Protocol/DocumentHighlightClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/DocumentHighlightClientCapabilities.cs new file mode 100644 index 0000000000000..a045bf5b730d6 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/DocumentHighlightClientCapabilities.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/documentHighlight` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DocumentHighlightClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentHighlightOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentHighlightOptions.cs index c01c7eb95adb7..6c3abfc614bc3 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentHighlightOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentHighlightOptions.cs @@ -7,7 +7,7 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents workspace symbols capabilities. + /// Server capabilities specific to Document Highlight. /// /// See the Language Server Protocol specification for additional information. /// diff --git a/src/LanguageServer/Protocol/Protocol/DocumentHighlightParams.cs b/src/LanguageServer/Protocol/Protocol/DocumentHighlightParams.cs index 9fed8bdcc35fe..4933d02d3dd54 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentHighlightParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentHighlightParams.cs @@ -9,22 +9,20 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the parameters sent for a textDocument/documentHighlight request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class DocumentHighlightParams - : TextDocumentPositionParams, - IPartialResultParams + internal class DocumentHighlightParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialResultParams { - /// - /// Gets or sets the value of the PartialResultToken instance. - /// - [JsonPropertyName("partialResultToken")] + /// + [JsonPropertyName(Methods.PartialResultTokenName)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public IProgress? PartialResultToken - { - get; - set; - } + public IProgress? PartialResultToken { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/DocumentHighlightRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentHighlightRegistrationOptions.cs new file mode 100644 index 0000000000000..601c22ac19e69 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/DocumentHighlightRegistrationOptions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DocumentHighlightRegistrationOptions : DocumentHighlightOptions, ITextDocumentRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentLink.cs b/src/LanguageServer/Protocol/Protocol/DocumentLink.cs index a4fe991aef507..f060bec505004 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentLink.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentLink.cs @@ -8,14 +8,16 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the response of a textDocument/documentLink request. - /// + /// A document link is a range in a text document that links to an internal or + /// external resource, like another text document or a web site. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DocumentLink { /// - /// Gets or sets the range the link applies to. + /// The range this link applies to. /// [JsonPropertyName("range")] public Range Range @@ -25,7 +27,7 @@ public Range Range } /// - /// Gets or sets the uri that the link points to. + /// The uri this link points to. If missing a resolve request is sent later. /// [JsonPropertyName("target")] [JsonConverter(typeof(DocumentUriConverter))] @@ -35,5 +37,26 @@ public Uri? Target get; set; } + + /// + /// The tooltip text when you hover over this link. + /// + /// If a tooltip is provided, it will be displayed in a string that includes + /// instructions on how to trigger the link, such as {0} (ctrl + click). + /// The specific instructions vary depending on OS, user settings, and localization. + /// + /// + /// Since LSP 3.15 + [JsonPropertyName("tooltip")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Tooltip { get; init; } + + /// + /// A data entry field that is preserved on a document link between a + /// DocumentLinkRequest and a DocumentLinkResolveRequest. + /// + [JsonPropertyName("data")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public object? Data { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/DocumentLinkClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/DocumentLinkClientCapabilities.cs new file mode 100644 index 0000000000000..6cef7742f0095 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/DocumentLinkClientCapabilities.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/documentLink` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DocumentLinkClientCapabilities : DynamicRegistrationSetting +{ + /// + /// Whether the client supports the property. + /// + /// Since LSP 3.15 + [JsonPropertyName("tooltipSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool TooltipSupport { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentLinkOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentLinkOptions.cs index c01515f8ae949..42dea0909a2cb 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentLinkOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentLinkOptions.cs @@ -8,21 +8,18 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the document link options for server capabilities. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DocumentLinkOptions : IWorkDoneProgressOptions { /// - /// Gets or sets a value indicating whether or not the server supports resolve providers. + /// Whether or not the server has a resolve provider for document links. /// [JsonPropertyName("resolveProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool ResolveProvider - { - get; - set; - } + public bool ResolveProvider { get; set; } /// /// Gets or sets a value indicating whether work done progress is supported. diff --git a/src/LanguageServer/Protocol/Protocol/DocumentLinkParams.cs b/src/LanguageServer/Protocol/Protocol/DocumentLinkParams.cs index 780a15fceded5..b69ec733fc76d 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentLinkParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentLinkParams.cs @@ -4,17 +4,19 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// /// Class representing the parameters sent for a textDocument/documentLink request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class DocumentLinkParams : ITextDocumentParams + internal class DocumentLinkParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams { /// - /// Gets or sets the to provide links for. + /// The to provide links for. /// [JsonPropertyName("textDocument")] public TextDocumentIdentifier TextDocument @@ -22,5 +24,15 @@ public TextDocumentIdentifier TextDocument get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/DocumentLinkRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentLinkRegistrationOptions.cs new file mode 100644 index 0000000000000..9be4a9d90e132 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/DocumentLinkRegistrationOptions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DocumentLinkRegistrationOptions : DocumentLinkOptions, ITextDocumentRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingOptions.cs index 13105e53003d7..499f65841100b 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingOptions.cs @@ -8,15 +8,17 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the options for on type formatting. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DocumentOnTypeFormattingOptions { /// - /// Gets or sets the first trigger character. + /// A character on which formatting should be triggered, like {. /// [JsonPropertyName("firstTriggerCharacter")] + [JsonRequired] public string FirstTriggerCharacter { get; @@ -24,7 +26,7 @@ public string FirstTriggerCharacter } /// - /// Gets or sets additional trigger characters. + /// Optional additional trigger characters. /// [JsonPropertyName("moreTriggerCharacter")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -34,4 +36,4 @@ public string[]? MoreTriggerCharacter set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingParams.cs b/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingParams.cs index 919c36c1275ae..988496d36acf9 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingParams.cs @@ -8,29 +8,46 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the parameters sent for a textDocument/onTypeFormatting request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class DocumentOnTypeFormattingParams : TextDocumentPositionParams + internal class DocumentOnTypeFormattingParams : ITextDocumentPositionParams { /// - /// Gets or sets the character that was typed. + /// The document to format. + /// + [JsonPropertyName("textDocument")] + public TextDocumentIdentifier TextDocument { get; set; } + + /// + /// The position around which the on type formatting should happen. + /// + /// This is not necessarily the exact position where the character denoted + /// by the property got typed. + /// + /// + [JsonPropertyName("position")] + public Position Position { get; set; } + + /// + /// The character that has been typed that triggered the formatting + /// on type request. + /// + /// That is not necessarily the last character that + /// got inserted into the document since the client could auto insert + /// characters as well (e.g. like automatic brace completion). + /// /// [JsonPropertyName("ch")] - public string Character - { - get; - set; - } + [JsonRequired] + public string Character { get; set; } /// /// Gets or sets the for the request. /// [JsonPropertyName("options")] - public FormattingOptions Options - { - get; - set; - } + [JsonRequired] + public FormattingOptions Options { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingRegistrationOptions.cs index eefb4bfcf3352..73267582a2aec 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentOnTypeFormattingRegistrationOptions.cs @@ -7,19 +7,18 @@ namespace Roslyn.LanguageServer.Protocol; /// -/// Class representing the registration options for document on type formatting support. -/// +/// Subclass of that allows scoping the registration. +/// /// See the Language Server Protocol specification for additional information. +/// /// internal class DocumentOnTypeFormattingRegistrationOptions : DocumentOnTypeFormattingOptions, ITextDocumentRegistrationOptions { /// - /// Gets or sets the document filters for this registration option. + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. /// [JsonPropertyName("documentSelector")] - public DocumentFilter[]? DocumentSelector - { - get; - set; - } -} \ No newline at end of file + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingOptions.cs index 1c4cbe2ce2c7c..28ae43959d26b 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingOptions.cs @@ -8,14 +8,13 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the document range formatting options for server capabilities. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DocumentRangeFormattingOptions : IWorkDoneProgressOptions { - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// + /// [JsonPropertyName("workDoneProgress")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool WorkDoneProgress { get; init; } diff --git a/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingParams.cs b/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingParams.cs index 104830b737a1b..8977dbd117016 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingParams.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents the parameter that is sent with textDocument/rangeFormatting message. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DocumentRangeFormattingParams : ITextDocumentParams { @@ -17,6 +18,7 @@ internal class DocumentRangeFormattingParams : ITextDocumentParams /// Gets or sets the identifier for the text document to be formatted. /// [JsonPropertyName("textDocument")] + [JsonRequired] public TextDocumentIdentifier TextDocument { get; @@ -27,6 +29,7 @@ public TextDocumentIdentifier TextDocument /// Gets or sets the selection range to be formatted. /// [JsonPropertyName("range")] + [JsonRequired] public Range Range { get; @@ -37,6 +40,7 @@ public Range Range /// Gets or sets the formatting options. /// [JsonPropertyName("options")] + [JsonRequired] public FormattingOptions Options { get; diff --git a/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingRegistrationOptions.cs index d89599bd5ec30..1872ee874d632 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentRangeFormattingRegistrationOptions.cs @@ -7,19 +7,15 @@ namespace Roslyn.LanguageServer.Protocol; /// -/// Class representing the registration options for document range formatting support. -/// +/// Subclass of that allows scoping the registration. +/// /// See the Language Server Protocol specification for additional information. +/// /// internal class DocumentRangeFormattingRegistrationOptions : DocumentRangeFormattingOptions, ITextDocumentRegistrationOptions { - /// - /// Gets or sets the document filters for this registration option. - /// + /// [JsonPropertyName("documentSelector")] - public DocumentFilter[]? DocumentSelector - { - get; - set; - } -} \ No newline at end of file + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentSymbol.cs b/src/LanguageServer/Protocol/Protocol/DocumentSymbol.cs index e9110e2f82bc0..83b1b775eb408 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentSymbol.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentSymbol.cs @@ -4,19 +4,22 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// /// Represents programming constructs like variables, classes, interfaces etc. that appear in a document. Document symbols can be /// hierarchical and they have two ranges: one that encloses its definition and one that points to its most interesting range, /// e.g. the range of an identifier. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DocumentSymbol { /// - /// Gets or sets the name of this symbol. + /// The name of this symbol. Will be displayed in the user interface and + /// therefore must not be an empty string or a string consisting only of whitespace. /// [JsonPropertyName("name")] [JsonRequired] @@ -27,7 +30,7 @@ public string Name } /// - /// Gets or sets more detail for this symbol, e.g the signature of a function. + /// More detail for this symbol, e.g the signature of a function. /// [JsonPropertyName("detail")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -38,7 +41,7 @@ public string? Detail } /// - /// Gets or sets the of this symbol. + /// The of this symbol. /// [JsonPropertyName("kind")] public SymbolKind Kind @@ -48,10 +51,19 @@ public SymbolKind Kind } /// - /// Gets or sets a value indicating whether this symbol is deprecated. + /// Tags for this document symbol. + /// + /// Since 3.16 + [JsonPropertyName("tags")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SymbolTag[]? Tags { get; init; } + + /// + /// Indicates whether this symbol is deprecated. /// [JsonPropertyName("deprecated")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + [Obsolete("Use Tags instead")] public bool Deprecated { get; @@ -59,9 +71,9 @@ public bool Deprecated } /// - /// Gets or sets the range enclosing this symbol not including leading/trailing whitespace but everything else - /// like comments.This information is typically used to determine if the clients cursor is - /// inside the symbol to reveal in the symbol in the UI. + /// Gets or sets the range enclosing this symbol not including leading/trailing whitespace + /// but everything else like comments. This information is typically used to determine + /// if the client's cursor is inside the symbol to reveal in the symbol in the UI. /// [JsonPropertyName("range")] [JsonRequired] @@ -73,7 +85,7 @@ public Range Range /// /// Gets or sets the range that should be selected and revealed when this symbol is being picked, e.g the name of a function. - /// Must be contained by the `range`. + /// Must be contained by the . /// [JsonPropertyName("selectionRange")] [JsonRequired] diff --git a/src/LanguageServer/Protocol/Protocol/DocumentSymbolOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentSymbolOptions.cs index 9298ac3d94632..021dd0c3cd78c 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentSymbolOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentSymbolOptions.cs @@ -7,9 +7,10 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents workspace symbols capabilities. - /// + /// Server capabilities specific to Document Symbols. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DocumentSymbolOptions : IWorkDoneProgressOptions { @@ -19,5 +20,14 @@ internal class DocumentSymbolOptions : IWorkDoneProgressOptions [JsonPropertyName("workDoneProgress")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool WorkDoneProgress { get; init; } + + /// + /// A human-readable string that is shown when multiple outlines trees + /// are shown for the same document. + /// + /// Sicne LSP 3.16 + [JsonPropertyName("label")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Label { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/DocumentSymbolParams.cs b/src/LanguageServer/Protocol/Protocol/DocumentSymbolParams.cs index b12f359aec536..25ad0f315d286 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentSymbolParams.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentSymbolParams.cs @@ -2,25 +2,42 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace Roslyn.LanguageServer.Protocol -{ - using System.Text.Json.Serialization; +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; +/// +/// Class which represents the parameter sent with textDocument/documentSymbol requests. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DocumentSymbolParams + : ITextDocumentParams, IWorkDoneProgressParams, +#pragma warning disable CS0618 // SymbolInformation is obsolete but this class is not + IPartialResultParams> +#pragma warning restore CS0618 +{ /// - /// Class which represents the parameter sent with textDocument/documentSymbol requests. - /// - /// See the Language Server Protocol specification for additional information. + /// Gets or sets the text document. /// - internal class DocumentSymbolParams : ITextDocumentParams + [JsonPropertyName("textDocument")] + public TextDocumentIdentifier TextDocument { - /// - /// Gets or sets the text document. - /// - [JsonPropertyName("textDocument")] - public TextDocumentIdentifier TextDocument - { - get; - set; - } + get; + set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] +#pragma warning disable CS0618 // SymbolInformation is obsolete but this property is not + public IProgress>? PartialResultToken { get; set; } +#pragma warning restore CS0618 } diff --git a/src/LanguageServer/Protocol/Protocol/DocumentSymbolRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/DocumentSymbolRegistrationOptions.cs new file mode 100644 index 0000000000000..0d907db48ce29 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/DocumentSymbolRegistrationOptions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DocumentSymbolRegistrationOptions : DocumentSymbolOptions, ITextDocumentRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/DocumentSymbolSetting.cs b/src/LanguageServer/Protocol/Protocol/DocumentSymbolSetting.cs index 6b4274a7d9fdc..d00d8f8626e5e 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentSymbolSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentSymbolSetting.cs @@ -7,14 +7,15 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the initialization setting for document symbols. - /// + /// Client capabilities specific to the textDocument/documentSymbol request. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DocumentSymbolSetting : DynamicRegistrationSetting { /// - /// Gets or sets the capabilities. + /// Specific capabilities for in textDocument/documentSymbol requests /// [JsonPropertyName("symbolKind")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -34,5 +35,27 @@ public bool HierarchicalDocumentSymbolSupport get; set; } + + /// + /// The client supports tags on . Tags are supported on + /// if is + /// set to . + /// + /// Clients supporting tags have to handle unknown tags gracefully. + /// + /// + /// Since LSP 3.16 + [JsonPropertyName("tagSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SymbolTagSupport? TagSupport { get; init; } + + /// + /// The client supports an additional label presented in the UI when + /// registering a document symbol provider. + /// + /// Since LSP 3.16 + [JsonPropertyName("labelSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool LabelSupport { get; init; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/DynamicRegistrationSetting.cs b/src/LanguageServer/Protocol/Protocol/DynamicRegistrationSetting.cs index 9bc210064c78f..58a671f772169 100644 --- a/src/LanguageServer/Protocol/Protocol/DynamicRegistrationSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/DynamicRegistrationSetting.cs @@ -9,7 +9,7 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents a setting that can be dynamically registered. /// - internal class DynamicRegistrationSetting + internal class DynamicRegistrationSetting : IDynamicRegistrationSetting { /// /// Initializes a new instance of the class. diff --git a/src/LanguageServer/Protocol/Protocol/ExecuteCommandClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/ExecuteCommandClientCapabilities.cs new file mode 100644 index 0000000000000..d1f8593dc575f --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ExecuteCommandClientCapabilities.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `workspace/executeCommand` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class ExecuteCommandClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/ExecuteCommandOptions.cs b/src/LanguageServer/Protocol/Protocol/ExecuteCommandOptions.cs index d79e56516f134..63b3ce8174c5e 100644 --- a/src/LanguageServer/Protocol/Protocol/ExecuteCommandOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/ExecuteCommandOptions.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the options for execute command support. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class ExecuteCommandOptions : IWorkDoneProgressOptions { @@ -23,9 +24,7 @@ public string[] Commands set; } - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// + /// [JsonPropertyName("workDoneProgress")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool WorkDoneProgress { get; init; } diff --git a/src/LanguageServer/Protocol/Protocol/ExecuteCommandParams.cs b/src/LanguageServer/Protocol/Protocol/ExecuteCommandParams.cs index 6269066a2ad07..7f7fea2bcafa5 100644 --- a/src/LanguageServer/Protocol/Protocol/ExecuteCommandParams.cs +++ b/src/LanguageServer/Protocol/Protocol/ExecuteCommandParams.cs @@ -4,14 +4,16 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// /// Class representing the parameters sent from client to server for the workspace/executeCommand request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class ExecuteCommandParams + internal class ExecuteCommandParams : IWorkDoneProgressParams { /// /// Gets or sets the command identifier associated with the command handler. @@ -33,5 +35,10 @@ public object[]? Arguments get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/ExecuteCommandRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/ExecuteCommandRegistrationOptions.cs new file mode 100644 index 0000000000000..cd96e68405708 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ExecuteCommandRegistrationOptions.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class ExecuteCommandRegistrationOptions : ExecuteCommandOptions, ITextDocumentRegistrationOptions +{ + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Extensions/Converters/VSExtensionUtilities.cs b/src/LanguageServer/Protocol/Protocol/Extensions/Converters/VSExtensionUtilities.cs index 0cd191528ca56..4db11ecf2f68b 100644 --- a/src/LanguageServer/Protocol/Protocol/Extensions/Converters/VSExtensionUtilities.cs +++ b/src/LanguageServer/Protocol/Protocol/Extensions/Converters/VSExtensionUtilities.cs @@ -34,7 +34,9 @@ private static void AddConverters(IList converters) TryAddConverter(); TryAddConverter(); TryAddConverter(); +#pragma warning disable CS0618 // SymbolInformation is obsolete but we need the converter regardless TryAddConverter(); +#pragma warning restore CS0618 TryAddConverter(); void TryAddConverter() diff --git a/src/LanguageServer/Protocol/Protocol/Extensions/VSSymbolInformation.cs b/src/LanguageServer/Protocol/Protocol/Extensions/VSSymbolInformation.cs index 84d77d40b6219..49d524328e2e1 100644 --- a/src/LanguageServer/Protocol/Protocol/Extensions/VSSymbolInformation.cs +++ b/src/LanguageServer/Protocol/Protocol/Extensions/VSSymbolInformation.cs @@ -9,7 +9,10 @@ namespace Roslyn.LanguageServer.Protocol /// /// extends providing additional properties used by Visual Studio. /// - internal class VSSymbolInformation : SymbolInformation + internal class VSSymbolInformation +#pragma warning disable CS0618 // SymbolInformation is obsolete but this class is not (yet) + : SymbolInformation +#pragma warning restore { /// /// Gets or sets the icon associated with the symbol. If specified, this icon is used instead of . diff --git a/src/LanguageServer/Protocol/Protocol/FailureHandlingKind.cs b/src/LanguageServer/Protocol/Protocol/FailureHandlingKind.cs new file mode 100644 index 0000000000000..6bd54bc7181ee --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FailureHandlingKind.cs @@ -0,0 +1,46 @@ +// 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.ComponentModel; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Describes the client's failure handling strategy for workspace changes. +/// +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since 3.13 +[JsonConverter(typeof(StringEnumConverter))] +[TypeConverter(typeof(StringEnumConverter.TypeConverter))] +internal readonly record struct FailureHandlingKind(string Value) : IStringEnum +{ + /// + /// Applying the workspace change is simply aborted if one of the changes + /// provided fails. All operations executed before the failing operation + /// stay executed. + /// + public static readonly FailureHandlingKind Abort = new("abort"); + + /// + /// All operations are executed transactionally. That means they either all + /// succeed or no changes at all are applied to the workspace. + /// + public static readonly FailureHandlingKind Transactional = new("transactional"); + + /// + /// If the workspace edit contains only textual file changes they are + /// executed transactional. If resource changes (create, rename or delete + /// file) are part of the change the failure handling strategy is . + /// + public static readonly FailureHandlingKind TextOnlyTransactional = new("textOnlyTransactional"); + + /// + /// The client tries to undo the operations already executed, but there is no + /// guarantee that will succeed. + /// + public static readonly FailureHandlingKind Undo = new("undo"); +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/CreateFilesParams.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/CreateFilesParams.cs new file mode 100644 index 0000000000000..8ce2c42e4a190 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/CreateFilesParams.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The parameters sent in notifications/requests for user-initiated creation of files. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class CreateFilesParams +{ + /// + /// An array of all files/folders created in this operation. + /// + [JsonPropertyName("files")] + [JsonRequired] + public FileCreate[] Files { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/DeleteFilesParams.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/DeleteFilesParams.cs new file mode 100644 index 0000000000000..d952fc88593c0 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/DeleteFilesParams.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The parameters sent in notifications/requests for user-initiated deletes of files. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class DeleteFilesParams +{ + /// + /// An array of all files/folders deleted in this operation. + /// + [JsonPropertyName("files")] + [JsonRequired] + public FileCreate[] Files { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWatchedFilesClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWatchedFilesClientCapabilities.cs new file mode 100644 index 0000000000000..967953eb6e963 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWatchedFilesClientCapabilities.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `workspace/didChangeWatchedFiles` notification. +/// +/// +/// See the Language Server Protocol specification for additional information. +/// +internal class DidChangeWatchedFilesClientCapabilities : DynamicRegistrationSetting +{ + /// + /// Whether the client has support for relative patterns. + /// + /// Since LSP 3.17 + [JsonPropertyName("relativePatternSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool RelativePatternSupport { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/DidChangeWatchedFilesParams.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWatchedFilesParams.cs similarity index 94% rename from src/LanguageServer/Protocol/Protocol/DidChangeWatchedFilesParams.cs rename to src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWatchedFilesParams.cs index e090da167da4e..e677fc58cb3e1 100644 --- a/src/LanguageServer/Protocol/Protocol/DidChangeWatchedFilesParams.cs +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWatchedFilesParams.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents the parameter that is sent with workspace/didChangeWatchedFiles message. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class DidChangeWatchedFilesParams { @@ -17,6 +18,7 @@ internal class DidChangeWatchedFilesParams /// Gets or sets of the collection of file change events. /// [JsonPropertyName("changes")] + [JsonRequired] public FileEvent[] Changes { get; diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWatchedFilesRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWatchedFilesRegistrationOptions.cs new file mode 100644 index 0000000000000..6747cb4a7a0f4 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWatchedFilesRegistrationOptions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Describe options to be used when registering for file system change events. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DidChangeWatchedFilesRegistrationOptions : DynamicRegistrationSetting +{ + /// + /// The watchers to register. + /// + /// Since LSP 3.17 + [JsonPropertyName("watchers")] + [JsonRequired] + public FileSystemWatcher[] Watchers { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWorkspaceFoldersParams.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWorkspaceFoldersParams.cs new file mode 100644 index 0000000000000..1fd3cfc39b118 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/DidChangeWorkspaceFoldersParams.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Class which represents the parameter sent with workspace/didChangeWorkspaceFolders requests. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.6 +internal class DidChangeWorkspaceFoldersParams +{ + /// + /// The actual workspace folder change event. + /// + [JsonPropertyName("event")] + [JsonRequired] + public WorkspaceFoldersChangeEvent Event { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileChangeType.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileChangeType.cs similarity index 96% rename from src/LanguageServer/Protocol/Protocol/FileChangeType.cs rename to src/LanguageServer/Protocol/Protocol/FileOperations/FileChangeType.cs index e09e40a3478b2..72e22a71d06f1 100644 --- a/src/LanguageServer/Protocol/Protocol/FileChangeType.cs +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileChangeType.cs @@ -6,8 +6,9 @@ namespace Roslyn.LanguageServer.Protocol { /// /// File event type enum. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal enum FileChangeType { diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileCreate.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileCreate.cs new file mode 100644 index 0000000000000..ddd7192f4af3e --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileCreate.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Represents information on a file/folder create. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class FileCreate +{ + /// + /// A file:// URI for the location of the file/folder being created. + /// + [JsonPropertyName("uri")] + [JsonRequired] + [JsonConverter(typeof(DocumentUriConverter))] + public Uri Uri { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileDelete.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileDelete.cs new file mode 100644 index 0000000000000..f5ff575a3cc27 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileDelete.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Represents information on a file/folder delete. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class FileDelete +{ + /// + /// A file:// URI for the location of the file/folder being deleted. + /// + [JsonPropertyName("uri")] + [JsonRequired] + [JsonConverter(typeof(DocumentUriConverter))] + public Uri Uri { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileEvent.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileEvent.cs similarity index 92% rename from src/LanguageServer/Protocol/Protocol/FileEvent.cs rename to src/LanguageServer/Protocol/Protocol/FileOperations/FileEvent.cs index 6133abc68ec98..6a45333d8a5ee 100644 --- a/src/LanguageServer/Protocol/Protocol/FileEvent.cs +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileEvent.cs @@ -9,8 +9,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents a file change event. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class FileEvent { @@ -19,11 +20,7 @@ internal class FileEvent /// [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri - { - get; - set; - } + public Uri Uri { get; set; } /// /// Gets or sets the file change type. diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationFilter.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationFilter.cs new file mode 100644 index 0000000000000..4a70d2ee13a83 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationFilter.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A filter to describe in which file operation requests or notifications +/// the server is interested in. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class FileOperationFilter +{ + /// + /// A Uri like `file` or `untitled`. + /// + [JsonPropertyName("scheme")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Scheme { get; init; } + + /// + /// The actual file operation pattern. + /// + [JsonPropertyName("pattern")] + [JsonRequired] + public FileOperationPattern Pattern { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationPattern.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationPattern.cs new file mode 100644 index 0000000000000..88ac96f5f57ef --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationPattern.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A filter to describe in which file operation requests or notifications +/// the server is interested in. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class FileOperationPattern +{ + /// + /// The glob pattern to match. Glob patterns can have the following syntax: + /// + /// * to match one or more characters in a path segment + /// ? to match on one character in a path segment + /// ** to match any number of path segments, including none + /// {} to group sub patterns into an OR expression. + /// (e.g. **​/*.{ts,js}matches all TypeScript and JavaScript files) + /// []to declare a range of characters to match in a path segment + /// (e.g., example.[0-9] to match on example.0, example.1, …) + /// [!...] to negate a range of characters to match in a path segment + /// (e.g., example.[!0-9] to match on example.a, example.b, but not example.0) + /// + /// + [JsonPropertyName("glob")] + [JsonRequired] + public string Glob { get; init; } + + /// + /// Whether to match files or folders with this pattern. + /// Matches both if undefined. + /// + [JsonPropertyName("matches")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public FileOperationPatternKind? Matches { get; init; } + + /// + /// Additional options used during matching. + /// + [JsonPropertyName("options")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public FileOperationPatternOptions? Options { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationPatternKind.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationPatternKind.cs new file mode 100644 index 0000000000000..ca3ce3486e43d --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationPatternKind.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.ComponentModel; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A pattern kind describing if a glob pattern matches a file a folder or both. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +[JsonConverter(typeof(StringEnumConverter))] +[TypeConverter(typeof(StringEnumConverter.TypeConverter))] +internal readonly record struct FileOperationPatternKind(string Value) : IStringEnum +{ + /// + /// The pattern matches a file only. + /// + public static readonly FileOperationPatternKind File = new("file"); + + /// + /// The pattern matches a folder only. + /// + public static readonly FileOperationPatternKind Folder = new("folder"); +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationPatternOptions.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationPatternOptions.cs new file mode 100644 index 0000000000000..a5f20e8b99e9c --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationPatternOptions.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Matching options for the file operation pattern. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since LSP 3.16 +internal class FileOperationPatternOptions +{ + /// + /// The pattern should be matched ignoring casing. + /// + [JsonPropertyName("ignoreCase")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool IgnoreCase { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationRegistrationOptions.cs new file mode 100644 index 0000000000000..b0fb7a3ff8895 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationRegistrationOptions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The options to register for file operations +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class FileOperationRegistrationOptions +{ + /// + /// The actual filters. + /// + [JsonPropertyName("filters")] + [JsonRequired] + public FileOperationFilter[] Filters { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationsWorkspaceClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationsWorkspaceClientCapabilities.cs new file mode 100644 index 0000000000000..ca9af203384ad --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileOperationsWorkspaceClientCapabilities.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The client's capabilities for file requests/notifications. +/// +internal class FileOperationsWorkspaceClientCapabilities +{ + /// + /// The client has support for sending didCreateFiles notifications. + /// + [JsonPropertyName("didCreate")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DidCreate { get; init; } + + /// + /// The client has support for sending willCreateFiles requests. + /// + [JsonPropertyName("willCreate")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WillCreate { get; init; } + + /// + /// The client has support for sending didRenameFiles notifications. + /// + [JsonPropertyName("didRename")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DidRename { get; init; } + + /// + /// The client has support for sending willRenameFiles requests. + /// + [JsonPropertyName("willRename")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WillRename { get; init; } + + /// + /// The client has support for sending didDeleteFiles notifications. + /// + [JsonPropertyName("didDelete")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DidDelete { get; init; } + + /// + /// The client has support for sending willDeleteFiles requests. + /// /// + [JsonPropertyName("willDelete")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WillDelete { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileRename.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileRename.cs new file mode 100644 index 0000000000000..fada354f69415 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileRename.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Represents information on a file/folder rename. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class FileRename +{ + /// + /// A file:// URI for the original location of the file/folder being renamed + /// + [JsonPropertyName("oldUri")] + [JsonRequired] + [JsonConverter(typeof(DocumentUriConverter))] + public Uri OldUri { get; set; } + + /// + /// A file:// URI for the new location of the file/folder being renamed. + /// + [JsonPropertyName("newUri")] + [JsonRequired] + [JsonConverter(typeof(DocumentUriConverter))] + public Uri NewUri { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileSystemWatcher.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileSystemWatcher.cs new file mode 100644 index 0000000000000..0fba2560eadfe --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileSystemWatcher.cs @@ -0,0 +1,36 @@ +// 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.ComponentModel; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Specifies patterns and kinds of file events to watch. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class FileSystemWatcher +{ + /// + /// The glob pattern to watch. See Glob Pattern + /// and for more detail. + /// + [JsonPropertyName("globPattern")] + [JsonRequired] + public SumType GlobPattern { get; init; } + + /// The kind of events of interest. + /// + /// + /// If omitted it defaults to + /// WatchKind.Create | WatchKind.Change | WatchKind.Delete + /// which is 7. + /// + [JsonPropertyName("kind")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public WatchKind? Kind { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/RelativePattern.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/RelativePattern.cs new file mode 100644 index 0000000000000..6126ef4a7c3b7 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/RelativePattern.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A relative pattern is a helper to construct glob patterns that are matched +/// relatively to a base URI. The common value for a is a workspace +/// folder root, but it can be another absolute URI as well. +/// +/// Since LSP 3.17 +internal class RelativePattern +{ + /// + /// A workspace folder or a base URI to which this pattern will be matched + /// against relatively. + /// + [JsonPropertyName("baseUri")] + [JsonRequired] + public SumType BaseUri { get; init; } + + /// + /// The actual glob pattern. See Glob Pattern for more detail. + /// + [JsonPropertyName("pattern")] + [JsonRequired] + public string Pattern { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/RenameFilesParams.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/RenameFilesParams.cs new file mode 100644 index 0000000000000..bf016ae48f83f --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/RenameFilesParams.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The parameters sent in notifications/requests for user-initiated renames of files. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class RenameFilesParams +{ + /// + /// An array of all files/folders renamed in this operation. When a folder + /// is renamed, only the folder will be included, and not its children. + /// + [JsonPropertyName("files")] + [JsonRequired] + public FileRename[] Files { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/WatchKind.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/WatchKind.cs new file mode 100644 index 0000000000000..7d5ef0306bef4 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/WatchKind.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// File watch events of interest to a +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +[Flags] +internal enum WatchKind +{ + /// + /// Interested in create events. + /// + Create = 1, + + /// + /// Interested in change events + /// + Change = 2, + + /// + /// Interested in delete events + /// + Delete = 4, +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/WorkspaceFileOperationsServerCapabilities.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/WorkspaceFileOperationsServerCapabilities.cs new file mode 100644 index 0000000000000..5b5c161ab8e62 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/WorkspaceFileOperationsServerCapabilities.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The server capabilities specific to workspace file operations. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class WorkspaceFileOperationsServerCapabilities +{ + /// + /// The server is interested in receiving didCreateFiles notifications. + /// + [JsonPropertyName("didCreate")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public FileOperationRegistrationOptions? DidCreate { get; init; } + + /// + /// The server is interested in receiving willCreateFiles requests. + /// + [JsonPropertyName("willCreate")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public FileOperationRegistrationOptions? WillCreate { get; init; } + + /// + /// The server is interested in receiving didRenameFiles notifications. + /// + [JsonPropertyName("didRename")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public FileOperationRegistrationOptions? DidRename { get; init; } + + /// + /// The server is interested in receiving willRenameFiles requests. + /// + [JsonPropertyName("willRename")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public FileOperationRegistrationOptions? WillRename { get; init; } + + /// + /// The server is interested in receiving didDeleteFiles file notifications. + /// + [JsonPropertyName("didDelete")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public FileOperationRegistrationOptions? DidDelete { get; init; } + + /// + /// The server is interested in receiving willDeleteFiles file requests. + /// + [JsonPropertyName("willDelete")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public FileOperationRegistrationOptions? WillDelete { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/WorkspaceFoldersChangeEvent.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/WorkspaceFoldersChangeEvent.cs new file mode 100644 index 0000000000000..8e7abed2dc04e --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/WorkspaceFoldersChangeEvent.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The workspace folder change event provided by the +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.6 +internal class WorkspaceFoldersChangeEvent +{ + /// + /// The array of added workspace folders + /// + [JsonPropertyName("added")] + [JsonRequired] + public WorkspaceFolder[] Added { get; init; } + + /// + /// The array of the removed workspace folders + /// + [JsonPropertyName("removed")] + [JsonRequired] + public WorkspaceFolder[] Removed { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/WorkspaceFoldersServerCapabilities.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/WorkspaceFoldersServerCapabilities.cs new file mode 100644 index 0000000000000..789f2da3d90e4 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/WorkspaceFoldersServerCapabilities.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The server capabilities specific to workspace folders +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.6 +internal class WorkspaceFoldersServerCapabilities +{ + /// + /// The server has support for workspace folders + /// + [JsonPropertyName("supported")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool? Supported { get; init; } + + /// + /// Whether the server wants to receive workspace folder + /// change notifications. + /// + /// If a string is provided, the string is treated as an ID + /// under which the notification is registered on the client + /// side. The ID can be used to unregister for these events + /// using the request. + /// + /// + [JsonPropertyName("changeNotifications")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SumType? ChangeNotifications { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FoldingRange.cs b/src/LanguageServer/Protocol/Protocol/FoldingRange.cs index 78f0c975a205d..d2ec8c52d55b5 100644 --- a/src/LanguageServer/Protocol/Protocol/FoldingRange.cs +++ b/src/LanguageServer/Protocol/Protocol/FoldingRange.cs @@ -7,16 +7,28 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing a folding range in a document. - /// + /// Represents a folding range in a document. + /// + /// To be valid, start and end line must be bigger than zero and smaller than + /// the number of lines in the document. Clients are free to ignore invalid ranges. + /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal class FoldingRange { /// - /// Gets or sets the start line value. + /// The zero-based start line of the range to fold. + /// + /// The folded area starts after the line's last character. To be + /// valid, the end must be zero or larger and smaller than the + /// number of lines in the document. + /// /// [JsonPropertyName("startLine")] + [JsonRequired] public int StartLine { get; @@ -24,7 +36,10 @@ public int StartLine } /// - /// Gets or sets the start character value. + /// The zero-based character offset from where the folded range starts. + /// + /// If not defined, defaults to the length of the start line. + /// /// [JsonPropertyName("startCharacter")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -35,9 +50,15 @@ public int? StartCharacter } /// - /// Gets or sets the end line value. + /// The zero-based end line of the range to fold. + /// + /// The folded area ends with the line's last character. To be valid, + /// the end must be zero or larger and smaller than the number of + /// lines in the document. + /// /// [JsonPropertyName("endLine")] + [JsonRequired] public int EndLine { get; @@ -45,7 +66,10 @@ public int EndLine } /// - /// Gets or sets the end character value. + /// The zero-based character offset before the folded range ends. + /// + /// If not defined, defaults to the length of the end line. + /// /// [JsonPropertyName("endCharacter")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -56,7 +80,13 @@ public int? EndCharacter } /// - /// Gets or sets the folding range kind. + /// Describes the kind of the folding range such as + /// or . + /// + /// The kind is used to categorize folding ranges and used by commands like + /// 'Fold all comments'. See for an + /// enumeration of standardized kinds. + /// /// [JsonPropertyName("kind")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -67,8 +97,13 @@ public FoldingRangeKind? Kind } /// - /// Gets or sets the collapsedText. + /// The text that the client should show when the specified range is + /// collapsed. + /// + /// If not defined or not supported by the client, a default will be chosen by the client + /// /// + /// Since LSP 3.17 [JsonPropertyName("collapsedText")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? CollapsedText diff --git a/src/LanguageServer/Protocol/Protocol/FoldingRangeKind.cs b/src/LanguageServer/Protocol/Protocol/FoldingRangeKind.cs index ee256741290b3..a00bbba153d57 100644 --- a/src/LanguageServer/Protocol/Protocol/FoldingRangeKind.cs +++ b/src/LanguageServer/Protocol/Protocol/FoldingRangeKind.cs @@ -9,9 +9,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Value representing various folding range kinds. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 [JsonConverter(typeof(StringEnumConverter))] [TypeConverter(typeof(StringEnumConverter.TypeConverter))] internal readonly record struct FoldingRangeKind(string Value) : IStringEnum diff --git a/src/LanguageServer/Protocol/Protocol/FoldingRangeKindSet.cs b/src/LanguageServer/Protocol/Protocol/FoldingRangeKindSet.cs new file mode 100644 index 0000000000000..a6b20278f41e6 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/FoldingRangeKindSet.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A set of values +/// +/// Since LSP 3.17 +internal class FoldingRangeKindSet +{ + /// + /// The folding range kind values the client supports. + /// + /// When this property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + /// + /// + [JsonPropertyName("valueSet")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public FoldingRangeKind[]? ValueSet { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FoldingRangeParams.cs b/src/LanguageServer/Protocol/Protocol/FoldingRangeParams.cs index fed7123c0cb67..bb36a5c01fb56 100644 --- a/src/LanguageServer/Protocol/Protocol/FoldingRangeParams.cs +++ b/src/LanguageServer/Protocol/Protocol/FoldingRangeParams.cs @@ -4,23 +4,33 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// - /// Class representing the folding range request parameter. - /// + /// Class representing the parameter for the 'textDocument/foldingRange' request. + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class FoldingRangeParams : ITextDocumentParams + /// Since LSP 3.17 + internal class FoldingRangeParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams { /// /// Gets or sets the text document associated with the folding range request. /// [JsonPropertyName("textDocument")] - public TextDocumentIdentifier TextDocument - { - get; - set; - } + [JsonRequired] + public TextDocumentIdentifier TextDocument { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/FoldingRangeRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/FoldingRangeRegistrationOptions.cs index b04277c9e8308..b62a9ff9b0abc 100644 --- a/src/LanguageServer/Protocol/Protocol/FoldingRangeRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/FoldingRangeRegistrationOptions.cs @@ -7,19 +7,26 @@ namespace Roslyn.LanguageServer.Protocol; /// -/// Class representing the registration options for folding range support. -/// +/// Subclass of that allows scoping the registration. +/// /// See the Language Server Protocol specification for additional information. +/// /// -internal class FoldingRangeRegistrationOptions : FoldingRangeOptions, ITextDocumentRegistrationOptions +/// Since LSP 3.17 +internal class FoldingRangeRegistrationOptions : FoldingRangeOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions { /// - /// Gets or sets the document filters for this registration option. + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. /// [JsonPropertyName("documentSelector")] - public DocumentFilter[]? DocumentSelector - { - get; - set; - } -} \ No newline at end of file + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + /// The id used to register the request. The id can be used to deregister the request again. + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/FoldingRangeSetting.cs b/src/LanguageServer/Protocol/Protocol/FoldingRangeSetting.cs index e57fde0b348aa..c5cb807ded664 100644 --- a/src/LanguageServer/Protocol/Protocol/FoldingRangeSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/FoldingRangeSetting.cs @@ -7,14 +7,17 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the folding range setting for initialization. - /// + /// Client capabilities specific to the textDocument/foldingRange request. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class FoldingRangeSetting : DynamicRegistrationSetting { /// - /// Gets or sets the range limit for folding ranges. + /// The maximum number of folding ranges that the client prefers to receive + /// per document. The value serves as a hint, servers are free to follow the + /// limit. /// [JsonPropertyName("rangeLimit")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -25,7 +28,9 @@ public int? RangeLimit } /// - /// Gets or sets a value indicating whether if client only supports entire line folding only. + /// If set, the client signals that it only supports folding complete lines, + /// and will ignore and + /// properties. /// [JsonPropertyName("lineFoldingOnly")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -35,15 +40,20 @@ public bool LineFoldingOnly set; } + /// + /// Client capabilities specific to + /// + /// Since 3.17 + [JsonPropertyName("foldingRangeKind")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public FoldingRangeKindSet? FoldingRangeKind { get; init; } + /// /// Gets or sets a value indicating the specific options for the folding range. /// + /// Since 3.17 [JsonPropertyName("foldingRange")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public FoldingRangeSettingOptions? FoldingRange - { - get; - set; - } + public FoldingRangeSettingOptions? FoldingRange { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/FoldingRangeSettingOptions.cs b/src/LanguageServer/Protocol/Protocol/FoldingRangeSettingOptions.cs index 35b524fd67379..d211b60683682 100644 --- a/src/LanguageServer/Protocol/Protocol/FoldingRangeSettingOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/FoldingRangeSettingOptions.cs @@ -7,14 +7,17 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the specific options for the folding range. - /// + /// Client capabilities specific to + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class FoldingRangeSettingOptions : DynamicRegistrationSetting + /// Since LSP 3.17 + internal class FoldingRangeSettingOptions { /// - /// Gets or sets a value indicating whether if client supports collapsedText on folding ranges. + /// If set, the client signals that it supports setting + /// to display custom labels instead of the default text. /// [JsonPropertyName("collapsedText")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] diff --git a/src/LanguageServer/Protocol/Protocol/FormattingOptions.cs b/src/LanguageServer/Protocol/Protocol/FormattingOptions.cs index c7385acedce78..aec4268abece8 100644 --- a/src/LanguageServer/Protocol/Protocol/FormattingOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/FormattingOptions.cs @@ -9,39 +9,57 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents formatting options. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + // NOTE: The FormattingOptionsConverter enables the FormattingOptions.OtherOptions JsonExtensionData to be strongly typed. + // The Json* attributes on the members are for reference only - the converter is fully custom and ignores them. + [JsonConverter(typeof(FormattingOptionsConverter))] internal class FormattingOptions { /// - /// Gets or sets the number of spaces to be inserted per tab. + /// Size of a tab in spaces. /// [JsonPropertyName("tabSize")] - public int TabSize - { - get; - set; - } + [JsonRequired] + public int TabSize { get; set; } /// - /// Gets or sets a value indicating whether tabs should be spaces. + /// Whether tabs should be spaces. /// [JsonPropertyName("insertSpaces")] - public bool InsertSpaces - { - get; - set; - } + [JsonRequired] + public bool InsertSpaces { get; set; } /// - /// Gets or sets the other potential formatting options. + /// Trim trailing whitespace on a line. + /// + /// Since LSP 3.15 + [JsonPropertyName("trimTrailingWhitespace")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool TrimTrailingWhitespace { get; init; } + + /// + /// Insert a newline character at the end of the file if one does not exist. + /// + /// Since LSP 3.15 + [JsonPropertyName("insertFinalNewline")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool InsertFinalNewline { get; init; } + + /// + /// Trim all newlines after the final newline at the end of the file. + /// + /// Since LSP 3.15 + [JsonPropertyName("trimFinalNewlines")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool TrimFinalNewlines { get; init; } + + /// + /// Other potential formatting options. /// [JsonExtensionData] - public Dictionary? OtherOptions - { - get; - set; - } + public Dictionary>? OtherOptions { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/FullDocumentDiagnosticReport.cs b/src/LanguageServer/Protocol/Protocol/FullDocumentDiagnosticReport.cs index 17eaadd82514a..e98006f8f428e 100644 --- a/src/LanguageServer/Protocol/Protocol/FullDocumentDiagnosticReport.cs +++ b/src/LanguageServer/Protocol/Protocol/FullDocumentDiagnosticReport.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Class representing a diagnostic report with a full set of problems. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 [Kind(DocumentDiagnosticReportKind.Full)] internal class FullDocumentDiagnosticReport { @@ -23,7 +25,9 @@ internal class FullDocumentDiagnosticReport #pragma warning restore CA1822 // Mark members as static /// - /// Gets or sets the optional result id. + /// An optional result id. If provided it will + /// be sent on the next diagnostic request for the + /// same document. /// [JsonPropertyName("resultId")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/GeneralClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/GeneralClientCapabilities.cs new file mode 100644 index 0000000000000..ef59c332a543b --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/GeneralClientCapabilities.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Class which represents general client capabilities. +/// +/// Since LSP 3.16 +internal class GeneralClientCapabilities +{ + /// + /// Client capability that signals how the client + /// handles stale requests (e.g. a request + /// for which the client will not process the response + /// anymore since the information is outdated). + /// + /// Since LSP 3.17 + [JsonPropertyName("staleRequestSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public StaleRequestSupport? StaleRequestSupport { get; init; } + + /// + /// Client capabilities specific to regular expressions. + /// + [JsonPropertyName("regularExpressions")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public RegularExpressionsClientCapabilities? RegularExpressions { get; init; } + + /// + /// Client capabilities specific to the client's markdown parser. + /// + [JsonPropertyName("markdown")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public MarkdownClientCapabilities? Markdown { get; init; } + + /// + /// The position encodings supported by the client. Client and server + /// have to agree on the same position encoding to ensure that offsets + /// (e.g. character position in a line) are interpreted the same on both + /// side. + /// + /// To keep the protocol backwards compatible the following applies: if + /// the value 'utf-16' is missing from the array of position encodings + /// servers can assume that the client supports UTF-16. UTF-16 is + /// therefore a mandatory encoding. + /// + /// + /// If omitted it defaults to ['utf-16']. + /// + /// + /// Implementation considerations: since the conversion from one encoding + /// into another requires the content of the file / line the conversion + /// is best done where the file is read which is usually on the server + /// side. + /// + /// + /// Since LSP 3.17 + [JsonPropertyName("positionEncodings")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public PositionEncodingKind[]? PositionEncodings { get; init; } + +} diff --git a/src/LanguageServer/Protocol/Protocol/Hover.cs b/src/LanguageServer/Protocol/Protocol/Hover.cs index 27c8399906956..0f73a4a751d67 100644 --- a/src/LanguageServer/Protocol/Protocol/Hover.cs +++ b/src/LanguageServer/Protocol/Protocol/Hover.cs @@ -7,34 +7,28 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the data returned by a textDocument/hover request. - /// + /// Class representing the data returned by a textDocument/hover request. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class Hover { /// - /// Gets or sets the content for the hover. Object can either be an array or a single object. - /// If the object is an array the array can contain objects of type and . - /// If the object is not an array it can be of type , , or . + /// The hover's content /// - // This is nullable because in VS we allow null when VSInternalHover.RawContent is specified instead of Contents [JsonPropertyName("contents")] - public SumType[], MarkupContent>? Contents - { - get; - set; - } + [JsonRequired] +#pragma warning disable CS0618 // MarkedString is obsolete but this property is not + public SumType[], MarkupContent> Contents { get; set; } +#pragma warning restore CS0618 /// - /// Gets or sets the range over which the hover applies. + /// An optional range inside a text document that is used to visualize the applicable + /// range of the hover, e.g. by changing the background color. /// [JsonPropertyName("range")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public Range? Range - { - get; - set; - } + public Range? Range { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/HoverOptions.cs b/src/LanguageServer/Protocol/Protocol/HoverOptions.cs index 51c8a83658f0d..18de3820c7048 100644 --- a/src/LanguageServer/Protocol/Protocol/HoverOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/HoverOptions.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents the server hover support. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class HoverOptions : IWorkDoneProgressOptions { diff --git a/src/LanguageServer/Protocol/Protocol/HoverParams.cs b/src/LanguageServer/Protocol/Protocol/HoverParams.cs new file mode 100644 index 0000000000000..57bd0c85a5fd5 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/HoverParams.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a 'textDocument/hover' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class HoverParams : TextDocumentPositionParams, IWorkDoneProgressParams +{ + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/HoverRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/HoverRegistrationOptions.cs index 5163fd5dfd935..d2f278aaf9fd9 100644 --- a/src/LanguageServer/Protocol/Protocol/HoverRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/HoverRegistrationOptions.cs @@ -7,19 +7,18 @@ namespace Roslyn.LanguageServer.Protocol; /// -/// Class representing the registration options for hover support. -/// +/// Subclass of that allows scoping the registration. +/// /// See the Language Server Protocol specification for additional information. +/// /// internal class HoverRegistrationOptions : HoverOptions, ITextDocumentRegistrationOptions { /// - /// Gets or sets the document filters for this registration option. + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. /// [JsonPropertyName("documentSelector")] - public DocumentFilter[]? DocumentSelector - { - get; - set; - } -} \ No newline at end of file + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/HoverSetting.cs b/src/LanguageServer/Protocol/Protocol/HoverSetting.cs index e19b54f371fe0..d5af4e8609a2a 100644 --- a/src/LanguageServer/Protocol/Protocol/HoverSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/HoverSetting.cs @@ -7,14 +7,19 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents the initialization setting for hover. - /// + /// Client capabilities specific to the `textDocument/hover` request. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class HoverSetting : DynamicRegistrationSetting { /// - /// Gets or sets the values supported. + /// The client supports the following content formats in a + /// instance in . + /// + /// The order describes the preferred format of the client. + /// /// [JsonPropertyName("contentFormat")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/IAnnotatedChange.cs b/src/LanguageServer/Protocol/Protocol/IAnnotatedChange.cs new file mode 100644 index 0000000000000..ac61f94458d0f --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/IAnnotatedChange.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A change operation with a change annotation identifier +/// +interface IAnnotatedChange +{ + /// + /// Optional annotation identifier describing the operation + /// + /// Since 3.16 + [JsonPropertyName("annotationId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ChangeAnnotationIdentifier? AnnotationId { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/IDynamicRegistrationSetting.cs b/src/LanguageServer/Protocol/Protocol/IDynamicRegistrationSetting.cs new file mode 100644 index 0000000000000..581e5a957eac8 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/IDynamicRegistrationSetting.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// A setting that can be dynamically registered via the `client/registerCapability` method. +/// +internal interface IDynamicRegistrationSetting +{ + /// + /// Whether the implementation supports dynamic registration. + /// + [JsonPropertyName("dynamicRegistration")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DynamicRegistration { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/IPartialResultParams.cs b/src/LanguageServer/Protocol/Protocol/IPartialResultParams.cs index 194dc57dc96cc..61db86ddda7b6 100644 --- a/src/LanguageServer/Protocol/Protocol/IPartialResultParams.cs +++ b/src/LanguageServer/Protocol/Protocol/IPartialResultParams.cs @@ -5,22 +5,24 @@ namespace Roslyn.LanguageServer.Protocol { using System; + using System.Text.Json.Serialization; /// /// Interface to describe parameters for requests that support streaming results. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// /// The type to be reported by . internal interface IPartialResultParams { /// - /// Gets or sets the value of the PartialResultToken instance. + /// An instance that can be used to report partial results + /// via the $/progress notification. /// - public IProgress? PartialResultToken - { - get; - set; - } + // NOTE: these JSON attributes are not inherited, they are here as a reference for implementations + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/IStaticRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/IStaticRegistrationOptions.cs index 52fab2aad3cbd..4411c446a28ee 100644 --- a/src/LanguageServer/Protocol/Protocol/IStaticRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/IStaticRegistrationOptions.cs @@ -2,17 +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.Text.Json.Serialization; + namespace Roslyn.LanguageServer.Protocol; /// /// Interface representing the static registration options for options returned in the initialize request. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// internal interface IStaticRegistrationOptions { /// - /// Gets or sets the id used to register the request. The id can be used to deregister the request again. + /// Gets or sets the id used to register the request. The id can be used to deregister the request again. /// + // NOTE: these JSON attributes are not inherited, they are here as a reference for implementations + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? Id { get; set; } } diff --git a/src/LanguageServer/Protocol/Protocol/ITextDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/ITextDocumentParams.cs index 4fa13027b0903..6f271165befec 100644 --- a/src/LanguageServer/Protocol/Protocol/ITextDocumentParams.cs +++ b/src/LanguageServer/Protocol/Protocol/ITextDocumentParams.cs @@ -2,19 +2,21 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Text.Json.Serialization; + namespace Roslyn.LanguageServer.Protocol { /// - /// Interface to identify a text document. + /// Interface for request/notification params that apply to a document /// internal interface ITextDocumentParams { /// - /// Gets or sets the value which identifies the document. + /// The identifier of the document. /// - public TextDocumentIdentifier TextDocument - { - get; - } + // NOTE: these JSON attributes are not inherited, they are here as a reference for implementations + [JsonPropertyName("textDocument")] + [JsonRequired] + public TextDocumentIdentifier TextDocument { get; } } } diff --git a/src/LanguageServer/Protocol/Protocol/ITextDocumentPositionParams.cs b/src/LanguageServer/Protocol/Protocol/ITextDocumentPositionParams.cs index 22901df807aa9..a567a5b949ab4 100644 --- a/src/LanguageServer/Protocol/Protocol/ITextDocumentPositionParams.cs +++ b/src/LanguageServer/Protocol/Protocol/ITextDocumentPositionParams.cs @@ -2,31 +2,24 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Text.Json.Serialization; + namespace Roslyn.LanguageServer.Protocol { /// - /// Interface to identify a text document and a position inside that document. - /// - /// See the Language Server Protocol specification for additional information. + /// Interface for request/notification params that apply to a a position inside a document + /// + /// See the Language Server Protocol specification for additional information. + /// /// internal interface ITextDocumentPositionParams : ITextDocumentParams { /// - /// Gets or sets the value which identifies the document. - /// - public new TextDocumentIdentifier TextDocument - { - get; - set; - } - - /// - /// Gets or sets the value which indicates the position within the document. + /// The position within the document. /// - public Position Position - { - get; - set; - } + // NOTE: these JSON attributes are not inherited, they are here as a reference for implementations + [JsonPropertyName("position")] + [JsonRequired] + public Position Position { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/ITextDocumentRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/ITextDocumentRegistrationOptions.cs index b919469dfb16f..22fa3f67e4daf 100644 --- a/src/LanguageServer/Protocol/Protocol/ITextDocumentRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/ITextDocumentRegistrationOptions.cs @@ -2,17 +2,24 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Text.Json.Serialization; + namespace Roslyn.LanguageServer.Protocol; /// -/// Interface representing the text document registration options. -/// -/// See the Language Server Protocol specification for additional information. +/// Interface for registration options that can be scoped to particular text documents. +/// +/// See the Language Server Protocol specification for additional information. +/// /// internal interface ITextDocumentRegistrationOptions { /// - /// Gets or sets the document filters for this registration option. + /// A document selector to identify the scope of the registration. If set to + /// the document selector provided on the client side will be used. /// + // NOTE: these JSON attributes are not inherited, they are here as a reference for implementations + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public DocumentFilter[]? DocumentSelector { get; set; } } diff --git a/src/LanguageServer/Protocol/Protocol/IWorkDoneProgressOptions.cs b/src/LanguageServer/Protocol/Protocol/IWorkDoneProgressOptions.cs index 5ed79725eacb1..4dfd193f32bf8 100644 --- a/src/LanguageServer/Protocol/Protocol/IWorkDoneProgressOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/IWorkDoneProgressOptions.cs @@ -2,18 +2,26 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Text.Json.Serialization; + namespace Roslyn.LanguageServer.Protocol { /// /// Options to signal work done progress support in server capabilities. /// + /// Since LSP 3.15 internal interface IWorkDoneProgressOptions { /// /// Gets or sets a value indicating whether work done progress is supported. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - bool WorkDoneProgress { get; init; } + /// Since LSP 3.15 + // NOTE: these JSON attributes are not inherited, they are here as a reference for implementations + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/IWorkDoneProgressParams.cs b/src/LanguageServer/Protocol/Protocol/IWorkDoneProgressParams.cs new file mode 100644 index 0000000000000..5c315d40f706f --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/IWorkDoneProgressParams.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Interface to describe parameters for requests that support reporting work done via the $/progress notification. +/// +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since LSP 3.15 +internal interface IWorkDoneProgressParams +{ + /// + /// An optional token that a server can use to report work done progress. + /// + /// The derived classes , and + /// are used to report the beginning, progression, and end of the operation. + /// + /// + /// Since LSP 3.15 + // NOTE: these JSON attributes are not inherited, they are here as a reference for implementations + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/InitializeParams.cs b/src/LanguageServer/Protocol/Protocol/InitializeParams.cs index f4a1f88cceb2b..1d6aa360525e3 100644 --- a/src/LanguageServer/Protocol/Protocol/InitializeParams.cs +++ b/src/LanguageServer/Protocol/Protocol/InitializeParams.cs @@ -10,10 +10,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents the parameter sent with an initialize method request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class InitializeParams + internal class InitializeParams : IWorkDoneProgressParams { /// /// Gets or sets the ID of the process which launched the language server. @@ -25,6 +26,13 @@ public int? ProcessId set; } + /// + /// Information about the client. + /// + /// Since LSP 3.15 + [JsonPropertyName("clientInfo")] + public ClientInfo? ClientInfo { get; set; } + /// /// Gets or sets the locale the client is currently showing the user interface in. /// This must not necessarily be the locale of the operating system. @@ -32,6 +40,7 @@ public int? ProcessId /// Uses IETF language tags as the value's syntax. /// (See https://en.wikipedia.org/wiki/IETF_language_tag) /// + /// Since LSP 3.16 [JsonPropertyName("locale")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? Locale @@ -45,7 +54,7 @@ public string? Locale /// [JsonPropertyName("rootPath")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [Obsolete("Deprecated in favour of RootUri")] + [Obsolete("Deprecated in favor of RootUri")] public string? RootPath { get; @@ -53,12 +62,10 @@ public string? RootPath } /// - /// Gets or sets the workspace root path. + /// Gets or sets the workspace root path. Take precedence over if both are set. /// - /// - /// This should be a string representation of an URI. - /// [JsonPropertyName("rootUri")] + [Obsolete("Deprecated in favor of WorkspaceFolders")] [JsonConverter(typeof(DocumentUriConverter))] public Uri? RootUri { @@ -100,5 +107,28 @@ public TraceSetting Trace #pragma warning disable SA1500, SA1513 // Braces for multi-line statements should not share line, Closing brace should be followed by blank line } = TraceSetting.Off; #pragma warning restore SA1500, SA1513 // Braces for multi-line statements should not share line, Closing brace should be followed by blank line + + /// + /// Workspace folders configured in the client when the server starts. + /// + /// An empty array indicates that the client supports workspace folders but none are open, + /// and indicates that the client does not support workspace folders. + /// + /// + /// Note that this is a minor change from the raw protocol, where if the property is present in JSON but , + /// it is equivalent to an empty array value. This distinction cannot easily be represented idiomatically in .NET, + /// but is not important to preserve. + /// + /// + /// Since LSP 3.6 + [JsonPropertyName("workspaceFolders")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonConverter(typeof(InitializeParamsWorkspaceFoldersConverter))] + public WorkspaceFolder[]? WorkspaceFolders { get; init; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/InitializeResult.cs b/src/LanguageServer/Protocol/Protocol/InitializeResult.cs index b3cf86842bdfd..6653657181d1c 100644 --- a/src/LanguageServer/Protocol/Protocol/InitializeResult.cs +++ b/src/LanguageServer/Protocol/Protocol/InitializeResult.cs @@ -17,10 +17,19 @@ internal class InitializeResult /// Gets or sets the server capabilities. /// [JsonPropertyName("capabilities")] + [JsonRequired] public ServerCapabilities Capabilities { get; set; } + + /// + /// Information about the server name and version + /// + /// Since LSP 3.15 + [JsonPropertyName("serverInfo")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ServerInfo? ServerInfo { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/InlayHint.cs b/src/LanguageServer/Protocol/Protocol/InlayHint.cs index 3b934f479d901..3baccb3001f60 100644 --- a/src/LanguageServer/Protocol/Protocol/InlayHint.cs +++ b/src/LanguageServer/Protocol/Protocol/InlayHint.cs @@ -8,15 +8,22 @@ namespace Roslyn.LanguageServer.Protocol /// /// A class representing inlay hints that appear next to parameters or types. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal class InlayHint { /// - /// Gets or sets the position that the inlay hint applies to. + /// The position of this hint. + /// + /// If multiple hints have the same position, they will be shown in the order + /// they appear in the response. + /// /// [JsonPropertyName("position")] + [JsonRequired] public Position Position { get; @@ -24,9 +31,14 @@ public Position Position } /// - /// Gets or sets the label associated with this inlay hint. + /// The label of this hint. A human readable string or an array of + /// label parts. + /// + /// Note that neither the string nor the label part can be empty. + /// /// [JsonPropertyName("label")] + [JsonRequired] public SumType Label { get; @@ -34,7 +46,8 @@ public SumType Label } /// - /// Gets or sets the InlayHintKind associated with this inlay hint. + /// The kind of this hint. Can be omitted in which case the client + /// should fall back to a reasonable default. /// [JsonPropertyName("kind")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -45,7 +58,16 @@ public InlayHintKind? Kind } /// - /// Gets or sets the TextEdits associated with this inlay hint. + /// Optional text edits that are performed when accepting this inlay hint. + /// + /// Note* that edits are expected to change the document so that the inlay + /// hint(or its nearest variant) is now part of the document and the inlay + /// hint itself is now obsolete. + /// + /// + /// Depending on the client capability clients + /// might resolve this property late using the resolve request. + /// /// [JsonPropertyName("textEdits")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -56,7 +78,11 @@ public TextEdit[]? TextEdits } /// - /// Gets or sets the tooltip of this inlay hint. + /// The tooltip text when you hover over this item. + /// + /// Depending on the client capability clients + /// might resolve this property late using the resolve request. + /// /// [JsonPropertyName("tooltip")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -67,7 +93,12 @@ public SumType? ToolTip } /// - /// Gets or sets the padding before this inlay hint. + /// Render padding before the hint. + /// + /// Note: Padding should use the editor's background color, not the + /// background color of the hint itself. That means padding can be used + /// to visually align/separate an inlay hint. + /// /// [JsonPropertyName("paddingLeft")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -78,7 +109,12 @@ public bool PaddingLeft } /// - /// Gets or sets the padding after this inlay hint. + /// Render padding after the hint. + /// + /// Note: Padding should use the editor's background color, not the + /// background color of the hint itself.That means padding can be used + /// to visually align/separate an inlay hint. + /// /// [JsonPropertyName("paddingRight")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -89,7 +125,8 @@ public bool PaddingRight } /// - /// Gets or sets the data that should be preserved between a textDocument/inlayHint request and a inlayHint/resolve request. + /// Gets or sets the data that should be preserved between a + /// textDocument/inlayHint request and a inlayHint/resolve request. /// [JsonPropertyName("data")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/InlayHintKind.cs b/src/LanguageServer/Protocol/Protocol/InlayHintKind.cs index 9e8ccb1548903..bfdd221883fc6 100644 --- a/src/LanguageServer/Protocol/Protocol/InlayHintKind.cs +++ b/src/LanguageServer/Protocol/Protocol/InlayHintKind.cs @@ -6,18 +6,20 @@ namespace Roslyn.LanguageServer.Protocol { /// /// Enum values for inlay hint kinds. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal enum InlayHintKind { /// - /// Type. + /// An inlay hint that for a type annotation /// Type = 1, /// - /// Parameter. + /// An inlay hint that is for a parameter /// Parameter = 2, } diff --git a/src/LanguageServer/Protocol/Protocol/InlayHintLabelPart.cs b/src/LanguageServer/Protocol/Protocol/InlayHintLabelPart.cs index 1946a23322ced..dcb07d48583b8 100644 --- a/src/LanguageServer/Protocol/Protocol/InlayHintLabelPart.cs +++ b/src/LanguageServer/Protocol/Protocol/InlayHintLabelPart.cs @@ -8,13 +8,15 @@ namespace Roslyn.LanguageServer.Protocol /// /// A class representing inlay hint label parts. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal class InlayHintLabelPart { /// - /// Gets or sets the value associated with this label part. + /// The value of this label part. /// [JsonPropertyName("value")] public string Value @@ -24,7 +26,11 @@ public string Value } /// - /// Gets or sets the tooltip of this label part. + /// The tooltip text when you hover over this label part. + /// + /// Depending on the client capability clients + /// might resolve this property late using the resolve request. + /// /// [JsonPropertyName("tooltip")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -35,7 +41,18 @@ public SumType? ToolTip } /// - /// Gets or sets the location of this label part. + /// An optional source code location that represents this label part. + /// + /// The editor will use this location for the hover and for code navigation + /// features. This part will become a clickable link that resolves to the + /// definition of the symbol at the given location (not necessarily the + /// location itself), it shows the hover that shows at the given location, + /// and it shows a context menu with further code navigation commands. + /// + /// + /// Depending on the client capability clients + /// might resolve this property late using the resolve request. + /// /// [JsonPropertyName("location")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -46,7 +63,11 @@ public Location? Location } /// - /// Gets or sets the command of this label part. + /// An optional command for this label part. + /// + /// Depending on the client capability clients + /// might resolve this property late using the resolve request. + /// /// [JsonPropertyName("command")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/InlayHintOptions.cs b/src/LanguageServer/Protocol/Protocol/InlayHintOptions.cs index ce9e1c5aef33a..fb24530ce5980 100644 --- a/src/LanguageServer/Protocol/Protocol/InlayHintOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/InlayHintOptions.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Server capabilities for inlay hints. - /// - /// See the Language Server Protocol specification for additional information. + /// + /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal class InlayHintOptions : IWorkDoneProgressOptions { /// @@ -21,7 +23,7 @@ internal class InlayHintOptions : IWorkDoneProgressOptions public bool WorkDoneProgress { get; init; } /// - /// Gets or sets a value indicating whether or not the inlay hints support has a resolve provider. + /// The server provides support to resolve additional information for an inlay hint item. /// [JsonPropertyName("resolveProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] diff --git a/src/LanguageServer/Protocol/Protocol/InlayHintParams.cs b/src/LanguageServer/Protocol/Protocol/InlayHintParams.cs index 9761b7c09c83d..0db0d373aaa6a 100644 --- a/src/LanguageServer/Protocol/Protocol/InlayHintParams.cs +++ b/src/LanguageServer/Protocol/Protocol/InlayHintParams.cs @@ -4,33 +4,35 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// /// Class representing the parameters sent from the client to the server for a textDocument/inlayHint request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class InlayHintParams : ITextDocumentParams + /// Since LSP 3.17 + internal class InlayHintParams : ITextDocumentParams, IWorkDoneProgressParams { /// /// Gets or sets the document identifier to fetch inlay hints results for. /// [JsonPropertyName("textDocument")] - public TextDocumentIdentifier TextDocument - { - get; - set; - } + [JsonRequired] + public TextDocumentIdentifier TextDocument { get; set; } /// /// Gets or sets the range to fetch inlay hints results for. /// [JsonPropertyName("range")] - public Range Range - { - get; - set; - } + [JsonRequired] + public Range Range { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/InlayHintRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/InlayHintRegistrationOptions.cs index 614eb9d3f459d..9a973b526507d 100644 --- a/src/LanguageServer/Protocol/Protocol/InlayHintRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/InlayHintRegistrationOptions.cs @@ -8,30 +8,21 @@ namespace Roslyn.LanguageServer.Protocol /// /// Inlay hint registration options. - /// - /// See the Language Server Protocol specification for additional information. + /// + /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal class InlayHintRegistrationOptions : InlayHintOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions { - /// - /// Gets or sets the document filters for this registration option. - /// + /// [JsonPropertyName("documentSelector")] - public DocumentFilter[]? DocumentSelector - { - get; - set; - } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// + /// [JsonPropertyName("id")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? Id - { - get; - set; - } + public string? Id { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/InlayHintResolveSupportSetting.cs b/src/LanguageServer/Protocol/Protocol/InlayHintResolveSupportSetting.cs index 25d1c6a154cc3..f5852d7c6e246 100644 --- a/src/LanguageServer/Protocol/Protocol/InlayHintResolveSupportSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/InlayHintResolveSupportSetting.cs @@ -7,14 +7,16 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing settings for inlayHint/resolve support. - /// + /// Client capabilities specific to the `inlayHint/resolve` request. + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal class InlayHintResolveSupportSetting { /// - /// Gets or sets a value indicating the properties that a client can resolve lazily. + /// The names of the properties that the client can resolve lazily. /// [JsonPropertyName("properties")] public string[] Properties diff --git a/src/LanguageServer/Protocol/Protocol/InlayHintSetting.cs b/src/LanguageServer/Protocol/Protocol/InlayHintSetting.cs index d6f8008ba47b6..2b418db0e0607 100644 --- a/src/LanguageServer/Protocol/Protocol/InlayHintSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/InlayHintSetting.cs @@ -7,15 +7,16 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing settings for inlay hint support. - /// + /// Inlay hint client capabilities. + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal class InlayHintSetting : DynamicRegistrationSetting { /// - /// Gets or sets a value indicating whether the client supports - /// resolving lazily on an inlay hint. + /// Indicates which properties a client can resolve lazily on an inlay hint. /// [JsonPropertyName("resolveSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/InlayHintWorkspaceSetting.cs b/src/LanguageServer/Protocol/Protocol/InlayHintWorkspaceSetting.cs index 7308f9b3d2ec5..92e9c682df3b4 100644 --- a/src/LanguageServer/Protocol/Protocol/InlayHintWorkspaceSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/InlayHintWorkspaceSetting.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol { /// /// Class representing the workspace inlay hint client capabilities. - /// - /// See the Language Server Protocol specification for additional information. + /// + /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.17 internal class InlayHintWorkspaceSetting { /// diff --git a/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueClientCapability.cs b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueClientCapability.cs new file mode 100644 index 0000000000000..28a6da214db57 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueClientCapability.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. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/inlineValue` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class InlineValueClientCapability : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueContext.cs b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueContext.cs new file mode 100644 index 0000000000000..7dd094a53a762 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueContext.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Additional information about the context in which inline values were requested. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class InlineValueContext +{ + /// + /// The stack frame (as a DAP Id) where the execution has stopped. + /// + [JsonPropertyName("frameId")] + [JsonRequired] + public int FrameId { get; set; } + + /// + /// The document range where execution has stopped. Typically the end + /// position of the range denotes the line where the inline values are shown + /// + [JsonPropertyName("stoppedLocation")] + [JsonRequired] + public Range StoppedLocation { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueEvaluatableExpression.cs b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueEvaluatableExpression.cs new file mode 100644 index 0000000000000..c56509b4d03e2 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueEvaluatableExpression.cs @@ -0,0 +1,39 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Provide an inline value through an expression evaluation. +/// +/// If only a range is specified, the expression will be extracted from the +/// underlying document. +/// +/// +/// An optional expression can be used to override the extracted expression. +/// +/// +/// Since LSP 3.17 +internal class InlineValueEvaluatableExpression +{ + /// + /// The document range for which the inline value applies. + /// + /// The range is used to extract the evaluatable expression from the + /// underlying document. + /// + /// + [JsonPropertyName("range")] + [JsonRequired] + public Range Range { get; init; } + + /// + /// If specified the expression overrides the extracted expression. + /// + [JsonPropertyName("expression")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Expression { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueOptions.cs b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueOptions.cs new file mode 100644 index 0000000000000..3dc248ac311b2 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueOptions.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Server capabilities specific to Inline Values. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class InlineValueOptions : IWorkDoneProgressOptions +{ + /// + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueParams.cs b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueParams.cs new file mode 100644 index 0000000000000..1d105d755e6cc --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueParams.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. + +namespace Roslyn.LanguageServer.Protocol; + +using System; +using System.Text.Json.Serialization; + +/// +/// Class representing the parameters sent from the client to the server for a textDocument/inlineValue request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class InlineValueParams : ITextDocumentParams, IWorkDoneProgressParams +{ + /// + /// The text document. + /// + [JsonPropertyName("textDocument")] + [JsonRequired] + public TextDocumentIdentifier TextDocument { get; set; } + + /// + /// The document range for which inline values should be computed. + /// + [JsonPropertyName("range")] + [JsonRequired] + public Range Range { get; set; } + + /// + /// Additional information about the context in which inline values were + /// requested. + /// + [JsonPropertyName("context")] + [JsonRequired] + public InlineValueContext Context { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueRegistrationOptions.cs new file mode 100644 index 0000000000000..0eeea40bc2a60 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueRegistrationOptions.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class InlineValueRegistrationOptions : InlineValueOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions +{ + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueText.cs b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueText.cs new file mode 100644 index 0000000000000..7ac60bacf0825 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueText.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Provide inline value as text. +/// +/// Since LSP 3.17 +internal class InlineValueText +{ + /// + /// The document range for which the inline value applies. + /// + [JsonPropertyName("range")] + [JsonRequired] + public Range Range { get; init; } + + /// + /// The text of the inline value. + /// + [JsonPropertyName("text")] + [JsonRequired] + public string Text { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueVariableLookup.cs b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueVariableLookup.cs new file mode 100644 index 0000000000000..e8b84bb39d42d --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueVariableLookup.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. + +namespace Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Provide inline value through a variable lookup. +/// +/// If only a range is specified, the variable name will be extracted from +/// the underlying document. +/// +/// +/// An optional variable name can be used to override the extracted name. +/// +/// +/// Since LSP 3.17 +internal class InlineValueVariableLookup +{ + /// + /// The document range for which the inline value applies. + /// + /// The range is used to extract the variable name from the underlying document. + /// + /// + [JsonPropertyName("range")] + [JsonRequired] + public Range Range { get; init; } + + /// + /// If specified the name of the variable to look up. + /// + [JsonPropertyName("variableName")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? VariableName { get; init; } + + /// + /// How to perform the lookup. + /// + [JsonPropertyName("caseSensitiveLookup")] + [JsonRequired] + public bool CaseSensitiveLookup { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueWorkspaceClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueWorkspaceClientCapabilities.cs new file mode 100644 index 0000000000000..8ad1cc84c3d39 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/InlineValues/InlineValueWorkspaceClientCapabilities.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Client workspace capabilities specific to inline values. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class InlineValueWorkspaceClientCapabilities +{ + /// + /// Whether the client implementation supports a refresh request sent from + /// the server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// inline values currently shown. It should be used with absolute care and + /// is useful for situation where a server for example detect a project wide + /// change that requires such a calculation. + /// + /// + [JsonPropertyName("refreshSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool RefreshSupport { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/InsertReplaceEdit.cs b/src/LanguageServer/Protocol/Protocol/InsertReplaceEdit.cs index 44c06ee7f3aef..067a0d240ba04 100644 --- a/src/LanguageServer/Protocol/Protocol/InsertReplaceEdit.cs +++ b/src/LanguageServer/Protocol/Protocol/InsertReplaceEdit.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// A special text edit to provide an insert and a replace operation. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class InsertReplaceEdit { /// diff --git a/src/LanguageServer/Protocol/Protocol/InsertTextFormat.cs b/src/LanguageServer/Protocol/Protocol/InsertTextFormat.cs index 537c41b695637..5cca5cbf13299 100644 --- a/src/LanguageServer/Protocol/Protocol/InsertTextFormat.cs +++ b/src/LanguageServer/Protocol/Protocol/InsertTextFormat.cs @@ -5,19 +5,27 @@ namespace Roslyn.LanguageServer.Protocol { /// - /// Enum representing insert text format for completion items. - /// + /// Defines whether the insert text in a completion item should be + /// interpreted as plain text or as a snippet. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal enum InsertTextFormat { /// - /// Completion item insertion is plaintext. + /// The primary text to be inserted is treated as a plain string. /// Plaintext = 1, /// - /// Completion item insertion is snippet. + /// The primary text to be inserted is treated as a snippet. + /// + /// A snippet can define tab stops and placeholders with $1, $2 + /// and ${3:foo}. $0 defines the final tab stop and defaults to + /// the end of the snippet. Placeholders with equal identifiers are + /// linked, such that typing in one will update others too. + /// /// Snippet = 2, } diff --git a/src/LanguageServer/Protocol/Protocol/InsertTextMode.cs b/src/LanguageServer/Protocol/Protocol/InsertTextMode.cs index 68d7be59e0c45..73ac303b4785a 100644 --- a/src/LanguageServer/Protocol/Protocol/InsertTextMode.cs +++ b/src/LanguageServer/Protocol/Protocol/InsertTextMode.cs @@ -6,18 +6,32 @@ namespace Roslyn.LanguageServer.Protocol { /// /// How whitespace and indentation is handled during completion item insertion. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal enum InsertTextMode { /// - /// The insertion or replace strings is taken as it is. + /// The insertion or replace string is taken as-is. + /// + /// If the value is multi-line the lines below the cursor will be + /// inserted using the indentation defined in the string value. + /// The client will not apply any kind of adjustments to the string. + /// /// AsIs = 1, /// - /// The editor adjusts leading whitespace of new lines so that they match the indentation up to the cursor of the line for which the item is accepted. + /// The editor adjusts leading whitespace of new lines so that + /// they match the indentation up to the cursor of the line for + /// which the item is accepted. + /// + /// Consider a line like this: <2tabs><cursor><3tabs>foo. Accepting a + /// multi line completion item is indented using 2 tabs and all + /// following lines inserted will be indented using 2 tabs as well. + /// /// AdjustIndentation = 2, } diff --git a/src/LanguageServer/Protocol/Protocol/InsertTextModeSupportSetting.cs b/src/LanguageServer/Protocol/Protocol/InsertTextModeSupportSetting.cs index 7b7e24c261a79..81bde42941994 100644 --- a/src/LanguageServer/Protocol/Protocol/InsertTextModeSupportSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/InsertTextModeSupportSetting.cs @@ -7,14 +7,14 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents initialization setting for the tag property on a completion item. - /// - /// See the Language Server Protocol specification for additional information. + /// The client's capabilities specific to the property. /// + /// Since 3.16 internal class InsertTextModeSupportSetting { /// - /// Gets or sets a value indicating the client supports the `insertTextMode` property on a completion item to override the whitespace handling mode as defined by the client. + /// The values that the client supports + /// onf the the property. /// [JsonPropertyName("valueSet")] [JsonRequired] diff --git a/src/LanguageServer/Protocol/Protocol/Internal/Converters/VSInternalExtensionUtilities.cs b/src/LanguageServer/Protocol/Protocol/Internal/Converters/VSInternalExtensionUtilities.cs index 15e162c6c13eb..32ef117def30d 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/Converters/VSInternalExtensionUtilities.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/Converters/VSInternalExtensionUtilities.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.LanguageServer.Handler; namespace Roslyn.LanguageServer.Protocol; @@ -41,12 +42,15 @@ private static void AddConverters(IList converters) AddOrReplaceConverter(); AddOrReplaceConverter(); AddOrReplaceConverter(); +#pragma warning disable CS0618 // SymbolInformation is obsolete but we need the converter regardless AddOrReplaceConverter(); +#pragma warning restore CS0618 AddOrReplaceConverter(); AddOrReplaceConverter(); AddOrReplaceConverter(); AddOrReplaceConverter(); AddOrReplaceConverter(); + AddOrReplaceConverter(); void AddOrReplaceConverter() where TExtension : TBase diff --git a/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalDocumentDiagnosticsParams.cs b/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalDocumentDiagnosticsParams.cs index 2a136bb3fab29..b717a780f70a3 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalDocumentDiagnosticsParams.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalDocumentDiagnosticsParams.cs @@ -10,18 +10,14 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing a diagnostic pull request for a specific document. /// - internal class VSInternalDocumentDiagnosticsParams : VSInternalDiagnosticParams, IPartialResultParams + internal class VSInternalDocumentDiagnosticsParams : VSInternalDiagnosticParams, IPartialResultParams, IWorkDoneProgressParams { - /// - /// Gets or sets an optional token that a server can use to report work done progress. - /// + /// [JsonPropertyName(Methods.WorkDoneTokenName)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public IProgress? WorkDoneToken { get; set; } + public IProgress WorkDoneToken { get; set; } - /// - /// Gets or sets an optional token that a server can use to report partial results (e.g. streaming) to the client. - /// + /// [JsonPropertyName(Methods.PartialResultTokenName)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public IProgress? PartialResultToken { get; set; } diff --git a/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalWorkspaceDiagnosticsParams.cs b/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalWorkspaceDiagnosticsParams.cs index 61d145c73c8bc..8dec2ac09d500 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalWorkspaceDiagnosticsParams.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/Diagnostics/VSInternalWorkspaceDiagnosticsParams.cs @@ -19,16 +19,12 @@ internal class VSInternalWorkspaceDiagnosticsParams : IPartialResultParams - /// Gets or sets an optional token that a server can use to report work done progress. - /// + /// [JsonPropertyName(Methods.WorkDoneTokenName)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public IProgress? WorkDoneToken { get; set; } + public IProgress? WorkDoneToken { get; set; } - /// - /// Gets or sets an optional token that a server can use to report partial results (e.g. streaming) to the client. - /// + /// [JsonPropertyName(Methods.PartialResultTokenName)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public IProgress? PartialResultToken { get; set; } diff --git a/src/LanguageServer/Protocol/Protocol/Internal/Efficiency/OptimizedVSCompletionListJsonConverter.cs b/src/LanguageServer/Protocol/Protocol/Internal/Efficiency/OptimizedVSCompletionListJsonConverter.cs index 5288dde922493..7f46d8dd8ed51 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/Efficiency/OptimizedVSCompletionListJsonConverter.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/Efficiency/OptimizedVSCompletionListJsonConverter.cs @@ -57,14 +57,8 @@ public override void Write(Utf8JsonWriter writer, OptimizedVSCompletionList valu JsonSerializer.Serialize(writer, completionList.CommitCharacters, options); } - if (completionList.IsIncomplete) - { - writer.WriteBoolean("isIncomplete", completionList.IsIncomplete); - } - else - { - // Default is "false" so no need to serialize - } + // this is a required property per the LSP spec + writer.WriteBoolean("isIncomplete", completionList.IsIncomplete); writer.WritePropertyName("items"); if (completionList.Items == null || completionList.Items.Length == 0) @@ -154,10 +148,7 @@ private static void WriteCompletionItem(Utf8JsonWriter writer, CompletionItem co } var label = completionItem.Label; - if (label != null) - { - writer.WriteString("label", label); - } + writer.WriteString("label", label); if (completionItem.LabelDetails != null) { diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalDocumentSpellCheckableParams.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalDocumentSpellCheckableParams.cs index e3634b57d5e98..cb5b5f5b550aa 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalDocumentSpellCheckableParams.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalDocumentSpellCheckableParams.cs @@ -8,13 +8,11 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Parameter for tD/_vs_spellCheckableRanges. + /// Parameter for textDocument/_vs_spellCheckableRanges. /// - internal class VSInternalDocumentSpellCheckableParams : VSInternalStreamingParams, IPartialResultParams + internal sealed class VSInternalDocumentSpellCheckableParams : VSInternalStreamingParams, IPartialResultParams { - /// - /// Gets or sets an optional token that a server can use to report partial results (e.g. streaming) to the client. - /// + /// [JsonPropertyName(Methods.PartialResultTokenName)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public IProgress? PartialResultToken diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalHover.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalHover.cs index 54c83f2ebf742..99dba5a0617a4 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalHover.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalHover.cs @@ -19,10 +19,31 @@ internal class VSInternalHover : Hover [JsonPropertyName("_vs_rawContent")] [JsonConverter(typeof(ObjectContentConverter))] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public object? RawContent + public object? RawContent { get; set; } + + /// + /// The hover's content + /// + /// + /// This may only be null when is specified instead of . + /// + [JsonPropertyName("contents")] + [JsonRequired] +#pragma warning disable CS0618 // MarkedString is obsolete but this property is not + public new SumType[], MarkupContent>? Contents { - get; - set; + get => contentsIsNull ? (SumType[], MarkupContent>?)null : base.Contents; + set + { + contentsIsNull = value is null; + if (value is not null) + { + base.Contents = value.Value; + } + } } + + bool contentsIsNull = false; +#pragma warning restore CS0618 } } diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMethods.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMethods.cs index 19902a762fd0b..1be519d95de57 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMethods.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalMethods.cs @@ -9,6 +9,11 @@ namespace Roslyn.LanguageServer.Protocol /// internal static class VSInternalMethods { + /// + /// Method name for 'copilot/_related_documents'. + /// + public const string CopilotRelatedDocumentsName = "copilot/_related_documents"; + /// /// Method name for 'textDocument/foldingRange/_vs_refresh'. /// diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalReferenceParams.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalReferenceParams.cs index 790b9ef24d951..7b5748228994d 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalReferenceParams.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalReferenceParams.cs @@ -4,12 +4,13 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// /// Class which represents extensions of passed as parameter of find reference requests. /// - internal class VSInternalReferenceParams : ReferenceParams + internal class VSInternalReferenceParams : ReferenceParams, IPartialResultParams[]> { /// /// Gets or sets a value indicating the scope of returned items. @@ -21,5 +22,11 @@ public VSInternalItemOrigin? Scope get; set; } + + // overrides the IPartialResultParams version on ReferenceParams + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public new IProgress[]>? PartialResultToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalRelatedDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalRelatedDocumentParams.cs new file mode 100644 index 0000000000000..c2c4014f2da96 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalRelatedDocumentParams.cs @@ -0,0 +1,41 @@ +// 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 Roslyn.LanguageServer.Protocol +{ + using System; + using System.Text.Json.Serialization; + + /// + /// Parameter for copilot/_related_documents. + /// + internal sealed class VSInternalRelatedDocumentParams : IPartialResultParams + { + /// + /// Gets or sets the document for which the feature is being requested for. + /// + [JsonPropertyName("_vs_textDocument")] + [JsonRequired] + public TextDocumentIdentifier TextDocument { get; set; } + + /// + /// Gets or sets the value which indicates the position within the document. + /// + [JsonPropertyName("position")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Position? Position { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } + } + + internal sealed class VSInternalRelatedDocumentReport + { + [JsonPropertyName("_vs_file_paths")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string[]? FilePaths { get; set; } + } +} diff --git a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalWorkspaceSpellCheckableParams.cs b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalWorkspaceSpellCheckableParams.cs index 417638b7bd55d..a3e3577f9ae33 100644 --- a/src/LanguageServer/Protocol/Protocol/Internal/VSInternalWorkspaceSpellCheckableParams.cs +++ b/src/LanguageServer/Protocol/Protocol/Internal/VSInternalWorkspaceSpellCheckableParams.cs @@ -19,9 +19,7 @@ internal class VSInternalWorkspaceSpellCheckableParams : IPartialResultParams - /// Gets or sets an optional token that a server can use to report partial results (e.g. streaming) to the client. - /// + /// [JsonPropertyName("_vs_partialResultToken")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public IProgress? PartialResultToken diff --git a/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeClientCapabilities.cs new file mode 100644 index 0000000000000..f5d2d093b2509 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeClientCapabilities.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. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/linkedEditingRange` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class LinkedEditingRangeClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeOptions.cs b/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeOptions.cs index 16d07390197b3..b337ac9739456 100644 --- a/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeOptions.cs @@ -8,14 +8,14 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents linked editing range capabilities. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class LinkedEditingRangeOptions : IWorkDoneProgressOptions { - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// + /// [JsonPropertyName("workDoneProgress")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool WorkDoneProgress { get; init; } diff --git a/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeParams.cs b/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeParams.cs index 78cbad670a95f..03a900cf05bed 100644 --- a/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeParams.cs +++ b/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeParams.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. +using System; +using System.Text.Json.Serialization; + namespace Roslyn.LanguageServer.Protocol { /// @@ -9,7 +12,12 @@ namespace Roslyn.LanguageServer.Protocol /// /// See the Language Server Protocol specification for additional information. /// - internal class LinkedEditingRangeParams : TextDocumentPositionParams + /// Since LSP 3.16 + internal class LinkedEditingRangeParams : TextDocumentPositionParams, IWorkDoneProgressParams { + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeRegistrationOptions.cs new file mode 100644 index 0000000000000..b3814a440c761 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/LinkedEditingRangeRegistrationOptions.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class LinkedEditingRangeRegistrationOptions : LinkedEditingRangeOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + /// The id used to register the request. The id can be used to deregister the request again. + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/LinkedEditingRanges.cs b/src/LanguageServer/Protocol/Protocol/LinkedEditingRanges.cs index a60978b1e0cb9..953e0f8533861 100644 --- a/src/LanguageServer/Protocol/Protocol/LinkedEditingRanges.cs +++ b/src/LanguageServer/Protocol/Protocol/LinkedEditingRanges.cs @@ -8,15 +8,20 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the response of an LinkedEditingRanges response. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class LinkedEditingRanges { /// - /// Gets or sets the ranges for the type rename. + /// A list of ranges that can be renamed together. The ranges must have + /// identical length and contain identical text content. The ranges cannot + /// overlap. /// [JsonPropertyName("ranges")] + [JsonRequired] public Range[] Ranges { get; @@ -24,7 +29,9 @@ public Range[] Ranges } /// - /// Gets or sets the word pattern for the type rename. + /// An optional word pattern (regular expression) that describes valid + /// contents for the given ranges. If no pattern is provided, the client + /// configuration's word pattern will be used. /// [JsonPropertyName("wordPattern")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/LocationLink.cs b/src/LanguageServer/Protocol/Protocol/LocationLink.cs new file mode 100644 index 0000000000000..8f2fff57d4246 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/LocationLink.cs @@ -0,0 +1,79 @@ +// 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.Text.Json.Serialization; + +using Roslyn.Utilities; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Represents a link between a source and a target location. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.14 +internal class LocationLink : IEquatable +{ + /// + /// Span of the origin of this link. + /// + /// Used as the underlined span for mouse interaction. Defaults to the word + /// range at the mouse position. + /// + /// + [JsonPropertyName("originSelectionRange")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Range? OriginSelectionRange { get; init; } + + /// + /// The URI for the target document. + /// + [JsonPropertyName("targetUri")] + [JsonRequired] + [JsonConverter(typeof(DocumentUriConverter))] + public Uri TargetUri { get; init; } + + /// + /// The full target range of the linked location in the target document, which includes + /// the and additional context such as comments (but + /// not leading/trailing whitespace). This information is typically used to highlight + /// the range in the editor. + /// + [JsonPropertyName("targetRange")] + [JsonRequired] + public Range TargetRange { get; init; } + + /// + /// Gets or sets the range to be selected and revealed in the target document e.g. the + /// name of the linked symbol. Must be contained by the . + /// + [JsonPropertyName("targetSelectionRange")] + [JsonRequired] + public Range TargetSelectionRange { get; init; } + + /// + public override bool Equals(object obj) => Equals(obj as LocationLink); + + /// + public bool Equals(LocationLink? other) => + other != null + && EqualityComparer.Default.Equals(this.OriginSelectionRange, other.OriginSelectionRange) + && this.TargetUri != null && other.TargetUri != null && this.TargetUri.Equals(other.TargetUri) + && EqualityComparer.Default.Equals(this.TargetRange, other.TargetRange) + && EqualityComparer.Default.Equals(this.TargetSelectionRange, other.TargetSelectionRange); + + /// + public override int GetHashCode() => +#if NET + HashCode.Combine(OriginSelectionRange, TargetUri, TargetRange, TargetSelectionRange); +#else + Hash.Combine(OriginSelectionRange, + Hash.Combine(TargetUri, + Hash.Combine(TargetRange, TargetSelectionRange.GetHashCode()))); +#endif +} diff --git a/src/LanguageServer/Protocol/Protocol/LogMessageParams.cs b/src/LanguageServer/Protocol/Protocol/LogMessageParams.cs index 6918677cc3014..c0bfa9aef0f71 100644 --- a/src/LanguageServer/Protocol/Protocol/LogMessageParams.cs +++ b/src/LanguageServer/Protocol/Protocol/LogMessageParams.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents parameter sent with window/logMessage requests. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class LogMessageParams { @@ -17,6 +18,7 @@ internal class LogMessageParams /// Gets or sets the type of message. /// [JsonPropertyName("type")] + [JsonRequired] public MessageType MessageType { get; @@ -26,6 +28,7 @@ public MessageType MessageType /// /// Gets or sets the message. /// + [JsonRequired] [JsonPropertyName("message")] public string Message { diff --git a/src/LanguageServer/Protocol/Protocol/LogTraceParams.cs b/src/LanguageServer/Protocol/Protocol/LogTraceParams.cs new file mode 100644 index 0000000000000..ba127418ecf2c --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/LogTraceParams.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Class representing the parameters for the notification. +/// +/// See the Language Server Protocol specification for additional information. +/// +internal class LogTraceParams +{ + /// + /// The message to be logged. + /// + [JsonPropertyName("message")] + [JsonRequired] + public string Message { get; init; } + + /// + /// Additional information that can be computed if the `trace` configuration + /// is set to . + /// + [JsonPropertyName("verbose")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Verbose { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/MarkdownClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/MarkdownClientCapabilities.cs new file mode 100644 index 0000000000000..9276f7c6f4eb2 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/MarkdownClientCapabilities.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Describes capabilities of the client's markdown parser +/// +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since LSP 3.16 +internal class MarkdownClientCapabilities +{ + /// + /// The name of the parser. + /// + [JsonPropertyName("parser")] + [JsonRequired] + public string Parser { get; init; } + + /// + /// The version of the parser. + /// + [JsonPropertyName("version")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Version { get; init; } + + /// + /// A list of HTML tags that the client allows/support in markdown + /// + /// Since LSP 3.17 + [JsonPropertyName("allowedTags")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string[]? AllowedTags { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/MarkedString.cs b/src/LanguageServer/Protocol/Protocol/MarkedString.cs index 3ca516d0589ab..2e2f8b072067a 100644 --- a/src/LanguageServer/Protocol/Protocol/MarkedString.cs +++ b/src/LanguageServer/Protocol/Protocol/MarkedString.cs @@ -4,20 +4,43 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// - /// Class representing human readable text that should be rendered. - /// + /// MarkedString can be used to render human readable text. It is either a + /// markdown string or a code-block that provides a language and a code snippet. + /// + /// The language identifier is semantically equal to the optional language + /// identifier in fenced code blocks in GitHub issues. + /// + /// The pair of a language and a value is an equivalent to markdown: + /// + /// ```${language} + /// ${value} + /// ``` + /// + /// + /// Note that markdown strings will be sanitized - that means html will be escaped. + /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class MarkedString { + // Code has to reference MarkedString in a SumType even if it's not using the class itself. + // This means that if we deprecate the type itself, referencing code would have to suppress + // deprecation warnings even if they are only using non-deprecated types. We work around + // by deprecating the members instead of the type itself. + const string DeprecationMessage = "The MarkedString class is deprecated. Use MarkupContent instead."; + /// /// Gets or sets the language of the code stored in . /// [JsonPropertyName("language")] [JsonRequired] + [Obsolete(DeprecationMessage)] public string Language { get; @@ -29,6 +52,7 @@ public string Language /// [JsonPropertyName("value")] [JsonRequired] + [Obsolete(DeprecationMessage)] public string Value { get; diff --git a/src/LanguageServer/Protocol/Protocol/MessageActionItem.cs b/src/LanguageServer/Protocol/Protocol/MessageActionItem.cs index 8f4739241c9e2..d6b9d342a9409 100644 --- a/src/LanguageServer/Protocol/Protocol/MessageActionItem.cs +++ b/src/LanguageServer/Protocol/Protocol/MessageActionItem.cs @@ -4,17 +4,19 @@ namespace Roslyn.LanguageServer.Protocol { + using System.Collections.Generic; using System.Text.Json.Serialization; /// /// Class which represent an action the user performs after a window/showMessageRequest request is sent. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class MessageActionItem { /// - /// Gets or sets the title. + /// A short title like 'Retry', 'Open Log' etc. /// [JsonPropertyName("title")] public string Title @@ -22,5 +24,14 @@ public string Title get; set; } + + /// + /// Additional properties which will be returned to the server in the request's response. + /// + /// Support for this depends on the client capability . + /// + /// + [JsonExtensionData] + public Dictionary AdditionalProperties { get; set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/MessageActionItemClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/MessageActionItemClientCapabilities.cs new file mode 100644 index 0000000000000..5f1dd17c821fa --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/MessageActionItemClientCapabilities.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `MessageActionItem` type +/// +/// Since LSP 3.16 +internal class MessageActionItemClientCapabilities +{ + /// + /// Whether the client supports additional attributes which + /// are preserved and sent back to the server in the + /// request's response. + /// + [JsonPropertyName("additionalPropertiesSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool AdditionalPropertiesSupport { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/MessageType.cs b/src/LanguageServer/Protocol/Protocol/MessageType.cs index b36f16e24c9d4..f52d7428c280b 100644 --- a/src/LanguageServer/Protocol/Protocol/MessageType.cs +++ b/src/LanguageServer/Protocol/Protocol/MessageType.cs @@ -6,8 +6,9 @@ namespace Roslyn.LanguageServer.Protocol { /// /// Message type enum. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal enum MessageType { @@ -30,5 +31,11 @@ internal enum MessageType /// Log message. /// Log = 4, + + /// + /// Debug message + /// + /// Since LSP 3.18 + Debug = 5, } } diff --git a/src/LanguageServer/Protocol/Protocol/Methods.Diagnostics.cs b/src/LanguageServer/Protocol/Protocol/Methods.Diagnostics.cs new file mode 100644 index 0000000000000..41caa8cf3f0f4 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Methods.Diagnostics.cs @@ -0,0 +1,103 @@ +// 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 Roslyn.LanguageServer.Protocol; + +// diagnostics methods from https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#languageFeatures +partial class Methods +{ + // NOTE: these are sorted in the order used by the spec + + /// + /// Method name for 'textDocument/publishDiagnostics'. + /// + /// Diagnostics notifications are sent from the server to the client to signal results of validation runs. + /// + /// + /// Diagnostics are “owned” by the server so it is the server’s responsibility to clear them if necessary. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentPublishDiagnosticsName = "textDocument/publishDiagnostics"; + + /// + /// Strongly typed message object for 'textDocument/publishDiagnostics'. + /// + public static readonly LspNotification TextDocumentPublishDiagnostics = new(TextDocumentPublishDiagnosticsName); + + /// + /// Method name for 'textDocument/diagnostic'. + /// + /// Pull diagnostics are a preferred alternative to 'textDocument/publishDiagnostics' push diagnostics that give + /// the client more control over the documents for which diagnostics should be computed and at which point in time. + /// + /// + /// The text document diagnostic request is sent from the client to the server to ask the server to compute the + /// diagnostics for a given document. As with other pull requests the server is asked to compute the diagnostics + /// for the currently synced version of the document. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string TextDocumentDiagnosticName = "textDocument/diagnostic"; + + /// + /// Strongly typed message object for 'textDocument/diagnostic'. + /// + /// Since LSP 3.17 + public static readonly LspNotification TextDocumentDiagnostic = new(TextDocumentDiagnosticName); + + /// + /// Method name for 'workspace/diagnostic'. + /// + /// The workspace diagnostic request is sent from the client to the server to ask the server to compute workspace + /// wide diagnostics which previously were pushed from the server to the client. + /// + /// + /// In contrast to the document diagnostic request the workspace request can be long running and is not bound + /// to a specific workspace or document state. + /// + /// + /// If the client supports streaming for the workspace diagnostic pull it is legal to provide a document diagnostic + /// report multiple times for the same document URI. The last one reported will win over previous reports. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string WorkspaceDiagnosticName = "workspace/diagnostic"; + + /// + /// Strongly typed message object for 'workspace/diagnostic'. + /// + /// Since LSP 3.17 + public static readonly LspRequest WorkspaceDiagnostic = new(WorkspaceDiagnosticName); + + /// + /// Method name for 'workspace/diagnostic/refresh'. + /// + /// The workspace/diagnostic/refresh request is sent from the server to the client. Servers can use it to ask clients + /// to refresh all needed document and workspace diagnostics. + /// + /// + /// This is useful if a server detects a project wide configuration change which requires a re-calculation of all diagnostics. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string WorkspaceDiagnosticRefreshName = "workspace/diagnostic/refresh"; + + /// + /// Strongly typed message object for 'workspace/diagnostic/refresh'. + /// + /// Since LSP 3.17 + public static readonly LspNotification WorkspaceDiagnosticRefresh = new(WorkspaceDiagnosticRefreshName); +} diff --git a/src/LanguageServer/Protocol/Protocol/Methods.Document.cs b/src/LanguageServer/Protocol/Protocol/Methods.Document.cs new file mode 100644 index 0000000000000..cf9ee709397e9 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Methods.Document.cs @@ -0,0 +1,620 @@ +// 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 Roslyn.LanguageServer.Protocol; + +// non-navigation methods from https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#languageFeatures +partial class Methods +{ + // NOTE: these are sorted in the order used by the spec + + /// + /// Method name for 'textDocument/hover'. + /// + /// The hover request is sent from the client to the server to request hover information at a given text document position. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentHoverName = "textDocument/hover"; + + /// + /// Strongly typed message object for 'textDocument/hover'. + /// + public static readonly LspRequest TextDocumentHover = new(TextDocumentHoverName); + + /// + /// Method name for 'textDocument/codeLens'. + /// + /// The code lens request is sent from the client to the server to compute code lenses for a given text document. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentCodeLensName = "textDocument/codeLens"; + + /// + /// Strongly typed message object for 'textDocument/codeLens'. + /// + public static readonly LspRequest TextDocumentCodeLens = new(TextDocumentCodeLensName); + + /// + /// Method name for 'codeLens/resolve'. + /// + /// The code lens resolve request is sent from the client to the server to resolve the command for a given code lens item. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string CodeLensResolveName = "codeLens/resolve"; + + /// + /// Strongly typed message object for 'codeLens/resolve'. + /// + public static readonly LspRequest CodeLensResolve = new(CodeLensResolveName); + + /// + /// Method name for 'workspace/codeLens/refresh'. + /// + /// The workspace/codeLens/refresh request is sent from the server to the client. Servers can use it to ask clients to + /// refresh the code lenses currently shown in editors. As a result the client should ask the server to recompute the + /// code lenses for these editors. + /// + /// This is useful if a server detects a configuration change which requires a re-calculation of all code lenses. Note + /// that the client still has the freedom to delay the re-calculation of the code lenses if for example an editor + /// is currently not visible. + /// + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string WorkspaceCodeLensRefreshName = "workspace/codeLens/refresh"; + + /// + /// Strongly typed message object for 'workspace/codeLens/refresh'. + /// + public static readonly LspRequest WorkspaceCodeLensRefresh = new(WorkspaceCodeLensRefreshName); + + /// + /// Method name for 'textDocument/foldingRange'. + /// + /// The folding range request is sent from the client to the server to return all folding ranges found in a given text document. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.10 + public const string TextDocumentFoldingRangeName = "textDocument/foldingRange"; + + /// + /// Strongly typed message object for 'textDocument/foldingRange'. + /// + public static readonly LspRequest TextDocumentFoldingRange = new(TextDocumentFoldingRangeName); + + /// + /// Method name for 'textDocument/selectionRange'. + /// + /// The selection range request is sent from the client to the server to return suggested selection ranges at an array of given positions. + /// + /// + /// A selection range is a range around the cursor position which the user might be interested in selecting. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.15 + public const string TextDocumentSelectionRangeName = "textDocument/selectionRange"; + + /// + /// Strongly typed message object for 'textDocument/selectionRange'. + /// + public static readonly LspRequest TextDocumentSelectionRange = new(TextDocumentSelectionRangeName); + + /// + /// Method name for 'textDocument/documentSymbol'. + /// + /// + /// The document symbol request is sent from the client to the server to return a collection of symbols in the document. + /// + /// The returned result is either: + /// + /// + /// An array of , which is a flat list of all symbols found in a given text document. Neither the symbol’s location range nor the symbol’s container name should be used to infer a hierarchy. + /// + /// + /// An array of , which is a hierarchy of symbols found in a given text document. + /// + /// + /// Servers should whenever possible return since it is the richer data structure. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentDocumentSymbolName = "textDocument/documentSymbol"; + + /// + /// Strongly typed message object for 'textDocument/documentSymbol'. + /// +#pragma warning disable CS0618 // SymbolInformation is obsolete but this property is not + public static readonly LspRequest?> TextDocumentDocumentSymbol = new(TextDocumentDocumentSymbolName); +#pragma warning restore CS0618 + + /// + /// Method name for 'textDocument/semanticTokens'. + /// + /// This method name is used only for registering for semantic tokens requests. + /// + /// + /// For actual requests, the specific methods textDocument/semanticTokens/{full,full/delta,range} are used. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string TextDocumentSemanticTokensName = "textDocument/semanticTokens"; + + /// + /// Method name for 'textDocument/semanticTokens/full'. + /// + /// Returns semantic tokens for the full document. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string TextDocumentSemanticTokensFullName = "textDocument/semanticTokens/full"; + + /// + /// Strongly typed message object for 'textDocument/semanticTokens/full'. + /// + /// Since LSP 3.16 + public static readonly LspRequest TextDocumentSemanticTokensFull = new(TextDocumentSemanticTokensFullName); + + /// + /// Method name for 'textDocument/semanticTokens/full/delta'. + /// + /// Returns a delta against a previous set of semantic tokens for the full document. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string TextDocumentSemanticTokensFullDeltaName = "textDocument/semanticTokens/full/delta"; + + /// + /// Strongly typed message object for 'textDocument/semanticTokens/full/delta'. + /// + /// Since LSP 3.16 + public static readonly LspRequest?> TextDocumentSemanticTokensFullDelta = new(TextDocumentSemanticTokensFullDeltaName); + + /// + /// Method name for 'textDocument/semanticTokens/range'. + /// + /// Returns semantic tokens for a visible range of the document. + /// + /// + /// This allows clients to improved rendering performance when opening files + /// and allow rendering documents that are too large for full semantic coloring. + /// + /// + /// A server is allowed to compute the semantic tokens for a broader range than + /// requested by the client. However if the server does the semantic tokens + /// for the broader range must be complete and correct. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string TextDocumentSemanticTokensRangeName = "textDocument/semanticTokens/range"; + + /// + /// Strongly typed message object for 'textDocument/semanticTokens/range'. + /// + /// Since LSP 3.16 + public static readonly LspRequest TextDocumentSemanticTokensRange = new(TextDocumentSemanticTokensRangeName); + + /// + /// Method name for 'workspace/semanticTokens/refresh'. + /// + /// This request is sent from the server to the client. Servers can use it to ask clients to refresh the editors for + /// which this server provides semantic tokens. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string WorkspaceSemanticTokensRefreshName = "workspace/semanticTokens/refresh"; + + /// + /// Strongly typed message object for 'workspace/semanticTokens/refresh'. + /// + /// Since LSP 3.16 + public static readonly LspRequest WorkspaceSemanticTokensRefresh = new(WorkspaceSemanticTokensRefreshName); + + /// + /// Method name for 'textDocument/inlayHint'. + /// + /// The inlay hints request is sent from the client to the server to compute inlay hints + /// for a given [text document, range] tuple that may be rendered in the editor in place with other text. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string TextDocumentInlayHintName = "textDocument/inlayHint"; + + /// + /// Strongly typed message object for 'textDocument/inlayHint'. + /// + /// Since LSP 3.17 + public static readonly LspRequest TextDocumentInlayHint = new(TextDocumentInlayHintName); + + /// + /// Method name for 'inlayHint/resolve'. + /// + /// The request is sent from the client to the server to resolve additional information for + /// a given inlay hint. + /// + /// + /// This is usually used to compute the tooltip, location or command + /// properties of an inlay hint’s label part to avoid its unnecessary computation during + /// the textDocument/inlayHint request. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string InlayHintResolveName = "inlayHint/resolve"; + + /// + /// Strongly typed message object for 'inlayHint/resolve'. + /// + /// Since LSP 3.17 + public static readonly LspRequest InlayHintResolve = new(InlayHintResolveName); + + /// + /// Method name for 'workspace/inlayHint/refresh'. + /// + /// This request is sent from the server to ask the client to refresh the inlay hints currently shown in editors. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string WorkspaceInlayHintRefreshName = "workspace/inlayHint/refresh"; + + /// + /// Strongly typed message object for 'workspace/inlayHint/refresh'. + /// + /// Since LSP 3.17 + public static readonly LspRequest WorkspaceInlayHintRefresh = new(WorkspaceInlayHintRefreshName); + + /// + /// Method name for 'textDocument/inlineValue'. + /// + /// The inline value request is sent from the client to the server to compute inline values for + /// a given text document that may be rendered in the editor at the end of lines.. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string TextDocumentInlineValueName = "textDocument/inlineValue"; + + /// + /// Strongly typed message object for 'textDocument/inlineValue'. + /// + /// Since LSP 3.17 + public static readonly LspRequest[]?> TextDocumentInlineValue = new(TextDocumentInlineValueName); + + /// + /// Method name for 'workspace/inlineValue/refresh'. + /// + /// This request is sent from the server to ask the client to refresh the inline values currently shown in editors. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string WorkspaceInlineValueRefreshName = "workspace/inlineValue/refresh"; + + /// + /// Strongly typed message object for 'workspace/inlineValue/refresh'. + /// + /// Since LSP 3.17 + public static readonly LspRequest WorkspaceInlineValueRefresh = new(WorkspaceInlineValueRefreshName); + + /// + /// Method name for 'textDocument/moniker'. + /// + /// Provide the same symbol moniker information used by Language Server Index Format (LSIF) given a text document position. + /// + /// + /// Clients can utilize this method to get the moniker at the current location in a file user is editing and do + /// further code navigation queries in other services that rely on LSIF indexes and link symbols together. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string TextDocumentMonikerName = "textDocument/moniker"; + + /// + /// Strongly typed message object for 'textDocument/moniker'. + /// + /// Since LSP 3.17 + public static readonly LspRequest TextDocumentMoniker = new(TextDocumentMonikerName); + + /// + /// Method name for 'textDocument/completion'. + /// + /// The Completion request is sent from the client to the server to compute completion items at a given cursor position. + /// + /// + /// If computing full completion items is expensive, servers can additionally provide a handler for the completion + /// item resolve request (‘completionItem/resolve’), which is sent when a completion item is selected in the user interface. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentCompletionName = "textDocument/completion"; + + /// + /// Strongly typed message object for 'textDocument/completion'. + /// + public static readonly LspRequest?> TextDocumentCompletion = new(TextDocumentCompletionName); + + /// + /// Method name for 'completionItem/resolve'. + /// + /// The request is sent from the client to the server to resolve additional information for a given completion item. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentCompletionResolveName = "completionItem/resolve"; + + /// + /// Strongly typed message object for 'completionItem/resolve'. + /// + public static readonly LspRequest TextDocumentCompletionResolve = new(TextDocumentCompletionResolveName); + + /// + /// Method name for 'textDocument/signatureHelp'. + /// + /// The signature help request is sent from the client to the server to request signature information at a given cursor position. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentSignatureHelpName = "textDocument/signatureHelp"; + + /// + /// Strongly typed message object for 'textDocument/signatureHelp'. + /// + public static readonly LspRequest TextDocumentSignatureHelp = new(TextDocumentSignatureHelpName); + + /// + /// Method name for 'textDocument/codeAction'. + /// + public const string TextDocumentCodeActionName = "textDocument/codeAction"; + + /// + /// Strongly typed message object for 'textDocument/codeAction'. + /// + /// The code action request is sent from the client to the server to compute commands for a + /// given text document and range. These commands are typically code fixes to either fix + /// problems or to beautify/refactor code. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public static readonly LspRequest[]?> TextDocumentCodeAction = new(TextDocumentCodeActionName); + + /// + /// Method name for 'codeAction/resolve'. + /// + /// The request is sent from the client to the server to resolve additional information + /// for a given code action. + /// + /// + /// This is usually used to compute the edit property of a code action to avoid its + /// unnecessary computation during the textDocument/codeAction request. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string CodeActionResolveName = "codeAction/resolve"; + + /// + /// Strongly typed message object for 'codeAction/resolve'. + /// + public static readonly LspRequest CodeActionResolve = new(CodeActionResolveName); + + /// + /// Method name for 'textDocument/documentColor'. + /// + /// The document color request is sent from the client to the server to list all color references + /// found in a given text document. Along with the range, a color value in RGB is returned. + /// + /// + /// Clients can use the result to decorate color references in an editor. For example: + /// + /// + /// Color boxes showing the actual color next to the reference + /// + /// + /// Show a color picker when a color reference is edited + /// + /// + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.6 + public const string TextDocumentDocumentColorName = "textDocument/documentColor"; + + /// + /// Strongly typed message object for 'textDocument/documentColor'. + /// + /// Since LSP 3.6 + public static readonly LspRequest TextDocumentDocumentColor = new(TextDocumentDocumentColorName); + + /// + /// Method name for 'textDocument/colorPresentation'. + /// + /// The color presentation request is sent from the client to the server to obtain a list of presentations for a color value at a given location. + /// + /// + /// Clients can use the result to: + /// + /// + /// modify a color reference. + /// + /// + /// show in a color picker and let users pick one of the presentations + /// + /// + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.6 + public const string TextDocumentColorPresentationName = "textDocument/colorPresentation"; + + /// + /// Strongly typed message object for 'textDocument/colorPresentation'. + /// + /// Since LSP 3.6 + public static readonly LspRequest TextDocumentColorPresentation = new(TextDocumentColorPresentationName); + + /// + /// Method name for 'textDocument/formatting'. + /// + /// The document formatting request is sent from the client to the server to format a whole document. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentFormattingName = "textDocument/formatting"; + + /// + /// Strongly typed message object for 'textDocument/formatting'. + /// + public static readonly LspRequest TextDocumentFormatting = new(TextDocumentFormattingName); + + /// + /// Method name for 'textDocument/rangeFormatting'. + /// + /// The document range formatting request is sent from the client to the server to format a given range in a document. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentRangeFormattingName = "textDocument/rangeFormatting"; + + /// + /// Strongly typed message object for 'textDocument/rangeFormatting'. + /// + public static readonly LspRequest TextDocumentRangeFormatting = new(TextDocumentRangeFormattingName); + + /// + /// Method name for 'textDocument/onTypeFormatting'. + /// + /// The document on type formatting request is sent from the client to the server to format parts of the document during typing. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentOnTypeFormattingName = "textDocument/onTypeFormatting"; + + /// + /// Strongly typed message object for 'textDocument/onTypeFormatting'. + /// + public static readonly LspRequest TextDocumentOnTypeFormatting = new(TextDocumentOnTypeFormattingName); + + /// + /// Method name for 'textDocument/rename'. + /// + /// The rename request is sent from the client to the server to ask the server to compute + /// a workspace change so that the client can perform a workspace-wide rename of a symbol. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentRenameName = "textDocument/rename"; + + /// + /// Strongly typed message object for 'textDocument/rename'. + /// + public static readonly LspRequest TextDocumentRename = new(TextDocumentRenameName); + + /// + /// Method name for 'textDocument/prepareRename'. + /// + /// The prepare rename request is sent from the client to the server to setup and test the + /// validity of a rename operation at a given location. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.12 + public const string TextDocumentPrepareRenameName = "textDocument/prepareRename"; + + /// + /// Strongly typed message object for 'textDocument/prepareRename'. + /// + /// Since LSP 3.12 + public static readonly LspRequest?> TextDocumentPrepareRename = new(TextDocumentPrepareRenameName); + + /// + /// Method name for 'textDocument/linkedEditingRange'. + /// + /// The linked editing request is sent from the client to the server to return for a given + /// position in a document the range of the symbol at the position and all ranges that have the same content. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string TextDocumentLinkedEditingRangeName = "textDocument/linkedEditingRange"; + + /// + /// Strongly typed message object for 'textDocument/linkedEditingRange'. + /// + /// Since LSP 3.16 + public static readonly LspRequest TextDocumentLinkedEditingRange = new(TextDocumentLinkedEditingRangeName); +} diff --git a/src/LanguageServer/Protocol/Protocol/Methods.DocumentSynchronization.cs b/src/LanguageServer/Protocol/Protocol/Methods.DocumentSynchronization.cs new file mode 100644 index 0000000000000..cf3b68c31e35a --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Methods.DocumentSynchronization.cs @@ -0,0 +1,112 @@ +// 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.LanguageServer.Protocol; + +namespace Roslyn.LanguageServer.Protocol; + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_synchronization +partial class Methods +{ + // NOTE: these are sorted/grouped in the order used by the spec + + /// + /// Method name for 'textDocument/didOpen'. + /// + /// The document open notification is sent from the client to the server to signal newly opened text documents. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentDidOpenName = "textDocument/didOpen"; + + /// + /// Strongly typed message object for 'textDocument/didOpen'. + /// + public static readonly LspNotification TextDocumentDidOpen = new(TextDocumentDidOpenName); + + /// + /// Method name for 'textDocument/didChange'. + /// + /// The document change notification is sent from the client to the server to signal changes to a text document. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentDidChangeName = "textDocument/didChange"; + + /// + /// Strongly typed message object for 'textDocument/didChange'. + /// + public static readonly LspNotification TextDocumentDidChange = new(TextDocumentDidChangeName); + + /// + /// Method name for 'textDocument/willSave'. + /// + /// The document will save notification is sent from the client to the server before the document is actually saved. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentWillSaveName = "textDocument/willSave"; + + /// + /// Strongly typed message object for 'textDocument/willSave'. + /// + public static readonly LspNotification TextDocumentWillSave = new(TextDocumentWillSaveName); + + /// + /// Method name for 'textDocument/willSaveWaitUntil'. + /// + /// The document will save wait until request is sent from the client to the server before the document is actually saved. + /// The request can return an array of TextEdits which will be applied to the text document before it is saved. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentWillSaveWaitUntilName = "textDocument/willSaveWaitUntil"; + + /// + /// Strongly typed message object for 'textDocument/willSaveWaitUntil'. + /// + public static readonly LspRequest TextDocumentWillSaveWaitUntil = new(TextDocumentWillSaveWaitUntilName); + + /// + /// Method name for 'textDocument/didSave'. + /// + /// The document save notification is sent from the client to the server when the document was saved in the client. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentDidSaveName = "textDocument/didSave"; + + /// + /// Strongly typed message object for 'textDocument/didSave'. + /// + public static readonly LspNotification TextDocumentDidSave = new(TextDocumentDidSaveName); + + /// + /// Method name for 'textDocument/didClose'. + /// + /// The document close notification is sent from the client to the server when the document + /// got closed in the client. The document’s master now exists where the document’s Uri + /// points to (e.g. if the document’s Uri is a file Uri the master now exists on disk) + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentDidCloseName = "textDocument/didClose"; + + /// + /// Strongly typed message object for 'textDocument/didSave'. + /// + public static readonly LspNotification TextDocumentDidClose = new(TextDocumentDidCloseName); +} diff --git a/src/LanguageServer/Protocol/Protocol/Methods.Lifecyle.cs b/src/LanguageServer/Protocol/Protocol/Methods.Lifecyle.cs new file mode 100644 index 0000000000000..535f76eb920c9 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Methods.Lifecyle.cs @@ -0,0 +1,147 @@ +// 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 Roslyn.LanguageServer.Protocol; + +// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#lifeCycleMessages +partial class Methods +{ + // NOTE: these are sorted/grouped in the order used by the spec + + /// + /// Method name for 'initialize'. + /// + /// The initialize request is sent as the first request from the client to the server and is used to exchange capabilities. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string InitializeName = "initialize"; + + /// + /// Strongly typed message object for 'initialize'. + /// + public static readonly LspRequest Initialize = new(InitializeName); + + /// + /// Method name for 'initialized'. + /// + /// The initialized notification is sent from the client to the server after the client received the + /// result of the initialize request but before the client is sending any other request or notification to the server. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string InitializedName = "initialized"; + + /// + /// Strongly typed message object for 'initialized'. + /// + public static readonly LspNotification Initialized = new(InitializedName); + + /// + /// Method name for 'client/registerCapability'. + /// + /// The client/registerCapability request is sent from the server to the client to register for a new capability on the client side. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string ClientRegisterCapabilityName = "client/registerCapability"; + + /// + /// Strongly typed message object for 'client/registerCapability'. + /// + public static readonly LspRequest ClientRegisterCapability = new(ClientRegisterCapabilityName); + + /// + /// Method name for 'client/unregisterCapability'. + /// + /// The client/unregisterCapability request is sent from the server to the client to unregister a previously registered capability. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string ClientUnregisterCapabilityName = "client/unregisterCapability"; + + /// + /// Strongly typed message object for 'client/unregisterCapability'. + /// + public static readonly LspRequest ClientUnregisterCapability = new(ClientUnregisterCapabilityName); + + /// + /// Method name for '$/setTrace' notifications. + /// + /// A notification that should be used by the client to modify the trace setting of the server. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string SetTraceName = "$/setTrace"; + + /// + /// Strongly typed message object for '$/setTrace'. + /// + public static readonly LspNotification SetTrace = new(SetTraceName); + + /// + /// Method name for '$/logTrace' notifications. + /// + /// A notification to log the trace of the server’s execution. This must + /// respect the current trace configuration set by the $/logTrace notification. + /// + /// + /// This should only be used for systematic trace reporting For single debugging messages, + /// the server should instead send window/logMessage notifications. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string LogTraceName = "$/logTrace"; + + /// + /// Strongly typed message object for '$/logTrace'. + /// + public static readonly LspNotification LogTrace = new(LogTraceName); + + /// + /// Method name for 'shutdown'. + /// + /// The shutdown request is sent from the client to the server. It asks the server to shut + /// down, but to not exit (otherwise the response might not be delivered correctly to the + /// client). There is a separate exit notification that asks the server to exit. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string ShutdownName = "shutdown"; + + /// + /// Strongly typed message object for 'shutdown'. + /// + public static readonly LspRequest Shutdown = new(ShutdownName); + + /// + /// Method name for 'exit'. + /// + /// A notification to ask the server to exit its process. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string ExitName = "exit"; + + /// + /// Strongly typed message object for 'exit'. + /// + public static readonly LspNotification Exit = new(ExitName); +} diff --git a/src/LanguageServer/Protocol/Protocol/Methods.Navigation.cs b/src/LanguageServer/Protocol/Protocol/Methods.Navigation.cs new file mode 100644 index 0000000000000..55ead1428fef7 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Methods.Navigation.cs @@ -0,0 +1,278 @@ +// 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 Roslyn.LanguageServer.Protocol; + +// navigation methods from https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#languageFeatures +partial class Methods +{ + // NOTE: these are sorted in the order used by the spec + + /// + /// Method name for 'textDocument/declaration'. + /// + /// The go to declaration request is sent from the client to the server to resolve the declaration location of a symbol at a given text document position. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.14 + public const string TextDocumentDeclarationName = "textDocument/declaration"; + + /// + /// Strongly typed message object for 'textDocument/declaration'. + /// + /// may only be returned if the client opts in via + /// + /// + /// Since LSP 3.14 + public static readonly LspRequest?> TextDocumentDeclaration = new(TextDocumentDeclarationName); + + /// + /// Method name for 'textDocument/definition'. + /// + /// The go to definition request is sent from the client to the server to resolve the definition location of a symbol at a given text document position. + /// + /// + /// may only be returned if the client opts in via + /// + /// + public const string TextDocumentDefinitionName = "textDocument/definition"; + + /// + /// Strongly typed message object for 'textDocument/definition'. + /// + /// may only be returned if the client opts in via + /// + /// + public static readonly LspRequest?> TextDocumentDefinition = new(TextDocumentDefinitionName); + + /// + /// Method name for 'textDocument/typeDefinition'. + /// + /// The go to type definition request is sent from the client to the server to resolve the type definition location of a symbol at a given text document position. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentTypeDefinitionName = "textDocument/typeDefinition"; + + /// + /// Strongly typed message object for 'textDocument/typeDefinition'. + /// + /// may only be returned if the client opts in via + /// + /// + public static readonly LspRequest?> TextDocumentTypeDefinition = new(TextDocumentTypeDefinitionName); + + /// + /// Method name for 'textDocument/implementation'. + /// + /// The go to implementation request is sent from the client to the server to resolve the implementation location of a symbol at a given text document position. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentImplementationName = "textDocument/implementation"; + + /// + /// Strongly typed message object for 'textDocument/implementation'. + /// + /// may only be returned if the client opts in via + /// + /// + public static readonly LspRequest?> TextDocumentImplementation = new(TextDocumentImplementationName); + + /// + /// Method name for 'textDocument/references'. + /// + /// The references request is sent from the client to the server to resolve project-wide references for the symbol denoted by the given text document position. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentReferencesName = "textDocument/references"; + + /// + /// Strongly typed message object for 'textDocument/references'. + /// + public static readonly LspRequest TextDocumentReferences = new(TextDocumentReferencesName); + + /// + /// Method name for 'textDocument/prepareCallHierarchy'. + /// + /// The call hierarchy request is sent from the client to the server to return a call hierarchy for the language element of given text document positions. The call hierarchy requests are executed in two steps: + /// + /// first a call hierarchy item is resolved for the given text document position + /// for a call hierarchy item the incoming or outgoing call hierarchy items are resolved. + /// + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string PrepareCallHierarchyName = "textDocument/prepareCallHierarchy"; + + /// + /// Strongly typed message object for 'textDocument/prepareCallHierarchy'. + /// + /// Since LSP 3.16 + public static readonly LspRequest PrepareCallHierarchy = new(PrepareCallHierarchyName); + + /// + /// Method name for 'callHierarchy/incomingCalls'. + /// + /// The request is sent from the client to the server to resolve incoming calls for a given call hierarchy item. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string CallHierarchyIncomingCallsName = "callHierarchy/incomingCalls"; + + /// + /// Strongly typed message object for 'callHierarchy/incomingCalls'. + /// + /// Since LSP 3.16 + public static readonly LspRequest CallHierarchyIncomingCalls = new(CallHierarchyIncomingCallsName); + + /// + /// Method name for 'callHierarchy/outgoingCalls'. + /// + /// The request is sent from the client to the server to resolve outgoing calls for a given call hierarchy item. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string CallHierarchyOutgoingCallsName = "callHierarchy/outgoingCalls"; + + /// + /// Strongly typed message object for 'callHierarchy/outgoingCalls'. + /// + /// Since LSP 3.16 + public static readonly LspRequest CallHierarchyOutgoingCalls = new(CallHierarchyOutgoingCallsName); + + /// + /// Method name for 'textDocument/prepareTypeHierarchy'. + /// + /// The type hierarchy request is sent from the client to the server to return a type hierarchy for the language element of given text + /// document positions. Will return null if the server couldn't infer a valid type from the position. + /// + /// + /// The type hierarchy requests are executed in two steps: + /// + /// first a type hierarchy item is prepared for the given text document position. + /// for a type hierarchy item the supertype or subtype type hierarchy items are resolved. + /// + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string PrepareTypeHierarchyName = "textDocument/prepareTypeHierarchy"; + + /// + /// Strongly typed message object for 'textDocument/prepareTypeHierarchy'. + /// + /// Since LSP 3.17 + public static readonly LspRequest PrepareTypeHierarchy = new(PrepareTypeHierarchyName); + + /// + /// Method name for 'typeHierarchy/supertypes'. + /// + /// The request is sent from the client to the server to resolve the supertypes for a given type hierarchy item. + /// Will return null if the server couldn't infer a valid type from item in the params. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string TypeHierarchySupertypesName = "typeHierarchy/supertypes"; + + /// + /// Strongly typed message object for 'typeHierarchy/supertypes'. + /// + /// Since LSP 3.17 + public static readonly LspRequest TypeHierarchySupertypes = new(TypeHierarchySupertypesName); + + /// + /// Method name for 'typeHierarchy/subtypes'. + /// + /// The request is sent from the client to the server to resolve outgoing calls for a given call hierarchy item. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TypeHierarchySubtypesName = "typeHierarchy/subtypes"; + + /// + /// Strongly typed message object for 'typeHierarchy/subtypes'. + /// + /// Since LSP 3.17 + public static readonly LspRequest TypeHierarchySubtypes = new(TypeHierarchySubtypesName); + + /// + /// Method name for 'textDocument/documentHighlight'. + /// + /// The document highlight request is sent from the client to the server to resolve document highlights for a given text document position. + /// For programming languages this usually highlights all references to the symbol scoped to this file. + /// + /// + /// However, we kept ‘textDocument/documentHighlight’ and ‘textDocument/references’ separate requests since the first one is allowed to be + /// more fuzzy. Symbol matches usually have a of or + /// whereas fuzzy or textual matches use as the kind. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentDocumentHighlightName = "textDocument/documentHighlight"; + + /// + /// Strongly typed message object for 'textDocument/documentHighlight'. + /// + public static readonly LspRequest TextDocumentDocumentHighlight = new(TextDocumentDocumentHighlightName); + + /// + /// Method name for 'textDocument/documentLink'. + /// + /// The document links request is sent from the client to the server to request the location of links in a document. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TextDocumentDocumentLinkName = "textDocument/documentLink"; + + /// + /// Strongly typed message object for 'textDocument/documentLink'. + /// + public static readonly LspRequest TextDocumentDocumentLink = new(TextDocumentDocumentLinkName); + + /// + /// Method name for 'documentLink/resolve'. + /// + /// The document link resolve request is sent from the client to the server to resolve the target of a given document link. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string DocumentLinkResolveName = "documentLink/resolve"; + + /// + /// Strongly typed message object for 'documentLink/resolve'. + /// + public static readonly LspRequest DocumentLinkResolve = new(DocumentLinkResolveName); +} diff --git a/src/LanguageServer/Protocol/Protocol/Methods.Notebook.cs b/src/LanguageServer/Protocol/Protocol/Methods.Notebook.cs new file mode 100644 index 0000000000000..5d67fa0bbe37c --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Methods.Notebook.cs @@ -0,0 +1,87 @@ +// 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 Roslyn.LanguageServer.Protocol; + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notebookDocument_synchronization +partial class Methods +{ + // NOTE: these are sorted/grouped in the order used by the spec + + /// + /// Method name for 'notebookDocument/didOpen'. + /// + /// The open notification is sent from the client to the server when a notebook document is opened. It is only + /// sent by a client if the server specified a in its + /// capability. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string NotebookDidOpenName = "notebookDocument/didOpen"; + + /// + /// Strongly typed message object for 'notebookDocument/didOpen'. + /// + public static readonly LspNotification NotebookDidOpen = new(NotebookDidOpenName); + + /// + /// Method name for 'notebookDocument/didChange'. + /// + /// The change notification is sent from the client to the server when a notebook document changes. It is only + /// sent by a client if the server specified a in its + /// capability. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string NotebookDidChangeName = "notebookDocument/didChange"; + + /// + /// Strongly typed message object for 'notebookDocument/didChange'. + /// + public static readonly LspNotification NotebookDidChange = new(NotebookDidChangeName); + + /// + /// Method name for 'notebookDocument/didSave'. + /// + /// The change notification is sent from the client to the server when a notebook document is saved. It is only + /// sent by a client if the server specified a in its + /// capability. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string NotebookDidSaveName = "notebookDocument/didSave"; + + /// + /// Strongly typed message object for 'notebookDocument/didSave'. + /// + public static readonly LspNotification NotebookDidSave = new(NotebookDidSaveName); + + /// + /// Method name for 'notebookDocument/didClose'. + /// + /// The change notification is sent from the client to the server when a notebook document is closed. It is only + /// sent by a client if the server specified a in its + /// capability. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.17 + public const string NotebookDidCloseName = "notebookDocument/didClose"; + + /// + /// Strongly typed message object for 'notebookDocument/didClose'. + /// + public static readonly LspNotification NotebookDidClose = new(NotebookDidCloseName); +} diff --git a/src/LanguageServer/Protocol/Protocol/Methods.Window.cs b/src/LanguageServer/Protocol/Protocol/Methods.Window.cs new file mode 100644 index 0000000000000..2750c9f4b6776 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Methods.Window.cs @@ -0,0 +1,140 @@ +// 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 Roslyn.LanguageServer.Protocol; + +// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#windowFeatures +partial class Methods +{ + /// + /// Method name for 'window/showMessage'. + /// + /// The show message notification is sent from a server to a client to ask the client to display a particular message in the user interface. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string WindowShowMessageName = "window/showMessage"; + + /// + /// Strongly typed message object for 'window/showMessage'. + /// + public static readonly LspNotification WindowShowMessage = new(WindowShowMessageName); + + /// + /// Method name for 'window/showMessageRequest'. + /// + /// The show message request is sent from a server to a client to ask the client to display a particular message in the user interface. + /// + /// + /// In addition to the show message notification the request allows to pass actions and to wait for an answer from the client. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string WindowShowMessageRequestName = "window/showMessageRequest"; + + /// + /// Strongly typed message object for 'window/showMessageRequest'. + /// + public static readonly LspRequest WindowShowMessageRequest = new(WindowShowMessageRequestName); + + /// + /// Method name for 'window/showDocument'. + /// + /// The show document request is sent from a server to a client to ask the client to display a particular resource referenced by a URI in the user interface. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string WindowShowDocumentName = "window/showDocument"; + + /// + /// Strongly typed message object for 'window/showDocument'. + /// + /// Since LSP 3.16 + public static readonly LspRequest WindowShowDocument = new(WindowShowDocumentName); + + /// + /// Method name for 'window/logMessage'. + /// + /// The log message notification is sent from the server to the client to ask the client to log a particular message. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string WindowLogMessageName = "window/logMessage"; + + /// + /// Strongly typed message object for 'window/logMessage'. + /// + public static readonly LspNotification WindowLogMessage = new(WindowLogMessageName); + + /// + /// Method name for 'window/workDoneProgress/create' + /// + /// Sent from the server to the client to ask the client to create a work done progress. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.15 + public const string WindowWorkDoneProgressCreateName = "window/workDoneProgress/create"; + + /// + /// Strongly typed message object for 'window/workDoneProgress/create'. + /// + /// Since LSP 3.15 + public static readonly LspRequest WindowWorkDoneProgressCreate = new(WindowWorkDoneProgressCreateName); + + /// + /// Method name for 'window/workDoneProgress/cancel' + /// + /// The window/workDoneProgress/cancel notification is sent from the client to the server to cancel a progress + /// initiated on the server side using the window/workDoneProgress/create. + /// + /// + /// The progress need not be marked as cancellable to be cancelled and a client may cancel a + /// progress for any number of reasons: in case of error, reloading a workspace etc. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.15 + public const string WindowWorkDoneProgressCancelName = "window/workDoneProgress/cancel"; + + /// + /// Strongly typed message object for 'window/workDoneProgress/cancel'. + /// + /// Since LSP 3.15 + public static readonly LspNotification WindowWorkDoneProgressCancel = new(WindowWorkDoneProgressCancelName); + + /// + /// Method name for 'telemetry/event'. + /// + /// The telemetry notification is sent from the server to the client to ask the client to log a telemetry event. + /// + /// + /// The protocol doesn't specify the payload since no interpretation of the data happens in the protocol. + /// Most clients even don’t handle the event directly but forward them to the extensions owing the + /// corresponding server issuing the event. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string TelemetryEventName = "telemetry/event"; + + /// + /// Strongly typed message object for 'telemetry/event'. + /// + public static readonly LspNotification TelemetryEvent = new(TelemetryEventName); +} diff --git a/src/LanguageServer/Protocol/Protocol/Methods.Workspace.cs b/src/LanguageServer/Protocol/Protocol/Methods.Workspace.cs new file mode 100644 index 0000000000000..811c75796666c --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Methods.Workspace.cs @@ -0,0 +1,299 @@ +// 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 Roslyn.LanguageServer.Protocol; + +// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspaceFeatures +partial class Methods +{ + // NOTE: these are sorted/grouped in the order used by the spec + + /// + /// Method name for 'workspace/symbol'. + /// + /// The workspace symbol request is sent from the client to the server to list project-wide symbols matching the query string. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string WorkspaceSymbolName = "workspace/symbol"; + + /// + /// Strongly typed message object for 'workspace/symbol'. + /// +#pragma warning disable CS0618 // SymbolInformation is obsolete but this property is not + public static readonly LspRequest?> WorkspaceSymbol = new(WorkspaceSymbolName); +#pragma warning restore CS0618 + + /// + /// Method name for 'workspaceSymbol/resolve'. + /// + /// The request is sent from the client to the server to resolve additional information for a given workspace symbol. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string WorkspaceSymbolResolveName = "workspaceSymbol/resolve"; + + /// + /// Strongly typed message object for 'workspaceSymbol/resolve'. + /// + public static readonly LspRequest WorkspaceSymbolResolve = new(WorkspaceSymbolResolveName); + + /// + /// Method name for 'workspace/configuration'. + /// + /// The workspace/configuration request is sent from the server to the client to fetch configuration + /// settings from the client. The request can fetch several configuration settings in one roundtrip. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.6 + public const string WorkspaceConfigurationName = "workspace/configuration"; + + /// + /// Strongly typed message object for 'workspace/configuration'. + /// + /// Since LSP 3.6 + public static readonly LspRequest WorkspaceConfiguration = new(WorkspaceConfigurationName); + + /// + /// Method name for 'workspace/didChangeConfiguration'. + /// + /// A notification sent from the client to the server to signal the change of configuration settings. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string WorkspaceDidChangeConfigurationName = "workspace/didChangeConfiguration"; + + /// + /// Strongly typed message object for 'workspace/didChangeConfiguration'. + /// + public static readonly LspNotification WorkspaceDidChangeConfiguration = new(WorkspaceDidChangeConfigurationName); + + /// + /// Method name for 'workspace/workspaceFolders'. + /// + /// The workspace/workspaceFolders request is sent from the server to the client to fetch the current open + /// list of workspace folders. Returns in the response if only a single file is open in the tool. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.6 + public const string WorkspaceFoldersName = "workspace/workspaceFolders"; + + /// + /// Strongly typed message object for 'workspace/workspaceFolders'. + /// + /// Since LSP 3.6 + public static readonly LspRequest WorkspaceFolders = new(WorkspaceFoldersName); + + /// + /// Method name for 'workspace/didChangeWorkspaceFolders'. + /// + /// The workspace/didChangeWorkspaceFolders notification is sent from the client to the server + /// to inform the server about workspace folder configuration changes. + /// + /// + /// A server can register for this notification by using either the server capability + /// or by using the dynamic capability registration mechanism. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.6 + public const string WorkspaceDidChangeWorkspaceFoldersName = "workspace/didChangeWorkspaceFolders"; + + /// + /// Strongly typed message object for 'workspace/didChangeWorkspaceFolders'. + /// + /// Since LSP 3.6 + public static readonly LspNotification WorkspaceDidChangeWorkspaceFolders = new(WorkspaceDidChangeWorkspaceFoldersName); + + /// + /// Method name for 'workspace/willCreateFiles'. + /// + /// The will create files request is sent from the client to the server before files are actually created as long + /// as the creation is triggered from within the client either by a user action or by applying a workspace edit. + /// + /// + /// The request can return a which will be applied to the workspace before the files are created + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string WorkspaceWillCreateFilesName = "workspace/willCreateFiles"; + + /// + /// Strongly typed message object for 'workspace/willCreateFiles'. + /// + /// Since LSP 3.16 + public static readonly LspRequest WorkspaceWillCreateFiles = new(WorkspaceWillCreateFilesName); + + /// + /// Method name for 'workspace/didCreateFiles'. + /// + /// The did create files notification is sent from the client to the server when files were created from within the client. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string WorkspaceDidCreateFilesName = "workspace/didCreateFiles"; + + /// + /// Strongly typed message object for 'workspace/didCreateFiles'. + /// + /// Since LSP 3.16 + public static readonly LspNotification WorkspaceDidCreateFiles = new(WorkspaceDidCreateFilesName); + + /// + /// Method name for 'workspace/willRenameFiles'. + /// + /// The will rename files request is sent from the client to the server before files are actually renamed as long as the + /// rename is triggered from within the client either by a user action or by applying a workspace edit. + /// + /// + /// The request can return a which will be applied to the workspace before the files are renamed. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string WorkspaceWillRenameFilesName = "workspace/willRenameFiles"; + + /// + /// Strongly typed message object for 'workspace/willRenameFiles'. + /// + /// Since LSP 3.16 + public static readonly LspRequest WorkspaceWillRenameFiles = new(WorkspaceWillRenameFilesName); + + /// + /// Method name for 'workspace/didRenameFiles'. + /// + /// The did rename files notification is sent from the client to the server when files were renamed from within the client. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string WorkspaceDidRenameFilesName = "workspace/didRenameFiles"; + + /// + /// Strongly typed message object for 'workspace/didRenameFiles'. + /// + /// Since LSP 3.16 + public static readonly LspNotification WorkspaceDidRenameFiles = new(WorkspaceDidRenameFilesName); + + /// + /// Method name for 'workspace/willDeleteFiles'. + /// + /// The will delete files request is sent from the client to the server before files are actually deleted as + /// long as the deletion is triggered from within the client either by a user action or by applying a workspace edit. + /// + /// + /// The request can return a which will be applied to workspace before the files are deleted. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string WorkspaceWillDeleteFilesName = "workspace/willDeleteFiles"; + + /// + /// Strongly typed message object for 'workspace/willDeleteFiles'. + /// + /// Since LSP 3.16 + public static readonly LspRequest WorkspaceWillDeleteFiles = new(WorkspaceWillDeleteFilesName); + + /// + /// Method name for 'workspace/didDeleteFiles'. + /// + /// The did delete files notification is sent from the client to the server when files were deleted from within the client. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + /// Since LSP 3.16 + public const string WorkspaceDidDeleteFilesName = "workspace/didDeleteFiles"; + + /// + /// Strongly typed message object for 'workspace/didDeleteFiles'. + /// + /// Since LSP 3.16 + public static readonly LspNotification WorkspaceDidDeleteFiles = new(WorkspaceDidDeleteFilesName); + + /// + /// Method name for 'workspace/didChangeWatchedFiles'. + /// + /// The watched files notification is sent from the client to the server when the client detects changes to files + /// and folders watched by the language client. + /// + /// + /// Note that although the name suggest that only file events are sent, it is about file system events, which includes folders as well. + /// It is recommended that servers register for these file system events using the registration mechanism. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string WorkspaceDidChangeWatchedFilesName = "workspace/didChangeWatchedFiles"; + + /// + /// Strongly typed message object for 'workspace/didChangeWatchedFiles'. + /// + public static readonly LspNotification WorkspaceDidChangeWatchedFiles = new(WorkspaceDidChangeWatchedFilesName); + + /// + /// Method name for 'workspace/executeCommand'. + /// + /// The workspace/executeCommand request is sent from the client to the server to trigger command execution on the server. + /// + /// + /// In most cases the server creates a WorkspaceEdit structure and applies the changes to the workspace using the + /// request workspace/applyEdit which is sent from the server to the client. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public const string WorkspaceExecuteCommandName = "workspace/executeCommand"; + + /// + /// Strongly typed message object for 'workspace/executeCommand'. + /// + public static readonly LspRequest WorkspaceExecuteCommand = new(WorkspaceExecuteCommandName); + + /// + /// Method name for 'workspace/applyEdit'. + /// + public const string WorkspaceApplyEditName = "workspace/applyEdit"; + + /// + /// Strongly typed message object for 'workspace/applyEdit'. + /// + /// The workspace/applyEdit request is sent from the server to the client to modify resource on the client side. + /// + /// + /// See the Language Server Protocol specification for additional information. + /// + /// + public static readonly LspRequest WorkspaceApplyEdit = new(WorkspaceApplyEditName); +} diff --git a/src/LanguageServer/Protocol/Protocol/Methods.cs b/src/LanguageServer/Protocol/Protocol/Methods.cs index 0bf3fd4109733..7a2a7cc5efb51 100644 --- a/src/LanguageServer/Protocol/Protocol/Methods.cs +++ b/src/LanguageServer/Protocol/Protocol/Methods.cs @@ -7,17 +7,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which contains the string values for all common language protocol methods. /// - internal static class Methods + internal static partial class Methods { - /// - /// Method name for 'initialize'. - /// - public const string InitializeName = "initialize"; - - /// - /// Method name for 'initialized'. - /// - public const string InitializedName = "initialized"; + // NOTE: these are sorted/grouped in the order used by the spec /// /// Method name for '$/progress' notifications. @@ -29,11 +21,6 @@ internal static class Methods /// public const string PartialResultTokenName = "partialResultToken"; - /// - /// Name of the progress token in the request. - /// - public const string PartialResultTokenPropertyName = "PartialResultToken"; - /// /// Name of the work done token in the request. /// @@ -43,561 +30,5 @@ internal static class Methods /// Name of the progress token in the $/progress notification. /// public const string ProgressNotificationTokenName = "token"; - - /// - /// Method name for 'textDocument/codeAction'. - /// - public const string TextDocumentCodeActionName = "textDocument/codeAction"; - - /// - /// Method name for 'textDocument/codeLens'. - /// - public const string TextDocumentCodeLensName = "textDocument/codeLens"; - - /// - /// Method name for 'codeAction/resolve'. - /// - public const string CodeActionResolveName = "codeAction/resolve"; - - /// - /// Method name for 'codeLens/resolve'. - /// - public const string CodeLensResolveName = "codeLens/resolve"; - - /// - /// Method name for 'textDocument/completion'. - /// - public const string TextDocumentCompletionName = "textDocument/completion"; - - /// - /// Method name for 'completionItem/resolve'. - /// - public const string TextDocumentCompletionResolveName = "completionItem/resolve"; - - /// - /// Method name for 'textDocument/definition'. - /// - public const string TextDocumentDefinitionName = "textDocument/definition"; - - /// - /// Method name for 'textDocument/diagnostic'. - /// - public const string TextDocumentDiagnosticName = "textDocument/diagnostic"; - - /// - /// Method name for 'textDocument/didOpen'. - /// - public const string TextDocumentDidOpenName = "textDocument/didOpen"; - - /// - /// Method name for 'textDocument/didClose'. - /// - public const string TextDocumentDidCloseName = "textDocument/didClose"; - - /// - /// Method name for 'textDocument/didChange'. - /// - public const string TextDocumentDidChangeName = "textDocument/didChange"; - - /// - /// Method name for 'textDocument/didSave'. - /// - public const string TextDocumentDidSaveName = "textDocument/didSave"; - - /// - /// Method name for 'textDocument/documentHighlight'. - /// - public const string TextDocumentDocumentHighlightName = "textDocument/documentHighlight"; - - /// - /// Method name for 'textDocument/documentLink'. - /// - public const string TextDocumentDocumentLinkName = "textDocument/documentLink"; - - /// - /// Method name for 'documentLink/resolve'. - /// - public const string DocumentLinkResolveName = "documentLink/resolve"; - - /// - /// Method name for 'textDocument/documentColor'. - /// - public const string TextDocumentDocumentColorName = "textDocument/documentColor"; - - /// - /// Method name for 'textDocument/documentSymbol'. - /// - public const string TextDocumentDocumentSymbolName = "textDocument/documentSymbol"; - - /// - /// Method name for 'textDocument/foldingRange'. - /// - public const string TextDocumentFoldingRangeName = "textDocument/foldingRange"; - - /// - /// Method name for 'textDocument/formatting'. - /// - public const string TextDocumentFormattingName = "textDocument/formatting"; - - /// - /// Method name for 'textDocument/hover'. - /// - public const string TextDocumentHoverName = "textDocument/hover"; - - /// - /// Method name for 'textDocument/onTypeFormatting'. - /// - public const string TextDocumentOnTypeFormattingName = "textDocument/onTypeFormatting"; - - /// - /// Method name for 'textDocument/rangeFormatting'. - /// - public const string TextDocumentRangeFormattingName = "textDocument/rangeFormatting"; - - /// - /// Method name for 'textDocument/publishDiagnostics'. - /// - public const string TextDocumentPublishDiagnosticsName = "textDocument/publishDiagnostics"; - - /// - /// Method name for 'textDocument/implementation'. - /// - public const string TextDocumentImplementationName = "textDocument/implementation"; - - /// - /// Method name for 'textDocument/inlayHint'. - /// - public const string TextDocumentInlayHintName = "textDocument/inlayHint"; - - /// - /// Method name for 'inlayHint/resolve'. - /// - public const string InlayHintResolveName = "inlayHint/resolve"; - - /// - /// Method name for 'textDocument/typeDefinition'. - /// - public const string TextDocumentTypeDefinitionName = "textDocument/typeDefinition"; - - /// - /// Method name for 'textDocument/references'. - /// - public const string TextDocumentReferencesName = "textDocument/references"; - - /// - /// Method name for 'textDocument/rename'. - /// - public const string TextDocumentRenameName = "textDocument/rename"; - - /// - /// Method name for 'textDocument/prepareRename'. - /// - public const string TextDocumentPrepareRenameName = "textDocument/prepareRename"; - - /// - /// Method name for 'textDocument/semanticTokens/full'. - /// - public const string TextDocumentSemanticTokensFullName = "textDocument/semanticTokens/full"; - - /// - /// Method name for 'textDocument/semanticTokens/range'. - /// - public const string TextDocumentSemanticTokensRangeName = "textDocument/semanticTokens/range"; - - /// - /// Method name for 'textDocument/semanticTokens/full/delta'. - /// - public const string TextDocumentSemanticTokensFullDeltaName = "textDocument/semanticTokens/full/delta"; - - /// - /// Method name for 'textDocument/signatureHelp'. - /// - public const string TextDocumentSignatureHelpName = "textDocument/signatureHelp"; - - /// - /// Method name for 'textDocument/willSave'. - /// - public const string TextDocumentWillSaveName = "textDocument/willSave"; - - /// - /// Method name for 'textDocument/willSaveWaitUntil'. - /// - public const string TextDocumentWillSaveWaitUntilName = "textDocument/willSaveWaitUntil"; - - /// - /// Method name for 'textDocument/linkedEditingRange'. - /// - public const string TextDocumentLinkedEditingRangeName = "textDocument/linkedEditingRange"; - - /// - /// Method name for 'window/logMessage'. - /// - public const string WindowLogMessageName = "window/logMessage"; - - /// - /// Method name for 'window/showMessage'. - /// - public const string WindowShowMessageName = "window/showMessage"; - - /// - /// Method name for 'window/showMessageRequest'. - /// - public const string WindowShowMessageRequestName = "window/showMessageRequest"; - - /// - /// Method name for 'workspace/applyEdit'. - /// - public const string WorkspaceApplyEditName = "workspace/applyEdit"; - - /// - /// Method name for 'workspace/semanticTokens/refresh'. - /// - public const string WorkspaceSemanticTokensRefreshName = "workspace/semanticTokens/refresh"; - - /// - /// Method name for 'workspace/configuration'. - /// - public const string WorkspaceConfigurationName = "workspace/configuration"; - - /// - /// Method name for 'workspace/diagnostic'. - /// - public const string WorkspaceDiagnosticName = "workspace/diagnostic"; - - /// - /// Method name for 'workspace/diagnostic/refresh'. - /// - public const string WorkspaceDiagnosticRefreshName = "workspace/diagnostic/refresh"; - - /// - /// Method name for 'workspace/didChangeConfiguration'. - /// - public const string WorkspaceDidChangeConfigurationName = "workspace/didChangeConfiguration"; - - /// - /// Method name for 'workspace/executeCommand'. - /// - public const string WorkspaceExecuteCommandName = "workspace/executeCommand"; - - /// - /// Method name for 'workspace/symbol'. - /// - public const string WorkspaceSymbolName = "workspace/symbol"; - - /// - /// Method name for 'workspace/didChangeWatchedFiles'. - /// - public const string WorkspaceDidChangeWatchedFilesName = "workspace/didChangeWatchedFiles"; - - /// - /// Method name for 'workspace/codeLens/refresh'. - /// - public const string WorkspaceCodeLensRefreshName = "workspace/codeLens/refresh"; - - /// - /// Method name for 'workspace/inlayHint/refresh'. - /// - public const string WorkspaceInlayHintRefreshName = "workspace/inlayHint/refresh"; - - /// - /// Method name for 'shutdown'. - /// - public const string ShutdownName = "shutdown"; - - /// - /// Method name for 'exit'. - /// - public const string ExitName = "exit"; - - /// - /// Method name for 'telemetry/event'. - /// - public const string TelemetryEventName = "telemetry/event"; - - /// - /// Method name for 'client/registerCapability'. - /// - public const string ClientRegisterCapabilityName = "client/registerCapability"; - - /// - /// Method name for 'client/unregisterCapability'. - /// - public const string ClientUnregisterCapabilityName = "client/unregisterCapability"; - - /// - /// Strongly typed message object for 'initialize'. - /// - public static readonly LspRequest Initialize = new LspRequest(InitializeName); - - /// - /// Strongly typed message object for 'initialized'. - /// - public static readonly LspNotification Initialized = new LspNotification(InitializedName); - - /// - /// Strongly typed message object for 'textDocument/codeAction'. - /// - public static readonly LspRequest[]?> TextDocumentCodeAction = new LspRequest[]?>(TextDocumentCodeActionName); - - /// - /// Strongly typed message object for 'textDocument/codeLens'. - /// - public static readonly LspRequest TextDocumentCodeLens = new LspRequest(TextDocumentCodeLensName); - - /// - /// Strongly typed message object for 'codeAction/resolve'. - /// - public static readonly LspRequest CodeActionResolve = new LspRequest(CodeActionResolveName); - - /// - /// Strongly typed message object for 'codeLens/resolve'. - /// - public static readonly LspRequest CodeLensResolve = new LspRequest(CodeLensResolveName); - - /// - /// Strongly typed message object for 'textDocument/completion'. - /// - public static readonly LspRequest?> TextDocumentCompletion = new LspRequest?>(TextDocumentCompletionName); - - /// - /// Strongly typed message object for 'completionItem/resolve'. - /// - public static readonly LspRequest TextDocumentCompletionResolve = new LspRequest(TextDocumentCompletionResolveName); - - /// - /// Strongly typed message object for 'textDocument/definition'. - /// - public static readonly LspRequest?> TextDocumentDefinition = new LspRequest?>(TextDocumentDefinitionName); - - /// - /// Strongly typed message object for 'textDocument/didOpen'. - /// - public static readonly LspNotification TextDocumentDidOpen = new LspNotification(TextDocumentDidOpenName); - - /// - /// Strongly typed message object for 'textDocument/didClose'. - /// - public static readonly LspNotification TextDocumentDidClose = new LspNotification(TextDocumentDidCloseName); - - /// - /// Strongly typed message object for 'textDocument/didChange'. - /// - public static readonly LspNotification TextDocumentDidChange = new LspNotification(TextDocumentDidChangeName); - - /// - /// Strongly typed message object for 'textDocument/didSave'. - /// - public static readonly LspNotification TextDocumentDidSave = new LspNotification(TextDocumentDidSaveName); - - /// - /// Strongly typed message object for 'textDocument/documentHighlight'. - /// - public static readonly LspRequest TextDocumentDocumentHighlight = new LspRequest(TextDocumentDocumentHighlightName); - - /// - /// Strongly typed message object for 'textDocument/documentLink'. - /// - public static readonly LspRequest TextDocumentDocumentLink = new LspRequest(TextDocumentDocumentLinkName); - - /// - /// Strongly typed message object for 'documentLink/resolve'. - /// - public static readonly LspRequest DocumentLinkResolve = new LspRequest(DocumentLinkResolveName); - - /// - /// Strongly typed message object for 'textDocument/documentColor'. - /// - public static readonly LspRequest DocumentColorRequest = new LspRequest(TextDocumentDocumentColorName); - - /// - /// Strongly typed message object for 'textDocument/documentSymbol'. - /// - public static readonly LspRequest TextDocumentDocumentSymbol = new LspRequest(TextDocumentDocumentSymbolName); - - /// - /// Stronly typed message object for 'textDocument/foldingRange'. - /// - public static readonly LspRequest TextDocumentFoldingRange = new LspRequest(TextDocumentFoldingRangeName); - - /// - /// Strongly typed message object for 'textDocument/formatting'. - /// - public static readonly LspRequest TextDocumentFormatting = new LspRequest(TextDocumentFormattingName); - - /// - /// Strongly typed message object for 'textDocument/hover'. - /// - public static readonly LspRequest TextDocumentHover = new LspRequest(TextDocumentHoverName); - - /// - /// Strongly typed message object for 'textDocument/onTypeFormatting'. - /// - public static readonly LspRequest TextDocumentOnTypeFormatting = new LspRequest(TextDocumentOnTypeFormattingName); - - /// - /// Strongly typed message object for 'textDocument/rangeFormatting'. - /// - public static readonly LspRequest TextDocumentRangeFormatting = new LspRequest(TextDocumentRangeFormattingName); - - /// - /// Strongly typed message object for 'textDocument/publishDiagnostics'. - /// - public static readonly LspNotification TextDocumentPublishDiagnostics = new LspNotification(TextDocumentPublishDiagnosticsName); - - /// - /// Strongly typed message object for 'textDocument/implementation'. - /// - public static readonly LspRequest?> TextDocumentImplementation = new LspRequest?>(TextDocumentImplementationName); - - /// - /// Strongly typed message object for 'textDocument/inlayHint'. - /// - public static readonly LspRequest TextDocumentInlayHint = new LspRequest(TextDocumentInlayHintName); - - /// - /// Strongly typed message object for 'inlayHint/resolve'. - /// - public static readonly LspRequest InlayHintResolve = new LspRequest(InlayHintResolveName); - - /// - /// Strongly typed message object for 'textDocument/typeDefinition'. - /// - public static readonly LspRequest?> TextDocumentTypeDefinition = new LspRequest?>(TextDocumentTypeDefinitionName); - - /// - /// Strongly typed message object for 'textDocument/references'. - /// - public static readonly LspRequest TextDocumentReferences = new LspRequest(TextDocumentReferencesName); - - /// - /// Strongly typed message object for 'textDocument/rename'. - /// - public static readonly LspRequest TextDocumentRename = new LspRequest(TextDocumentRenameName); - - /// - /// Strongly typed message object for 'textDocument/prepareRename'. - /// - public static readonly LspRequest?> TextDocumentPrepareRename = new LspRequest?>(TextDocumentPrepareRenameName); - - /// - /// Strongly typed message object for 'textDocument/signatureHelp'. - /// - public static readonly LspRequest TextDocumentSignatureHelp = new LspRequest(TextDocumentSignatureHelpName); - - /// - /// Strongly typed message object for 'textDocument/willSave'. - /// - public static readonly LspNotification TextDocumentWillSave = new LspNotification(TextDocumentWillSaveName); - - /// - /// Strongly typed message object for 'textDocument/willSaveWaitUntil'. - /// - public static readonly LspRequest TextDocumentWillSaveWaitUntil = new LspRequest(TextDocumentWillSaveWaitUntilName); - - /// - /// Strongly typed message object for 'textDocument/linkedEditingRange'. - /// - public static readonly LspRequest TextDocumentLinkedEditingRange = new LspRequest(TextDocumentLinkedEditingRangeName); - - /// - /// Strongly typed message object for 'window/logMessage'. - /// - public static readonly LspNotification WindowLogMessage = new LspNotification(WindowLogMessageName); - - /// - /// Strongly typed message object for 'window/showMessage'. - /// - public static readonly LspNotification WindowShowMessage = new LspNotification(WindowShowMessageName); - - /// - /// Strongly typed message object for 'window/showMessageRequest'. - /// - public static readonly LspRequest WindowShowMessageRequest = new LspRequest(WindowShowMessageRequestName); - - /// - /// Strongly typed message object for 'workspace/applyEdit'. - /// - public static readonly LspRequest WorkspaceApplyEdit = new LspRequest(WorkspaceApplyEditName); - - /// - /// Strongly typed message object for 'workspace/semanticTokens/refresh'. - /// - public static readonly LspRequest WorkspaceSemanticTokensRefresh = new LspRequest(WorkspaceSemanticTokensRefreshName); - - /// - /// Strongly typed message object for 'workspace/configuration'. - /// - public static readonly LspRequest WorkspaceConfiguration = new LspRequest(WorkspaceConfigurationName); - - /// - /// Strongly typed message object for 'workspace/didChangeConfiguration'. - /// - public static readonly LspNotification WorkspaceDidChangeConfiguration = new LspNotification(WorkspaceDidChangeConfigurationName); - - /// - /// Strongly typed message object for 'workspace/executeCommand'. - /// - public static readonly LspRequest WorkspaceExecuteCommand = new LspRequest(WorkspaceExecuteCommandName); - - /// - /// Strongly typed message object for 'workspace/symbol'. - /// - public static readonly LspRequest WorkspaceSymbol = new LspRequest(WorkspaceSymbolName); - - /// - /// Strongly typed message object for 'workspace/didChangeWatchedFiles'. - /// - public static readonly LspNotification WorkspaceDidChangeWatchedFiles = new LspNotification(WorkspaceDidChangeWatchedFilesName); - - /// - /// Strongly typed message object for 'workspace/codeLens/refresh'. - /// - public static readonly LspRequest WorkspaceCodeLensRefresh = new LspRequest(WorkspaceCodeLensRefreshName); - - /// - /// Strongly typed message object for 'workspace/inlayHint/refresh'. - /// - public static readonly LspRequest WorkspaceInlayHintRefresh = new LspRequest(WorkspaceInlayHintRefreshName); - - /// - /// Strongly typed message object for 'shutdown'. - /// - public static readonly LspRequest Shutdown = new LspRequest(ShutdownName); - - /// - /// Strongly typed message object for 'exit'. - /// - public static readonly LspNotification Exit = new LspNotification(ExitName); - - /// - /// Strongly typed message object for 'telemetry/event'. - /// - public static readonly LspNotification TelemetryEvent = new LspNotification(TelemetryEventName); - - /// - /// Strongly typed message object for 'client/registerCapability'. - /// - public static readonly LspRequest ClientRegisterCapability = new LspRequest(ClientRegisterCapabilityName); - - /// - /// Strongly typed message object for 'client/unregisterCapability'. - /// - public static readonly LspRequest ClientUnregisterCapability = new LspRequest(ClientUnregisterCapabilityName); - - /// - /// Strongly typed message object for 'textDocument/semanticTokens/full'. - /// - public static readonly LspRequest TextDocumentSemanticTokensFull = new LspRequest(TextDocumentSemanticTokensFullName); - - /// - /// Strongly typed message object for 'textDocument/semanticTokens/range'. - /// - public static readonly LspRequest TextDocumentSemanticTokensRange = new LspRequest(TextDocumentSemanticTokensRangeName); - - /// - /// Strongly typed message object for 'textDocument/semanticTokens/full/delta'. - /// - public static readonly LspRequest?> TextDocumentSemanticTokensFullDelta - = new LspRequest?>(TextDocumentSemanticTokensFullDeltaName); } } diff --git a/src/LanguageServer/Protocol/Protocol/Moniker/Moniker.cs b/src/LanguageServer/Protocol/Protocol/Moniker/Moniker.cs new file mode 100644 index 0000000000000..5d2fca4260aad --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Moniker/Moniker.cs @@ -0,0 +1,46 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Moniker definition to match LSIF 0.5 moniker definition. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class Moniker +{ + /// + /// The scheme of the moniker. For example tsc or .Net + /// + [JsonPropertyName("scheme")] + [JsonRequired] + public string Scheme { get; init; } + + /// + /// The identifier of the moniker. The value is opaque in LSIF however + /// schema owners are allowed to define the structure if they want. + /// + [JsonPropertyName("identifier")] + [JsonRequired] + public string Identifier { get; init; } + + /// + /// The scope in which the moniker is unique + /// + [JsonPropertyName("unique")] + [JsonRequired] + public UniquenessLevel Unique { get; init; } + + /// + /// The moniker kind if known. + /// + [JsonPropertyName("kind")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public MonikerKind? Kind { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Moniker/MonikerClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/Moniker/MonikerClientCapabilities.cs new file mode 100644 index 0000000000000..55c91437ce62a --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Moniker/MonikerClientCapabilities.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. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/moniker` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class MonikerClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/Moniker/MonikerKind.cs b/src/LanguageServer/Protocol/Protocol/Moniker/MonikerKind.cs new file mode 100644 index 0000000000000..7f90f07b89535 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Moniker/MonikerKind.cs @@ -0,0 +1,36 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.ComponentModel; +using System.Text.Json.Serialization; + +/// +/// The kind of a . +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +[JsonConverter(typeof(StringEnumConverter))] +[TypeConverter(typeof(StringEnumConverter.TypeConverter))] +internal readonly record struct MonikerKind(string Value) : IStringEnum +{ + /// + /// The moniker represent a symbol that is imported into a project + /// + public static readonly MonikerKind Import = new("import"); + + /// + /// The moniker represents a symbol that is exported from a project + /// + public static readonly MonikerKind Export = new("export"); + + /// + /// The moniker represents a symbol that is local to a project (e.g. a local + /// variable of a function, a class not visible outside the project, ...) + /// + public static readonly MonikerKind Local = new("local"); +} diff --git a/src/LanguageServer/Protocol/Protocol/Moniker/MonikerOptions.cs b/src/LanguageServer/Protocol/Protocol/Moniker/MonikerOptions.cs new file mode 100644 index 0000000000000..3d3a51b7103a7 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Moniker/MonikerOptions.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Class which represents Moniker capabilities. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class MonikerOptions : IWorkDoneProgressOptions +{ + /// + /// Gets or sets a value indicating whether work done progress is supported. + /// + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Moniker/MonikerParams.cs b/src/LanguageServer/Protocol/Protocol/Moniker/MonikerParams.cs new file mode 100644 index 0000000000000..1f385a972b10f --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Moniker/MonikerParams.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +using System; +using System.Text.Json.Serialization; + +/// +/// Class representing the parameters sent from the client to the server for a textDocument/moniker request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class MonikerParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialResultParams +{ + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Moniker/MonikerRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/Moniker/MonikerRegistrationOptions.cs new file mode 100644 index 0000000000000..c51dd950d0ea3 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Moniker/MonikerRegistrationOptions.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class MonikerRegistrationOptions : CallHierarchyOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + /// The id used to register the request. The id can be used to deregister the request again. + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Moniker/UniquenessLevel.cs b/src/LanguageServer/Protocol/Protocol/Moniker/UniquenessLevel.cs new file mode 100644 index 0000000000000..82896bc5a1e38 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Moniker/UniquenessLevel.cs @@ -0,0 +1,46 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.ComponentModel; +using System.Text.Json.Serialization; + +/// +/// Moniker uniqueness level to define scope of a . +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +/// +[JsonConverter(typeof(StringEnumConverter))] +[TypeConverter(typeof(StringEnumConverter.TypeConverter))] +internal readonly record struct UniquenessLevel(string Value) : IStringEnum +{ + /// + /// The moniker is only unique inside a document + /// + public static readonly UniquenessLevel Document = new("document"); + + /// + /// The moniker is unique inside a project for which a dump got created + /// + public static readonly UniquenessLevel Project = new("project"); + + /// + /// The moniker is unique inside the group to which a project belongs + /// + public static readonly UniquenessLevel Group = new("group"); + + /// + /// The moniker is unique inside the moniker scheme. + /// + public static readonly UniquenessLevel Scheme = new("scheme"); + + /// + /// The moniker is globally unique + /// + public static readonly UniquenessLevel Global = new("global"); +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyClientCapabilities.cs new file mode 100644 index 0000000000000..9e6930b721fa2 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyClientCapabilities.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. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the various type hierarchy requests. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class CallHierarchyClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyIncomingCall.cs b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyIncomingCall.cs new file mode 100644 index 0000000000000..cfd4ef2e20d74 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyIncomingCall.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The item returned from a 'callHierarchy/incomingCalls' request +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class CallHierarchyIncomingCall +{ + /// + /// The for which to return incoming calls + /// + [JsonPropertyName("from")] + [JsonRequired] + public CallHierarchyItem From { get; init; } + + /// + /// The ranges at which the calls appear. This is relative to the caller + /// denoted by [`this.from`](#CallHierarchyIncomingCall.from). + /// + [JsonPropertyName("fromRanges")] + [JsonRequired] + + public Range[] FromRanges { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyIncomingCallsParams.cs b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyIncomingCallsParams.cs new file mode 100644 index 0000000000000..0569630a6b1ae --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyIncomingCallsParams.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a 'callHierarchy/incomingCalls' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class CallHierarchyIncomingCallsParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialResultParams +{ + /// + /// The item returned from `textDocument/prepareCallHierarchy` + /// + [JsonPropertyName("item")] + [JsonRequired] + public CallHierarchyItem Item { get; init; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + /// + /// may only be used if the client opts in via + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyItem.cs b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyItem.cs new file mode 100644 index 0000000000000..384c225efa4cd --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyItem.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Represents an item in the call hierarchy +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class CallHierarchyItem +{ + /// + /// The name of this item. + /// + [JsonPropertyName("name")] + [JsonRequired] + public string Name { get; init; } + + /// + /// The kind of this item. + /// + [JsonPropertyName("kind")] + [JsonRequired] + public SymbolKind Kind { get; init; } + + /// + /// Tags for this item. + /// + [JsonPropertyName("tags")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SymbolTag[]? Tags { get; init; } + + /// + /// More detail for this item, e.g. the signature of a function. + /// + [JsonPropertyName("detail")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Detail { get; init; } + + /// + /// The resource identifier of this item. + /// + [JsonPropertyName("uri")] + [JsonRequired] + [JsonConverter(typeof(DocumentUriConverter))] + public Uri Uri { get; init; } + + /// + /// The range enclosing this symbol not including leading/trailing whitespace + /// but everything else, e.g. comments and code. + /// + [JsonPropertyName("range")] + [JsonRequired] + public Range Range { get; init; } + + /// + /// The range that should be selected and revealed when this symbol is being + /// picked, e.g. the name of a function. Must be contained by the + /// + /// + [JsonPropertyName("selectionRange")] + [JsonRequired] + public Range SelectionRange { get; init; } + + /// + /// A data field that is preserved between a call hierarchy prepare and + /// incoming calls or outgoing calls requests. + /// + [JsonPropertyName("data")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public object? Data { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyOptions.cs new file mode 100644 index 0000000000000..28d0d339c8cd1 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyOptions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Class which represents Call Hierarchy server capabilities. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class CallHierarchyOptions : IWorkDoneProgressOptions +{ + /// + /// Gets or sets a value indicating whether work done progress is supported. + /// + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyOutgoingCall.cs b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyOutgoingCall.cs new file mode 100644 index 0000000000000..f1f787e51fe77 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyOutgoingCall.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The item returned from a 'callHierarchy/outgoingCalls' request +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class CallHierarchyOutgoingCall +{ + /// + /// The for which to return outgoing calls + /// + [JsonPropertyName("to")] + [JsonRequired] + public CallHierarchyItem To { get; init; } + + /// + /// The range at which this item is called. This is the range relative to + /// the caller, e.g the item passed to the callHierarchy/outgoingCalls request. + /// + [JsonPropertyName("fromRanges")] + [JsonRequired] + public Range[] FromRanges { get; init; } +} + diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyOutgoingCallsParams.cs b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyOutgoingCallsParams.cs new file mode 100644 index 0000000000000..61863c4fe4f1b --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyOutgoingCallsParams.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a 'callHierarchy/incomingCalls' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class CallHierarchyOutgoingCallsParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialResultParams +{ + /// + /// The item returned from `textDocument/prepareCallHierarchy` + /// + [JsonPropertyName("item")] + [JsonRequired] + public CallHierarchyItem Item { get; init; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + /// + /// may only be used if the client opts in via + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyPrepareParams.cs b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyPrepareParams.cs new file mode 100644 index 0000000000000..931bb20ae55e1 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyPrepareParams.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a 'textDocument/prepareCallHierarchy' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class CallHierarchyPrepareParams : TextDocumentPositionParams, IWorkDoneProgressParams +{ + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyRegistrationOptions.cs new file mode 100644 index 0000000000000..61aecb53647e2 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyRegistrationOptions.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class CallHierarchyRegistrationOptions : CallHierarchyOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + /// The id used to register the request. The id can be used to deregister the request again. + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationClientCapabilities.cs new file mode 100644 index 0000000000000..1e3df13871094 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationClientCapabilities.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/declaration` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.14 +internal class DeclarationClientCapabilities : DynamicRegistrationSetting +{ + /// + /// Whether the client supports supports additional metadata in the form of definition links + /// + [JsonPropertyName("linkSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool LinkSupport { get; init; } +} + diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationOptions.cs new file mode 100644 index 0000000000000..a45524997fc68 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationOptions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Server capabilities specific to Go to Declaration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.14 +internal class DeclarationOptions : IWorkDoneProgressOptions +{ + /// + /// Gets or sets a value indicating whether work done progress is supported. + /// + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationParams.cs b/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationParams.cs new file mode 100644 index 0000000000000..b68720b420d46 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationParams.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a 'textDocument/declaration' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DeclarationParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialResultParams> +{ + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + /// + /// may only be used if the client opts in via + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress>? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationRegistrationOptions.cs new file mode 100644 index 0000000000000..81ec9e915f4de --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/DeclarationRegistrationOptions.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.14 +internal class DeclarationRegistrationOptions : DeclarationOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + /// The id used to register the request. The id can be used to deregister the request again. + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/DefinitionClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/Navigation/DefinitionClientCapabilities.cs new file mode 100644 index 0000000000000..191d43b5aab67 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/DefinitionClientCapabilities.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/definition` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DefinitionClientCapabilities : DynamicRegistrationSetting +{ + /// + /// Whether the client supports supports additional metadata in the form of definition links + /// + /// Since LSP 3.14 + [JsonPropertyName("linkSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool LinkSupport { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/DefinitionOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/DefinitionOptions.cs new file mode 100644 index 0000000000000..6415053e4b0ed --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/DefinitionOptions.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Server capabilities specific to Go to Definition. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DefinitionOptions : IWorkDoneProgressOptions +{ + /// + /// Gets or sets a value indicating whether work done progress is supported. + /// + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/DefinitionParams.cs b/src/LanguageServer/Protocol/Protocol/Navigation/DefinitionParams.cs new file mode 100644 index 0000000000000..dc77005dd6543 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/DefinitionParams.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a 'textDocument/definition' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class DefinitionParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialResultParams> +{ + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + /// + /// may only be used if the client opts in via + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress>? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/DefinitionRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/DefinitionRegistrationOptions.cs similarity index 65% rename from src/LanguageServer/Protocol/Protocol/DefinitionRegistrationOptions.cs rename to src/LanguageServer/Protocol/Protocol/Navigation/DefinitionRegistrationOptions.cs index 2aa6d31942493..1f6859fc5bd96 100644 --- a/src/LanguageServer/Protocol/Protocol/DefinitionRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/Navigation/DefinitionRegistrationOptions.cs @@ -2,24 +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.Text.Json.Serialization; - namespace Roslyn.LanguageServer.Protocol; +using System.Text.Json.Serialization; + /// -/// Class representing the registration options for go to definition support. +/// Subclass of that allows scoping the registration. /// /// See the Language Server Protocol specification for additional information. /// internal class DefinitionRegistrationOptions : DefinitionOptions, ITextDocumentRegistrationOptions { /// - /// Gets or sets the document filters for this registration option. + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. /// [JsonPropertyName("documentSelector")] - public DocumentFilter[]? DocumentSelector - { - get; - set; - } -} \ No newline at end of file + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/ImplementationClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/Navigation/ImplementationClientCapabilities.cs new file mode 100644 index 0000000000000..98ac0fd7d0c87 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/ImplementationClientCapabilities.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/implementation` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.6 +internal class ImplementationClientCapabilities : DynamicRegistrationSetting +{ + /// + /// Whether the client supports supports additional metadata in the form of definition links + /// + /// Since LSP 3.14 + [JsonPropertyName("linkSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool LinkSupport { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/ImplementationOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/ImplementationOptions.cs similarity index 93% rename from src/LanguageServer/Protocol/Protocol/ImplementationOptions.cs rename to src/LanguageServer/Protocol/Protocol/Navigation/ImplementationOptions.cs index afd33c2190764..14fe2999d1fd8 100644 --- a/src/LanguageServer/Protocol/Protocol/ImplementationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/Navigation/ImplementationOptions.cs @@ -7,7 +7,7 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents workspace symbols capabilities. + /// Server capabilities specific to Go to Implementation. /// /// See the Language Server Protocol specification for additional information. /// diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/ImplementationParams.cs b/src/LanguageServer/Protocol/Protocol/Navigation/ImplementationParams.cs new file mode 100644 index 0000000000000..9e6c1f7be75ac --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/ImplementationParams.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a 'textDocument/implementation' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class ImplementationParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialResultParams> +{ + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + /// + /// may only be used if the client opts in via + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress>? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/ImplementationRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/ImplementationRegistrationOptions.cs new file mode 100644 index 0000000000000..76602354149a5 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/ImplementationRegistrationOptions.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol +{ + using System.Text.Json.Serialization; + + /// + /// Subclass of that allows scoping the registration. + /// + /// See the Language Server Protocol specification for additional information. + /// + internal class ImplementationRegistrationOptions : ImplementationOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions + { + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + /// The id used to register the request. The id can be used to deregister the request again. + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } + } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceClientCapabilities.cs new file mode 100644 index 0000000000000..92c201b84f0f4 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceClientCapabilities.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. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/references` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.6 +internal class ReferenceClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceContext.cs b/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceContext.cs new file mode 100644 index 0000000000000..e92832b883726 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceContext.cs @@ -0,0 +1,22 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Class representing reference context information for find reference request parameter. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class ReferenceContext +{ + /// + /// Include the declaration of the current symbol. + /// + [JsonPropertyName("includeDeclaration")] + public bool IncludeDeclaration { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/ReferenceOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceOptions.cs similarity index 93% rename from src/LanguageServer/Protocol/Protocol/ReferenceOptions.cs rename to src/LanguageServer/Protocol/Protocol/Navigation/ReferenceOptions.cs index 2282473292523..389c0c37cb131 100644 --- a/src/LanguageServer/Protocol/Protocol/ReferenceOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceOptions.cs @@ -7,7 +7,7 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents workspace symbols capabilities. + /// Server capabilities specific to Find References. /// /// See the Language Server Protocol specification for additional information. /// diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceParams.cs b/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceParams.cs new file mode 100644 index 0000000000000..e6b3a42264302 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceParams.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a textDocument/references request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class ReferenceParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialResultParams +{ + /// + /// Gets or sets the reference context. + /// + [JsonPropertyName("context")] + [JsonRequired] + public ReferenceContext Context { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceRegistrationOptions.cs new file mode 100644 index 0000000000000..85fb9087594cb --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/ReferenceRegistrationOptions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol +{ + using System.Text.Json.Serialization; + + /// + /// Subclass of that allows scoping the registration. + /// + /// See the Language Server Protocol specification for additional information. + /// + internal class ReferenceRegistrationOptions : ReferenceOptions, ITextDocumentRegistrationOptions + { + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionClientCapabilities.cs new file mode 100644 index 0000000000000..04c6d63d749ab --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionClientCapabilities.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/typeDefinition` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.6 +internal class TypeDefinitionClientCapabilities : DynamicRegistrationSetting +{ + /// + /// Whether the client supports supports additional metadata in the form of definition links + /// + /// Since LSP 3.14 + [JsonPropertyName("linkSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool LinkSupport { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionOptions.cs new file mode 100644 index 0000000000000..24cd04ee611ce --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionOptions.cs @@ -0,0 +1,23 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Server capabilities specific to Go to Type Declaration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class TypeDefinitionOptions : IWorkDoneProgressOptions +{ + /// + /// Gets or sets a value indicating whether work done progress is supported. + /// + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionParams.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionParams.cs new file mode 100644 index 0000000000000..dfce5158d3e15 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionParams.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a 'textDocument/typeDefinition' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class TypeDefinitionParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialResultParams> +{ + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + /// + /// may only be used if the client opts in via + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress>? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionRegistrationOptions.cs new file mode 100644 index 0000000000000..5b821d0cc78e3 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeDefinitionRegistrationOptions.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class TypeDefinitionRegistrationOptions : TypeDefinitionOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + /// The id used to register the request. The id can be used to deregister the request again. + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyClientCapabilities.cs new file mode 100644 index 0000000000000..28fd856c2b53c --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyClientCapabilities.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. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the various type hierarchy requests. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class TypeHierarchyClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyItem.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyItem.cs new file mode 100644 index 0000000000000..860eba4cc1d1a --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyItem.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Represents an item in the type hierarchy +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class TypeHierarchyItem +{ + /// + /// The name of this item. + /// + [JsonPropertyName("name")] + [JsonRequired] + public string Name { get; init; } + + /// + /// The kind of this item. + /// + [JsonPropertyName("kind")] + [JsonRequired] + public SymbolKind Kind { get; init; } + + /// + /// Tags for this item. + /// + [JsonPropertyName("tags")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SymbolTag[]? Tags { get; init; } + + /// + /// More detail for this item, e.g. the signature of a function. + /// + [JsonPropertyName("detail")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Detail { get; init; } + + /// + /// The resource identifier of this item. + /// + [JsonPropertyName("uri")] + [JsonRequired] + [JsonConverter(typeof(DocumentUriConverter))] + public Uri Uri { get; init; } + + /// + /// The range enclosing this symbol not including leading/trailing whitespace + /// but everything else, e.g. comments and code. + /// + [JsonPropertyName("range")] + [JsonRequired] + public Range Range { get; init; } + + /// + /// The range that should be selected and revealed when this symbol is being + /// picked, e.g. the name of a function. Must be contained by the + /// + /// + [JsonPropertyName("selectionRange")] + [JsonRequired] + public Range SelectionRange { get; init; } + + /// + /// A data field that is preserved between a type hierarchy prepare and + /// supertypes or subtypes requests. It could also be used to identify the + /// type hierarchy in the server, helping improve the performance on + /// resolving supertypes and subtypes. + /// + [JsonPropertyName("data")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public object? Data { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyOptions.cs new file mode 100644 index 0000000000000..43b02fadad74a --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyOptions.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Sever capabilities specific to Type Hierarchy. +/// +/// See the Language Server Protocol specification for additional information. +/// +internal class TypeHierarchyOptions : IWorkDoneProgressOptions +{ + /// + /// Gets or sets a value indicating whether work done progress is supported. + /// + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyPrepareParams.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyPrepareParams.cs new file mode 100644 index 0000000000000..17c33d3c3ffb3 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyPrepareParams.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a 'textDocument/prepareTypeHierarchy' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class TypeHierarchyPrepareParams : TextDocumentPositionParams, IWorkDoneProgressParams +{ + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyRegistrationOptions.cs new file mode 100644 index 0000000000000..7b77860abd991 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyRegistrationOptions.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +internal class TypeHierarchyRegistrationOptions : TypeHierarchyOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + /// The id used to register the request. The id can be used to deregister the request again. + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchySubtypesParams.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchySubtypesParams.cs new file mode 100644 index 0000000000000..dd7d5927dc23b --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchySubtypesParams.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a 'typeHierarchy/subtypes' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class TypeHierarchySubtypesParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialResultParams +{ + /// + /// The for which to return subtypes + /// + [JsonPropertyName("item")] + [JsonRequired] + public TypeHierarchyItem Item { get; init; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + /// + /// may only be used if the client opts in via + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchySupertypesParams.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchySupertypesParams.cs new file mode 100644 index 0000000000000..c356e0d6789c1 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchySupertypesParams.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a 'typeHierarchy/supertypes' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class TypeHierarchySupertypesParams : TextDocumentPositionParams, IWorkDoneProgressParams, IPartialResultParams +{ + /// + /// The for which to return supertypes + /// + [JsonPropertyName("item")] + [JsonRequired] + public TypeHierarchyItem Item { get; init; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + /// + /// may only be used if the client opts in via + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/DidChangeNotebookDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/Notebook/DidChangeNotebookDocumentParams.cs new file mode 100644 index 0000000000000..4870ca9f5b401 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/DidChangeNotebookDocumentParams.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a notebookDocument/didChange notification. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class DidChangeNotebookDocumentParams +{ + /// + /// The notebook document that did change. The version number points + /// to the version after all provided changes have been applied. + /// + [JsonPropertyName("notebookDocument")] + [JsonRequired] + public VersionedNotebookDocumentIdentifier NotebookDocument { get; init; } + + /// + /// The actual changes to the notebook document. + /// + /// The change describes single state change to the notebook document. + /// So it moves a notebook document, its cells and its cell text document + /// contents from state S to S'. + /// + /// + /// To mirror the content of a notebook using change events use the + /// following approach: + /// + /// start with the same initial content + /// apply the notebookDocument/didChange notifications in the order you receive them. + /// + /// + /// + [JsonPropertyName("change")] + [JsonRequired] + public NotebookDocumentChangeEvent Change { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/DidCloseNotebookDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/Notebook/DidCloseNotebookDocumentParams.cs new file mode 100644 index 0000000000000..7bd04c8d90e1c --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/DidCloseNotebookDocumentParams.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a notebookDocument/didClose notification. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class DidCloseNotebookDocumentParams +{ + + /// + /// The notebook document that got closed. + /// + [JsonPropertyName("notebookDocument")] + [JsonRequired] + public NotebookDocumentIdentifier NotebookDocument { get; init; } + + /// + /// The text documents that represent the content + /// of a notebook cell that got closed. + /// + [JsonPropertyName("cellTextDocuments")] + [JsonRequired] + public TextDocumentIdentifier[] CellTextDocuments { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/DidOpenNotebookDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/Notebook/DidOpenNotebookDocumentParams.cs new file mode 100644 index 0000000000000..4d9646d0d1813 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/DidOpenNotebookDocumentParams.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in notebookDocument/didOpen notification. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class DidOpenNotebookDocumentParams +{ + /// + /// The notebook document that got opened. + /// + [JsonPropertyName("notebookDocument")] + [JsonRequired] + public NotebookDocument NotebookDocument { get; init; } + + /// + /// The text documents that represent the content of a notebook cell. + /// + [JsonPropertyName("cellTextDocuments")] + [JsonRequired] + public TextDocumentItem[] CellTextDocuments { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/DidSaveNotebookDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/Notebook/DidSaveNotebookDocumentParams.cs new file mode 100644 index 0000000000000..959cdadb248d7 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/DidSaveNotebookDocumentParams.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The params sent in a notebookDocument/didSave notification. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class DidSaveNotebookDocumentParams +{ + /// + /// The notebook document that got saved. + /// + [JsonPropertyName("notebookDocument")] + [JsonRequired] + public NotebookDocumentIdentifier NotebookDocument { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/ExecutionSummary.cs b/src/LanguageServer/Protocol/Protocol/Notebook/ExecutionSummary.cs new file mode 100644 index 0000000000000..59411c815213a --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/ExecutionSummary.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Additional execution summary information +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class ExecutionSummary +{ + /// + /// A strict monotonically increasing value indicating the + /// execution order of a cell inside a notebook. + /// + [JsonPropertyName("executionOrder")] + [JsonRequired] + public int ExecutionOrder { get; init; } + + /// + /// Whether the execution was successful or not, if known by the client. + /// + [JsonPropertyName("success")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? Success { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCell.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCell.cs new file mode 100644 index 0000000000000..a738797ac815b --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCell.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A notebook cell. +/// +/// A cell's document URI must be unique across ALL notebook +/// cells and can therefore be used to uniquely identify a +/// notebook cell or the cell's text document. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since LSP 3.17 +internal class NotebookCell +{ + + /// + /// The cell's kind + /// + [JsonPropertyName("kind")] + [JsonRequired] + public NotebookCellKind Kind { get; init; } + + /// + /// The URI of the cell's text document content. + /// + [JsonPropertyName("document")] + [JsonConverter(typeof(DocumentUriConverter))] + [JsonRequired] + public Uri Document { get; init; } + + /// + /// Additional metadata stored with the cell. + /// + [JsonPropertyName("metadata")] + public object? Metadata { get; init; } + + /// + /// Additional execution summary information if supported by the client. + /// + [JsonPropertyName("executionSummary")] + public ExecutionSummary? ExecutionSummary { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCellArrayChange.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCellArrayChange.cs new file mode 100644 index 0000000000000..7c743cac151b7 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCellArrayChange.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A change describing how to move a array from state S to S'. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class NotebookCellArrayChange +{ + /// + /// The start offset of the cell that changed. + /// + [JsonPropertyName("start")] + [JsonRequired] + public int Start { get; set; } + + /// + /// The deleted cells + /// + [JsonPropertyName("deleteCount")] + [JsonRequired] + public int DeleteCount { get; init; } + + /// + /// The new cells, if any + /// + [JsonPropertyName("cells")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public NotebookCell[]? Cells { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCellKind.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCellKind.cs new file mode 100644 index 0000000000000..9be94fa10c2fc --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCellKind.cs @@ -0,0 +1,25 @@ +// 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 Roslyn.LanguageServer.Protocol; + +/// +/// A notebook cell kind. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal enum NotebookCellKind +{ + /// + /// A markup-cell is formatted source that is used for display. + /// + Markup = 1, + + /// + /// A code-cell is source code. + /// + Code = 2 +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCellTextDocumentFilter.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCellTextDocumentFilter.cs new file mode 100644 index 0000000000000..84bbb757511ee --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCellTextDocumentFilter.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A notebook cell text document filter denotes a cell text document by +/// different properties. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since LSP 3.17 +internal class NotebookCellTextDocumentFilter +{ + /// + /// A filter that matches against the notebook + /// containing the notebook cell. If a string + /// value is provided it matches against the + /// notebook type. '*' matches every notebook. + /// + [JsonPropertyName("notebook")] + [JsonRequired] + public SumType Notebook { get; init; } + + /// + /// A language id like `python`. + /// + /// Will be matched against the language id of the + /// notebook cell document. '*' matches every language. + /// + [JsonPropertyName("language")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Language { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocument.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocument.cs new file mode 100644 index 0000000000000..0ae70f36870a2 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocument.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A notebook document. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class NotebookDocument +{ + /// + /// The notebook document's URI. + /// + [JsonPropertyName("uri")] + [JsonRequired] + // NOTE: not a DocumentURI + public Uri Uri { get; init; } + + /// + /// The type of the notebook. + /// + [JsonPropertyName("notebookType")] + [JsonRequired] + public string NotebookType { get; init; } + + /// + /// The version number of this document (it will increase after each change, including undo/redo). + /// + [JsonPropertyName("version")] + [JsonRequired] + public int Version { get; init; } + + /// + /// Additional metadata stored with the notebook document. + /// + [JsonPropertyName("metadata")] + public object? Metadata { get; init; } + + /// + /// The cells of a notebook. + /// + [JsonPropertyName("cells")] + [JsonRequired] + public NotebookCell[] Cells { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeCells.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeCells.cs new file mode 100644 index 0000000000000..43b748cf64057 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeCells.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Represents changes to the notebook cells in a +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class NotebookDocumentChangeCells +{ + /// + /// Changes to the cell structure to add or remove cells. + /// + [JsonPropertyName("structure")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public NotebookDocumentChangeCellsStructure? Structure { get; init; } + + /// + /// Changes to notebook cells properties like its + /// kind, execution summary or metadata. + /// + [JsonPropertyName("data")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public NotebookCell[]? Data { get; init; } + + /// + /// Changes to the text content of notebook cells. + /// + [JsonPropertyName("textContent")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public NotebookDocumentChangeCellsText[]? TextContent { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeCellsStructure.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeCellsStructure.cs new file mode 100644 index 0000000000000..455d24f5fcf4b --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeCellsStructure.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Represents changes to the notebook structure to add or remove cells in a +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class NotebookDocumentChangeCellsStructure +{ + /// + /// The change to the cell array. + /// + [JsonPropertyName("array")] + [JsonRequired] + public NotebookCellArrayChange Array { get; init; } + + /// + /// Additional opened cell text documents. + /// + [JsonPropertyName("didOpen")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public TextDocumentItem[]? DidOpen { get; init; } + + /// + /// Additional closed cell text documents. + /// + [JsonPropertyName("didClose")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public TextDocumentIdentifier[]? DidClose { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeCellsText.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeCellsText.cs new file mode 100644 index 0000000000000..34c60f56b61f9 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeCellsText.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Changes to the text content of a notebook cell in a +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class NotebookDocumentChangeCellsText +{ + /// + /// Identifier for the document representing the cell + /// + [JsonPropertyName("document")] + [JsonRequired] + public VersionedTextDocumentIdentifier Document { get; init; } + + /// + /// The changes to the document representing the cell + /// + [JsonPropertyName("changes")] + [JsonRequired] + public TextDocumentContentChangeEvent[] Changes { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeEvent.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeEvent.cs new file mode 100644 index 0000000000000..f575097f0e478 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentChangeEvent.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A change event for a notebook document. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class NotebookDocumentChangeEvent +{ + /// + /// The changed metadata, if any. + /// + [JsonPropertyName("metadata")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IDictionary? Metadata { get; init; } + + /// + /// Changes to cells + /// + [JsonPropertyName("cells")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public NotebookDocumentChangeCells? Cells { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentClientCapabilities.cs new file mode 100644 index 0000000000000..ae0c62673d076 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentClientCapabilities.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the notebook document support +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class NotebookDocumentClientCapabilities +{ + /// + /// Capabilities specific to notebook document synchronization + /// + [JsonPropertyName("synchronization")] + [JsonRequired] + public NotebookDocumentSyncClientCapabilities Synchronization { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentFilter.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentFilter.cs new file mode 100644 index 0000000000000..23baade1b6e51 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentFilter.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A notebook document filter denotes a notebook document by +/// different properties. +/// +/// NOTE: One or more of the properties NotebookType, Scheme and Pattern must be non-null +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since LSP 3.17 +internal class NotebookDocumentFilter +{ + /// + /// The type of the enclosing notebook. */ + /// + [JsonPropertyName("notebookType")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? NotebookType { get; init; } + + /// + /// A Uri scheme () like file or untitled. + /// + [JsonPropertyName("scheme")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Scheme { get; init; } + + /// + /// A glob pattern. + /// + [JsonPropertyName("pattern")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Pattern { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentIdentifier.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentIdentifier.cs new file mode 100644 index 0000000000000..f7ec5f7dc9fa2 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentIdentifier.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A literal to identify a notebook document in the client. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class NotebookDocumentIdentifier +{ + /// + /// The notebook document's URI. + /// + [JsonPropertyName("uri")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Uri Uri { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncCellSelector.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncCellSelector.cs new file mode 100644 index 0000000000000..a82fc5b937393 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncCellSelector.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Specifies languages of cells to be matched in a notebook sync. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since LSP 3.17 +/// +internal class NotebookDocumentSyncCellSelector +{ + [JsonPropertyName("language")] + [JsonRequired] + public string Language { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncClientCapabilities.cs new file mode 100644 index 0000000000000..aa51a0e356249 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncClientCapabilities.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Notebook specific client capabilities +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class NotebookDocumentSyncClientCapabilities : IDynamicRegistrationSetting +{ + /// + /// The client supports sending execution summary data per cell. + /// + [JsonPropertyName("executionSummarySupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool ExecutionSummarySupport { get; init; } + + /// + /// Whether the implementation supports dynamic registration. If this is set to + /// the client supports the new and + /// return values for the corresponding server capabilities. + /// + [JsonPropertyName("dynamicRegistration")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DynamicRegistration { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncOptions.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncOptions.cs new file mode 100644 index 0000000000000..ecc8f8d6d73de --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncOptions.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Options specific to a notebook plus its cells +/// to be synced to the server. +/// +/// If a selector provides a notebook document +/// filter but no cell selector all cells of a +/// matching notebook document will be synced. +/// +/// +/// If a selector provides no notebook document +/// filter but only a cell selector all notebook +/// documents that contain at least one matching +/// cell will be synced. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since LSP 3.17 +internal class NotebookDocumentSyncOptions +{ + /// + /// The notebooks to be synced + /// + [JsonPropertyName("notebookSelector")] + [JsonRequired] + public NotebookDocumentSyncSelector[] NotebookSelector { get; init; } + + /// + /// Whether save notification should be forwarded to + /// the server. Will only be honored if mode === `notebook`. + /// + [JsonPropertyName("save")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool Save { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncRegistrationOptions.cs new file mode 100644 index 0000000000000..2968e35aa4bf4 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncRegistrationOptions.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that implements +/// , allowing it to be registered +/// with an ID that can be used to unregister it later. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class NotebookDocumentSyncRegistrationOptions : NotebookDocumentSyncOptions, IStaticRegistrationOptions +{ + /// + /// The id used to register the request. The id can be used to deregister the request again. + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncSelector.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncSelector.cs new file mode 100644 index 0000000000000..dd849cf2cac4f --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookDocumentSyncSelector.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Matches notebooks and cells to be synced +/// +/// NOTE: either one or both of the Notebook and Cells properties must be non-null. +/// +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class NotebookDocumentSyncSelector +{ + /// + /// The notebook to be synced. If a string + /// value is provided it matches against the + /// notebook type. '*' matches every notebook. + /// + [JsonPropertyName("notebook")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SumType? Notebook { get; init; } + + /// + /// The cells of the matching notebook to be synced. + /// + [JsonPropertyName("cells")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public NotebookDocumentSyncCellSelector[]? Cells { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/VersionedNotebookDocumentIdentifier.cs b/src/LanguageServer/Protocol/Protocol/Notebook/VersionedNotebookDocumentIdentifier.cs new file mode 100644 index 0000000000000..f28811a85e485 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/Notebook/VersionedNotebookDocumentIdentifier.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A versioned notebook document identifier. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class VersionedNotebookDocumentIdentifier +{ + + /// + /// The version number of this notebook document. + /// + [JsonPropertyName("version")] + [JsonRequired] + public int Version { get; init; } + + /// + /// The notebook document's URI. + /// + [JsonPropertyName("uri")] + [JsonRequired] + public Uri Uri { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/OnTypeFormattingClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/OnTypeFormattingClientCapabilities.cs new file mode 100644 index 0000000000000..6d5f5414b19b5 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/OnTypeFormattingClientCapabilities.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/onTypeFormatting` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class OnTypeFormattingClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/ParameterInformation.cs b/src/LanguageServer/Protocol/Protocol/ParameterInformation.cs index e92aeb737af31..9967582e52d8c 100644 --- a/src/LanguageServer/Protocol/Protocol/ParameterInformation.cs +++ b/src/LanguageServer/Protocol/Protocol/ParameterInformation.cs @@ -8,15 +8,28 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing a parameter of a callable signature. - /// + /// Represents a parameter of a callable-signature. A parameter can + /// have a label and documentation. + /// /// See the Language Server Protocol specification for additional information. + /// /// [JsonConverter(typeof(ParameterInformationConverter))] internal class ParameterInformation { /// - /// Gets or sets the label of the parameter. + /// The label of this parameter information. + /// + /// Either a string or an inclusive start and exclusive end offsets within + /// its containing signature label (see ). + /// The offsets are based on a UTF-16 string representation, like and + /// . + /// + /// + /// Note*: a label of type should be a substring of its containing + /// signature label. Its intended use case is to highlight the parameter + /// label part in the . + /// /// [JsonPropertyName("label")] public SumType> Label @@ -26,7 +39,7 @@ public SumType> Label } /// - /// Gets or sets the human-readable documentation of the parameter. + /// Human-readable documentation of the parameter. Will be shown in the UI but can be omitted. /// [JsonPropertyName("documentation")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/ParameterInformationSetting.cs b/src/LanguageServer/Protocol/Protocol/ParameterInformationSetting.cs index a392f4102186d..1733e9fbb0a0c 100644 --- a/src/LanguageServer/Protocol/Protocol/ParameterInformationSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/ParameterInformationSetting.cs @@ -7,15 +7,18 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the parameter information initialization setting. - /// + /// Client capabilities specific to + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.14 internal class ParameterInformationSetting { /// - /// Gets or sets a value indicating whether the client supports label offset. + /// The client supports processing label offsets instead of a simple label string. /// + /// Since LSP 3.14 [JsonPropertyName("labelOffsetSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool LabelOffsetSupport @@ -24,4 +27,4 @@ public bool LabelOffsetSupport set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/PositionEncodingKind.cs b/src/LanguageServer/Protocol/Protocol/PositionEncodingKind.cs new file mode 100644 index 0000000000000..d433d2333ebeb --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/PositionEncodingKind.cs @@ -0,0 +1,42 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.ComponentModel; +using System.Text.Json.Serialization; + +/// +/// The encoding used for representing character offsets in documents +/// as negotiated between the client and server during initialization +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +[JsonConverter(typeof(StringEnumConverter))] +[TypeConverter(typeof(StringEnumConverter.TypeConverter))] +internal readonly record struct PositionEncodingKind(string Value) : IStringEnum +{ + /// + /// Character offsets count UTF-8 code units (e.g bytes). + /// + public static readonly PositionEncodingKind UTF8 = new("utf-8"); + + /// + /// Character offsets count UTF-16 code units. + /// + /// This is the default and must always be supported by servers + /// + /// + public static readonly PositionEncodingKind UTF16 = new("utf-16"); + + /// + /// Character offsets count UTF-32 code units. + /// + /// Implementation note: these are the same as Unicode code points, so + /// this may also be used for an encoding-agnostic + /// representation of character offsets. + /// + public static readonly PositionEncodingKind UTF32 = new("utf-32"); +} diff --git a/src/LanguageServer/Protocol/Protocol/PrepareRenameParams.cs b/src/LanguageServer/Protocol/Protocol/PrepareRenameParams.cs index 2ef5c34b6eb05..3e9e051756d3b 100644 --- a/src/LanguageServer/Protocol/Protocol/PrepareRenameParams.cs +++ b/src/LanguageServer/Protocol/Protocol/PrepareRenameParams.cs @@ -4,33 +4,33 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// - /// Class representing the parameters for the 'textDocument/prepare' request. - /// + /// Class representing the parameters for the 'textDocument/prepareRename' request. + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class PrepareRenameParams : ITextDocumentPositionParams + /// Since LSP 3.12 + internal class PrepareRenameParams : ITextDocumentPositionParams, IWorkDoneProgressParams { - /// - /// Gets or sets the value which identifies the document. - /// + /// [JsonPropertyName("textDocument")] - public TextDocumentIdentifier TextDocument - { - get; - set; - } + [JsonRequired] + public TextDocumentIdentifier TextDocument { get; set; } /// - /// Gets or sets the position in which the rename is requested. + /// The position in which the rename is requested. /// [JsonPropertyName("position")] - public Position Position - { - get; - set; - } + [JsonRequired] + public Position Position { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/PrepareSupportDefaultBehavior.cs b/src/LanguageServer/Protocol/Protocol/PrepareSupportDefaultBehavior.cs index fb4a1319a87e1..3b4e76f26745d 100644 --- a/src/LanguageServer/Protocol/Protocol/PrepareSupportDefaultBehavior.cs +++ b/src/LanguageServer/Protocol/Protocol/PrepareSupportDefaultBehavior.cs @@ -6,9 +6,11 @@ namespace Roslyn.LanguageServer.Protocol { /// /// Enum representing the default behavior used by the client for computing a rename range. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal enum PrepareSupportDefaultBehavior { /// diff --git a/src/LanguageServer/Protocol/Protocol/PreviousResultId.cs b/src/LanguageServer/Protocol/Protocol/PreviousResultId.cs index e8ae0c7e4e6bc..610de39552d7c 100644 --- a/src/LanguageServer/Protocol/Protocol/PreviousResultId.cs +++ b/src/LanguageServer/Protocol/Protocol/PreviousResultId.cs @@ -8,10 +8,12 @@ namespace Roslyn.LanguageServer.Protocol; using System.Text.Json.Serialization; /// -/// Class representing a previous result id in a workspace pull request. -/// -/// See the Language Server Protocol specification for additional information. +/// Class representing a previous result id in a 'workspace/diagnostic' request. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 internal class PreviousResultId { /// @@ -34,4 +36,4 @@ public string Value get; set; } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/PublishDiagnosticParams.cs b/src/LanguageServer/Protocol/Protocol/PublishDiagnosticParams.cs index 5b759a01c9aa3..4656113a54618 100644 --- a/src/LanguageServer/Protocol/Protocol/PublishDiagnosticParams.cs +++ b/src/LanguageServer/Protocol/Protocol/PublishDiagnosticParams.cs @@ -25,6 +25,14 @@ public Uri Uri set; } + /// + /// Optional version number of the document for which the diagnostics are published + /// + /// Since LSP 3.15 + [JsonPropertyName("version")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? Version { get; init; } + /// /// Gets or sets the collection of diagnostics. /// diff --git a/src/LanguageServer/Protocol/Protocol/PublishDiagnosticsSetting.cs b/src/LanguageServer/Protocol/Protocol/PublishDiagnosticsSetting.cs index 63f44c94aabbf..ddfb07c089ca7 100644 --- a/src/LanguageServer/Protocol/Protocol/PublishDiagnosticsSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/PublishDiagnosticsSetting.cs @@ -7,21 +7,56 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the initialization setting for publish diagnostics. - /// + /// Client capabilities specific to the textDocument/publishDiagnostics notification + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class PublishDiagnosticsSetting { /// - /// Gets or sets a value indicating whether gets or sets the capabilities. + /// Whether the client supports the property. + /// + public bool RelatedInformation { get; init; } + + /// + /// Client supports the property to provide meta data about a diagnostic. + /// + /// Clients supporting tags have to handle unknown tags gracefully. + /// /// [JsonPropertyName("tagSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public TagSupport? TagSupport + public DiagnosticTagSupport? TagSupport { get; set; } + + /// + /// Whether the client interprets the property + /// of the textDocument/publishDiagnostics notification's parameter. + /// + /// Since LSP 3.15 + [JsonPropertyName("versionSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool VersionSupport { get; init; } + + /// + /// Whether the client supports the property. + /// + /// Since LSP 3.15 + [JsonPropertyName("codeDescriptionSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool CodeDescriptionSupport { get; init; } + + /// + /// Whether the client supports propagating the property from + /// a textDocument/publishDiagnostics notification to a textDocument/codeAction request. + /// + /// Since LSP 3.16 + [JsonPropertyName("dataSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DataSupport { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/RangeFormattingClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/RangeFormattingClientCapabilities.cs new file mode 100644 index 0000000000000..4d0c885a15d6b --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/RangeFormattingClientCapabilities.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/rangeFormatting` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class RangeFormattingClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/ReferenceContext.cs b/src/LanguageServer/Protocol/Protocol/ReferenceContext.cs deleted file mode 100644 index 2e7411b4411a0..0000000000000 --- a/src/LanguageServer/Protocol/Protocol/ReferenceContext.cs +++ /dev/null @@ -1,26 +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 Roslyn.LanguageServer.Protocol -{ - using System.Text.Json.Serialization; - - /// - /// Class representing reference context information for find reference request parameter. - /// - /// See the Language Server Protocol specification for additional information. - /// - internal class ReferenceContext - { - /// - /// Gets or sets a value indicating whether declaration should be included. - /// - [JsonPropertyName("includeDeclaration")] - public bool IncludeDeclaration - { - get; - set; - } - } -} diff --git a/src/LanguageServer/Protocol/Protocol/ReferenceParams.cs b/src/LanguageServer/Protocol/Protocol/ReferenceParams.cs deleted file mode 100644 index 00a2106a75ddc..0000000000000 --- a/src/LanguageServer/Protocol/Protocol/ReferenceParams.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. - -namespace Roslyn.LanguageServer.Protocol -{ - using System; - using System.Text.Json.Serialization; - - /// - /// Class representing find reference parameter for find reference request. - /// - /// See the Language Server Protocol specification for additional information. - /// - internal class ReferenceParams : TextDocumentPositionParams, IPartialResultParams - { - // Using IPartialResultParams instead of IPartialResultParams to - // allow the VS protocol extension to allow returning VSReferenceItem[] - - /// - /// Gets or sets the reference context. - /// - [JsonPropertyName("context")] - public ReferenceContext Context - { - get; - set; - } - - /// - /// Gets or sets the value of the PartialResultToken instance. - /// - [JsonPropertyName(Methods.PartialResultTokenName)] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public IProgress? PartialResultToken - { - get; - set; - } - } -} diff --git a/src/LanguageServer/Protocol/Protocol/Registration.cs b/src/LanguageServer/Protocol/Protocol/Registration.cs index 906b4f4277d8e..d3b0e33e58b73 100644 --- a/src/LanguageServer/Protocol/Protocol/Registration.cs +++ b/src/LanguageServer/Protocol/Protocol/Registration.cs @@ -17,6 +17,7 @@ internal class Registration /// Gets or sets the id used to register the request. This can be used to deregister later. /// [JsonPropertyName("id")] + [JsonRequired] public string Id { get; @@ -27,6 +28,7 @@ public string Id /// Gets or sets the method / capability to register for. /// [JsonPropertyName("method")] + [JsonRequired] public string Method { get; diff --git a/src/LanguageServer/Protocol/Protocol/RegistrationParams.cs b/src/LanguageServer/Protocol/Protocol/RegistrationParams.cs index 4125036ab0e1f..25c68fca57c41 100644 --- a/src/LanguageServer/Protocol/Protocol/RegistrationParams.cs +++ b/src/LanguageServer/Protocol/Protocol/RegistrationParams.cs @@ -17,6 +17,7 @@ internal class RegistrationParams /// Gets or sets the set of capabilities that are being registered. /// [JsonPropertyName("registrations")] + [JsonRequired] public Registration[] Registrations { get; diff --git a/src/LanguageServer/Protocol/Protocol/RegularExpressionsClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/RegularExpressionsClientCapabilities.cs new file mode 100644 index 0000000000000..e0a4ee2e32893 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/RegularExpressionsClientCapabilities.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Describes the client's regular expression engine +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class RegularExpressionsClientCapabilities +{ + /// + /// The name of the regular expression engine. + /// + [JsonPropertyName("engine")] + [JsonRequired] + public string Engine { get; init; } + + /// + /// The version of the regular expression engine. + /// + [JsonPropertyName("version")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Version { get; init; } + +} diff --git a/src/LanguageServer/Protocol/Protocol/RelatedFullDocumentDiagnosticReport.cs b/src/LanguageServer/Protocol/Protocol/RelatedFullDocumentDiagnosticReport.cs index 7b6fbc77a4210..7468d207b9b13 100644 --- a/src/LanguageServer/Protocol/Protocol/RelatedFullDocumentDiagnosticReport.cs +++ b/src/LanguageServer/Protocol/Protocol/RelatedFullDocumentDiagnosticReport.cs @@ -10,14 +10,22 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Class representing a full diagnostic report with a set of related documents. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 [Kind(DocumentDiagnosticReportKind.Full)] internal class RelatedFullDocumentDiagnosticReport : FullDocumentDiagnosticReport { /// - /// Gets or sets the map of related document diagnostic reports. + /// Diagnostics of related documents. + /// + /// + /// This information is useful in programming languages where code in a + /// file A can generate diagnostics in a file B which A depends on. An + /// example of such a language is C/C++ where macro definitions in a file + /// a.cpp can result in errors in a header file b.hpp. /// [JsonPropertyName("relatedDocuments")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -26,4 +34,4 @@ public Dictionary /// Class representing an unchanged diagnostic report with a set of related documents. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 [Kind(DocumentDiagnosticReportKind.Unchanged)] internal class RelatedUnchangedDocumentDiagnosticReport : UnchangedDocumentDiagnosticReport { /// - /// Gets or sets the map of related document diagnostic reports. + /// Diagnostics of related documents. + /// + /// + /// This information is useful in programming languages where code in a + /// file A can generate diagnostics in a file B which A depends on. An + /// example of such a language is C/C++ where macro definitions in a file + /// a.cpp can result in errors in a header file b.hpp. /// [JsonPropertyName("relatedDocuments")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -26,4 +34,4 @@ public Dictionary /// Class which represents renaming client capabilities. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class RenameClientCapabilities : DynamicRegistrationSetting { /// /// Gets or sets a value indicating whether the client supports testing for validity of rename operations before execution. /// + /// Since LSP 3.12 [JsonPropertyName("prepareSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool PrepareSupport @@ -25,9 +27,10 @@ public bool PrepareSupport } /// - /// Gets or sets the value indicating the default behavior used by the client when the (`{ defaultBehavior: boolean }`) - /// result is used in the 'textDocument/prepareRename' request. + /// Gets or sets the value indicating the default behavior used by the client when the + /// result is used in the 'textDocument/prepareRename' request. /// + /// Since LSP 3.16 [JsonPropertyName("prepareSupportDefaultBehavior")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public PrepareSupportDefaultBehavior? PrepareSupportDefaultBehavior @@ -37,10 +40,11 @@ public PrepareSupportDefaultBehavior? PrepareSupportDefaultBehavior } /// - /// Gets or sets a value indicating whether the client honors the change annotations in text edits and resource + /// Whether the client honors the change annotations in text edits and resource /// operations returned via the rename request's workspace edit, by for example presenting the workspace edit in /// the user interface and asking for confirmation. /// + /// Since LSP 3.16 [JsonPropertyName("honorsChangeAnnotations")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool HonorsChangeAnnotations diff --git a/src/LanguageServer/Protocol/Protocol/RenameFile.cs b/src/LanguageServer/Protocol/Protocol/RenameFile.cs index 969e8a039d867..4b50223b1495c 100644 --- a/src/LanguageServer/Protocol/Protocol/RenameFile.cs +++ b/src/LanguageServer/Protocol/Protocol/RenameFile.cs @@ -9,11 +9,13 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing a rename file operation. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.13 [Kind("rename")] - internal class RenameFile + internal class RenameFile : IAnnotatedChange { /// /// Gets the kind value. @@ -56,5 +58,10 @@ public RenameFileOptions? Options get; set; } + + /// + [JsonPropertyName("annotationId")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ChangeAnnotationIdentifier? AnnotationId { get; init; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/RenameFileOptions.cs b/src/LanguageServer/Protocol/Protocol/RenameFileOptions.cs index 59d45c42a225b..1db7dab2344aa 100644 --- a/src/LanguageServer/Protocol/Protocol/RenameFileOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/RenameFileOptions.cs @@ -8,14 +8,19 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the options for a create file operation. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.13 internal class RenameFileOptions { /// /// Gets or sets a value indicating whether the rename should overwrite the target if it already exists. (Overwrite wins over ignoreIfExists). /// + /// + /// wins over . + /// [JsonPropertyName("overwrite")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool Overwrite @@ -27,6 +32,9 @@ public bool Overwrite /// /// Gets or sets a value indicating whether the action should be ignored if the file already exists. /// + /// + /// wins over . + /// [JsonPropertyName("ignoreIfExists")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool IgnoreIfExists diff --git a/src/LanguageServer/Protocol/Protocol/RenameOptions.cs b/src/LanguageServer/Protocol/Protocol/RenameOptions.cs index 841b679e2e005..cd98eac650b7d 100644 --- a/src/LanguageServer/Protocol/Protocol/RenameOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/RenameOptions.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the rename options for server capabilities. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class RenameOptions : IWorkDoneProgressOptions { @@ -24,9 +25,7 @@ public bool PrepareProvider set; } - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// + /// [JsonPropertyName("workDoneProgress")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool WorkDoneProgress { get; init; } diff --git a/src/LanguageServer/Protocol/Protocol/RenameParams.cs b/src/LanguageServer/Protocol/Protocol/RenameParams.cs index 3c95b96d9393e..ec271e314e866 100644 --- a/src/LanguageServer/Protocol/Protocol/RenameParams.cs +++ b/src/LanguageServer/Protocol/Protocol/RenameParams.cs @@ -4,23 +4,29 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// /// Class representing the rename parameters for the textDocument/rename request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class RenameParams : TextDocumentPositionParams + internal class RenameParams : TextDocumentPositionParams, IWorkDoneProgressParams { /// - /// Gets or sets the new name of the renamed symbol. + /// The new name of the symbol. If the given name is not valid the + /// request must return a ResponseError with an + /// appropriate message set. /// [JsonPropertyName("newName")] - public string NewName - { - get; - set; - } + [JsonRequired] + public string NewName { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/RenameRange.cs b/src/LanguageServer/Protocol/Protocol/RenameRange.cs index 984b50dc823a0..b74641538d752 100644 --- a/src/LanguageServer/Protocol/Protocol/RenameRange.cs +++ b/src/LanguageServer/Protocol/Protocol/RenameRange.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents a possible result value of the 'textDocument/prepareRename' request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.12 internal class RenameRange { /// diff --git a/src/LanguageServer/Protocol/Protocol/RenameRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/RenameRegistrationOptions.cs new file mode 100644 index 0000000000000..5f8876947fc0e --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/RenameRegistrationOptions.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class RenameRegistrationOptions : RenameOptions, ITextDocumentRegistrationOptions +{ + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/ResolveSupportSetting.cs b/src/LanguageServer/Protocol/Protocol/ResolveSupportSetting.cs index 6ff560bb95808..a9a1fc88afa0a 100644 --- a/src/LanguageServer/Protocol/Protocol/ResolveSupportSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/ResolveSupportSetting.cs @@ -7,10 +7,12 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents initialization setting for properties a client can resolve lazily on a completion item. - /// + /// Indicates which properties a client can resolve lazily on a . + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since 3.16 internal class ResolveSupportSetting { /// diff --git a/src/LanguageServer/Protocol/Protocol/ResourceOperationKind.cs b/src/LanguageServer/Protocol/Protocol/ResourceOperationKind.cs index 228b44234bf60..0f217bd338e94 100644 --- a/src/LanguageServer/Protocol/Protocol/ResourceOperationKind.cs +++ b/src/LanguageServer/Protocol/Protocol/ResourceOperationKind.cs @@ -9,8 +9,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Value representing the kind of resource operations supported by the client. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// [JsonConverter(typeof(StringEnumConverter))] [TypeConverter(typeof(StringEnumConverter.TypeConverter))] diff --git a/src/LanguageServer/Protocol/Protocol/SaveOptions.cs b/src/LanguageServer/Protocol/Protocol/SaveOptions.cs index 9d04b661df742..5284b1bddb6cd 100644 --- a/src/LanguageServer/Protocol/Protocol/SaveOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/SaveOptions.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents save option configurations. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class SaveOptions { diff --git a/src/LanguageServer/Protocol/Protocol/SelectionRange.cs b/src/LanguageServer/Protocol/Protocol/SelectionRange.cs new file mode 100644 index 0000000000000..904eea68d1f6a --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/SelectionRange.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A selection range is a range around the cursor position which the user might be interested in selecting. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.15 +internal class SelectionRange +{ + /// + /// The range of the selection range + /// + [JsonPropertyName("range")] + [JsonRequired] + public Range Range { get; init; } + + /// + /// The parent selection range containing this range. + /// + /// Parent.Range must contain this.Range. + /// + /// + [JsonPropertyName("parent")] + [JsonRequired] + public SelectionRange Parent { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/SelectionRangeClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/SelectionRangeClientCapabilities.cs new file mode 100644 index 0000000000000..9519bc9ce202a --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/SelectionRangeClientCapabilities.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. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the `textDocument/selectionRange` request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.15 +internal class SelectionRangeClientCapabilities : DynamicRegistrationSetting +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/SelectionRangeOptions.cs b/src/LanguageServer/Protocol/Protocol/SelectionRangeOptions.cs new file mode 100644 index 0000000000000..a16f0719437ba --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/SelectionRangeOptions.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Server capabilities specific to Selection Range. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.15 +internal class SelectionRangeOptions : IWorkDoneProgressOptions +{ + /// + /// Gets or sets a value indicating whether work done progress is supported. + /// + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/SelectionRangeParams.cs b/src/LanguageServer/Protocol/Protocol/SelectionRangeParams.cs new file mode 100644 index 0000000000000..68f235894251f --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/SelectionRangeParams.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Class representing the parameter for the 'textDocument/selectionRange' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.15 +internal class SelectionRangeParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams +{ + /// + /// The text document. + /// + [JsonPropertyName("textDocument")] + [JsonRequired] + public TextDocumentIdentifier TextDocument { get; init; } + + /// + /// The positions inside the text document. + /// + [JsonPropertyName("textDocument")] + [JsonRequired] + public Position[] Positions { get; init; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/SelectionRangeRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/SelectionRangeRegistrationOptions.cs new file mode 100644 index 0000000000000..ae53aa276c1e9 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/SelectionRangeRegistrationOptions.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.15 +internal class SelectionRangeRegistrationOptions : DeclarationOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + /// The id used to register the request. The id can be used to deregister the request again. + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenFormat.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenFormat.cs index 5a75e425e946b..997b024e78813 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenFormat.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenFormat.cs @@ -9,9 +9,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Value representing the format used to describe semantic tokens. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 [JsonConverter(typeof(StringEnumConverter))] [TypeConverter(typeof(StringEnumConverter.TypeConverter))] internal readonly record struct SemanticTokenFormat(string Value) : IStringEnum diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenModifiers.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenModifiers.cs index 2c96ef5b846ce..146c847484b25 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenModifiers.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenModifiers.cs @@ -8,7 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Well-known semantic token modifiers. + /// + /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal static class SemanticTokenModifiers { /// diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenTypes.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenTypes.cs index 835e5d708cf35..93d003ff703f9 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenTypes.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokenTypes.cs @@ -8,7 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Well-known semantic tokens types. + /// + /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal static class SemanticTokenTypes { /// @@ -17,7 +21,8 @@ internal static class SemanticTokenTypes public const string Namespace = "namespace"; /// - /// Semantic token modifier for 'type'. + /// Represents a generic type. Acts as a fallback for types which + /// can't be mapped to a specific type like class or enum /// public const string Type = "type"; @@ -122,6 +127,12 @@ internal static class SemanticTokenTypes /// public const string Operator = "operator"; + /// + /// Semantic token modifier for 'decorator'. + /// + /// Sicne LSP 3.17 + public const string Decorator = "decorator"; + /// /// Collection containing all well-known semantic tokens types. /// @@ -149,6 +160,7 @@ internal static class SemanticTokenTypes Number, Regexp, Operator, + Decorator ]; } } diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokens.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokens.cs index bd467fbf475d6..7fa8d682bb75c 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokens.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokens.cs @@ -8,13 +8,20 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing response to semantic tokens messages. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class SemanticTokens { /// - /// Gets or sets a property that identifies this version of the document's semantic tokens. + /// An optional result id. + /// + /// If provided and clients support delta updating the client will include the + /// result id in the next semantic token request. A server can then instead of + /// computing all semantic tokens again simply send a delta. + /// /// [JsonPropertyName("resultId")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDelta.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDelta.cs index f1697e0ac4939..6e756534a5a45 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDelta.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDelta.cs @@ -8,14 +8,15 @@ namespace Roslyn.LanguageServer.Protocol /// /// Represents a response from a semantic tokens Document provider Edits request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class SemanticTokensDelta { /// - /// Gets or sets the Id for the client's new version after applying all - /// edits to their current semantic tokens data. + /// The ID of this result, which can then be used as a base for future deltas. /// [JsonPropertyName("resultId")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDeltaParams.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDeltaParams.cs index aded0c9dd957b..c04e4ee5647d5 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDeltaParams.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDeltaParams.cs @@ -8,12 +8,13 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Parameters for a request for Edits that can be applied to a previous response - /// from a semantic tokens Document provider. - /// + /// Parameters for 'textDocument/semanticTokens/full/delta' request. + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class SemanticTokensDeltaParams : ITextDocumentParams, IPartialResultParams + /// Since LSP 3.16 + internal class SemanticTokensDeltaParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams { /// /// Gets or sets an identifier for the document to fetch semantic tokens from. @@ -22,21 +23,21 @@ internal class SemanticTokensDeltaParams : ITextDocumentParams, IPartialResultPa public TextDocumentIdentifier TextDocument { get; set; } /// - /// Gets or sets a property indicating the version of the semantic - /// tokens Document provider response that the edits will be applied to. + /// The result id of a previous response. The result Id can either point to + /// a full response or a delta response depending on what was received last. + /// The delta should be relative to this previous response. /// [JsonPropertyName("previousResultId")] public string PreviousResultId { get; set; } - /// - /// Gets or sets the value of the Progress instance. - /// + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// [JsonPropertyName(Methods.PartialResultTokenName)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public IProgress? PartialResultToken - { - get; - set; - } + public IProgress? PartialResultToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDeltaPartialResult.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDeltaPartialResult.cs index dadc783ce447f..d75e29bb5b796 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDeltaPartialResult.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensDeltaPartialResult.cs @@ -8,14 +8,15 @@ namespace Roslyn.LanguageServer.Protocol /// /// Represents a response from a semantic tokens Document provider Edits request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class SemanticTokensDeltaPartialResult { /// - /// Gets or sets an array of edits to apply to a previous response from a - /// semantic tokens Document provider. + /// The semantic token edits to transform a previous result into a new result. /// [JsonPropertyName("edits")] [JsonRequired] diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensEdit.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensEdit.cs index c06932c59a9f7..3f7751745f705 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensEdit.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensEdit.cs @@ -10,9 +10,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing an individual edit incrementally applied to a previous /// semantic tokens response from the Document provider. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1036:Override methods on comparable types", Justification = "Pending implementation of IComparable")] internal class SemanticTokensEdit : IComparable { @@ -21,6 +23,7 @@ internal class SemanticTokensEdit : IComparable /// to begin the edit. /// [JsonPropertyName("start")] + [JsonRequired] public int Start { get; set; } /// @@ -28,6 +31,7 @@ internal class SemanticTokensEdit : IComparable /// from the previous response. /// [JsonPropertyName("deleteCount")] + [JsonRequired] public int DeleteCount { get; set; } /// diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensFullOptions.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensFullOptions.cs index ff7dcdf3e4970..cf34aa147515f 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensFullOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensFullOptions.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Options for the full document semantic tokens classification provider. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class SemanticTokensFullOptions { /// diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensLegend.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensLegend.cs index 394c0d45c8f68..c0c00826c889c 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensLegend.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensLegend.cs @@ -7,16 +7,19 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Legend used to encode semantic token types in . - /// + /// Legend used by the server to describe how it encodes semantic token types in . + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class SemanticTokensLegend { - /// - /// Gets or sets an array of token types that can be encoded in semantic tokens responses. + /// . + /// The semantic token types the server uses. Indices into this array are used to encode token types in semantic tokens responses. /// [JsonPropertyName("tokenTypes")] + [JsonRequired] public string[] TokenTypes { get; @@ -24,9 +27,10 @@ public string[] TokenTypes } /// - /// Gets or sets an array of token modfiers that can be encoded in semantic tokens responses. + /// The semantic token modifiers the server uses. Indices into this array are used to encode modifiers in semantic tokens responses. /// [JsonPropertyName("tokenModifiers")] + [JsonRequired] public string[] TokenModifiers { get; diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensOptions.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensOptions.cs index 30fce0f5efaa6..081a47960fc69 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensOptions.cs @@ -8,15 +8,18 @@ namespace Roslyn.LanguageServer.Protocol /// /// Initialization options for semantic tokens support. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class SemanticTokensOptions : IWorkDoneProgressOptions { /// /// Gets or sets a legend describing how semantic token types and modifiers are encoded in responses. /// [JsonPropertyName("legend")] + [JsonRequired] public SemanticTokensLegend Legend { get; set; } /// @@ -33,9 +36,7 @@ internal class SemanticTokensOptions : IWorkDoneProgressOptions [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public SumType? Full { get; set; } - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// + /// [JsonPropertyName("workDoneProgress")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool WorkDoneProgress { get; init; } diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensParams.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensParams.cs index 5cf3738c12b6b..76a60692b2b43 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensParams.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensParams.cs @@ -8,27 +8,29 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Parameters for semantic tokens full Document request. - /// + /// Parameters for 'textDocument/semanticTokens/full' request. + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class SemanticTokensParams : ITextDocumentParams, IPartialResultParams + /// Since LSP 3.16 + internal class SemanticTokensParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams { /// /// Gets or sets an identifier for the document to fetch semantic tokens from. /// [JsonPropertyName("textDocument")] + [JsonRequired] public TextDocumentIdentifier TextDocument { get; set; } - /// - /// Gets or sets the value of the Progress instance. - /// + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// [JsonPropertyName(Methods.PartialResultTokenName)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public IProgress? PartialResultToken - { - get; - set; - } + public IProgress? PartialResultToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensPartialResult.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensPartialResult.cs index 3307b392e936a..538869edd5bae 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensPartialResult.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensPartialResult.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing response to semantic tokens messages. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class SemanticTokensPartialResult { /// diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRangeParams.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRangeParams.cs index 0523c2e25293f..62f2248286ca7 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRangeParams.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRangeParams.cs @@ -4,19 +4,40 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// - /// Parameters for the semantic tokens Range request. - /// + /// Parameters for 'textDocument/semanticTokens/range' request. + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class SemanticTokensRangeParams : SemanticTokensParams + /// Since LSP 3.16 + internal class SemanticTokensRangeParams : ITextDocumentParams, IWorkDoneProgressParams, IPartialResultParams { + /// + /// Gets or sets an identifier for the document to fetch semantic tokens from. + /// + [JsonPropertyName("textDocument")] + [JsonRequired] + public TextDocumentIdentifier TextDocument { get; set; } + /// /// Gets or sets the range within the document to fetch semantic tokens for. /// [JsonPropertyName("range")] + [JsonRequired] public Range Range { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } + + /// + [JsonPropertyName(Methods.PartialResultTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? PartialResultToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRegistrationOptions.cs new file mode 100644 index 0000000000000..b3789e270eec2 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRegistrationOptions.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since LSP 3.16 +internal class SemanticTokensRegistrationOptions : SemanticTokensOptions, ITextDocumentRegistrationOptions, IStaticRegistrationOptions +{ + /// + /// A document selector to identify the scope of the registration. If set to + /// null the document selector provided on the client side will be used. + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } + + /// + /// The id used to register the request. The id can be used to deregister the request again. + /// + [JsonPropertyName("id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Id { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRequestsFullSetting.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRequestsFullSetting.cs index ce6ad7de1e5d6..8cf128bd71670 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRequestsFullSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRequestsFullSetting.cs @@ -7,11 +7,12 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Client settings for semantic tokens related to the - /// `textDocument/semanticTokens/full` message. - /// + /// Client capabilities specific to the textDocument/semanticTokens/full request. + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class SemanticTokensRequestsFullSetting { /// @@ -19,7 +20,7 @@ internal class SemanticTokensRequestsFullSetting /// textDocument/semanticTokens/full/delta request if the server /// provides a corresponding handler. /// - [JsonPropertyName("range")] + [JsonPropertyName("delta")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool Delta { get; set; } } diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRequestsSetting.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRequestsSetting.cs index 7c9dbd73769b9..c3110ddad1898 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRequestsSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensRequestsSetting.cs @@ -7,25 +7,25 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Requests client settings for semantic tokens. - /// + /// Represents which semantic token requests are supported by the client. + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class SemanticTokensRequestsSetting { /// - /// Gets or sets a value indicating whether the client will send the - /// `textDocument/semanticTokens/range` request if the server provides a - /// corresponding handler. + /// The client will send the textDocument/semanticTokens/range request + /// if the server provides a corresponding handler. /// [JsonPropertyName("range")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public SumType? Range { get; set; } /// - /// Gets or sets a value indicating whether the client will send the - /// `textDocument/semanticTokens/full` request if the server provides a - /// corresponding handler. + /// The client will send the textDocument/semanticTokens/full request + /// if the server provides a corresponding handler. /// [JsonPropertyName("full")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensSetting.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensSetting.cs index 85e34d5680f9f..c93f244723338 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensSetting.cs @@ -7,17 +7,30 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Client settings for semantic tokens. - /// + /// Client capabilities for semantic tokens. + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class SemanticTokensSetting : DynamicRegistrationSetting { /// - /// Gets or sets a value indicating which requests the client supports and might send to the server + /// Which requests the client supports and might send to the server /// depending on the server's capability. /// + /// + /// Please note that clients might not + /// show semantic tokens or degrade some of the user experience if a range + /// or full request is advertised by the client but not provided by the + /// server. If for example the client capability + /// and are both set to true + /// but the server only provides a range provider the client might not + /// render a minimap correctly or might even decide to not show any + /// semantic tokens at all. + /// [JsonPropertyName("requests")] + [JsonRequired] public SemanticTokensRequestsSetting Requests { get; set; } /// @@ -25,6 +38,7 @@ internal class SemanticTokensSetting : DynamicRegistrationSetting /// semantic tokens. /// [JsonPropertyName("tokenTypes")] + [JsonRequired] public string[] TokenTypes { get; set; } /// @@ -32,12 +46,14 @@ internal class SemanticTokensSetting : DynamicRegistrationSetting /// semantic tokens. /// [JsonPropertyName("tokenModifiers")] + [JsonRequired] public string[] TokenModifiers { get; set; } /// /// Gets or sets an array of formats the clients supports. /// [JsonPropertyName("formats")] + [JsonRequired] public SemanticTokenFormat[] Formats { get; set; } /// @@ -53,5 +69,34 @@ internal class SemanticTokensSetting : DynamicRegistrationSetting [JsonPropertyName("multilineTokenSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool MultilineTokenSupport { get; set; } + + /// + /// Whether the client allows the server to actively cancel a + /// semantic token request, e.g. supports returning + /// ErrorCodes.ServerCancelled. + /// + /// If a server does the client needs to retrigger the request. + /// + /// + /// Since LSP 3.17 + [JsonPropertyName("serverCancelSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool ServerCancelSupport { get; init; } + + /// + /// Whether the client uses semantic tokens to augment existing + /// syntax tokens. If set to client side created syntax + /// tokens and semantic tokens are both used for colorization. If + /// set to the client only uses the returned semantic tokens + /// for colorization. + /// + /// If the value is then the client behavior is not + /// specified. + /// + /// + /// Since LSP 3.17 + [JsonPropertyName("augmentsSyntaxTokens")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? AugmentsSyntaxTokens { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensWorkspaceSetting.cs b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensWorkspaceSetting.cs index d560f44d6c5c2..3f76963721e9e 100644 --- a/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensWorkspaceSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/SemanticTokens/SemanticTokensWorkspaceSetting.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Capabilities specific to the semantic token requests scoped to the workspace. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.16 internal class SemanticTokensWorkspaceSetting { /// @@ -19,7 +21,7 @@ internal class SemanticTokensWorkspaceSetting /// /// /// Note that this event is global and will force the client to refresh all - /// semantic tokens currently shown.It should be used with absolute care + /// semantic tokens currently shown. It should be used with absolute care /// and is useful for situation where a server for example detect a project /// wide change that requires such a calculation. /// @@ -27,4 +29,4 @@ internal class SemanticTokensWorkspaceSetting [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool RefreshSupport { get; set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/ServerCapabilities.cs b/src/LanguageServer/Protocol/Protocol/ServerCapabilities.cs index 840da00bb13b1..d6c950e164745 100644 --- a/src/LanguageServer/Protocol/Protocol/ServerCapabilities.cs +++ b/src/LanguageServer/Protocol/Protocol/ServerCapabilities.cs @@ -9,11 +9,28 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents server capabilities. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class ServerCapabilities { + // NOTE: these are kept in the same order as the spec to make them easier to update + + /// + /// The position encoding the server picked from the encodings offered + /// by the client via the client capability `general.positionEncodings`. + /// + /// If the client didn't provide any position encodings the only valid + /// value that a server can return is 'utf-16'. + /// If omitted it defaults to 'utf-16'. + /// + /// + /// Since LSP 3.16 + [JsonPropertyName("positionEncoding")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public PositionEncodingKind? PositionEncoding { get; init; } + /// /// Gets or sets the value which indicates how text document are synced. /// @@ -36,278 +53,251 @@ public TextDocumentSyncOptions? TextDocumentSync }; /// - /// Gets or sets the value which indicates if completions are supported. + /// Defines how notebook documents are synced. + /// + /// Since LSP 3.17 + [JsonPropertyName("notebookDocumentSync")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SumType? NotebookDocumentSync { get; init; } + + /// + /// The server provides completion support. /// [JsonPropertyName("completionProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public CompletionOptions? CompletionProvider - { - get; - set; - } + public CompletionOptions? CompletionProvider { get; set; } /// - /// Gets or sets a value indicating whether the server provides hover support. + /// The server provides hover support. /// [JsonPropertyName("hoverProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? HoverProvider - { - get; - set; - } + public SumType? HoverProvider { get; set; } /// - /// Gets or sets the value which indicates if signature help is supported. + /// The server provides signature help support. /// [JsonPropertyName("signatureHelpProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SignatureHelpOptions? SignatureHelpProvider - { - get; - set; - } + public SignatureHelpOptions? SignatureHelpProvider { get; set; } + + /// + /// The server provides Go to Declaration support. + /// + /// Since LSP 3.14 + [JsonPropertyName("declarationProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SumType? DeclarationProvider { get; init; } /// - /// Gets or sets a value indicating whether go to definition is supported. + /// The server provides Go to Definition support. /// [JsonPropertyName("definitionProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? DefinitionProvider - { - get; - set; - } + public SumType? DefinitionProvider { get; set; } /// - /// Gets or sets a value indicating whether go to type definition is supported. + /// The server provides Go to Type Definition support. /// + /// Since LSP 3.6 [JsonPropertyName("typeDefinitionProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? TypeDefinitionProvider - { - get; - set; - } + public SumType? TypeDefinitionProvider { get; set; } /// - /// Gets or sets a value indicating whether go to implementation is supported. + /// The server provides Go to Implementation support. /// + /// Since LSP 3.6 [JsonPropertyName("implementationProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? ImplementationProvider - { - get; - set; - } + public SumType? ImplementationProvider { get; set; } /// - /// Gets or sets a value indicating whether find all references is supported. + /// The server provides Find References support. /// [JsonPropertyName("referencesProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? ReferencesProvider - { - get; - set; - } + public SumType? ReferencesProvider { get; set; } /// - /// Gets or sets a value indicating whether the server supports document highlight. + /// The server provides Document Highlight support. /// [JsonPropertyName("documentHighlightProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? DocumentHighlightProvider - { - get; - set; - } + public SumType? DocumentHighlightProvider { get; set; } /// - /// Gets or sets a value indicating whether document symbols are supported. + /// The server provides Document Symbols support. /// [JsonPropertyName("documentSymbolProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? DocumentSymbolProvider - { - get; - set; - } + public SumType? DocumentSymbolProvider { get; set; } /// - /// Gets or sets a value indicating whether code actions are supported. + /// The server provides code actions. The return type is + /// only valid if the client signals code action literal support via the + /// property . /// [JsonPropertyName("codeActionProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? CodeActionProvider - { - get; - set; - } + public SumType? CodeActionProvider { get; set; } /// /// Gets or sets the value which indicates if code lens is supported. /// [JsonPropertyName("codeLensProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public CodeLensOptions? CodeLensProvider - { - get; - set; - } + public CodeLensOptions? CodeLensProvider { get; set; } /// /// Gets or sets the value which indicates if document link is supported. /// [JsonPropertyName("documentLinkProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DocumentLinkOptions? DocumentLinkProvider - { - get; - set; - } + public DocumentLinkOptions? DocumentLinkProvider { get; set; } /// /// Gets or sets the value which indicates if document color is supported. /// + /// Since LSP 3.6 [JsonPropertyName("colorProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? DocumentColorProvider - { - get; - set; - } + public SumType? DocumentColorProvider { get; set; } /// /// Gets or sets a value indicating whether document formatting is supported. /// [JsonPropertyName("documentFormattingProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? DocumentFormattingProvider - { - get; - set; - } + public SumType? DocumentFormattingProvider { get; set; } /// /// Gets or sets a value indicating whether document range formatting is supported. /// [JsonPropertyName("documentRangeFormattingProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? DocumentRangeFormattingProvider - { - get; - set; - } + public SumType? DocumentRangeFormattingProvider { get; set; } /// /// Gets or sets the value which indicates if document on type formatting is supported. /// [JsonPropertyName("documentOnTypeFormattingProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DocumentOnTypeFormattingOptions? DocumentOnTypeFormattingProvider - { - get; - set; - } + public DocumentOnTypeFormattingOptions? DocumentOnTypeFormattingProvider { get; set; } /// /// Gets or sets a value indicating whether rename is supported. /// [JsonPropertyName("renameProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? RenameProvider - { - get; - set; - } + public SumType? RenameProvider { get; set; } /// /// Gets or sets the value which indicates if folding range is supported. /// + /// Since LSP 3.10 [JsonPropertyName("foldingRangeProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? FoldingRangeProvider - { - get; - set; - } + public SumType? FoldingRangeProvider { get; set; } /// /// Gets or sets the value which indicates if execute command is supported. /// [JsonPropertyName("executeCommandProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public ExecuteCommandOptions? ExecuteCommandProvider - { - get; - set; - } + public ExecuteCommandOptions? ExecuteCommandProvider { get; set; } /// - /// Gets or sets a value indicating whether workspace symbols are supported. + /// The server provides selection range support. /// - [JsonPropertyName("workspaceSymbolProvider")] + /// Since LSP 3.15 + [JsonPropertyName("selectionRangeProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? WorkspaceSymbolProvider - { - get; - set; - } + public SumType? SelectionRangeProvider { get; init; } /// - /// Gets or sets experimental server capabilities. + /// Gets or sets a value indicating whether the server supports linked editing range. /// - [JsonPropertyName("experimental")] + /// Since LSP 3.16 + [JsonPropertyName("linkedEditingRangeProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public object? Experimental - { - get; - set; - } + public SumType? LinkedEditingRangeProvider { get; set; } /// - /// Gets or sets a value indicating whether the server supports linked editing range. + /// The server provides call hierarchy support. /// - [JsonPropertyName("linkedEditingRangeProvider")] + /// Since LSP 3.16 + [JsonPropertyName("callHierarchyProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? LinkedEditingRangeProvider - { - get; - set; - } + public SumType? CallHierarchyProvider { get; init; } /// /// Gets or sets the value which indicates if semantic tokens is supported. /// + /// Since LSP 3.16 [JsonPropertyName("semanticTokensProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SemanticTokensOptions? SemanticTokensOptions - { - get; - set; - } + public SumType? SemanticTokensOptions { get; set; } /// - /// Gets or sets the value which indicates what support the server has for pull diagnostics. + /// Whether server provides moniker support. /// - [JsonPropertyName("diagnosticProvider")] + /// Since LSP 3.16 + [JsonPropertyName("monikerProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DiagnosticOptions? DiagnosticOptions - { - get; - set; - } + public SumType? MonikerProvider { get; init; } + + /// + /// The server provides type hierarchy support. + /// + /// Since LSP 3.17 + [JsonPropertyName("typeHierarchyProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SumType? TypeHierarchyProvider { get; init; } + + /// + /// The server provides inline values. + /// + /// Since LSP 3.17 + [JsonPropertyName("inlineValueProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SumType? InlineValueProvider { get; init; } /// /// Gets or sets the value which indicates what support the server has for inlay hints. /// + /// Since LSP 3.17 [JsonPropertyName("inlayHintProvider")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType? InlayHintOptions - { - get; - set; - } + public SumType? InlayHintOptions { get; set; } + + /// + /// Gets or sets the value which indicates what support the server has for pull diagnostics. + /// + /// Since LSP 3.17 + [JsonPropertyName("diagnosticProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SumType? DiagnosticOptions { get; set; } + + /// + /// Gets or sets a value indicating whether workspace symbols are supported. + /// + [JsonPropertyName("workspaceSymbolProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SumType? WorkspaceSymbolProvider { get; set; } + + /// + /// Workspace specific server capabilities. + /// + [JsonPropertyName("workspace")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public WorkspaceServerCapabilities? Workspace { get; init; } + + /// + /// Gets or sets experimental server capabilities. + /// + [JsonPropertyName("experimental")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public object? Experimental { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/ServerInfo.cs b/src/LanguageServer/Protocol/Protocol/ServerInfo.cs new file mode 100644 index 0000000000000..569070d82f696 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ServerInfo.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Information about the server name and version +/// +/// Since LSP 3.15 +internal class ServerInfo +{ + + /// + /// The server name + /// + [JsonPropertyName("name")] + [JsonRequired] + public string Name { get; init; } + + /// + /// The server version + /// + [JsonPropertyName("version")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Version { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/SetTraceParams.cs b/src/LanguageServer/Protocol/Protocol/SetTraceParams.cs new file mode 100644 index 0000000000000..3b3cbee100776 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/SetTraceParams.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Class representing the parameters for the $/setTrace notification. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class SetTraceParams +{ + /// + /// The new value that should be assigned to the trace setting. + /// + [JsonPropertyName("value")] + [JsonRequired] + public TraceValue Value { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/ShowDocumentClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/ShowDocumentClientCapabilities.cs new file mode 100644 index 0000000000000..77e02ee12fb42 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ShowDocumentClientCapabilities.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Client capabilities for the 'window/showDocument' request +/// +/// +/// See the Language Server Protocol specification for additional information. +/// +/// Since LSP 3.16 +internal class ShowDocumentClientCapabilities +{ + /// + /// The client has support for the show document request. + /// + [JsonPropertyName("support")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool Support { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/ShowDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/ShowDocumentParams.cs new file mode 100644 index 0000000000000..4226d8fa8e1ce --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ShowDocumentParams.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Params for the 'windows/showDocument' request +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class ShowDocumentParams +{ + /// + /// The uri to show. + /// + [JsonPropertyName("uri")] + [JsonRequired] + public Uri Uri { get; init; } + + /// + /// Indicates whether to show the resource in an external program. + /// + /// To show, for example, https://code.visualstudio.com/ in the default + /// web browser, set to . + /// + /// + [JsonPropertyName("external")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool External { get; init; } + + /// + /// Optionally indicates whether the editor showing the document should take focus or not. + /// + /// Clients might ignore this property if an external program is started. + /// + /// + [JsonPropertyName("takeFocus")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool TakeFocus { get; init; } + + /// + /// An optional selection range if the document is a text document. + /// + /// Clients might ignore the property if an external program is started or the file is not a text file. + /// + /// + [JsonPropertyName("selection")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Range? Selection { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/ShowDocumentResult.cs b/src/LanguageServer/Protocol/Protocol/ShowDocumentResult.cs new file mode 100644 index 0000000000000..e124b3b254847 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ShowDocumentResult.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The result of a 'windows/showDocument' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class ShowDocumentResult +{ + /// + /// Indicates whether the show was successful. + /// + [JsonPropertyName("success")] + [JsonRequired] + public bool Success { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/ShowMessageParams.cs b/src/LanguageServer/Protocol/Protocol/ShowMessageParams.cs index b7da5703aedba..7eb8186802a75 100644 --- a/src/LanguageServer/Protocol/Protocol/ShowMessageParams.cs +++ b/src/LanguageServer/Protocol/Protocol/ShowMessageParams.cs @@ -7,9 +7,10 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class which represents parameter sent with window/showMessage requests. - /// + /// The parameters sent with window/showMessage requests. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class ShowMessageParams { @@ -17,6 +18,7 @@ internal class ShowMessageParams /// Gets or sets the type of message. /// [JsonPropertyName("type")] + [JsonRequired] public MessageType MessageType { get; @@ -27,6 +29,7 @@ public MessageType MessageType /// Gets or sets the message. /// [JsonPropertyName("message")] + [JsonRequired] public string Message { get; diff --git a/src/LanguageServer/Protocol/Protocol/ShowMessageRequestClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/ShowMessageRequestClientCapabilities.cs new file mode 100644 index 0000000000000..6b03b48c5f284 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/ShowMessageRequestClientCapabilities.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Capabilities specific to the 'window/showMessage' request +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.16 +internal class ShowMessageRequestClientCapabilities +{ + /// + /// Capabilities specific to the `MessageActionItem` type + /// + [JsonPropertyName("messageActionItem")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public MessageActionItemClientCapabilities? MessageActionItem { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/ShowMessageRequestParams.cs b/src/LanguageServer/Protocol/Protocol/ShowMessageRequestParams.cs index b8df89cb3f998..3d169d5e36eb4 100644 --- a/src/LanguageServer/Protocol/Protocol/ShowMessageRequestParams.cs +++ b/src/LanguageServer/Protocol/Protocol/ShowMessageRequestParams.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents parameter sent with window/showMessageRequest requests. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class ShowMessageRequestParams : ShowMessageParams { diff --git a/src/LanguageServer/Protocol/Protocol/SignatureHelp.cs b/src/LanguageServer/Protocol/Protocol/SignatureHelp.cs index fbc02b0b71901..892cfca3fa794 100644 --- a/src/LanguageServer/Protocol/Protocol/SignatureHelp.cs +++ b/src/LanguageServer/Protocol/Protocol/SignatureHelp.cs @@ -8,13 +8,18 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the signature of something callable. This class is returned from the textDocument/signatureHelp request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class SignatureHelp { /// - /// Gets or sets an array of signatures associated with the callable item. + /// One or more signatures. + /// + /// If no signatures are available the signature help + /// request should return . + /// /// [JsonPropertyName("signatures")] [JsonRequired] @@ -25,7 +30,19 @@ public SignatureInformation[] Signatures } /// - /// Gets or sets the active signature. If the value is omitted or falls outside the range of Signatures it defaults to zero. + /// The active signature. + /// + /// + /// If omitted or the value lies outside the range of the + /// value defaults to zero or is ignored if the has no signatures. + /// + /// Whenever possible implementors should make an active decision about + /// the active signature and shouldn't rely on a default value. + /// + /// + /// In a future version of the protocol this property might become + /// mandatory to better express this. + /// /// [JsonPropertyName("activeSignature")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -36,7 +53,17 @@ public int? ActiveSignature } /// - /// Gets or sets the active parameter. If the value is omitted or falls outside the range of Signatures[ActiveSignature].Parameters it defaults to zero. + /// The active parameter of the active signature. + /// + /// If omitted or the value lies outside the range of Signatures[ActiveSignature].Parameters + /// it defaults to 0 if the active signature has parameters. + /// If the active signature has no parameters it is ignored. + /// + /// + /// In a future version of the protocol this property might become + /// mandatory to better express the active parameter if the active + /// signature has any parameters. + /// /// [JsonPropertyName("activeParameter")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] diff --git a/src/LanguageServer/Protocol/Protocol/SignatureHelpContext.cs b/src/LanguageServer/Protocol/Protocol/SignatureHelpContext.cs index 7d3a42675c951..562dbb0fdcb11 100644 --- a/src/LanguageServer/Protocol/Protocol/SignatureHelpContext.cs +++ b/src/LanguageServer/Protocol/Protocol/SignatureHelpContext.cs @@ -8,9 +8,11 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing additional information about the context in which a signature help request is triggered. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.15 internal class SignatureHelpContext { /// @@ -25,7 +27,10 @@ public SignatureHelpTriggerKind TriggerKind /// /// Gets or sets the character that caused signature help to be triggered. - /// This value is null when triggerKind is not TriggerCharacter. + /// + /// This is defined when when is not + /// . + /// /// [JsonPropertyName("triggerCharacter")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -37,6 +42,11 @@ public string? TriggerCharacter /// /// Gets or sets a value indicating whether signature help was already showing when it was triggered. + /// + /// Retriggers occur when the signature help is already active and can be + /// caused by actions such as typing a trigger character, a cursor move, or + /// document content changes. + /// /// [JsonPropertyName("isRetrigger")] public bool IsRetrigger @@ -46,7 +56,11 @@ public bool IsRetrigger } /// - /// Gets or sets the currently active . + /// The currently active . + /// + /// The has its + /// updated based on the user navigating through available signatures. + /// /// [JsonPropertyName("activeSignatureHelp")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -56,4 +70,4 @@ public SignatureHelp? ActiveSignatureHelp set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/SignatureHelpOptions.cs b/src/LanguageServer/Protocol/Protocol/SignatureHelpOptions.cs index 102ef229035f9..ecc68b5ad15fd 100644 --- a/src/LanguageServer/Protocol/Protocol/SignatureHelpOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/SignatureHelpOptions.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the options for signature help support. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class SignatureHelpOptions : IWorkDoneProgressOptions { @@ -28,6 +29,7 @@ public string[]? TriggerCharacters /// Gets or sets the characters that re-trigger signature help /// when signature help is already showing. /// + /// Since LSP 3.15 [JsonPropertyName("retriggerCharacters")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string[]? RetriggerCharacters @@ -36,9 +38,7 @@ public string[]? RetriggerCharacters set; } - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// + /// [JsonPropertyName("workDoneProgress")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool WorkDoneProgress { get; init; } diff --git a/src/LanguageServer/Protocol/Protocol/SignatureHelpParams.cs b/src/LanguageServer/Protocol/Protocol/SignatureHelpParams.cs index 52fbd2f43e10a..f68a1c87c94d7 100644 --- a/src/LanguageServer/Protocol/Protocol/SignatureHelpParams.cs +++ b/src/LanguageServer/Protocol/Protocol/SignatureHelpParams.cs @@ -4,24 +4,31 @@ namespace Roslyn.LanguageServer.Protocol { + using System; using System.Text.Json.Serialization; /// /// Class representing the parameters for the textDocument/signatureHelp request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class SignatureHelpParams : TextDocumentPositionParams + internal class SignatureHelpParams : TextDocumentPositionParams, IWorkDoneProgressParams { /// - /// Gets or sets the signature help context. + /// The signature help context. + /// + /// This is only available if the client specifies the client + /// capability + /// /// [JsonPropertyName("context")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SignatureHelpContext? Context - { - get; - set; - } + public SignatureHelpContext? Context { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/SignatureHelpRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/SignatureHelpRegistrationOptions.cs new file mode 100644 index 0000000000000..31b9e4f7fd83d --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/SignatureHelpRegistrationOptions.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Subclass of that allows scoping the registration. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class SignatureHelpRegistrationOptions : SignatureHelpOptions, ITextDocumentRegistrationOptions +{ + /// + [JsonPropertyName("documentSelector")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentFilter[]? DocumentSelector { get; set; } +} diff --git a/src/LanguageServer/Protocol/Protocol/SignatureHelpSetting.cs b/src/LanguageServer/Protocol/Protocol/SignatureHelpSetting.cs index 447b91419344d..7aba3296d7859 100644 --- a/src/LanguageServer/Protocol/Protocol/SignatureHelpSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/SignatureHelpSetting.cs @@ -7,14 +7,15 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the signature help initialization setting. - /// + /// Client capabilities specific to the `textDocument/signatureHelp` request. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class SignatureHelpSetting : DynamicRegistrationSetting { /// - /// Gets or sets the information. + /// Client capabilities specific to . /// [JsonPropertyName("signatureInformation")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -25,9 +26,13 @@ public SignatureInformationSetting? SignatureInformation } /// - /// Gets or sets a value indicating whether additional context information - /// is supported for the `textDocument/signatureHelp` request. + /// The client supports sending additional context information for + /// the textDocument/signatureHelp request. + /// + /// A client that opts into this will also support . + /// /// + /// Since LSP 3.15 [JsonPropertyName("contextSupport")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool ContextSupport @@ -36,4 +41,4 @@ public bool ContextSupport set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/SignatureHelpTriggerKind.cs b/src/LanguageServer/Protocol/Protocol/SignatureHelpTriggerKind.cs index 00ba1f6410d50..d029c0e97c9a6 100644 --- a/src/LanguageServer/Protocol/Protocol/SignatureHelpTriggerKind.cs +++ b/src/LanguageServer/Protocol/Protocol/SignatureHelpTriggerKind.cs @@ -6,9 +6,11 @@ namespace Roslyn.LanguageServer.Protocol { /// /// Enum which represents the various ways in which completion can be triggered. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// + /// Since LSP 3.15 internal enum SignatureHelpTriggerKind { /// @@ -26,4 +28,4 @@ internal enum SignatureHelpTriggerKind /// ContentChange = 3, } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/SignatureInformation.cs b/src/LanguageServer/Protocol/Protocol/SignatureInformation.cs index 462bd9c6e2b4a..8efea2b31091d 100644 --- a/src/LanguageServer/Protocol/Protocol/SignatureInformation.cs +++ b/src/LanguageServer/Protocol/Protocol/SignatureInformation.cs @@ -8,13 +8,14 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing a single signature of a callable item. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class SignatureInformation { /// - /// Gets or sets the label of this signature. + /// The label of this signature. Will be shown in the UI. /// [JsonPropertyName("label")] public string Label @@ -24,7 +25,8 @@ public string Label } /// - /// Gets or sets the human-readable documentation of this signature. + /// The human-readable documentation of this signature. + /// Will be shown in the UI but can be omitted. /// [JsonPropertyName("documentation")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -44,5 +46,16 @@ public ParameterInformation[]? Parameters get; set; } + + /// + /// The index of the active parameter. + /// + /// If provided, this is used in place of . + /// + /// + /// Since LSP 3.16 + [JsonPropertyName("activeParameter")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? ActiveParameter { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/SignatureInformationSetting.cs b/src/LanguageServer/Protocol/Protocol/SignatureInformationSetting.cs index efb21c658a425..16017694639d7 100644 --- a/src/LanguageServer/Protocol/Protocol/SignatureInformationSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/SignatureInformationSetting.cs @@ -8,13 +8,15 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the signature information initialization setting. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class SignatureInformationSetting { /// - /// Gets or sets the set of documentation formats the client supports. + /// The client supports the following content formats for the + /// property. The order describes the preferred format of the client. /// [JsonPropertyName("documentationFormat")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -25,7 +27,7 @@ public MarkupKind[]? DocumentationFormat } /// - /// Gets or sets the parameter information the client supports. + /// Client capabilities specific to /// [JsonPropertyName("parameterInformation")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -34,5 +36,13 @@ public ParameterInformationSetting? ParameterInformation get; set; } + + /// + /// The client supports the property + /// + /// Since LSP 3.16 + [JsonPropertyName("activeParameterSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool ActiveParameterSupport { get; init; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/StaleRequestSupport.cs b/src/LanguageServer/Protocol/Protocol/StaleRequestSupport.cs new file mode 100644 index 0000000000000..70163d1c45787 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/StaleRequestSupport.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Describes how the client handles stale requests +/// +internal class StaleRequestSupport +{ + /// + /// The client will actively cancel the request. + /// + [JsonPropertyName("cancel")] + [JsonRequired] + public bool Cancel { get; init; } + + /// + /// The list of requests for which the client + /// will retry the request if it receives a + /// response with error code `ContentModified` + /// + [JsonPropertyName("retryOnContentModified")] + public string[] RetryOnContentModified { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/SumType.cs b/src/LanguageServer/Protocol/Protocol/SumType.cs index 6d656e070a348..ec6100881756d 100644 --- a/src/LanguageServer/Protocol/Protocol/SumType.cs +++ b/src/LanguageServer/Protocol/Protocol/SumType.cs @@ -7,6 +7,7 @@ namespace Roslyn.LanguageServer.Protocol using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; + using System.Linq; using System.Text.Json.Serialization; using Microsoft.CodeAnalysis.LanguageServer; @@ -883,5 +884,19 @@ public static void ValidateTypeParameter(Type type) throw new NotSupportedException(LanguageServerProtocolResources.NestedSumType); } } + + public static TCommon Unify(this SumType sumType) + where TCommon : notnull + where TDerived : notnull, TCommon + => sumType.Match(common => common, derived => derived); + + public static TCommon[] Unify(this SumType sumType) + where TDerived : TCommon + => sumType.Match(common => common, derived => Array.ConvertAll(derived, d => (TCommon)d)); + + public static Dictionary AsUntyped(this Dictionary dictionary) + where TKey : notnull + where TValue : notnull, ISumType + => dictionary.ToDictionary(kvp => kvp.Key, kvp => (object)kvp.Value); } } diff --git a/src/LanguageServer/Protocol/Protocol/SymbolInformation.cs b/src/LanguageServer/Protocol/Protocol/SymbolInformation.cs index c35871bdaef2b..c64a6bfdf6f1a 100644 --- a/src/LanguageServer/Protocol/Protocol/SymbolInformation.cs +++ b/src/LanguageServer/Protocol/Protocol/SymbolInformation.cs @@ -6,19 +6,30 @@ namespace Roslyn.LanguageServer.Protocol { using System; using System.Collections.Generic; + using System.Linq; using System.Text.Json.Serialization; + using Roslyn.Utilities; /// /// Class representing information about programming constructs like variables, classes, interfaces, etc. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class SymbolInformation : IEquatable { + + // Code has to reference SymbolInformation in a SumType even if it's not using the class itself. + // This means that if we deprecate the type itself, referencing code would have to suppress + // deprecation warnings even if they are only using non-deprecated types. We work around + // by deprecating the members instead of the type itself. + const string DeprecationMessage = "The SymbolInformation class is deprecated. Use DocumentSymbol or WorkspaceSymbol instead."; + /// /// Gets or sets the name of this symbol. /// [JsonPropertyName("name")] + [Obsolete(DeprecationMessage)] public string Name { get; @@ -29,6 +40,7 @@ public string Name /// Gets or sets the of this symbol. /// [JsonPropertyName("kind")] + [Obsolete(DeprecationMessage)] public SymbolKind Kind { get; @@ -36,9 +48,37 @@ public SymbolKind Kind } /// - /// Gets or sets the of this symbol. + /// Tags for this document symbol. + /// + /// Since 3.16 + [JsonPropertyName("tags")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [Obsolete(DeprecationMessage)] + public SymbolTag[]? Tags { get; init; } + + /// + /// Indicates whether this symbol is deprecated. + /// + [JsonPropertyName("deprecated")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + [Obsolete("Use the Tags property instead")] + public bool Deprecated { get; init; } + + /// + /// The location of this symbol, used by a tool to reveal the location in the editor. + /// + /// If the symbol is selected in the tool the range's start information is used to + /// position the cursor. So the range usually spans more then the actual symbol's + /// name and does normally include things like visibility modifiers. + /// + /// + /// The range doesn't have to denote a node range in the sense of an abstract + /// syntax tree. It can therefore not be used to re-construct a hierarchy of + /// the symbols. + /// /// [JsonPropertyName("location")] + [Obsolete(DeprecationMessage)] public Location Location { get; @@ -46,10 +86,16 @@ public Location Location } /// - /// Gets or sets the name of the symbol containing this symbol. + /// + /// The name of the symbol containing this symbol. + /// + /// This information is for user interface purposes (e.g. to render a qualifier in + /// the user interface if necessary). It can't be used to re-infer a hierarchy for + /// the document symbols. /// [JsonPropertyName("containerName")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [Obsolete(DeprecationMessage)] public string? ContainerName { get; @@ -65,22 +111,31 @@ public override bool Equals(object obj) /// public bool Equals(SymbolInformation? other) { - return other != null && - this.Name == other.Name && - this.Kind == other.Kind && - EqualityComparer.Default.Equals(this.Location, other.Location) && - this.ContainerName == other.ContainerName; +#pragma warning disable CS0618 // Type or member is obsolete + return other != null + && this.Name == other.Name + && this.Kind == other.Kind + && (this.Tags == null + ? other.Tags == null + : (this.Tags.Equals(other.Tags) || this.Tags.SequenceEqual(other.Tags))) + && this.Deprecated == other.Deprecated + && EqualityComparer.Default.Equals(this.Location, other.Location) + && this.ContainerName == other.ContainerName; +#pragma warning restore CS0618 } /// - public override int GetHashCode() - { - var hashCode = 1633890234; - hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(this.Name); - hashCode = (hashCode * -1521134295) + (int)this.Kind; - hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(this.Location); - hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(this.ContainerName); - return hashCode; - } + public override int GetHashCode() => +#pragma warning disable CS0618 // Type or member is obsolete +#if NET + HashCode.Combine(Name, Kind, Hash.CombineValues(Tags), Deprecated, Location, ContainerName); +#else + Hash.Combine(Name, + Hash.Combine((int)Kind, + Hash.Combine(Hash.CombineValues(Tags), + Hash.Combine(Deprecated, + Hash.Combine(ContainerName, Location?.GetHashCode() ?? 0))))); +#endif +#pragma warning restore CS0618 } } diff --git a/src/LanguageServer/Protocol/Protocol/SymbolKindSetting.cs b/src/LanguageServer/Protocol/Protocol/SymbolKindSetting.cs index 3b9f98a15aad2..a8b5a19aec5e9 100644 --- a/src/LanguageServer/Protocol/Protocol/SymbolKindSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/SymbolKindSetting.cs @@ -7,14 +7,21 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the symbol kind setting in initialization. - /// - /// See the Language Server Protocol specification for additional information. + /// Represents the values that the client supports. /// internal class SymbolKindSetting { /// - /// Gets or sets the types of symbol kind the client supports. + /// The symbol kind values the client supports. + /// + /// When this property exists the client also guarantees that it will handle values outside + /// its set gracefully and falls back to a default value when unknown. + /// + /// + /// If this property is not present the client only supports the symbol kinds + /// from to as + /// defined in the initial version of the protocol. + /// /// [JsonPropertyName("valueSet")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -24,4 +31,4 @@ public SymbolKind[]? ValueSet set; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/SymbolSetting.cs b/src/LanguageServer/Protocol/Protocol/SymbolSetting.cs index bad49978458a1..cdb73488d4e61 100644 --- a/src/LanguageServer/Protocol/Protocol/SymbolSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/SymbolSetting.cs @@ -7,14 +7,15 @@ namespace Roslyn.LanguageServer.Protocol using System.Text.Json.Serialization; /// - /// Class representing the symbol setting for initialization. - /// + /// Capabilities specific to the workspace/symbol request. + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class SymbolSetting : DynamicRegistrationSetting { /// - /// Gets or sets the information. + /// Specific capabilities for in workspace/symbol requests /// [JsonPropertyName("symbolKind")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -23,5 +24,25 @@ public SymbolKindSetting? SymbolKind get; set; } + /// + /// The client supports tags on and . + /// + /// Clients supporting tags have to handle unknown tags gracefully. + /// + /// + /// Since LSP 3.16 + [JsonPropertyName("tagSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SymbolTagSupport? TagSupport { get; init; } + + /// + /// The client support partial workspace symbols. The client will send the + /// request `workspaceSymbol/resolve` to the server to resolve additional + /// properties. + /// + /// Since LSP 3.17 + [JsonPropertyName("resolveSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public WorkspaceSymbolResolveSupport? ResolveSupport { get; init; } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/SymbolTag.cs b/src/LanguageServer/Protocol/Protocol/SymbolTag.cs new file mode 100644 index 0000000000000..d5299fca50ab2 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/SymbolTag.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. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Symbol tags are extra annotations that tweak the rendering of a symbol. +/// +/// Since LSP 3.16 +internal enum SymbolTag +{ + /// + /// Render a symbol as obsolete, usually using a strike-out. + /// + Deprecated = 1 +} diff --git a/src/LanguageServer/Protocol/Protocol/SymbolTagSupport.cs b/src/LanguageServer/Protocol/Protocol/SymbolTagSupport.cs new file mode 100644 index 0000000000000..cbce90915e312 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/SymbolTagSupport.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Describes the tags supported by the client on and . +/// +/// Since LSP 3.16 +internal class SymbolTagSupport +{ + /// + /// The tags supported by the client. + /// + [JsonPropertyName("valueSet")] + public SymbolTag[] ValueSet { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/SynchronizationSetting.cs b/src/LanguageServer/Protocol/Protocol/SynchronizationSetting.cs index 82e339cb5ea56..c8064d376dbf0 100644 --- a/src/LanguageServer/Protocol/Protocol/SynchronizationSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/SynchronizationSetting.cs @@ -8,13 +8,14 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents synchronization initialization setting. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class SynchronizationSetting : DynamicRegistrationSetting { /// - /// Gets or sets a value indicating whether WillSave event is supported. + /// Whether the client supports sending textDocument/willSave notifications. /// [JsonPropertyName("willSave")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -25,7 +26,9 @@ public bool WillSave } /// - /// Gets or sets a value indicating whether WillSaveWaitUntil event is supported. + /// Whether the client supports sending textDocument/willSaveWaitUntil + /// notifications and waits for a response providing text edits which will be + /// applied to the document before it is saved. /// [JsonPropertyName("willSaveWaitUntil")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -36,7 +39,7 @@ public bool WillSaveWaitUntil } /// - /// Gets or sets a value indicating whether DidSave event is supported. + /// Whether the client supports sending textDocument/didSave notifications. /// [JsonPropertyName("didSave")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] diff --git a/src/LanguageServer/Protocol/Protocol/TagSupport.cs b/src/LanguageServer/Protocol/Protocol/TagSupport.cs deleted file mode 100644 index 2f27a28e442e8..0000000000000 --- a/src/LanguageServer/Protocol/Protocol/TagSupport.cs +++ /dev/null @@ -1,26 +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 Roslyn.LanguageServer.Protocol -{ - using System.Text.Json.Serialization; - - /// - /// Class representing the capabilities. - /// - /// See the Language Server Protocol specification for additional information. - /// - internal class TagSupport - { - /// - /// Gets or sets a value indicating the tags supported by the client. - /// - [JsonPropertyName("valueSet")] - public DiagnosticTag[] ValueSet - { - get; - set; - } - } -} diff --git a/src/LanguageServer/Protocol/Protocol/TextDocumentChangeRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/TextDocumentChangeRegistrationOptions.cs index fa152aa3d8140..4f5fbeb6a45c7 100644 --- a/src/LanguageServer/Protocol/Protocol/TextDocumentChangeRegistrationOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/TextDocumentChangeRegistrationOptions.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol { /// /// Class representing the registration options for didChange events. - /// - /// See the Language Server Protocol specification for additional information. + /// + /// See the Language Server Protocol specification for additional information. + /// /// internal class TextDocumentChangeRegistrationOptions : TextDocumentRegistrationOptions { diff --git a/src/LanguageServer/Protocol/Protocol/TextDocumentClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/TextDocumentClientCapabilities.cs index ee1b4051ae3ea..efde53965ed6d 100644 --- a/src/LanguageServer/Protocol/Protocol/TextDocumentClientCapabilities.cs +++ b/src/LanguageServer/Protocol/Protocol/TextDocumentClientCapabilities.cs @@ -8,261 +8,236 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents text document capabilities. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class TextDocumentClientCapabilities { + // NOTE: these are kept in the same order as the spec to make them easier to update + /// /// Gets or sets the synchronization setting. /// [JsonPropertyName("synchronization")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SynchronizationSetting? Synchronization - { - get; - set; - } + public SynchronizationSetting? Synchronization { get; set; } /// - /// Gets or sets the completion setting. + /// Capabilities specific to the `textDocument/completion` request. /// [JsonPropertyName("completion")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public CompletionSetting? Completion - { - get; - set; - } + public CompletionSetting? Completion { get; set; } /// - /// Gets or sets the setting which determines if hover can be dynamically registered. + /// Capabilities specific to the `textDocument/hover` request /// [JsonPropertyName("hover")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public HoverSetting? Hover - { - get; - set; - } + public HoverSetting? Hover { get; set; } /// - /// Gets or sets the setting which determines if signature help can be dynamically registered. + /// Capabilities specific to the `textDocument/signatureHelp` request /// [JsonPropertyName("signatureHelp")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SignatureHelpSetting? SignatureHelp - { - get; - set; - } + public SignatureHelpSetting? SignatureHelp { get; set; } + + /// + /// Capabilities specific to the `textDocument/declaration` request + /// + /// Since LSP 3.14 + [JsonPropertyName("declaration")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DeclarationClientCapabilities? Declaration { get; init; } /// - /// Gets or sets the setting which determines if definition can be dynamically registered. + /// Capabilities specific to the `textDocument/definition` request /// [JsonPropertyName("definition")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? Definition - { - get; - set; - } + public DefinitionClientCapabilities? Definition { get; set; } /// - /// Gets or sets the settings which determines if type definition can be dynamically registered. + /// Capabilities specific to the `textDocument/typeDefinition` request. /// + /// Since LSP 3.6 [JsonPropertyName("typeDefinition")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? TypeDefinition - { - get; - set; - } + public TypeDefinitionClientCapabilities? TypeDefinition { get; set; } /// - /// Gets or sets the settings which determines if implementation can be dynamically registered. + /// Capabilities specific to the `textDocument/implementation` request. /// + /// Since LSP 3.6 [JsonPropertyName("implementation")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? Implementation - { - get; - set; - } + public ImplementationClientCapabilities? Implementation { get; set; } /// - /// Gets or sets the setting which determines if references can be dynamically registered. + /// Capabilities specific to the `textDocument/references` request. /// [JsonPropertyName("references")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? References - { - get; - set; - } + public ReferenceClientCapabilities? References { get; set; } /// - /// Gets or sets the setting which determines if document highlight can be dynamically registered. + /// Capabilities specific to the `textDocument/documentHighlight` request. /// [JsonPropertyName("documentHighlight")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? DocumentHighlight - { - get; - set; - } + public DocumentHighlightClientCapabilities? DocumentHighlight { get; set; } /// - /// Gets or sets the setting which determines if document symbol can be dynamically registered. + /// Capabilities specific to the `textDocument/documentSymbol` request. /// [JsonPropertyName("documentSymbol")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DocumentSymbolSetting? DocumentSymbol - { - get; - set; - } + public DocumentSymbolSetting? DocumentSymbol { get; set; } /// - /// Gets or sets the setting which determines if code action can be dynamically registered. + /// Capabilities specific to the `textDocument/codeAction` request. /// [JsonPropertyName("codeAction")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public CodeActionSetting? CodeAction - { - get; - set; - } + public CodeActionSetting? CodeAction { get; set; } /// - /// Gets or sets the setting which determines if code lens can be dynamically registered. + /// Capabilities specific to the `textDocument/codeLens` request. /// [JsonPropertyName("codeLens")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? CodeLens - { - get; - set; - } + public CodeLensClientCapabilities? CodeLens { get; set; } /// - /// Gets or sets the setting which determines if document link can be dynamically registered. + /// Capabilities specific to the `textDocument/documentLink` request. /// [JsonPropertyName("documentLink")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? DocumentLink - { - get; - set; - } + public DocumentLinkClientCapabilities? DocumentLink { get; set; } + + /// + /// Capabilities specific to the `textDocument/documentColor` and the `textDocument/colorPresentation` request. + /// + /// Since LSP 3.6 + [JsonPropertyName("colorProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DocumentColorClientCapabilities? ColorProvider { get; set; } /// - /// Gets or sets the setting which determines if formatting can be dynamically registered. + /// Capabilities specific to the `textDocument/formatting` request. /// [JsonPropertyName("formatting")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? Formatting - { - get; - set; - } + public DocumentFormattingClientCapabilities? Formatting { get; set; } /// - /// Gets or sets the setting which determines if range formatting can be dynamically registered. + /// Capabilities specific to the `textDocument/rangeFormatting` request. /// [JsonPropertyName("rangeFormatting")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? RangeFormatting - { - get; - set; - } + public RangeFormattingClientCapabilities? RangeFormatting { get; set; } /// - /// Gets or sets the setting which determines if on type formatting can be dynamically registered. + /// Capabilities specific to the `textDocument/onTypeFormatting` request. /// [JsonPropertyName("onTypeFormatting")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? OnTypeFormatting - { - get; - set; - } + public OnTypeFormattingClientCapabilities? OnTypeFormatting { get; set; } /// - /// Gets or sets the setting which determines if rename can be dynamically registered. + /// Capabilities specific to the `textDocument/rename` request. /// [JsonPropertyName("rename")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public RenameClientCapabilities? Rename - { - get; - set; - } + public RenameClientCapabilities? Rename { get; set; } /// - /// Gets or sets the setting publish diagnostics setting. + /// Capabilities specific to the `textDocument/publishDiagnostics` notification. /// [JsonPropertyName("publishDiagnostics")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public PublishDiagnosticsSetting? PublishDiagnostics - { - get; - set; - } + public PublishDiagnosticsSetting? PublishDiagnostics { get; set; } /// - /// Gets or sets the setting which determines how folding range is supported. + /// Capabilities specific to the `textDocument/foldingRange` request. /// + /// Since LSP 3.10 [JsonPropertyName("foldingRange")] - public FoldingRangeSetting? FoldingRange - { - get; - set; - } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public FoldingRangeSetting? FoldingRange { get; set; } + + /// + /// Capabilities specific to the `textDocument/selectionRange` request. + /// + /// Since LSP 3.15 + [JsonPropertyName("selectionRange")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SelectionRangeClientCapabilities? SelectionRange { get; set; } /// - /// Gets or sets the setting which determines if linked editing range can be dynamically registered. + /// Capabilities specific to the `textDocument/linkedEditingRange` request. /// + /// Since LSP 3.16 [JsonPropertyName("linkedEditingRange")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting LinkedEditingRange - { - get; - set; - } + public LinkedEditingRangeClientCapabilities LinkedEditingRange { get; set; } + + /// + /// Capabilities specific to the various call hierarchy requests. + /// + /// Since LSP 3.16 + [JsonPropertyName("callHierarchy")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public CallHierarchyClientCapabilities CallHierarchy { get; init; } /// - /// Gets or sets a setting indicating whether semantic tokens is supported. + /// Capabilities specific to the various semantic token requests. /// + /// Since LSP 3.16 [JsonPropertyName("semanticTokens")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SemanticTokensSetting? SemanticTokens - { - get; - set; - } + public SemanticTokensSetting? SemanticTokens { get; set; } /// - /// Gets or sets the setting which determines what support the client has for pull diagnostics. + /// Capabilities specific to the `textDocument/moniker` request. /// - [JsonPropertyName("diagnostic")] + /// Since LSP 3.16 + [JsonPropertyName("moniker")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public MonikerClientCapabilities? Moniker { get; set; } + + /// + /// Capabilities specific to the various type hierarchy requests. + /// + /// Since LSP 3.17 + [JsonPropertyName("typeHierarchy")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public TypeHierarchyClientCapabilities? TypeHierarchy { get; init; } + + /// + /// Capabilities specific to the `textDocument/inlineValue` request. + /// + /// Since LSP 3.17 + [JsonPropertyName("inlineValue")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DiagnosticSetting? Diagnostic - { - get; - set; - } + public InlineValueClientCapability? InlineValue { get; set; } /// - /// Gets or sets the setting which determines what support the client has for pull diagnostics. + /// Capabilities specific to the `textDocument/inlayHint` request. /// + /// Since LSP 3.17 [JsonPropertyName("inlayHint")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public InlayHintSetting? InlayHint - { - get; - set; - } + public InlayHintSetting? InlayHint { get; set; } + + /// + /// Capabilities specific to the diagnostic pull model. + /// + /// Since LSP 3.17 + [JsonPropertyName("diagnostic")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public DiagnosticSetting? Diagnostic { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/TextDocumentContentChangeEvent.cs b/src/LanguageServer/Protocol/Protocol/TextDocumentContentChangeEvent.cs index 64568623fe4dc..2db2a3afb7fd8 100644 --- a/src/LanguageServer/Protocol/Protocol/TextDocumentContentChangeEvent.cs +++ b/src/LanguageServer/Protocol/Protocol/TextDocumentContentChangeEvent.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which encapsulates a text document changed event. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class TextDocumentContentChangeEvent { diff --git a/src/LanguageServer/Protocol/Protocol/TextDocumentEdit.cs b/src/LanguageServer/Protocol/Protocol/TextDocumentEdit.cs index 26af2f8e87483..d2f1e706699da 100644 --- a/src/LanguageServer/Protocol/Protocol/TextDocumentEdit.cs +++ b/src/LanguageServer/Protocol/Protocol/TextDocumentEdit.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing a set of changes to a single text document. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class TextDocumentEdit { @@ -27,12 +28,14 @@ public OptionalVersionedTextDocumentIdentifier TextDocument /// /// Gets or sets the array of edits to be applied to the document. /// + /// + /// Use of is guarded by the capability . + /// + /// + /// Since LSP 3.16 + /// [JsonPropertyName("edits")] [JsonRequired] - public TextEdit[] Edits - { - get; - set; - } + public SumType[] Edits { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/TextDocumentSaveRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/TextDocumentSaveRegistrationOptions.cs new file mode 100644 index 0000000000000..18a4903a1944b --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/TextDocumentSaveRegistrationOptions.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Options when registering for document-specific 'textDocument/didSave' notifications +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class TextDocumentSaveRegistrationOptions : TextDocumentRegistrationOptions +{ + /// + /// The client is supposed to include the content on save. + /// + [JsonPropertyName("IncludeText")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool IncludeText { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/TraceValue.cs b/src/LanguageServer/Protocol/Protocol/TraceValue.cs new file mode 100644 index 0000000000000..6951508b62953 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/TraceValue.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.ComponentModel; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A TraceValue represents the level of verbosity with which the server systematically reports its +/// execution trace using . The initial trace value is set by the +/// client at initialization and can be modified later using the notification. +/// +/// See the Language Server Protocol specification for additional information. +/// +[JsonConverter(typeof(StringEnumConverter))] +[TypeConverter(typeof(StringEnumConverter.TypeConverter))] +internal readonly record struct TraceValue(string Value) : IStringEnum +{ + public static readonly TraceValue Off = new("off"); + public static readonly TraceValue Messages = new("messages"); + public static readonly TraceValue Verbose = new("verbose"); +} diff --git a/src/LanguageServer/Protocol/Protocol/TypeDefinitionOptions.cs b/src/LanguageServer/Protocol/Protocol/TypeDefinitionOptions.cs deleted file mode 100644 index b17c3bec86600..0000000000000 --- a/src/LanguageServer/Protocol/Protocol/TypeDefinitionOptions.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. - -namespace Roslyn.LanguageServer.Protocol -{ - using System.Text.Json.Serialization; - - /// - /// Class which represents workspace symbols capabilities. - /// - /// See the Language Server Protocol specification for additional information. - /// - internal class TypeDefinitionOptions : IWorkDoneProgressOptions - { - /// - /// Gets or sets a value indicating whether work done progress is supported. - /// - [JsonPropertyName("workDoneProgress")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool WorkDoneProgress { get; init; } - } -} diff --git a/src/LanguageServer/Protocol/Protocol/UnchangedDocumentDiagnosticReport.cs b/src/LanguageServer/Protocol/Protocol/UnchangedDocumentDiagnosticReport.cs index 238da08d40af5..3457581ccbc33 100644 --- a/src/LanguageServer/Protocol/Protocol/UnchangedDocumentDiagnosticReport.cs +++ b/src/LanguageServer/Protocol/Protocol/UnchangedDocumentDiagnosticReport.cs @@ -7,10 +7,13 @@ namespace Roslyn.LanguageServer.Protocol; using System.Text.Json.Serialization; /// -/// Class representing a diagnostic report indicating that the last returned report is still accurate. -/// -/// See the Language Server Protocol specification for additional information. +/// A diagnostic report indicating that the last returned report is still accurate. +/// A server can only return this if result ids are provided. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 [Kind(DocumentDiagnosticReportKind.Unchanged)] internal class UnchangedDocumentDiagnosticReport { @@ -23,9 +26,11 @@ internal class UnchangedDocumentDiagnosticReport #pragma warning restore CA1822 // Mark members as static /// - /// Gets or sets the optional result id. + /// A result id which will be sent on the next + /// diagnostic request for the same document. /// [JsonPropertyName("resultId")] + [JsonRequired] public string ResultId { get; diff --git a/src/LanguageServer/Protocol/Protocol/Unregistration.cs b/src/LanguageServer/Protocol/Protocol/Unregistration.cs index ea2c9e8efbea3..9e0b337de4a22 100644 --- a/src/LanguageServer/Protocol/Protocol/Unregistration.cs +++ b/src/LanguageServer/Protocol/Protocol/Unregistration.cs @@ -17,6 +17,7 @@ internal class Unregistration /// Gets or sets the id of the unregistration. /// [JsonPropertyName("id")] + [JsonRequired] public string Id { get; @@ -27,6 +28,7 @@ public string Id /// Gets or sets the method to unregister. /// [JsonPropertyName("method")] + [JsonRequired] public string Method { get; diff --git a/src/LanguageServer/Protocol/Protocol/UnregistrationParams.cs b/src/LanguageServer/Protocol/Protocol/UnregistrationParams.cs index 118084c82212d..ca7108dee7b93 100644 --- a/src/LanguageServer/Protocol/Protocol/UnregistrationParams.cs +++ b/src/LanguageServer/Protocol/Protocol/UnregistrationParams.cs @@ -16,7 +16,9 @@ internal class UnregistrationParams /// /// Gets or sets the capabilities to unregister. /// - [JsonPropertyName("unregistrations")] + // NOTE: the 'unregisterations' typo is noted in the spec but cannot be changed until LSP 4.x for compat reasons + [JsonPropertyName("unregisterations")] + [JsonRequired] public Unregistration[] Unregistrations { get; diff --git a/src/LanguageServer/Protocol/Protocol/WillSaveTextDocumentParams.cs b/src/LanguageServer/Protocol/Protocol/WillSaveTextDocumentParams.cs index 46269ba196183..ba127c758fc73 100644 --- a/src/LanguageServer/Protocol/Protocol/WillSaveTextDocumentParams.cs +++ b/src/LanguageServer/Protocol/Protocol/WillSaveTextDocumentParams.cs @@ -8,8 +8,9 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing the parameters sent for the textDocument/willSave request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class WillSaveTextDocumentParams : ITextDocumentParams { @@ -17,6 +18,7 @@ internal class WillSaveTextDocumentParams : ITextDocumentParams /// Gets or sets the representing the document to be saved. /// [JsonPropertyName("textDocument")] + [JsonRequired] public TextDocumentIdentifier TextDocument { get; @@ -27,6 +29,7 @@ public TextDocumentIdentifier TextDocument /// Gets or sets the reason that the text document was saved. /// [JsonPropertyName("reason")] + [JsonRequired] public TextDocumentSaveReason Reason { get; diff --git a/src/LanguageServer/Protocol/Protocol/WindowClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/WindowClientCapabilities.cs new file mode 100644 index 0000000000000..d20a7703ba35c --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WindowClientCapabilities.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Notebook specific client capabilities +/// +/// Since LSP 3.15 +internal class WindowClientCapabilities : IWorkDoneProgressOptions +{ + /// + /// Indicates whether the client supports server initiated + /// progress using the `window/workDoneProgress/create` request. + /// + /// The capability also controls Whether client supports handling + /// of progress notifications. If set, servers are allowed to report a + /// `workDoneProgress` property in the request specific server + /// capabilities. + /// + /// + /// Since LSP 3.15 + [JsonPropertyName("workDoneProgress")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkDoneProgress { get; init; } + + /// + /// The client supports sending execution summary data per cell. + /// + /// Since LSP 3.16 + [JsonPropertyName("showMessage")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ShowMessageRequestClientCapabilities? ShowMessage { get; init; } + + /// + /// Client capabilities for the show document request. + /// + /// Since LSP 3.16 + [JsonPropertyName("showDocument")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public ShowDocumentClientCapabilities? ShowDocument { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkDoneProgress.cs b/src/LanguageServer/Protocol/Protocol/WorkDoneProgress.cs new file mode 100644 index 0000000000000..7b4cfb2672a1f --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkDoneProgress.cs @@ -0,0 +1,22 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// An IProgress<WorkDoneProgress> is used to report progress to the server via the $/progress notification. +/// +/// The derived classes , and +/// are used to report the beginning, progression, and end of the operation. +/// +/// +[JsonDerivedType(typeof(WorkDoneProgressBegin), "begin")] +[JsonDerivedType(typeof(WorkDoneProgressReport), "report")] +[JsonDerivedType(typeof(WorkDoneProgressEnd), "end")] +[JsonPolymorphic(TypeDiscriminatorPropertyName = "kind")] +internal abstract class WorkDoneProgress +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkDoneProgressBegin.cs b/src/LanguageServer/Protocol/Protocol/WorkDoneProgressBegin.cs new file mode 100644 index 0000000000000..9d2ed3d1b50e1 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkDoneProgressBegin.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Used to report the beginning of an operation to an IProgress<WorkDoneProgress>. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.15 +internal sealed class WorkDoneProgressBegin : WorkDoneProgress +{ + // NOTE: the kind property from the spec is used as a JsonPolymorphic discriminator on the base type + + /// + /// Title of the progress operation. Used to briefly inform about the kind of operation being performed. + /// Examples: "Indexing" or "Linking dependencies". + /// + [JsonPropertyName("title")] + [JsonRequired] + public string Title { get; init; } + + /// + /// Controls if a cancel button should show to allow the user to cancel the + /// long running operation. Clients that don't support cancellation are + /// allowed to ignore the setting. + /// + [JsonPropertyName("cancellable")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? Cancellable { get; init; } + + /// + /// Optional, more detailed associated progress message. Contains + /// complementary information to the `title`. + /// + /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + /// + [JsonPropertyName("message")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Message { get; init; } + + /// + /// Optional progress percentage to display (value 100 is considered 100%). + /// If not provided infinite progress is assumed and clients are allowed + /// to ignore the `percentage` value in subsequent in report notifications. + /// + /// The value should be steadily rising. Clients are free to ignore values + /// that are not following this rule. The value range is [0, 100] + /// + [JsonPropertyName("percentage")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? Percentage { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkDoneProgressCancelParams.cs b/src/LanguageServer/Protocol/Protocol/WorkDoneProgressCancelParams.cs new file mode 100644 index 0000000000000..2a88fabd1ad35 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkDoneProgressCancelParams.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The parameters sent with the 'window/workDoneProgress/cancel' notification. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.15 +internal class WorkDoneProgressCancelParams +{ + /// + /// The token used to report progress. + /// + [JsonPropertyName("token")] + [JsonRequired] + public SumType Token { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkDoneProgressCreateParams.cs b/src/LanguageServer/Protocol/Protocol/WorkDoneProgressCreateParams.cs new file mode 100644 index 0000000000000..fc07545043836 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkDoneProgressCreateParams.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// The parameters sent with the 'window/workDoneProgress/create' request. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.15 +internal class WorkDoneProgressCreateParams +{ + /// + /// The token to be used to report progress. + /// + [JsonPropertyName("token")] + [JsonRequired] + public SumType Token { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkDoneProgressEnd.cs b/src/LanguageServer/Protocol/Protocol/WorkDoneProgressEnd.cs new file mode 100644 index 0000000000000..4190436880f97 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkDoneProgressEnd.cs @@ -0,0 +1,26 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Used to report the end of an operation to an IProgress<WorkDoneProgress>. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.15 +internal class WorkDoneProgressEnd : WorkDoneProgress +{ + // NOTE: the kind property from the spec is used as a JsonPolymorphic discriminator on the base type + + /// + /// Optional final message indicating for example the outcome of the operation. + /// + [JsonPropertyName("message")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Message { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkDoneProgressReport.cs b/src/LanguageServer/Protocol/Protocol/WorkDoneProgressReport.cs new file mode 100644 index 0000000000000..7c00ddfe0f0b0 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkDoneProgressReport.cs @@ -0,0 +1,53 @@ +// 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 Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Used to report progress of an operation to an IProgress<WorkDoneProgress>. +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.15 +internal sealed class WorkDoneProgressReport : WorkDoneProgress +{ + // NOTE: the kind property from the spec is used as a JsonPolymorphic discriminator on the base type + + /// + /// Controls enablement state of a cancel button. This property is only valid + /// if a cancel button got requested in the payload. + /// Clients that don't support cancellation or don't support control the + /// button's enablement state are allowed to ignore the setting. + /// + [JsonPropertyName("cancellable")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? Cancellable { get; init; } + + /// + /// Optional, more detailed associated progress message. Contains + /// complementary information to the `title`. + /// + /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + /// + /// If unset, the previous progress message (if any) is still valid. + /// + [JsonPropertyName("message")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? Message { get; init; } + + /// + /// Optional progress percentage to display (value 100 is considered 100%). + /// If not provided infinite progress is assumed and clients are allowed + /// to ignore the `percentage` value in subsequent in report notifications. + /// + /// The value should be steadily rising. Clients are free to ignore values + /// that are not following this rule. The value range is [0, 100] + /// + [JsonPropertyName("percentage")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? Percentage { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceClientCapabilities.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceClientCapabilities.cs index a045161ec3973..1a10d7aea454b 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceClientCapabilities.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceClientCapabilities.cs @@ -8,130 +8,118 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents workspace capabilities. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class WorkspaceClientCapabilities { + // NOTE: these are kept in the same order as the spec to make them easier to update + /// - /// Gets or sets a value indicating whether apply edit is supported. + /// Whether the client supports applying batch edits to the workspace by supporting the request 'workspace/applyEdit' /// [JsonPropertyName("applyEdit")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool ApplyEdit - { - get; - set; - } + public bool ApplyEdit { get; set; } /// - /// Gets or sets the workspace edit setting. + /// Capabilities specific to /// [JsonPropertyName("workspaceEdit")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public WorkspaceEditSetting? WorkspaceEdit - { - get; - set; - } + public WorkspaceEditSetting? WorkspaceEdit { get; set; } /// - /// Gets or sets the setting which determines if did change configuration can be dynamically registered. + /// Capabilities specific to the `workspace/didChangeConfiguration` notification. /// [JsonPropertyName("didChangeConfiguration")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? DidChangeConfiguration - { - get; - set; - } + public DidChangeConfigurationClientCapabilities? DidChangeConfiguration { get; set; } /// - /// Gets or sets the setting which determines if did change watched files can be dynamically registered. + /// Capabilities specific to the `workspace/didChangeWatchedFiles` notification. /// [JsonPropertyName("didChangeWatchedFiles")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? DidChangeWatchedFiles - { - get; - set; - } + public DidChangeWatchedFilesClientCapabilities? DidChangeWatchedFiles { get; set; } /// - /// Gets or sets the setting which determines if symbols can be dynamically registered. + /// Capabilities specific to the `workspace/symbol` request. /// [JsonPropertyName("symbol")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SymbolSetting? Symbol - { - get; - set; - } + public SymbolSetting? Symbol { get; set; } /// - /// Gets or sets the setting which determines if execute command can be dynamically registered. + /// Capabilities specific to the `workspace/executeCommand` request. /// [JsonPropertyName("executeCommand")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DynamicRegistrationSetting? ExecuteCommand - { - get; - set; - } + public ExecuteCommandClientCapabilities? ExecuteCommand { get; set; } + + /// + /// The client has support for workspace folders. + /// + /// Since LSP 3.6 + [JsonPropertyName("workspaceFolders")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool WorkspaceFolders { get; init; } + + /// + /// The client supports `workspace/configuration` requests. + /// + /// Since LSP 3.6 + [JsonPropertyName("configuration")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool Configuration { get; set; } /// - /// Gets or sets capabilities specific to the semantic token requests scoped to the workspace. + /// Capabilities specific to the semantic token requests scoped to the workspace. /// + /// Since LSP 3.16 [JsonPropertyName("semanticTokens")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SemanticTokensWorkspaceSetting? SemanticTokens - { - get; - set; - } + public SemanticTokensWorkspaceSetting? SemanticTokens { get; set; } /// - /// Gets or sets capabilities indicating what support the client has for workspace pull diagnostics. + /// Capabilities specific to the code lens requests scoped to the workspace. /// - [JsonPropertyName("diagnostics")] + /// Since LSP 3.16 + [JsonPropertyName("codeLens")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DiagnosticWorkspaceSetting? Diagnostics - { - get; - set; - } + public CodeLensWorkspaceSetting? CodeLens { get; set; } /// - /// Gets or sets the capabilities if client support 'workspace/configuration' requests. + /// The client's capabilities for file requests/notifications. /// - [JsonPropertyName("configuration")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public bool Configuration - { - get; - set; - } + /// Since LSP 3.16 + [JsonPropertyName("fileOperations")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public FileOperationsWorkspaceClientCapabilities? FileOperations { get; init; } + + /// + /// Client workspace capabilities specific to inline values. + /// + /// Since LSP 3.17 + [JsonPropertyName("inlineValue")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public InlineValueWorkspaceClientCapabilities? InlineValue { get; init; } /// /// Gets of sets capabilities specific to the inlay hint requests scoped to the workspace. /// + /// Since LSP 3.17 [JsonPropertyName("inlayHint")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public InlayHintWorkspaceSetting? InlayHint - { - get; - set; - } + public InlayHintWorkspaceSetting? InlayHint { get; set; } /// - /// Gets of sets capabilities specific to the code lens requests scoped to the workspace. + /// Gets or sets capabilities indicating what support the client has for workspace pull diagnostics. /// - [JsonPropertyName("codeLens")] + /// Since LSP 3.17 + [JsonPropertyName("diagnostics")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public CodeLensWorkspaceSetting? CodeLens - { - get; - set; - } + public DiagnosticWorkspaceSetting? Diagnostics { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticParams.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticParams.cs index 850f8c4fa31ab..1dd136bc0148f 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticParams.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticParams.cs @@ -8,29 +8,35 @@ namespace Roslyn.LanguageServer.Protocol; using System.Text.Json.Serialization; /// -/// Class representing the workspace diagnostic request parameters -/// -/// See the Language Server Protocol specification for additional information. +/// Parameters of the 'workspace/diagnostic' request +/// +/// See the Language Server Protocol specification for additional information. +/// /// /// -/// Note that the first literal send needs to be a -/// followed by n literals. +/// Since LSP 3.17 /// -internal class WorkspaceDiagnosticParams : IPartialResultParams> +internal class WorkspaceDiagnosticParams : IWorkDoneProgressParams, IPartialResultParams> { /// - /// Gets or sets the value of the Progress instance. + /// An instance that can be used to report partial results + /// via the $/progress notification. + /// + /// Note that the first literal sent needs to be a + /// followed by n literals. + /// /// [JsonPropertyName(Methods.PartialResultTokenName)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public IProgress>? PartialResultToken - { - get; - set; - } + public IProgress>? PartialResultToken { get; set; } + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } /// - /// Gets or sets the identifier for which the client is requesting diagnostics for. + /// The additional identifier provided during registration. /// [JsonPropertyName("identifier")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -41,7 +47,7 @@ public string? Identifier } /// - /// Gets or sets the result id of a previous diagnostics response if provided. + /// The currently known diagnostic reports with their previous result ids. /// [JsonPropertyName("previousResultIds")] public PreviousResultId[] PreviousResultId @@ -49,4 +55,4 @@ public PreviousResultId[] PreviousResultId get; set; } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticReport.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticReport.cs index 49b33e63f135a..189a27aa11f8f 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticReport.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticReport.cs @@ -7,18 +7,21 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Class representing a workspace diagnostic report. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 internal class WorkspaceDiagnosticReport { /// /// Gets or sets the items in this diagnostic report. /// [JsonPropertyName("items")] + [JsonRequired] public SumType[] Items { get; set; } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticReportPartialResult.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticReportPartialResult.cs index 1c29c40074e81..ba3a7d8be4262 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticReportPartialResult.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceDiagnosticReportPartialResult.cs @@ -7,18 +7,21 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Class representing a partial result for a workspace diagnostic report. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 internal class WorkspaceDiagnosticReportPartialResult { /// /// Gets or sets the items in this diagnostic report. /// [JsonPropertyName("items")] + [JsonRequired] public SumType[] Items { get; set; } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceEdit.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceEdit.cs index d3739a5a90425..038937f3b8302 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceEdit.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceEdit.cs @@ -9,31 +9,48 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class representing a request sent from a language server to modify resources in the workspace. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class WorkspaceEdit { /// - /// Gets or sets a dictionary holding changes to existing resources. + /// Holds changes to existing resources. /// [JsonPropertyName("changes")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public Dictionary? Changes - { - get; - set; - } + public Dictionary? Changes { get; set; } /// - /// Gets or sets an array representing versioned document changes. + /// Depending on the client capability , + /// document changes are either an array of to express changes + /// to n different text documents where each text document edit addresses a specific version of a text document, + /// or it can contain above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. + /// + /// Whether a client supports versioned document edits is expressed via the + /// client capability. + /// + /// + /// If a client neither supports nor + /// then only plain s + /// using the property are supported. + /// /// [JsonPropertyName("documentChanges")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public SumType[]>? DocumentChanges - { - get; - set; - } + public SumType[]>? DocumentChanges { get; set; } + + /// + /// A map of change annotations that can be referenced in s or create, rename + /// and delete file / folder operations. + /// + /// + /// Whether clients honor this property depends on the client capability . + /// + /// Since 3.16 + [JsonPropertyName("changeAnnotations")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Dictionary? ChangeAnnotations { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceEditSetting.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceEditSetting.cs index c3aee573bdf8f..9926fbaf0642e 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceEditSetting.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceEditSetting.cs @@ -8,13 +8,14 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents initialization settings for workspace edit. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class WorkspaceEditSetting { /// - /// Gets or sets a value indicating whether document changes event is supported. + /// Whether the client supports versioned document changes in /// [JsonPropertyName("documentChanges")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -25,8 +26,9 @@ public bool DocumentChanges } /// - /// GEts or sets the resource operations the client supports. + /// The resource operations the client supports. /// + /// Since LSP 3.13 [JsonPropertyName("resourceOperations")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public ResourceOperationKind[]? ResourceOperations @@ -34,5 +36,31 @@ public ResourceOperationKind[]? ResourceOperations get; set; } + + /// + /// The client's failure handling strategy when applying workspace changes. + /// + /// Since LSP 3.13 + [JsonPropertyName("failureHandling")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public FailureHandlingKind? FailureHandling { get; init; } + + /// + /// Whether the client normalizes line endings to the client specific setting + /// when applying workspace changes. + /// + /// Since LSP 3.16 + [JsonPropertyName("normalizesLineEndings")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public bool? NormalizesLineEndings { get; init; } + + /// + /// Whether the client supports change annotations on workspace edits, and + /// information about how it handles them. + /// + /// Since LSP 3.16 + [JsonPropertyName("changeAnnotationSupport")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ChangeAnnotationSupport? ChangeAnnotationSupport { get; init; } } } diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceFolder.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceFolder.cs new file mode 100644 index 0000000000000..baa62b41407f1 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceFolder.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// Describes a workspace folder +/// Since LSP 3.6 +internal class WorkspaceFolder +{ + /// + /// The URI for this workspace folder. + /// + [JsonPropertyName("uri")] + [JsonConverter(typeof(DocumentUriConverter))] + [JsonRequired] + public Uri Uri { get; init; } + + /// + /// The name of the workspace folder used in the UI. + /// + [JsonPropertyName("name")] + [JsonRequired] + public string Name { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceFullDocumentDiagnosticReport.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceFullDocumentDiagnosticReport.cs index 95ec1cad08b96..a034368bf8bda 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceFullDocumentDiagnosticReport.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceFullDocumentDiagnosticReport.cs @@ -9,9 +9,11 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Class representing a full document diagnostic report for workspace diagnostic result. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 [Kind(DocumentDiagnosticReportKind.Full)] internal class WorkspaceFullDocumentDiagnosticReport : FullDocumentDiagnosticReport { @@ -19,6 +21,7 @@ internal class WorkspaceFullDocumentDiagnosticReport : FullDocumentDiagnosticRep /// Gets or sets the URI associated with this diagnostic report. /// [JsonPropertyName("uri")] + [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] public Uri Uri { @@ -31,6 +34,7 @@ public Uri Uri /// If the document is not marked as open 'null' can be provided. /// [JsonPropertyName("version")] + [JsonRequired] public int? Version { get; diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceServerCapabilities.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceServerCapabilities.cs new file mode 100644 index 0000000000000..94389e05a265e --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceServerCapabilities.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Workspace specific server capabilities. +/// +internal class WorkspaceServerCapabilities +{ + /// + /// The server supports workspace folder. + /// + /// Since LSP 3.6 + [JsonPropertyName("workspaceFolders")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public WorkspaceFoldersServerCapabilities? WorkspaceFolders { get; init; } + + /// + /// The server is interested in file notifications/requests. + /// + /// Since LSP 3.16 + [JsonPropertyName("fileOperations")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public WorkspaceFileOperationsServerCapabilities? FileOperations { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceSymbol.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbol.cs new file mode 100644 index 0000000000000..6cd2de0a10e39 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbol.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.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A special workspace symbol that supports locations without a range +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +/// Since LSP 3.17 +internal class WorkspaceSymbol +{ + /// + /// The name of this symbol. + /// + [JsonPropertyName("name")] + [JsonRequired] + public string Name { get; init; } + + /// + /// The kind of the symbol + /// + [JsonPropertyName("kind")] + [JsonRequired] + public SymbolKind Kind { get; init; } + + /// + /// Tags for this symbol. + /// + [JsonPropertyName("tags")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public SymbolTag? Tags { get; init; } + + /// + /// The name of the symbol containing this symbol. This information is for + /// user interface purposes (e.g. to render a qualifier in the user interface + /// if necessary). It can't be used to re-infer a hierarchy for the document + /// symbols. + /// + [JsonPropertyName("containerName")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? ContainerName { get; init; } + + /// + /// The location of this symbol. Whether a server is allowed to + /// return a location without a range depends on the client + /// workspace capability + /// + /// + [JsonPropertyName("location")] + [JsonRequired] + public SumType Location { get; init; } + + /// + /// Data field that is preserved on a workspace symbol between a + /// workspace symbol request and a workspace symbol resolve request. + /// + [JsonPropertyName("data")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public object? Data { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolLocation.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolLocation.cs new file mode 100644 index 0000000000000..6719e157caac2 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolLocation.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text.Json.Serialization; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// A workspace symbol location without a range +/// +internal class WorkspaceSymbolLocation +{ + [JsonPropertyName("uri")] + [JsonRequired] + [JsonConverter(typeof(DocumentUriConverter))] + public Uri Uri { get; init; } +} + diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolOptions.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolOptions.cs index 01ac93b66f538..8b3b362d3add8 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolOptions.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolOptions.cs @@ -8,14 +8,22 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents workspace symbols capabilities. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// internal class WorkspaceSymbolOptions : IWorkDoneProgressOptions { /// - /// Gets or sets a value indicating whether work done progress is supported. + /// The server provides support to resolve additional + /// information for a workspace symbol. /// + /// Since LSP 3.17 + [JsonPropertyName("resolveProvider")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool ResolveProvider { get; init; } + + /// [JsonPropertyName("workDoneProgress")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public bool WorkDoneProgress { get; init; } diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolParams.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolParams.cs index bc70cf64c559a..aa00f30785f83 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolParams.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolParams.cs @@ -9,30 +9,32 @@ namespace Roslyn.LanguageServer.Protocol /// /// Class which represents the parameter that's sent with the 'workspace/symbol' request. - /// + /// /// See the Language Server Protocol specification for additional information. + /// /// - internal class WorkspaceSymbolParams : IPartialResultParams + internal class WorkspaceSymbolParams +#pragma warning disable CS0618 // SymbolInformation is obsolete but this class is not + : IPartialResultParams>, IWorkDoneProgressParams +#pragma warning restore CS0618 { /// /// Gets or sets the query (a non-empty string). /// [JsonPropertyName("query")] - public string Query - { - get; - set; - } + [JsonRequired] + public string Query { get; set; } - /// - /// Gets or sets the value of the Progress instance. - /// + /// [JsonPropertyName(Methods.PartialResultTokenName)] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public IProgress? PartialResultToken - { - get; - set; - } +#pragma warning disable CS0618 // SymbolInformation is obsolete but this property is not + public IProgress>? PartialResultToken { get; set; } +#pragma warning restore CS0618 + + /// + [JsonPropertyName(Methods.WorkDoneTokenName)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IProgress? WorkDoneToken { get; set; } } } diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolRegistrationOptions.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolRegistrationOptions.cs new file mode 100644 index 0000000000000..a3798075060a4 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolRegistrationOptions.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Registration options for +/// +/// See the Language Server Protocol specification for additional information. +/// +/// +internal class WorkspaceSymbolRegistrationOptions : WorkspaceSymbolOptions +{ +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolResolveSupport.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolResolveSupport.cs new file mode 100644 index 0000000000000..696e780cbf395 --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolResolveSupport.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. + +namespace Roslyn.LanguageServer.Protocol; + +using System.Text.Json.Serialization; + +/// +/// Describes the client's support for partial workspace symbols +/// +/// Since LSP 3.17 +internal class WorkspaceSymbolResolveSupport +{ + /// + /// The properties that a client can resolve lazily. Usually `location.range` + /// + [JsonPropertyName("properties")] + [JsonRequired] + public string[] Properties { get; init; } +} diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceUnchangedDocumentDiagnosticReport.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceUnchangedDocumentDiagnosticReport.cs index 1fc1bd8cda697..84316ebaacbfa 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceUnchangedDocumentDiagnosticReport.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceUnchangedDocumentDiagnosticReport.cs @@ -9,9 +9,11 @@ namespace Roslyn.LanguageServer.Protocol; /// /// Class representing a unchanged document diagnostic report for workspace diagnostic result. -/// -/// See the Language Server Protocol specification for additional information. +/// +/// See the Language Server Protocol specification for additional information. +/// /// +/// Since LSP 3.17 [Kind(DocumentDiagnosticReportKind.Unchanged)] internal class WorkspaceUnchangedDocumentDiagnosticReport : UnchangedDocumentDiagnosticReport { @@ -19,6 +21,7 @@ internal class WorkspaceUnchangedDocumentDiagnosticReport : UnchangedDocumentDia /// Gets or sets the URI associated with this diagnostic report. /// [JsonPropertyName("uri")] + [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] public Uri Uri { @@ -31,6 +34,7 @@ public Uri Uri /// If the document is not marked as open 'null' can be provided. /// [JsonPropertyName("version")] + [JsonRequired] public int? Version { get; diff --git a/src/LanguageServer/Protocol/RequestExecutionQueueProvider.cs b/src/LanguageServer/Protocol/RequestExecutionQueueProvider.cs index a0d3526307fce..66bbad16e4f66 100644 --- a/src/LanguageServer/Protocol/RequestExecutionQueueProvider.cs +++ b/src/LanguageServer/Protocol/RequestExecutionQueueProvider.cs @@ -6,22 +6,19 @@ using System.Composition; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CommonLanguageServerProtocol.Framework; namespace Microsoft.CodeAnalysis.LanguageServer; [ExportCSharpVisualBasicStatelessLspService(typeof(IRequestExecutionQueueProvider)), Shared] -internal sealed class RequestExecutionQueueProvider : IRequestExecutionQueueProvider +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, true)] +internal sealed class RequestExecutionQueueProvider(IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider) : IRequestExecutionQueueProvider { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, true)] - public RequestExecutionQueueProvider() - { - } - public IRequestExecutionQueue CreateRequestExecutionQueue(AbstractLanguageServer languageServer, ILspLogger logger, AbstractHandlerProvider handlerProvider) { - var queue = new RoslynRequestExecutionQueue(languageServer, logger, handlerProvider); + var queue = new RoslynRequestExecutionQueue(languageServer, logger, handlerProvider, asynchronousOperationListenerProvider); queue.Start(); return queue; } diff --git a/src/LanguageServer/Protocol/RoslynLanguageServer.cs b/src/LanguageServer/Protocol/RoslynLanguageServer.cs index 6aa1623551766..37c845e4e7578 100644 --- a/src/LanguageServer/Protocol/RoslynLanguageServer.cs +++ b/src/LanguageServer/Protocol/RoslynLanguageServer.cs @@ -99,7 +99,7 @@ private FrozenDictionary> GetBaseServices( // those cases, we do not need to add an additional workspace to manage new files we hear about. So only // add the LspMiscellaneousFilesWorkspace for hosts that have not already brought their own. if (serverKind == WellKnownLspServerKinds.CSharpVisualBasicLspServer) - AddLazyService(lspServices => new LspMiscellaneousFilesWorkspace(lspServices, hostServices)); + AddLazyService(lspServices => lspServices.GetRequiredService().CreateLspMiscellaneousFilesWorkspace(lspServices, hostServices)); return baseServiceMap.ToFrozenDictionary( keySelector: kvp => kvp.Key, diff --git a/src/LanguageServer/Protocol/RoslynRequestExecutionQueue.cs b/src/LanguageServer/Protocol/RoslynRequestExecutionQueue.cs index 72796e0783a89..88f34255b8012 100644 --- a/src/LanguageServer/Protocol/RoslynRequestExecutionQueue.cs +++ b/src/LanguageServer/Protocol/RoslynRequestExecutionQueue.cs @@ -2,9 +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.Globalization; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CommonLanguageServerProtocol.Framework; using Roslyn.Utilities; @@ -13,27 +16,44 @@ namespace Microsoft.CodeAnalysis.LanguageServer internal sealed class RoslynRequestExecutionQueue : RequestExecutionQueue { private readonly IInitializeManager _initializeManager; + private readonly IAsynchronousOperationListener _listener; /// /// Serial access is guaranteed by the queue. /// private CultureInfo? _cultureInfo; - public RoslynRequestExecutionQueue(AbstractLanguageServer languageServer, ILspLogger logger, AbstractHandlerProvider handlerProvider) + public RoslynRequestExecutionQueue(AbstractLanguageServer languageServer, ILspLogger logger, AbstractHandlerProvider handlerProvider, IAsynchronousOperationListenerProvider provider) : base(languageServer, logger, handlerProvider) { _initializeManager = languageServer.GetLspServices().GetRequiredService(); + _listener = provider.GetListener(FeatureAttribute.LanguageServer); } - public override Task WrapStartRequestTaskAsync(Task nonMutatingRequestTask, bool rethrowExceptions) + public override async Task WrapStartRequestTaskAsync(Task nonMutatingRequestTask, bool rethrowExceptions) { + using var token = _listener.BeginAsyncOperation(nameof(WrapStartRequestTaskAsync)); if (rethrowExceptions) { - return nonMutatingRequestTask; + try + { + await nonMutatingRequestTask.ConfigureAwait(false); + } + catch (StreamJsonRpc.LocalRpcException localRpcException) when (localRpcException.ErrorCode == LspErrorCodes.ContentModified) + { + // Content modified exceptions are expected and should not be reported as NFWs. + throw; + } + // If we had an exception, we want to record a NFW for it AND propogate it out to the queue so it can be handled appropriately. + catch (Exception ex) when (FatalError.ReportAndPropagateUnlessCanceled(ex, ErrorSeverity.Critical)) + { + throw ExceptionUtilities.Unreachable(); + } } else { - return nonMutatingRequestTask.ReportNonFatalErrorAsync(); + // The caller has asked us to not rethrow, so record a NFW and swallow. + await nonMutatingRequestTask.ReportNonFatalErrorAsync().ConfigureAwait(false); } } diff --git a/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs b/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs index bb5490d3220ea..d6d9c2809bb8d 100644 --- a/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs +++ b/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Features.Workspaces; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.CommonLanguageServerProtocol.Framework; @@ -24,28 +25,32 @@ namespace Microsoft.CodeAnalysis.LanguageServer /// Future work for this workspace includes supporting basic metadata references (mscorlib, System dlls, etc), /// but that is dependent on having a x-plat mechanism for retrieving those references from the framework / sdk. /// - internal sealed class LspMiscellaneousFilesWorkspace : Workspace, ILspService, ILspWorkspace + internal sealed class LspMiscellaneousFilesWorkspace(ILspServices lspServices, IMetadataAsSourceFileService metadataAsSourceFileService, HostServices hostServices) + : Workspace(hostServices, WorkspaceKind.MiscellaneousFiles), ILspService, ILspWorkspace { - private readonly ILspServices _lspServices; - - public LspMiscellaneousFilesWorkspace(ILspServices lspServices, HostServices hostServices) : base(hostServices, WorkspaceKind.MiscellaneousFiles) - { - _lspServices = lspServices; - } - public bool SupportsMutation => true; /// /// Takes in a file URI and text and creates a misc project and document for the file. /// - /// Calls to this method and are made + /// Calls to this method and are made /// from LSP text sync request handling which do not run concurrently. /// public Document? AddMiscellaneousDocument(Uri uri, SourceText documentText, string languageId, ILspLogger logger) { var documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri); - var languageInfoProvider = _lspServices.GetRequiredService(); - var languageInformation = languageInfoProvider.GetLanguageInformation(documentFilePath, languageId); + + var container = new StaticSourceTextContainer(documentText); + if (metadataAsSourceFileService.TryAddDocumentToWorkspace(documentFilePath, container, out var documentId)) + { + var metadataWorkspace = metadataAsSourceFileService.TryGetWorkspace(); + Contract.ThrowIfNull(metadataWorkspace); + var document = metadataWorkspace.CurrentSolution.GetRequiredDocument(documentId); + return document; + } + + var languageInfoProvider = lspServices.GetRequiredService(); + var languageInformation = languageInfoProvider.GetLanguageInformation(uri, languageId); if (languageInformation == null) { // Only log here since throwing here could take down the LSP server. @@ -69,8 +74,14 @@ public LspMiscellaneousFilesWorkspace(ILspServices lspServices, HostServices hos /// Calls to this method and are made /// from LSP text sync request handling which do not run concurrently. /// - public void TryRemoveMiscellaneousDocument(Uri uri) + public void TryRemoveMiscellaneousDocument(Uri uri, bool removeFromMetadataWorkspace) { + var documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri); + if (removeFromMetadataWorkspace && metadataAsSourceFileService.TryRemoveDocumentFromWorkspace(documentFilePath)) + { + return; + } + // We'll only ever have a single document matching this URI in the misc solution. var matchingDocument = CurrentSolution.GetDocumentIds(uri).SingleOrDefault(); if (matchingDocument != null) @@ -96,5 +107,19 @@ public ValueTask UpdateTextIfPresentAsync(DocumentId documentId, SourceText sour this.OnDocumentTextChanged(documentId, sourceText, PreservationMode.PreserveIdentity, requireDocumentPresent: false); return ValueTaskFactory.CompletedTask; } + + private class StaticSourceTextContainer(SourceText text) : SourceTextContainer + { + public override SourceText CurrentText => text; + + /// + /// Text changes are handled by LSP forking the document, we don't need to actually update anything here. + /// + public override event EventHandler TextChanged + { + add { } + remove { } + } + } } } diff --git a/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspaceProvider.cs b/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspaceProvider.cs new file mode 100644 index 0000000000000..61dd7b2ae8dc3 --- /dev/null +++ b/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspaceProvider.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.Host; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.MetadataAsSource; +using Microsoft.CommonLanguageServerProtocol.Framework; + +namespace Microsoft.CodeAnalysis.LanguageServer; + +/// +/// Service to create instances. +/// This is not exported as a as it requires +/// special base language server dependencies such as the +/// +[ExportCSharpVisualBasicStatelessLspService(typeof(LspMiscellaneousFilesWorkspaceProvider)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class LspMiscellaneousFilesWorkspaceProvider(IMetadataAsSourceFileService metadataAsSourceFileService) : ILspService +{ + public LspMiscellaneousFilesWorkspace CreateLspMiscellaneousFilesWorkspace(ILspServices lspServices, HostServices hostServices) + { + return new LspMiscellaneousFilesWorkspace(lspServices, metadataAsSourceFileService, hostServices); + } +} diff --git a/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs b/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs index 5a7b6a6a69a09..41864db53d6dc 100644 --- a/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs +++ b/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs @@ -44,6 +44,56 @@ namespace Microsoft.CodeAnalysis.LanguageServer; /// internal sealed class LspWorkspaceManager : IDocumentChangeTracker, ILspService { + private class LspUriComparer : IEqualityComparer + { + public static readonly LspUriComparer Instance = new(); + public bool Equals(Uri? x, Uri? y) + { + // Compare the absolute URIs to handle the case where one URI is encoded and the other is not. + // By default, Uri.Equals will not consider the encoded version of a URI equal to the unencoded version. + // + // The client is expected to be consistent in how it sends the URIs (either encoded or unencoded). + // So we normally can safely store the URIs as they send us in our map and expect subsequent requests to be encoded in the same way and match. + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#uri + // + // However when we serialize URIs to the client, we serialize the AbsoluteUri property which is always % encoded (no matter the original representation). + // For some requests, the client sends us exactly back what we sent (e.g. the data in a codelens/resolve request). + // This means that for these requests, the URI we will get from the client is the encoded version (that we sent). + // If the client sent us an unencoded URI originally, Uri.Equals will not consider it equal to the encoded version and we will fail to find the document + // + // So in order to resolve the encoded URI to the correct text, we can compare the AbsoluteUri properties (which are always encoded). + if (x is not null && y is not null && x.IsAbsoluteUri && y.IsAbsoluteUri && x.AbsoluteUri == y.AbsoluteUri) + { + return true; + } + else + { + return Uri.Equals(x, y); + } + } + + public int GetHashCode(Uri obj) + { + if (obj.IsAbsoluteUri) + { + // Since the Uri type does not consider an encoded Uri equal to an unencoded Uri, we need to handle this ourselves. + // The AbsoluteUri property is always encoded, so we can use this to compare the URIs (see Equals above). + // + // However, depending on the kind of URI, case sensitivity in AbsoluteUri should be ignored. + // Uri.GetHashCode normally handles this internally, but the parameters it uses to determine which comparison to use are not exposed. + // + // Instead, we will always create the hash code ignoring case, and will rely on the Equals implementation + // to handle collisions (between two Uris with different casing). This should be very rare in practice. + // Collisions can happen for non UNC URIs (e.g. `git:/blah` vs `git:/Blah`). + return StringComparer.OrdinalIgnoreCase.GetHashCode(obj.AbsoluteUri); + } + else + { + return obj.GetHashCode(); + } + } + } + /// /// A cache from workspace to the last solution we returned for LSP. /// The forkedFromVersion is not null when the solution was created from a fork of the workspace with LSP @@ -61,7 +111,7 @@ internal sealed class LspWorkspaceManager : IDocumentChangeTracker, ILspService /// the URI. /// Access to this is guaranteed to be serial by the /// - private ImmutableDictionary _trackedDocuments = ImmutableDictionary.Empty; + private ImmutableDictionary _trackedDocuments = ImmutableDictionary.Empty.WithComparers(LspUriComparer.Instance); private readonly ILspLogger _logger; private readonly LspMiscellaneousFilesWorkspace? _lspMiscellaneousFilesWorkspace; @@ -145,8 +195,8 @@ public async ValueTask StopTrackingAsync(Uri uri, CancellationToken cancellation // If LSP changed, we need to compare against the workspace again to get the updated solution. _cachedLspSolutions.Clear(); - // Also remove it from our loose files workspace if it is still there. - _lspMiscellaneousFilesWorkspace?.TryRemoveMiscellaneousDocument(uri); + // Also remove it from our loose files or metadata workspace if it is still there. + _lspMiscellaneousFilesWorkspace?.TryRemoveMiscellaneousDocument(uri, removeFromMetadataWorkspace: true); LspTextChanged?.Invoke(this, EventArgs.Empty); @@ -160,8 +210,17 @@ async ValueTask TryCloseDocumentsInMutatingWorkspaceAsync(Uri uri) var registeredWorkspaces = _lspWorkspaceRegistrationService.GetAllRegistrations(); foreach (var workspace in registeredWorkspaces) { - await ApplyChangeToMutatingWorkspaceAsync(workspace, uri, (_, documentId) => - workspace.TryOnDocumentClosedAsync(documentId, cancellationToken)).ConfigureAwait(false); + await ApplyChangeToMutatingWorkspaceAsync(workspace, uri, async (_, documentId) => + { + if (documentId.IsSourceGenerated) + { + // Source generated documents cannot go through OnDocumentOpened/Closed. + // There is a separate OnSourceGeneratedDocumentOpened/Closed method, but there is no need + // for us to call it in LSP - it deals with mapping TextBuffers to text containers. + return; + } + await workspace.TryOnDocumentClosedAsync(documentId, cancellationToken).ConfigureAwait(false); + }).ConfigureAwait(false); } } } @@ -224,11 +283,9 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) // Find the matching document from the LSP solutions. foreach (var (workspace, lspSolution, isForked) in lspSolutions) { - var documents = lspSolution.GetTextDocuments(textDocumentIdentifier.Uri); - if (documents.Any()) + var document = await lspSolution.GetTextDocumentAsync(textDocumentIdentifier, cancellationToken).ConfigureAwait(false); + if (document != null) { - var document = documents.FindDocumentInProjectContext(textDocumentIdentifier, (sln, id) => sln.GetRequiredTextDocument(id)); - // Record metadata on how we got this document. var workspaceKind = document.Project.Solution.WorkspaceKind; _requestTelemetryLogger.UpdateFindDocumentTelemetryData(success: true, workspaceKind); @@ -238,7 +295,10 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) // As we found the document in a non-misc workspace, also attempt to remove it from the misc workspace // if it happens to be in there as well. if (workspace != _lspMiscellaneousFilesWorkspace) - _lspMiscellaneousFilesWorkspace?.TryRemoveMiscellaneousDocument(uri); + { + // Do not attempt to remove the file from the metadata workspace (the document is still open). + _lspMiscellaneousFilesWorkspace?.TryRemoveMiscellaneousDocument(uri, removeFromMetadataWorkspace: false); + } return (workspace, document.Project.Solution, document); } @@ -255,7 +315,7 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) { var miscDocument = _lspMiscellaneousFilesWorkspace?.AddMiscellaneousDocument(uri, trackedDocument.Text, trackedDocument.LanguageId, _logger); if (miscDocument is not null) - return (_lspMiscellaneousFilesWorkspace, miscDocument.Project.Solution, miscDocument); + return (miscDocument.Project.Solution.Workspace, miscDocument.Project.Solution, miscDocument); } return default; @@ -329,8 +389,23 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) workspaceCurrentSolution = workspace.CurrentSolution; // Step 3: Check to see if the LSP text matches the workspace text. + var documentsInWorkspace = GetDocumentsForUris(_trackedDocuments.Keys.ToImmutableArray(), workspaceCurrentSolution); - if (await DoesAllTextMatchWorkspaceSolutionAsync(documentsInWorkspace, cancellationToken).ConfigureAwait(false)) + var sourceGeneratedDocuments = + _trackedDocuments.Keys.Where(static uri => uri.Scheme == SourceGeneratedDocumentUri.Scheme) + .Select(uri => (identity: SourceGeneratedDocumentUri.DeserializeIdentity(workspaceCurrentSolution, uri), _trackedDocuments[uri].Text)) + .Where(tuple => tuple.identity.HasValue) + .SelectAsArray(tuple => (tuple.identity!.Value, DateTime.Now, tuple.Text)); + + // First we check if normal document text matches the workspace solution. + // This does not look at source generated documents. + var doesAllTextMatch = await DoesAllTextMatchWorkspaceSolutionAsync(documentsInWorkspace, cancellationToken).ConfigureAwait(false); + + // Then we check if source generated document text matches the workspace solution. + // This is intentionally done differently from normal documents because the normal method will cause + // source generators to run which we do not want to do in queue dispatch. + var doesAllSourceGeneratedTextMatch = DoesAllSourceGeneratedTextMatchWorkspaceSolution(sourceGeneratedDocuments, workspaceCurrentSolution); + if (doesAllTextMatch && doesAllSourceGeneratedTextMatch) { // Remember that the current LSP text matches the text in this workspace solution. _cachedLspSolutions[workspace] = (forkedFromVersion: null, workspaceCurrentSolution); @@ -343,8 +418,18 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) // Step 5: Fork a new solution from the workspace with the LSP text applied. var lspSolution = workspaceCurrentSolution; - foreach (var (uri, workspaceDocuments) in documentsInWorkspace) - lspSolution = lspSolution.WithDocumentText(workspaceDocuments.Select(d => d.Id), _trackedDocuments[uri].Text); + // If the workspace text matched we can leave the normal documents as-is + if (!doesAllTextMatch) + { + foreach (var (uri, workspaceDocuments) in documentsInWorkspace) + lspSolution = lspSolution.WithDocumentText(workspaceDocuments.Select(d => d.Id), _trackedDocuments[uri].Text); + } + + // If the source generated documents matched we can leave the source generated documents as-is + if (!doesAllSourceGeneratedTextMatch) + { + lspSolution = lspSolution.WithFrozenSourceGeneratedDocuments(sourceGeneratedDocuments); + } // Remember this forked solution and the workspace version it was forked from. _cachedLspSolutions[workspace] = (workspaceCurrentSolution.WorkspaceVersion, lspSolution); @@ -357,6 +442,13 @@ async ValueTask TryOpenAndEditDocumentsInMutatingWorkspaceAsync(Workspace worksp { await ApplyChangeToMutatingWorkspaceAsync(workspace, uri, async (mutatingWorkspace, documentId) => { + if (documentId.IsSourceGenerated) + { + // Source generated documents cannot go through OnDocumentOpened/Closed. + // There is a separate OnSourceGeneratedDocumentOpened/Closed method, but there is no need + // for us to call it in LSP - it deals with mapping TextBuffers to text containers. + return; + } // This may be the first time this workspace is hearing that this document is open from LSP's // perspective. Attempt to open it there. // @@ -377,6 +469,34 @@ await workspace.TryOnDocumentOpenedAsync( } } + /// + /// Checks if the open source generator document contents matches the contents of the workspace solution. + /// This looks at the source generator state explicitly to avoid actually running source generators + /// + private static bool DoesAllSourceGeneratedTextMatchWorkspaceSolution( + ImmutableArray<(SourceGeneratedDocumentIdentity Identity, DateTime Generated, SourceText Text)> sourceGenereatedDocuments, + Solution workspaceSolution) + { + var compilationState = workspaceSolution.CompilationState; + foreach (var (identity, _, text) in sourceGenereatedDocuments) + { + var existingState = compilationState.TryGetSourceGeneratedDocumentStateForAlreadyGeneratedId(identity.DocumentId); + if (existingState is null) + { + // We don't have existing state for at least one of the documents, so the text cannot match. + return false; + } + + var newState = existingState.WithText(text); + if (newState != existingState) + { + return false; + } + } + + return true; + } + /// /// Given a set of documents from the workspace current solution, verify that the LSP text is the same as the document contents. /// @@ -420,8 +540,7 @@ internal string GetLanguageForUri(Uri uri) languageId = trackedDocument.LanguageId; } - var documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri); - return _languageInfoProvider.GetLanguageInformation(documentFilePath, languageId).LanguageName; + return _languageInfoProvider.GetLanguageInformation(uri, languageId).LanguageName; } /// diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.cs.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.cs.xlf index c1e6b6b4e7cac..48f0f0b900e1f 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.cs.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.cs.xlf @@ -7,6 +7,21 @@ Nejde deserializovat identifikátor Uri. Zjistila se neočekávaná hodnota: {0}. + + Unable to deserialize FormattingOptions. Invalid token: {0} + Nejde deserializovat rozhraní FormattingOptions. Neplatný token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Nejde deserializovat rozhraní FormattingOptions, protože skončilo neočekávaně. + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Nejde deserializovat rozhraní FormattingOptions. Chybí požadovaná vlastnost: {0}. + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} Nejde deserializovat MarkupContent. Zjistila se neočekávaná hodnota: {0}. diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.de.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.de.xlf index 45a9a5ba4eb17..9cfc63d59b29c 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.de.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.de.xlf @@ -7,6 +7,21 @@ URI kann nicht deserialisiert werden kann. Unerwarteter Wert erkannt: {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + Formatierungsoptionen können nicht deserialisiert werden. Ungültiges Token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Formatierungsoptionen können nicht deserialisiert werden, weil sie unerwartet beendet wurden. + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Formatierungsoptionen können nicht deserialisiert werden. Erforderliche Eigenschaft fehlt: {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} MarkupContent kann nicht deserialisiert werden. Unerwarteter Wert erkannt: {0} diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.es.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.es.xlf index 7d5de84cbca99..9cca14ad10654 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.es.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.es.xlf @@ -7,6 +7,21 @@ No se puede deserializar el URI. Se encontró un valor inesperado: {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + No se puede deserializar FormattingOptions. Token no válido: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + No se puede deserializar FormattingOptions porque ha finalizado de manera inesperada + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + No se puede deserializar FormattingOptions. Falta la propiedad obligatoria: {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} No se puede deserializar MarkupContent. Se encontró un valor inesperado: {0} diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.fr.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.fr.xlf index b7736960fab22..7ec8e5261ad22 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.fr.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.fr.xlf @@ -7,6 +7,21 @@ Impossible de désérialiser l'URI. Valeur inattendue rencontrée : {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + Impossible de désérialiser FormattingOptions. Jeton non valide : {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Impossible de désérialiser FormattingOptions car il s'est terminé de manière inattendue + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Impossible de désérialiser FormattingOptions. Propriété requise manquante : {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} Impossible de désérialiser MarkupContent. Valeur inattendue rencontrée : {0} diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.it.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.it.xlf index 535ef4ddfaf44..8ab55adbda8c4 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.it.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.it.xlf @@ -7,6 +7,21 @@ Non è possibile deserializzare Uri. È stato rilevato il valore imprevisto {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + Non è possibile deserializzare FormattingOptions. Token non valido: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Non è possibile deserializzare FormattingOptions perché è terminato in modo imprevisto + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Non è possibile deserializzare FormattingOptions. Proprietà obbligatoria mancante: {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} Non è possibile deserializzare MarkupContent. È stato rilevato il valore imprevisto {0} diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ja.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ja.xlf index 41a6348a60e4b..599172dcef56b 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ja.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ja.xlf @@ -7,6 +7,21 @@ URI を逆シリアル化できません。予期しない値が発生しました: {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + FormattingOptions を逆シリアル化できません。トークンが無効です: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + FormattingOptions が予期せず終了したため、逆シリアル化できません + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + FormattingOptions を逆シリアル化できません。必須プロパティがありません: {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} MarkupContent を逆シリアル化できません。予期しない値が発生しました: {0} diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ko.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ko.xlf index 73b4b9378652b..1100e3bf41a5b 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ko.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ko.xlf @@ -7,6 +7,21 @@ URI를 역직렬화할 수 없습니다. 예기치 않은 값 {0}이(가) 있습니다. + + Unable to deserialize FormattingOptions. Invalid token: {0} + FormattingOptions를 역직렬화할 수 없습니다. 잘못된 토큰: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + FormattingOptions가 예기치 않게 종료되어 역직렬화할 수 없습니다. + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + FormattingOptions를 역직렬화할 수 없습니다. 누락된 필수 속성: {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} MarkupContent를 역직렬화할 수 없습니다. 예기치 않은 값 {0}이(가) 있습니다. diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.pl.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.pl.xlf index 5b943fd3b2952..b73eac46f1588 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.pl.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.pl.xlf @@ -7,6 +7,21 @@ Nie można zdeserializować identyfikatora Uri. Napotkano nieoczekiwaną wartość: {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + Nie można deserializować elementu FormattingOptions. Nieprawidłowy token: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Nie można deserializować elementu FormattingOptions, ponieważ został on nieoczekiwanie zakończony + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Nie można deserializować elementu FormattingOptions. Brakuje wymaganej właściwości: {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} Nie można zdeserializować elementu MarkupContent. Napotkano nieoczekiwaną wartość: {0} diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.pt-BR.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.pt-BR.xlf index 6ce3cec3aa0e9..8b6db4f5db3e2 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.pt-BR.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.pt-BR.xlf @@ -7,6 +7,21 @@ Não é possível desserializar o Uri. Valor inesperado encontrado: {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + Não é possível desserializar FormattingOptions. Token inválido: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Não foi possível desserializar FormattingOptions, pois terminou de forma inesperada + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Não é possível desserializar FormattingOptions. Propriedade exigida ausente: {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} Não é possível desserializar MarkupContent. Valor inesperado encontrado: {0} diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ru.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ru.xlf index 023bfe80b89d5..7699cc13df4bf 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ru.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.ru.xlf @@ -7,6 +7,21 @@ Не удалось десериализовать URI. Возникло непредвиденное значение: {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + Не удалось выполнить десериализацию FormattingOptions. Недопустимый маркер: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Не удалось выполнить десериализацию FormattingOptions из-за ее непредвиденного завершения + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + Не удалось выполнить десериализацию FormattingOptions. Отсутствует обязательное свойство: {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} Не удалось десериализовать MarkupContent. Возникло непредвиденное значение: {0} diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.tr.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.tr.xlf index c2ec945623cea..2a8e14aead174 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.tr.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.tr.xlf @@ -7,6 +7,21 @@ URI seri durumdan çıkarılamıyor. Beklenmeyen değerle karşılaşıldı: {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + FormattingOptions seri durumdan çıkarılamıyor. Geçersiz belirteç: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + Beklenmedik bir şekilde sonlandırıldığından FormattingOptions seri durumdan çıkarılamıyor + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + FormattingOptions seri durumdan çıkarılamıyor. Gerekli özellik eksik: {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} MarkupContent seri durumdan çıkarılamıyor. Beklenmeyen değerle karşılaşıldı: {0} diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.zh-Hans.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.zh-Hans.xlf index 12cd37c21ed35..e977191376f9d 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.zh-Hans.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.zh-Hans.xlf @@ -7,6 +7,21 @@ 无法反序列化 URI。出现意外值: {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + 无法反序列化 FormattingOptions。令牌无效: {0}。 + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + 无法反序列化 FormattingOptions,因为它已意外结束 + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + 无法反序列化 FormattingOptions。缺少必需属性: {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} 无法反序列化 MarkupContent。出现意外值: {0} diff --git a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.zh-Hant.xlf b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.zh-Hant.xlf index f050d702caef7..4a2d2e217b839 100644 --- a/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.zh-Hant.xlf +++ b/src/LanguageServer/Protocol/xlf/LanguageServerProtocolResources.zh-Hant.xlf @@ -7,6 +7,21 @@ 無法將 URI 還原序列化。發現非預期的值: {0} + + Unable to deserialize FormattingOptions. Invalid token: {0} + 無法取消初始化 FormattingOptions。無效的權杖: {0} + + + + Unable to deserialize FormattingOptions as it ended unexpectedly + 無法取消初始化 FormattingOptions,因為它已非預期地結束 + + + + Unable to deserialize FormattingOptions. Missing required property: {0} + 無法取消初始化 FormattingOptions。遺漏必要屬性: {0} + + Unable to deserialize MarkupContent. Unexpected value encountered: {0} 無法將 MarkupContent 還原序列化。發現非預期的值: {0} diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs index dc176ebbe4cd8..09b362a39c737 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs @@ -57,7 +57,7 @@ void M() // var i = 1; // } // } - var expectedTextEdits = new LSP.TextEdit[] + var expectedTextEdits = new SumType[] { GenerateTextEdit("var", new LSP.Range { Start = new Position(4, 8), End = new Position(4, 11) }) }; @@ -112,7 +112,7 @@ void M() // int i = V; // } // } - var expectedTextEdits = new LSP.TextEdit[] + var expectedTextEdits = new SumType[] { GenerateTextEdit(@"private const int V = 1; @@ -230,7 +230,7 @@ public async Task TestLinkedDocuments(bool mutatingLspWorkspace) diagnostics: null); var actualResolvedAction = await RunGetCodeActionResolveAsync(testLspServer, unresolvedCodeAction); - var edits = new TextEdit[] + var edits = new SumType[] { new TextEdit() { @@ -355,7 +355,7 @@ class BCD new TextDocumentEdit() { TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = newDocumentUri }, - Edits = new TextEdit[] + Edits = new SumType[] { new TextEdit() { @@ -383,7 +383,7 @@ class BCD new TextDocumentEdit() { TextDocument = new OptionalVersionedTextDocumentIdentifier() { Uri = existingDocumentUri }, - Edits = new TextEdit[] + Edits = new SumType[] { new TextEdit() { @@ -482,7 +482,7 @@ class {|caret:BCD|} new TextDocumentEdit() { TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = newDocumentUri }, - Edits = new TextEdit[] + Edits = new SumType[] { new TextEdit() { @@ -509,7 +509,7 @@ class {|caret:BCD|} new TextDocumentEdit() { TextDocument = new OptionalVersionedTextDocumentIdentifier() { Uri = existingDocumentUri }, - Edits = new TextEdit[] + Edits = new SumType[] { new TextEdit() { @@ -567,7 +567,7 @@ private static LSP.TextEdit GenerateTextEdit(string newText, LSP.Range range) private static WorkspaceEdit GenerateWorkspaceEdit( IList locations, - TextEdit[] edits) + SumType[] edits) => new LSP.WorkspaceEdit { DocumentChanges = new TextDocumentEdit[] diff --git a/src/LanguageServer/ProtocolUnitTests/CodeLens/CSharpCodeLensTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeLens/CSharpCodeLensTests.cs index 853cd7ef7225e..37ff9c71e2789 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeLens/CSharpCodeLensTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeLens/CSharpCodeLensTests.cs @@ -418,7 +418,7 @@ void M(A a) } }); var actualCodeLenses = await GetCodeLensAsync(testLspServer); - Assert.Empty(actualCodeLenses); + AssertEx.Empty(actualCodeLenses); } [Theory, CombinatorialData] diff --git a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs index 19994181f2183..eeb249d1e9e4a 100644 --- a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs @@ -292,8 +292,8 @@ class A { }"; var resolvedItem = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentCompletionResolveName, actualItem, CancellationToken.None).ConfigureAwait(false); var expectedEdit = new TextEdit { Range = new LSP.Range { Start = new(1, 5), End = new(1, 9) }, NewText = "summary" }; - Assert.Equal(DefaultLspCompletionResultCreationService.CompleteComplexEditCommand, resolvedItem.Command.CommandIdentifier); - Assert.Equal(nameof(DefaultLspCompletionResultCreationService.CompleteComplexEditCommand), resolvedItem.Command.Title); + Assert.Equal(CompletionResultFactory.CompleteComplexEditCommand, resolvedItem.Command.CommandIdentifier); + Assert.Equal(nameof(CompletionResultFactory.CompleteComplexEditCommand), resolvedItem.Command.Title); AssertJsonEquals(completionParams.TextDocument, resolvedItem.Command.Arguments[0]); AssertJsonEquals(expectedEdit, resolvedItem.Command.Arguments[1]); Assert.Equal(false, resolvedItem.Command.Arguments[2]); @@ -460,7 +460,7 @@ public async Task TestUsingServerDefaultCommitCharacters(bool mutatingLspWorkspa Assert.NotNull(results.ItemDefaults.CommitCharacters); var defaultCharArray = CompletionRules.Default.DefaultCommitCharacters.Select(c => c.ToString()).ToArray(); - var nonDefaultCharArray = AbstractLspCompletionResultCreationService.CreateCommitCharacterArrayFromRules(mockService.NonDefaultRule); + var nonDefaultCharArray = CompletionResultFactory.CreateCommitCharacterArrayFromRules(mockService.NonDefaultRule); if (shouldPromoteDefaultCommitCharsToList) { @@ -924,8 +924,8 @@ public async Task TestHandleExceptionFromGetCompletionChange(bool mutatingLspWor Assert.Null(item.TextEdit); Assert.Null(resolvedItem.AdditionalTextEdits); - Assert.Equal(nameof(DefaultLspCompletionResultCreationService.CompleteComplexEditCommand), resolvedItem.Command.Title); - Assert.Equal(DefaultLspCompletionResultCreationService.CompleteComplexEditCommand, resolvedItem.Command.CommandIdentifier); + Assert.Equal(nameof(CompletionResultFactory.CompleteComplexEditCommand), resolvedItem.Command.Title); + Assert.Equal(CompletionResultFactory.CompleteComplexEditCommand, resolvedItem.Command.CommandIdentifier); AssertJsonEquals(completionParams.TextDocument, resolvedItem.Command.Arguments[0]); @@ -981,8 +981,8 @@ public class MyClass : BaseClass Assert.Null(resolvedItem.AdditionalTextEdits); - Assert.Equal(nameof(DefaultLspCompletionResultCreationService.CompleteComplexEditCommand), resolvedItem.Command.Title); - Assert.Equal(DefaultLspCompletionResultCreationService.CompleteComplexEditCommand, resolvedItem.Command.CommandIdentifier); + Assert.Equal(nameof(CompletionResultFactory.CompleteComplexEditCommand), resolvedItem.Command.Title); + Assert.Equal(CompletionResultFactory.CompleteComplexEditCommand, resolvedItem.Command.CommandIdentifier); AssertJsonEquals(completionParams.TextDocument, resolvedItem.Command.Arguments[0]); diff --git a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs index d03e70a4b2c26..0256f966eca70 100644 --- a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs @@ -182,7 +182,7 @@ class B : A var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); var selectedItem = CodeAnalysis.Completion.CompletionItem.Create(displayText: "M", isComplexTextEdit: true); - var (textEdit, _, _) = await AbstractLspCompletionResultCreationService.GenerateComplexTextEditAsync( + var (textEdit, _, _) = await CompletionResultFactory.GenerateComplexTextEditAsync( document, new TestCaretOutOfScopeCompletionService(testLspServer.TestWorkspace.Services.SolutionServices), selectedItem, snippetsSupported: true, insertNewPositionPlaceholder: true, CancellationToken.None).ConfigureAwait(false); Assert.Equal(@"public override void M() @@ -428,14 +428,14 @@ private static VSInternalCompletionItem CreateResolvedCompletionItem( } private static ClassifiedTextRun[] CreateClassifiedTextRunForClass(string className) - => new ClassifiedTextRun[] - { + => + [ new ClassifiedTextRun("whitespace", string.Empty), new ClassifiedTextRun("keyword", "class"), new ClassifiedTextRun("whitespace", " "), new ClassifiedTextRun("class name", className), new ClassifiedTextRun("whitespace", string.Empty), - }; + ]; private static async Task GetCompletionItemToResolveAsync( TestLspServer testLspServer, diff --git a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs index 1a8bae1134a27..eb4ee12a49099 100644 --- a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs @@ -90,7 +90,7 @@ void M() var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - var expected = await CreateCompletionItemAsync(label: "A", kind: LSP.CompletionItemKind.Class, tags: new string[] { "Class", "Internal" }, + var expected = await CreateCompletionItemAsync(label: "A", kind: LSP.CompletionItemKind.Class, tags: ["Class", "Internal"], request: completionParams, document: document, commitCharacters: CompletionRules.Default.DefaultCommitCharacters).ConfigureAwait(false); var expectedCommitCharacters = expected.CommitCharacters; @@ -141,7 +141,7 @@ public async Task TestGetCompletions_PromotesNothingWhenNoCommitCharactersAsync( var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - var expected = await CreateCompletionItemAsync(label: "A", kind: LSP.CompletionItemKind.Class, tags: new string[] { "Class", "Internal" }, + var expected = await CreateCompletionItemAsync(label: "A", kind: LSP.CompletionItemKind.Class, tags: ["Class", "Internal"], request: completionParams, document: document, commitCharacters: CompletionRules.Default.DefaultCommitCharacters).ConfigureAwait(false); var expectedCommitCharacters = expected.CommitCharacters; @@ -174,7 +174,7 @@ void M() var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - var expected = await CreateCompletionItemAsync(label: "A", kind: LSP.CompletionItemKind.Class, tags: new string[] { "Class", "Internal" }, + var expected = await CreateCompletionItemAsync(label: "A", kind: LSP.CompletionItemKind.Class, tags: ["Class", "Internal"], request: completionParams, document: document, commitCharacters: null).ConfigureAwait(false); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); @@ -208,7 +208,7 @@ public static void Goo(this A a) { } var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - var expected = await CreateCompletionItemAsync(label: "Goo", kind: LSP.CompletionItemKind.Method, tags: new string[] { "ExtensionMethod", "Public" }, + var expected = await CreateCompletionItemAsync(label: "Goo", kind: LSP.CompletionItemKind.Method, tags: ["ExtensionMethod", "Public"], request: completionParams, document: document, commitCharacters: null).ConfigureAwait(false); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); @@ -247,7 +247,7 @@ public static void Goo(this A a) { } var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - var expected = await CreateCompletionItemAsync(label: "Goo", kind: LSP.CompletionItemKind.ExtensionMethod, tags: new string[] { "ExtensionMethod", "Public" }, + var expected = await CreateCompletionItemAsync(label: "Goo", kind: LSP.CompletionItemKind.ExtensionMethod, tags: ["ExtensionMethod", "Public"], request: completionParams, document: document, commitCharacters: null).ConfigureAwait(false); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); @@ -275,7 +275,7 @@ void M() var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - var expected = await CreateCompletionItemAsync(label: "A", kind: LSP.CompletionItemKind.Class, tags: new string[] { "Class", "Internal" }, + var expected = await CreateCompletionItemAsync(label: "A", kind: LSP.CompletionItemKind.Class, tags: ["Class", "Internal"], request: completionParams, document: document, commitCharacters: null).ConfigureAwait(false); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); @@ -353,7 +353,7 @@ void M() var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - var expected = await CreateCompletionItemAsync("A", LSP.CompletionItemKind.Class, new string[] { "Class", "Internal" }, + var expected = await CreateCompletionItemAsync("A", LSP.CompletionItemKind.Class, ["Class", "Internal"], completionParams, document, preselect: true, commitCharacters: ImmutableArray.Create(' ', '(', '[', '{', ';', '.')).ConfigureAwait(false); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); @@ -412,7 +412,7 @@ void M() var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); var expected = await CreateCompletionItemAsync( - label: "d", kind: LSP.CompletionItemKind.Text, tags: new string[] { "Text" }, request: completionParams, document: document, sortText: "0000", + label: "d", kind: LSP.CompletionItemKind.Text, tags: ["Text"], request: completionParams, document: document, sortText: "0000", labelDetails: new() { Description = "shortdate" }).ConfigureAwait(false); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); @@ -473,7 +473,7 @@ void M() }; var expected = await CreateCompletionItemAsync( - label: @"\A", kind: LSP.CompletionItemKind.Text, tags: new string[] { "Text" }, request: completionParams, document: document, textEditText: @"\\A", + label: @"\A", kind: LSP.CompletionItemKind.Text, tags: ["Text"], request: completionParams, document: document, textEditText: @"\\A", sortText: "0000", labelDetails: new() { Description = "startofstringonly" }).ConfigureAwait(false); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); @@ -510,7 +510,7 @@ void M() }; var expected = await CreateCompletionItemAsync( - label: @"\A", kind: LSP.CompletionItemKind.Text, tags: new string[] { "Text" }, request: completionParams, document: document, + label: @"\A", kind: LSP.CompletionItemKind.Text, tags: ["Text"], request: completionParams, document: document, sortText: "0000", vsResolveTextEditOnCommit: true, labelDetails: new() { Description = "startofstringonly" }).ConfigureAwait(false); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); @@ -547,7 +547,7 @@ void M() }; var expected = await CreateCompletionItemAsync( - label: @"\A", kind: LSP.CompletionItemKind.Text, tags: new string[] { "Text" }, request: completionParams, document: document, + label: @"\A", kind: LSP.CompletionItemKind.Text, tags: ["Text"], request: completionParams, document: document, sortText: "0000", vsResolveTextEditOnCommit: true, labelDetails: new() { Description = "startofstringonly" }).ConfigureAwait(false); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); @@ -601,7 +601,7 @@ void M() var textEdit = GenerateTextEdit(@"\\A", startLine: 5, startChar: 19, endLine: 5, endChar: 19); var expected = await CreateCompletionItemAsync( - label: @"\A", kind: LSP.CompletionItemKind.Text, tags: new string[] { "Text" }, request: completionParams, document: document, textEdit: textEdit, + label: @"\A", kind: LSP.CompletionItemKind.Text, tags: ["Text"], request: completionParams, document: document, textEdit: textEdit, sortText: "0000", labelDetails: new() { Description = "startofstringonly" }).ConfigureAwait(false); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); @@ -692,7 +692,7 @@ void M() var document = testLspServer.GetCurrentSolution().Projects.First().Documents.First(); - var expected = await CreateCompletionItemAsync("A", LSP.CompletionItemKind.Class, new string[] { "Class", "Internal" }, + var expected = await CreateCompletionItemAsync("A", LSP.CompletionItemKind.Class, ["Class", "Internal"], completionParams, document, commitCharacters: CompletionRules.Default.DefaultCommitCharacters).ConfigureAwait(false); var results = await RunGetCompletionsAsync(testLspServer, completionParams).ConfigureAwait(false); diff --git a/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs b/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs index ea13825ac98b0..d8c3e3e15ff66 100644 --- a/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs +++ b/src/LanguageServer/ProtocolUnitTests/Configuration/DidChangeConfigurationNotificationHandlerTest.cs @@ -40,7 +40,7 @@ public class B { }"; { Workspace = new WorkspaceClientCapabilities() { - DidChangeConfiguration = new DynamicRegistrationSetting() { DynamicRegistration = true }, + DidChangeConfiguration = new DidChangeConfigurationClientCapabilities() { DynamicRegistration = true }, Configuration = false } }; @@ -69,7 +69,7 @@ public class A { }"; { Workspace = new WorkspaceClientCapabilities() { - DidChangeConfiguration = new DynamicRegistrationSetting() { DynamicRegistration = true }, + DidChangeConfiguration = new DidChangeConfigurationClientCapabilities() { DynamicRegistration = true }, Configuration = true } }; @@ -107,16 +107,17 @@ public class A { }"; public void VerifyLspClientOptionNames() { var actualNames = DidChangeConfigurationNotificationHandler.SupportedOptions.Select( - DidChangeConfigurationNotificationHandler.GenerateFullNameForOption).OrderBy(name => name).ToArray(); - // These options are persist in the LSP client. Please make sure also modify the LSP client code if these strings are changed. + DidChangeConfigurationNotificationHandler.GenerateFullNameForOption); + // These options are persisted by the LSP client. Please make sure also modify the LSP client code if these strings are changed. var expectedNames = new[] { "symbol_search.dotnet_search_reference_assemblies", - "implement_type.dotnet_insertion_behavior", - "implement_type.dotnet_property_generation_behavior", + "type_members.dotnet_member_insertion_location", + "type_members.dotnet_property_generation_behavior", "completion.dotnet_show_name_completion_suggestions", "completion.dotnet_provide_regex_completions", "completion.dotnet_show_completion_items_from_unimported_namespaces", + "completion.dotnet_trigger_completion_in_argument_lists", "quick_info.dotnet_show_remarks_in_quick_info", "navigation.dotnet_navigate_to_decompiled_sources", "highlighting.dotnet_highlight_related_json_components", @@ -144,10 +145,11 @@ public void VerifyLspClientOptionNames() "code_lens.dotnet_enable_references_code_lens", "code_lens.dotnet_enable_tests_code_lens", "projects.dotnet_binary_log_path", - "projects.dotnet_enable_automatic_restore" - }.OrderBy(name => name); + "projects.dotnet_enable_automatic_restore", + "navigation.dotnet_navigate_to_source_link_and_embedded_sources" + }; - Assert.Equal(expectedNames, actualNames); + AssertEx.SetEqual(expectedNames, actualNames); } private static void VerifyValuesInServer(EditorTestWorkspace workspace, List expectedValues) diff --git a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs index 3b6aca89890ba..b1d249cbd3f68 100644 --- a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Roslyn.Test.Utilities; +using Roslyn.Test.Utilities.TestGenerators; using Xunit; using Xunit.Abstractions; using LSP = Roslyn.LanguageServer.Protocol; @@ -224,6 +225,37 @@ public async Task TestGotoDefinitionWithValueTuple(string statement) Assert.Single(results); } + [Theory, CombinatorialData] + public async Task TestGotoDefinitionAsync_SourceGeneratedDocument(bool mutatingLspWorkspace) + { + var source = + """ + namespace M + { + class A + { + public {|caret:|}B b; + } + } + """; + var generated = + """ + namespace M + { + class B + { + } + } + """; + + await using var testLspServer = await CreateTestLspServerAsync(source, mutatingLspWorkspace); + await AddGeneratorAsync(new SingleFileTestGenerator(generated), testLspServer.TestWorkspace); + + var results = await RunGotoDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); + var result = Assert.Single(results); + Assert.Equal(SourceGeneratedDocumentUri.Scheme, result.Uri.Scheme); + } + private static async Task RunGotoDefinitionAsync(TestLspServer testLspServer, LSP.Location caret) { return await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentDefinitionName, diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs index 556c9a4cc1282..b35a3e04649f3 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs @@ -327,7 +327,8 @@ private protected static InitializationOptions GetInitializationOptions( bool useVSDiagnostics, WellKnownLspServerKinds serverKind = WellKnownLspServerKinds.AlwaysActiveVSLspServer, string[]? sourceGeneratedMarkups = null, - IEnumerable? additionalAnalyzers = null) + IEnumerable? additionalAnalyzers = null, + bool enableDiagnosticsInSourceGeneratedFiles = true) { // If no explicit compiler diagnostics scope has been provided, match it with the provided analyzer diagnostics scope compilerDiagnosticsScope ??= analyzerDiagnosticsScope switch @@ -350,7 +351,7 @@ private protected static InitializationOptions GetInitializationOptions( globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, LanguageNames.CSharp, compilerDiagnosticsScope.Value); globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, LanguageNames.VisualBasic, compilerDiagnosticsScope.Value); globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.CompilerDiagnosticsScopeOption, InternalLanguageNames.TypeScript, compilerDiagnosticsScope.Value); - globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.EnableDiagnosticsInSourceGeneratedFiles, true); + globalOptions.SetGlobalOption(SolutionCrawlerOptionsStorage.EnableDiagnosticsInSourceGeneratedFiles, enableDiagnosticsInSourceGeneratedFiles); }, ServerKind = serverKind, SourceGeneratedMarkups = sourceGeneratedMarkups ?? [], diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs index 3495c0d71f9e1..79c732d12ec6e 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs @@ -35,12 +35,12 @@ public async Task TestWorkspaceDiagnosticsReportsAdditionalFileDiagnostic(bool u await using var testLspServer = await CreateTestWorkspaceFromXmlAsync(workspaceXml, mutatingLspWorkspace, BackgroundAnalysisScope.FullSolution, useVSDiagnostics); var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); - AssertEx.Equal(new[] - { + AssertEx.Equal( + [ @"C:\C.cs: []", @$"C:\Test.txt: [{MockAdditionalFileDiagnosticAnalyzer.Id}]", @"C:\CSProj1.csproj: []" - }, results.Select(r => $"{r.Uri.LocalPath}: [{string.Join(", ", r.Diagnostics.Select(d => d.Code?.Value?.ToString()))}]")); + ], results.Select(r => $"{r.Uri.LocalPath}: [{string.Join(", ", r.Diagnostics.Select(d => d.Code?.Value?.ToString()))}]")); // Asking again should give us back an unchanged diagnostic. var results2 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, previousResults: CreateDiagnosticParamsFromPreviousReports(results)); @@ -63,10 +63,10 @@ public async Task TestWorkspaceDiagnosticsWithRemovedAdditionalFile(bool useVSDi var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Empty(results[0].Diagnostics); + AssertEx.Empty(results[0].Diagnostics); Assert.Equal(MockAdditionalFileDiagnosticAnalyzer.Id, results[1].Diagnostics.Single().Code); Assert.Equal(@"C:\Test.txt", results[1].Uri.LocalPath); - Assert.Empty(results[2].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); var initialSolution = testLspServer.GetCurrentSolution(); var newSolution = initialSolution.RemoveAdditionalDocument(initialSolution.Projects.Single().AdditionalDocumentIds.Single()); @@ -80,9 +80,9 @@ public async Task TestWorkspaceDiagnosticsWithRemovedAdditionalFile(bool useVSDi Assert.Null(results2[0].ResultId); // The other files should have new results since the solution changed. - Assert.Empty(results2[1].Diagnostics); + AssertEx.Empty(results2[1].Diagnostics); Assert.NotNull(results2[1].ResultId); - Assert.Empty(results2[2].Diagnostics); + AssertEx.Empty(results2[2].Diagnostics); Assert.NotNull(results2[2].ResultId); } @@ -115,7 +115,7 @@ public async Task TestWorkspaceDiagnosticsWithAdditionalFileInMultipleProjects(b // Asking again should give us back an unchanged diagnostic. var results2 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics: true, previousResults: CreateDiagnosticParamsFromPreviousReports(results)); - Assert.Empty(results2); + AssertEx.Empty(results2); } protected override TestComposition Composition => base.Composition.AddParts(typeof(MockAdditionalFileDiagnosticAnalyzer)); diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/BuildOnlyDiagnosticIdsHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/BuildOnlyDiagnosticIdsHandlerTests.cs index 23ad8255dd37d..68fe2bf280f65 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/BuildOnlyDiagnosticIdsHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/BuildOnlyDiagnosticIdsHandlerTests.cs @@ -89,7 +89,7 @@ private static string[] GetExpectedBuildOnlyDiagnosticIds(string languageName) private sealed class BuildOnlyAnalyzer : DiagnosticAnalyzer { public const string Id = "BuildOnly0001"; - private static readonly DiagnosticDescriptor s_descriptor = new(Id, "Title", "Message", "Category", DiagnosticSeverity.Warning, isEnabledByDefault: true, customTags: new[] { WellKnownDiagnosticTags.CompilationEnd }); + private static readonly DiagnosticDescriptor s_descriptor = new(Id, "Title", "Message", "Category", DiagnosticSeverity.Warning, isEnabledByDefault: true, customTags: [WellKnownDiagnosticTags.CompilationEnd]); public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(s_descriptor); public override void Initialize(AnalysisContext context) diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs index 3ade0b2077921..6ab5e649f52ed 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs @@ -354,7 +354,7 @@ public async Task TestDocumentDiagnosticsRemovedAfterErrorIsFixed(bool useVSDiag await InsertTextAsync(testLspServer, document, buffer.CurrentSnapshot.Length, "}"); results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics, results.Single().ResultId); - Assert.Empty(results[0].Diagnostics); + AssertEx.Empty(results[0].Diagnostics); } [Theory, CombinatorialData] @@ -470,11 +470,11 @@ class B {"; testLspServer.TestWorkspace.SetDocumentContext(csproj1Document.Id); results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, csproj1Document.GetURI(), useVSDiagnostics); Assert.Equal(2, results.Single().Diagnostics!.Length); - Assert.All(results.Single().Diagnostics, d => Assert.Equal("CS1513", d.Code)); + AssertEx.All(results.Single().Diagnostics, d => Assert.Equal("CS1513", d.Code)); if (useVSDiagnostics) { - Assert.All(results.Single().Diagnostics, d => Assert.Equal("CSProj1", ((VSDiagnostic)d).Projects.Single().ProjectName)); + AssertEx.All(results.Single().Diagnostics, d => Assert.Equal("CSProj1", ((VSDiagnostic)d).Projects.Single().ProjectName)); } } @@ -565,7 +565,7 @@ public class {|caret:|} { } var originalResultId = results.Single().ResultId; results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, csproj1Document.GetURI(), useVSDiagnostics, originalResultId); Assert.Single(results); - Assert.Empty(results.Single().Diagnostics); + AssertEx.Empty(results.Single().Diagnostics); Assert.NotEqual(originalResultId, results.Single().ResultId); } @@ -687,7 +687,7 @@ public async Task TestDocumentDiagnosticsIncludesSourceGeneratorDiagnostics(bool var results = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics); - var diagnostic = Assert.Single(results.Single().Diagnostics); + var diagnostic = AssertEx.Single(results.Single().Diagnostics); Assert.Equal(DiagnosticProducingGenerator.Descriptor.Id, diagnostic.Code); } @@ -751,7 +751,7 @@ class A var results = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics); - Assert.All(results.Single().Diagnostics, d => Assert.False(d.Tags!.Contains(DiagnosticTag.Unnecessary))); + AssertEx.All(results.Single().Diagnostics, d => Assert.False(d.Tags!.Contains(DiagnosticTag.Unnecessary))); } [Theory, CombinatorialData] @@ -844,7 +844,7 @@ void M() var results = await RunGetDocumentPullDiagnosticsAsync( testLspServer, document.GetURI(), useVSDiagnostics); - Assert.Empty(results.Single().Diagnostics); + AssertEx.Empty(results.Single().Diagnostics); } [Theory, CombinatorialData] @@ -926,8 +926,8 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithFSAOn(bool useVSDiag Assert.Equal(3, results.Length); Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); - Assert.Empty(results[1].Diagnostics); - Assert.Empty(results[2].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/65967")] @@ -947,9 +947,9 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithRunCodeAnalysisAndFS Assert.Equal(3, results.Length); Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); // this should be considered a build-error, since it was produced by the last code-analysis run. - Assert.Contains(VSDiagnosticTags.BuildError, results[0].Diagnostics.Single().Tags); - Assert.Empty(results[1].Diagnostics); - Assert.Empty(results[2].Diagnostics); + Assert.Contains(VSDiagnosticTags.BuildError, results[0].Diagnostics.Single().Tags!); + AssertEx.Empty(results[1].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); // Now fix the compiler error, but don't re-execute code analysis. // Verify that we still get the workspace diagnostics from the prior snapshot on which code analysis was executed. @@ -962,7 +962,7 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithRunCodeAnalysisAndFS Assert.Equal(results[0].Diagnostics, results2[0].Diagnostics); // this should be considered a build-error, since it was produced by the last code-analysis run. - Assert.Contains(VSDiagnosticTags.BuildError, results2[0].Diagnostics.Single().Tags); + Assert.Contains(VSDiagnosticTags.BuildError, results2[0].Diagnostics.Single().Tags!); Assert.Equal(results[1].Diagnostics, results2[1].Diagnostics); Assert.Equal(results[2].Diagnostics, results2[2].Diagnostics); @@ -972,13 +972,13 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithRunCodeAnalysisAndFS var results3 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, previousResults: CreateDiagnosticParamsFromPreviousReports(results2)); Assert.Equal(results.Length, results3.Length); - Assert.Empty(results3[0].Diagnostics); - Assert.Empty(results3[1].Diagnostics); - Assert.Empty(results3[2].Diagnostics); + AssertEx.Empty(results3[0].Diagnostics); + AssertEx.Empty(results3[1].Diagnostics); + AssertEx.Empty(results3[2].Diagnostics); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/65967")] - public async Task TestWorkspaceDiagnosticsForClosedFilesWithWithRunCodeAnalysisFSAOn(bool useVSDiagnostics, bool mutatingLspWorkspace, bool scopeRunCodeAnalysisToProject) + public async Task TestWorkspaceDiagnosticsForClosedFilesWithRunCodeAnalysisFSAOn(bool useVSDiagnostics, bool mutatingLspWorkspace, bool scopeRunCodeAnalysisToProject) { var markup1 = @"class A {"; @@ -995,9 +995,9 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithWithRunCodeAnalysisF Assert.Equal(3, results.Length); Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); // this should *not* be considered a build-error, since it was produced by the live workspace results. - Assert.DoesNotContain(VSDiagnosticTags.BuildError, results[0].Diagnostics.Single().Tags); - Assert.Empty(results[1].Diagnostics); - Assert.Empty(results[2].Diagnostics); + Assert.DoesNotContain(VSDiagnosticTags.BuildError, results[0].Diagnostics.Single().Tags!); + AssertEx.Empty(results[1].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); // Now fix the compiler error, but don't rerun code analysis. // Verify that we get up-to-date workspace diagnostics, i.e. no compiler errors, from the current snapshot because FSA is enabled. @@ -1009,9 +1009,9 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithWithRunCodeAnalysisF Assert.Equal(results.Length, results2.Length); Assert.Equal(results.Length, results2.Length); - Assert.Empty(results2[0].Diagnostics); - Assert.Empty(results2[1].Diagnostics); - Assert.Empty(results2[2].Diagnostics); + AssertEx.Empty(results2[0].Diagnostics); + AssertEx.Empty(results2[1].Diagnostics); + AssertEx.Empty(results2[2].Diagnostics); // Now rerun code analysis and verify we still get up-to-date workspace diagnostics. await testLspServer.RunCodeAnalysisAsync(projectId); @@ -1025,6 +1025,28 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesWithWithRunCodeAnalysisF Assert.Equal(results2[2].Diagnostics, results3[2].Diagnostics); } + [Theory, CombinatorialData] + public async Task SourceGeneratorFailures_FSA(bool useVSDiagnostics, bool mutatingLspWorkspace, bool enableDiagnosticsInSourceGeneratedFiles) + { + await using var testLspServer = await CreateTestLspServerAsync(["class C {}"], mutatingLspWorkspace, + GetInitializationOptions(BackgroundAnalysisScope.FullSolution, CompilerDiagnosticsScope.FullSolution, useVSDiagnostics, enableDiagnosticsInSourceGeneratedFiles: enableDiagnosticsInSourceGeneratedFiles)); + + var generator = new Roslyn.Test.Utilities.TestGenerators.TestSourceGenerator() + { + ExecuteImpl = context => throw new InvalidOperationException("Source generator failed") + }; + + var solution = testLspServer.TestWorkspace.CurrentSolution; + solution = solution.AddAnalyzerReference(solution.ProjectIds.Single(), new TestGeneratorReference(generator)); + Assert.True(testLspServer.TestWorkspace.TryApplyChanges(solution)); + + var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); + + Assert.Equal(2, results.Length); + AssertEx.Empty(results[0].Diagnostics); + Assert.True(results[1].Diagnostics.Single().Message.Contains("Source generator failed")); + } + [Theory, CombinatorialData] public async Task TestWorkspaceTodoForClosedFilesWithFSAOffAndTodoOff(bool mutatingLspWorkspace) { @@ -1143,6 +1165,32 @@ class A { Assert.Equal("TODO", results[0].Diagnostics![0].Code); } + [Theory, CombinatorialData] + public async Task EditAndContinue_NonHostWorkspace(bool mutatingLspWorkspace) + { + var xmlWorkspace = """ + + + 1+1 + + + """; + + var options = GetInitializationOptions(BackgroundAnalysisScope.OpenFiles, compilerDiagnosticsScope: null, useVSDiagnostics: false); + await using var testLspServer = await CreateXmlTestLspServerAsync(xmlWorkspace, mutatingLspWorkspace, WorkspaceKind.Interactive, options); + + var document = testLspServer.TestWorkspace.CurrentSolution.Projects.Single().Documents.Single(); + await OpenDocumentAsync(testLspServer, document); + + var encSessionState = testLspServer.TestWorkspace.GetService(); + + // active session, but should get no EnC diagnostics for Interactive workspace + encSessionState.IsSessionActive = true; + + var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), useVSDiagnostics: false, category: PullDiagnosticCategories.EditAndContinue); + AssertEx.Empty(results.Single().Diagnostics); + } + [Theory, CombinatorialData] public async Task EditAndContinue_NoActiveSession(bool mutatingLspWorkspace) { @@ -1152,8 +1200,6 @@ public async Task EditAndContinue_NoActiveSession(bool mutatingLspWorkspace) await using var testLspServer = await CreateTestLspServerAsync([markup1], LanguageNames.CSharp, mutatingLspWorkspace, options); - var encSessionState = testLspServer.TestWorkspace.GetService(); - var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics: false, includeTaskListItems: false, category: PullDiagnosticCategories.EditAndContinue); Assert.Empty(results); } @@ -1295,7 +1341,7 @@ public async Task TestWorkspaceDiagnosticsIncludesSourceGeneratorDiagnosticsClos var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(DiagnosticProducingGenerator.Descriptor.Id, results[0].Diagnostics.Single().Code); - Assert.Empty(results[1].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); } [Theory, CombinatorialData] @@ -1361,9 +1407,9 @@ public async Task TestWorkspaceDiagnosticsForSourceGeneratedFiles(bool useVSDiag Assert.Equal(3, results.Length); // Since we sorted above by URI the first result is the project. - Assert.Empty(results[0].Diagnostics); + AssertEx.Empty(results[0].Diagnostics); Assert.Equal("CS1513", results[1].Diagnostics.Single().Code); - Assert.Empty(results[2].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); } [Theory, CombinatorialData] @@ -1379,8 +1425,8 @@ public async Task TestWorkspaceDiagnosticsForRemovedDocument(bool useVSDiagnosti Assert.Equal(3, results.Length); Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); - Assert.Empty(results[1].Diagnostics); - Assert.Empty(results[2].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); testLspServer.TestWorkspace.OnDocumentRemoved(testLspServer.TestWorkspace.Documents.First().Id); @@ -1393,9 +1439,9 @@ public async Task TestWorkspaceDiagnosticsForRemovedDocument(bool useVSDiagnosti Assert.Null(results2[0].ResultId); // Second and third doc should be changed as the project has changed. - Assert.Empty(results2[1].Diagnostics); + AssertEx.Empty(results2[1].Diagnostics); Assert.NotEqual(results[1].ResultId, results2[1].ResultId); - Assert.Empty(results2[2].Diagnostics); + AssertEx.Empty(results2[2].Diagnostics); Assert.NotEqual(results[2].ResultId, results2[2].ResultId); } @@ -1412,8 +1458,8 @@ public async Task TestNoChangeIfWorkspaceDiagnosticsCalledTwice(bool useVSDiagno Assert.Equal(3, results.Length); Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); - Assert.Empty(results[1].Diagnostics); - Assert.Empty(results[2].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); var results2 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, previousResults: CreateDiagnosticParamsFromPreviousReports(results)); @@ -1434,8 +1480,8 @@ public async Task TestWorkspaceDiagnosticsRemovedAfterErrorIsFixed(bool useVSDia Assert.Equal(3, results.Length); Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); - Assert.Empty(results[1].Diagnostics); - Assert.Empty(results[2].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); var buffer = testLspServer.TestWorkspace.Documents.First().GetTextBuffer(); buffer.Insert(buffer.CurrentSnapshot.Length, "}"); @@ -1443,11 +1489,11 @@ public async Task TestWorkspaceDiagnosticsRemovedAfterErrorIsFixed(bool useVSDia var results2 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, previousResults: CreateDiagnosticParamsFromPreviousReports(results)); Assert.Equal(3, results2.Length); - Assert.Empty(results2[0].Diagnostics); + AssertEx.Empty(results2[0].Diagnostics); // Project has changed, so we re-computed diagnostics as changes in the first file // may have changed results in the second. - Assert.Empty(results2[1].Diagnostics); - Assert.Empty(results2[2].Diagnostics); + AssertEx.Empty(results2[1].Diagnostics); + AssertEx.Empty(results2[2].Diagnostics); Assert.NotEqual(results[0].ResultId, results2[0].ResultId); Assert.NotEqual(results[1].ResultId, results2[1].ResultId); @@ -1469,8 +1515,8 @@ public async Task TestWorkspaceDiagnosticsRemainAfterErrorIsNotFixed(bool useVSD Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); Assert.Equal(new Position { Line = 0, Character = 9 }, results[0].Diagnostics.Single().Range.Start); - Assert.Empty(results[1].Diagnostics); - Assert.Empty(results[2].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); var buffer = testLspServer.TestWorkspace.Documents.First().GetTextBuffer(); buffer.Insert(0, " "); @@ -1488,9 +1534,9 @@ public async Task TestWorkspaceDiagnosticsRemainAfterErrorIsNotFixed(bool useVSD Assert.Equal("CS1513", results2[0].Diagnostics.Single().Code); Assert.Equal(new Position { Line = 0, Character = 10 }, results2[0].Diagnostics.Single().Range.Start); - Assert.Empty(results2[1].Diagnostics); + AssertEx.Empty(results2[1].Diagnostics); Assert.NotEqual(results[1].ResultId, results2[1].ResultId); - Assert.Empty(results2[2].Diagnostics); + AssertEx.Empty(results2[2].Diagnostics); Assert.NotEqual(results[2].ResultId, results2[2].ResultId); } @@ -1529,8 +1575,8 @@ class A {"; Assert.Equal(ProtocolConversions.CreateAbsoluteUri(@"C:\test1.cs"), results[0].TextDocument!.Uri); Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); Assert.Equal(1, results[0].Diagnostics.Single().Range.Start.Line); - Assert.Empty(results[1].Diagnostics); - Assert.Empty(results[2].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); } [Theory, CombinatorialData] @@ -1582,11 +1628,11 @@ public class {|caret:|} { } Assert.Equal(4, results.Length); // Verify diagnostics for A.cs are updated as the type B now exists. - Assert.Empty(results[0].Diagnostics); + AssertEx.Empty(results[0].Diagnostics); Assert.NotEqual(previousResultIds[0].resultId, results[0].ResultId); // Verify diagnostics for B.cs are updated as the class definition is now correct. - Assert.Empty(results[2].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); Assert.NotEqual(previousResultIds[2].resultId, results[2].ResultId); } @@ -1637,12 +1683,12 @@ public class {|caret:|} var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); AssertEx.NotNull(results); Assert.Equal(6, results.Length); - Assert.Empty(results[0].Diagnostics); - Assert.Empty(results[1].Diagnostics); - Assert.Empty(results[2].Diagnostics); - Assert.Empty(results[3].Diagnostics); + AssertEx.Empty(results[0].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); + AssertEx.Empty(results[3].Diagnostics); Assert.Equal("CS1001", results[4].Diagnostics.Single().Code); - Assert.Empty(results[5].Diagnostics); + AssertEx.Empty(results[5].Diagnostics); // Insert C into C.cs via the workspace. var caretLocation = testLspServer.GetLocations("caret").First().Range; @@ -1658,19 +1704,19 @@ public class {|caret:|} // Verify that new diagnostics are returned for all files (even though the diagnostics for the first two files are the same) // since we re-calculate when transitive project dependencies change. - Assert.Empty(results[0].Diagnostics); + AssertEx.Empty(results[0].Diagnostics); Assert.NotEqual(previousResultIds[0].resultId, results[0].ResultId); - Assert.Empty(results[1].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); Assert.NotEqual(previousResultIds[1].resultId, results[1].ResultId); - Assert.Empty(results[2].Diagnostics); + AssertEx.Empty(results[2].Diagnostics); Assert.NotEqual(previousResultIds[2].resultId, results[2].ResultId); - Assert.Empty(results[3].Diagnostics); + AssertEx.Empty(results[3].Diagnostics); Assert.NotEqual(previousResultIds[3].resultId, results[3].ResultId); - Assert.Empty(results[4].Diagnostics); + AssertEx.Empty(results[4].Diagnostics); Assert.NotEqual(previousResultIds[4].resultId, results[4].ResultId); - Assert.Empty(results[5].Diagnostics); + AssertEx.Empty(results[5].Diagnostics); Assert.NotEqual(previousResultIds[5].resultId, results[5].ResultId); } @@ -1707,9 +1753,9 @@ public class {|caret:|} { } AssertEx.NotNull(results); Assert.Equal(4, results.Length); Assert.Equal("CS0246", results[0].Diagnostics.Single().Code); - Assert.Empty(results[1].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); Assert.Equal("CS1001", results[2].Diagnostics.Single().Code); - Assert.Empty(results[3].Diagnostics); + AssertEx.Empty(results[3].Diagnostics); // Insert B into B.cs via the workspace. var caretLocation = testLspServer.GetLocations("caret").First().Range; @@ -1725,9 +1771,9 @@ public class {|caret:|} { } // Note: tehre will be no results for A.cs as it is unchanged and does not reference CSProj2. // Verify that the diagnostics result for B.cs reflects the change we made to it. - Assert.Empty(results[0].Diagnostics); + AssertEx.Empty(results[0].Diagnostics); Assert.NotEqual(previousResultIds[2].resultId, results[0].ResultId); - Assert.Empty(results[1].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); Assert.NotEqual(previousResultIds[3].resultId, results[1].ResultId); } @@ -2007,6 +2053,12 @@ public async Task TestWorkspaceDiagnosticsWaitsForLspTextChangesWithMultipleSour Assert.NotEmpty(resultsOne); Assert.Empty(resultsTwo); + // For the mutating workspace, the change in the document can cause to change events + // 1. LSP changed, which triggers immediately via the queue. + // 2. Workspace changed, which can be delayed until after the requests complete. + // To ensure the workspace changed is processed, we need to wait for all workspace events. + await testLspServer.WaitForDiagnosticsAsync(); + // Make new requests - these requests should again wait for new changes. resultTaskOne = RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, useProgress: true, category: PullDiagnosticCategories.WorkspaceDocumentsAndProject, triggerConnectionClose: false); resultTaskTwo = RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, useProgress: true, category: PullDiagnosticCategories.EditAndContinue, triggerConnectionClose: false); @@ -2038,7 +2090,7 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesSwitchFSAFromOnToOff(boo Assert.Equal(2, results.Length); Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); - Assert.Empty(results[1].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); var options = testLspServer.TestWorkspace.ExportProvider.GetExportedValue(); options.SetGlobalOption(SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp, BackgroundAnalysisScope.OpenFiles); @@ -2059,8 +2111,8 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesSwitchFSAFromOnToOff(boo } else { - Assert.Empty(results[0].Diagnostics); - Assert.Empty(results[1].Diagnostics); + AssertEx.Empty(results[0].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); } } @@ -2084,7 +2136,7 @@ public async Task TestWorkspaceDiagnosticsForClosedFilesSwitchFSAFromOffToOn(boo Assert.Equal(2, results.Length); Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); - Assert.Empty(results[1].Diagnostics); + AssertEx.Empty(results[1].Diagnostics); } #endregion diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs index bf060ae5b2fc0..3e9c8413166d8 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -27,7 +28,7 @@ public async Task TestWorkspaceDiagnosticsReportsProjectDiagnostic(bool useVSDia var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(2, results.Length); - Assert.Empty(results[0].Diagnostics); + AssertEx.Empty(results[0].Diagnostics); Assert.Equal(MockProjectDiagnosticAnalyzer.Id, results[1].Diagnostics.Single().Code); Assert.Equal(ProtocolConversions.CreateAbsoluteUri(testLspServer.GetCurrentSolution().Projects.First().FilePath!), results[1].Uri); @@ -44,7 +45,7 @@ public async Task TestWorkspaceDiagnosticsWithRemovedProject(bool useVSDiagnosti var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(2, results.Length); - Assert.Empty(results[0].Diagnostics); + AssertEx.Empty(results[0].Diagnostics); Assert.Equal(MockProjectDiagnosticAnalyzer.Id, results[1].Diagnostics.Single().Code); Assert.Equal(ProtocolConversions.CreateAbsoluteUri(testLspServer.GetCurrentSolution().Projects.First().FilePath!), results[1].Uri); diff --git a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs index 3bafb1e06a808..83bb8b0438328 100644 --- a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer.Handler.DocumentChanges; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -234,7 +235,7 @@ void M() await DidChange(testLspServer, locationTyped.Uri, (4, 8, "// hi there")); - var documentTextFromWorkspace = (await testLspServer.GetCurrentSolution().GetDocuments(locationTyped.Uri).Single().GetTextAsync()).ToString(); + var documentTextFromWorkspace = (await testLspServer.GetDocumentTextAsync(locationTyped.Uri)).ToString(); Assert.NotNull(documentTextFromWorkspace); Assert.Equal(documentText, documentTextFromWorkspace); @@ -245,7 +246,7 @@ void M() } [Theory, CombinatorialData] - public async Task DidChange_MultipleChanges1(bool mutatingLspWorkspace) + public async Task DidChange_MultipleChanges_ForwardOrder(bool mutatingLspWorkspace) { var source = """ @@ -285,7 +286,7 @@ void M() } [Theory, CombinatorialData] - public async Task DidChange_MultipleChanges2(bool mutatingLspWorkspace) + public async Task DidChange_MultipleChanges_Overlapping(bool mutatingLspWorkspace) { var source = """ @@ -323,6 +324,89 @@ void M() } } + [Theory, CombinatorialData] + public async Task DidChange_MultipleChanges_ReverseOrder(bool mutatingLspWorkspace) + { + var source = + """ + class A + { + void M() + { + {|type:|} + } + } + """; + var expected = + """ + class A + { + void M() + { + // hi there + // this builds on that + } + } + """; + + var (testLspServer, locationTyped, _) = await GetTestLspServerAndLocationAsync(source, mutatingLspWorkspace); + + await using (testLspServer) + { + await DidOpen(testLspServer, locationTyped.Uri); + + await DidChange(testLspServer, locationTyped.Uri, (5, 0, " // this builds on that\r\n"), (4, 8, "// hi there")); + + var document = testLspServer.GetTrackedTexts().FirstOrDefault(); + + AssertEx.NotNull(document); + Assert.Equal(expected, document.ToString()); + } + } + + private LSP.TextDocumentContentChangeEvent CreateTextDocumentContentChangeEvent(int startLine, int startCol, int endLine, int endCol, string newText) + { + return new LSP.TextDocumentContentChangeEvent() + { + Range = new LSP.Range() + { + Start = new LSP.Position(startLine, startCol), + End = new LSP.Position(endLine, endCol) + }, + Text = newText + }; + } + + [Fact] + public void DidChange_AreChangesInReverseOrder_True() + { + LSP.TextDocumentContentChangeEvent change1 = CreateTextDocumentContentChangeEvent(startLine: 0, startCol: 7, endLine: 0, endCol: 9, newText: "test3"); + LSP.TextDocumentContentChangeEvent change2 = CreateTextDocumentContentChangeEvent(startLine: 0, startCol: 5, endLine: 0, endCol: 7, newText: "test2"); + LSP.TextDocumentContentChangeEvent change3 = CreateTextDocumentContentChangeEvent(startLine: 0, startCol: 1, endLine: 0, endCol: 3, newText: "test1"); + + Assert.True(DidChangeHandler.AreChangesInReverseOrder([change1, change2, change3])); + } + + [Fact] + public void DidChange_AreChangesInReverseOrder_InForwardOrder() + { + LSP.TextDocumentContentChangeEvent change1 = CreateTextDocumentContentChangeEvent(startLine: 0, startCol: 1, endLine: 0, endCol: 3, newText: "test1"); + LSP.TextDocumentContentChangeEvent change2 = CreateTextDocumentContentChangeEvent(startLine: 0, startCol: 5, endLine: 0, endCol: 7, newText: "test2"); + LSP.TextDocumentContentChangeEvent change3 = CreateTextDocumentContentChangeEvent(startLine: 0, startCol: 7, endLine: 0, endCol: 9, newText: "test3"); + + Assert.False(DidChangeHandler.AreChangesInReverseOrder([change1, change2, change3])); + } + + [Fact] + public void DidChange_AreChangesInReverseOrder_Overlapping() + { + LSP.TextDocumentContentChangeEvent change1 = CreateTextDocumentContentChangeEvent(startLine: 0, startCol: 1, endLine: 0, endCol: 3, newText: "test1"); + LSP.TextDocumentContentChangeEvent change2 = CreateTextDocumentContentChangeEvent(startLine: 0, startCol: 2, endLine: 0, endCol: 4, newText: "test2"); + LSP.TextDocumentContentChangeEvent change3 = CreateTextDocumentContentChangeEvent(startLine: 0, startCol: 3, endLine: 0, endCol: 5, newText: "test3"); + + Assert.False(DidChangeHandler.AreChangesInReverseOrder([change1, change2, change3])); + } + [Theory, CombinatorialData] public async Task DidChange_MultipleRequests(bool mutatingLspWorkspace) { @@ -368,7 +452,7 @@ void M() { var testLspServer = await CreateTestLspServerAsync(source, mutatingLspWorkspace, CapabilitiesWithVSExtensions); var locationTyped = testLspServer.GetLocations("type").Single(); - var documentText = await testLspServer.GetCurrentSolution().GetDocuments(locationTyped.Uri).Single().GetTextAsync(); + var documentText = await testLspServer.GetDocumentTextAsync(locationTyped.Uri); return (testLspServer, locationTyped, documentText.ToString()); } diff --git a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentOnTypeTests.cs b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentOnTypeTests.cs index 4da943682de44..1ee3fbc732ffe 100644 --- a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentOnTypeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentOnTypeTests.cs @@ -44,7 +44,7 @@ void M() await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var characterTyped = ";"; var locationTyped = testLspServer.GetLocations("type").Single(); - var documentText = await testLspServer.GetCurrentSolution().GetDocuments(locationTyped.Uri).Single().GetTextAsync(); + var documentText = await testLspServer.GetDocumentTextAsync(locationTyped.Uri); var results = await RunFormatDocumentOnTypeAsync(testLspServer, characterTyped, locationTyped); var actualText = ApplyTextEdits(results, documentText); @@ -75,7 +75,7 @@ void M() await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var characterTyped = ";"; var locationTyped = testLspServer.GetLocations("type").Single(); - var documentText = await testLspServer.GetCurrentSolution().GetDocuments(locationTyped.Uri).Single().GetTextAsync(); + var documentText = await testLspServer.GetDocumentTextAsync(locationTyped.Uri); var results = await RunFormatDocumentOnTypeAsync(testLspServer, characterTyped, locationTyped, insertSpaces: false, tabSize: 4); var actualText = ApplyTextEdits(results, documentText); diff --git a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentRangeTests.cs b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentRangeTests.cs index 70acb3ab8995a..7bc1a67e4d17c 100644 --- a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentRangeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentRangeTests.cs @@ -41,7 +41,7 @@ void M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var rangeToFormat = testLspServer.GetLocations("format").Single(); - var documentText = await testLspServer.GetCurrentSolution().GetDocuments(rangeToFormat.Uri).Single().GetTextAsync(); + var documentText = await testLspServer.GetDocumentTextAsync(rangeToFormat.Uri); var results = await RunFormatDocumentRangeAsync(testLspServer, rangeToFormat); var actualText = ApplyTextEdits(results, documentText); @@ -69,7 +69,7 @@ void M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var rangeToFormat = testLspServer.GetLocations("format").Single(); - var documentText = await testLspServer.GetCurrentSolution().GetDocuments(rangeToFormat.Uri).Single().GetTextAsync(); + var documentText = await testLspServer.GetDocumentTextAsync(rangeToFormat.Uri); var results = await RunFormatDocumentRangeAsync(testLspServer, rangeToFormat, insertSpaces: false, tabSize: 4); var actualText = ApplyTextEdits(results, documentText); diff --git a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs index bc85cdaf0a894..e4ae2a35b33cc 100644 --- a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs @@ -42,7 +42,7 @@ void M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var documentURI = testLspServer.GetLocations("caret").Single().Uri; - var documentText = await testLspServer.GetCurrentSolution().GetDocuments(documentURI).Single().GetTextAsync(); + var documentText = await testLspServer.GetDocumentTextAsync(documentURI); var results = await RunFormatDocumentAsync(testLspServer, documentURI); var actualText = ApplyTextEdits(results, documentText); @@ -70,7 +70,7 @@ void M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var documentURI = testLspServer.GetLocations("caret").Single().Uri; - var documentText = await testLspServer.GetCurrentSolution().GetDocuments(documentURI).Single().GetTextAsync(); + var documentText = await testLspServer.GetDocumentTextAsync(documentURI); var results = await RunFormatDocumentAsync(testLspServer, documentURI, insertSpaces: false, tabSize: 4); var actualText = ApplyTextEdits(results, documentText); @@ -98,7 +98,7 @@ void M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var documentURI = testLspServer.GetLocations("caret").Single().Uri; - var documentText = await testLspServer.GetCurrentSolution().GetDocuments(documentURI).Single().GetTextAsync(); + var documentText = await testLspServer.GetDocumentTextAsync(documentURI); var results = await RunFormatDocumentAsync(testLspServer, documentURI, insertSpaces: true, tabSize: 2); var actualText = ApplyTextEdits(results, documentText); diff --git a/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs index 86d9c2446c33e..71c0dce7b5aaa 100644 --- a/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs @@ -7,8 +7,10 @@ using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CommonLanguageServerProtocol.Framework; using Roslyn.LanguageServer.Protocol; @@ -32,7 +34,8 @@ public HandlerTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) typeof(TestNotificationHandlerFactory), typeof(TestNotificationWithoutParamsHandlerFactory), typeof(TestLanguageSpecificHandler), - typeof(TestLanguageSpecificHandlerWithDifferentParams)); + typeof(TestLanguageSpecificHandlerWithDifferentParams), + typeof(TestConfigurableDocumentHandler)); [Theory, CombinatorialData] public async Task CanExecuteRequestHandler(bool mutatingLspWorkspace) @@ -135,6 +138,130 @@ public async Task ShutsdownIfDeserializationFailsOnMutatingRequest(bool mutating await server.AssertServerShuttingDownAsync(); } + [Theory, CombinatorialData] + public async Task NonMutatingHandlerExceptionNFWIsReported(bool mutatingLspWorkspace) + { + await using var server = await CreateTestLspServerAsync("", mutatingLspWorkspace); + + var request = new TestRequestWithDocument(new TextDocumentIdentifier + { + Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs") + }); + + var didReport = false; + FatalError.OverwriteHandler((exception, severity, dumps) => + { + if (exception.Message == nameof(HandlerTests) || exception.InnerException.Message == nameof(HandlerTests)) + { + didReport = true; + } + }); + + var response = Task.FromException(new InvalidOperationException(nameof(HandlerTests))); + TestConfigurableDocumentHandler.ConfigureHandler(server, mutatesSolutionState: false, requiresLspSolution: true, response); + + await Assert.ThrowsAnyAsync(async () + => await server.ExecuteRequestAsync(TestConfigurableDocumentHandler.MethodName, request, CancellationToken.None)); + + var provider = server.TestWorkspace.ExportProvider.GetExportedValue(); + await provider.WaitAllDispatcherOperationAndTasksAsync( + server.TestWorkspace, + FeatureAttribute.LanguageServer); + + Assert.True(didReport); + } + + [Theory, CombinatorialData] + public async Task MutatingHandlerExceptionNFWIsReported(bool mutatingLspWorkspace) + { + var server = await CreateTestLspServerAsync("", mutatingLspWorkspace); + + var request = new TestRequestWithDocument(new TextDocumentIdentifier + { + Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs") + }); + + var didReport = false; + FatalError.OverwriteHandler((exception, severity, dumps) => + { + if (exception.Message == nameof(HandlerTests) || exception.InnerException.Message == nameof(HandlerTests)) + { + didReport = true; + } + }); + + var response = Task.FromException(new InvalidOperationException(nameof(HandlerTests))); + TestConfigurableDocumentHandler.ConfigureHandler(server, mutatesSolutionState: true, requiresLspSolution: true, response); + + await Assert.ThrowsAnyAsync(async () + => await server.ExecuteRequestAsync(TestConfigurableDocumentHandler.MethodName, request, CancellationToken.None)); + + await server.AssertServerShuttingDownAsync(); + + Assert.True(didReport); + } + + [Theory, CombinatorialData] + public async Task NonMutatingHandlerCancellationExceptionNFWIsNotReported(bool mutatingLspWorkspace) + { + await using var server = await CreateTestLspServerAsync("", mutatingLspWorkspace); + + var request = new TestRequestWithDocument(new TextDocumentIdentifier + { + Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs") + }); + + var didReport = false; + FatalError.OverwriteHandler((exception, severity, dumps) => + { + if (exception.Message == nameof(HandlerTests) || exception.InnerException.Message == nameof(HandlerTests)) + { + didReport = true; + } + }); + + var response = Task.FromException(new OperationCanceledException(nameof(HandlerTests))); + TestConfigurableDocumentHandler.ConfigureHandler(server, mutatesSolutionState: false, requiresLspSolution: true, response); + + await Assert.ThrowsAnyAsync(async () + => await server.ExecuteRequestAsync(TestConfigurableDocumentHandler.MethodName, request, CancellationToken.None)); + + var provider = server.TestWorkspace.ExportProvider.GetExportedValue(); + await provider.WaitAllDispatcherOperationAndTasksAsync( + server.TestWorkspace, + FeatureAttribute.LanguageServer); + + Assert.False(didReport); + } + + [Theory, CombinatorialData] + public async Task MutatingHandlerCancellationExceptionNFWIsNotReported(bool mutatingLspWorkspace) + { + await using var server = await CreateTestLspServerAsync("", mutatingLspWorkspace); + + var request = new TestRequestWithDocument(new TextDocumentIdentifier + { + Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs") + }); + + var didReport = false; + FatalError.OverwriteHandler((exception, severity, dumps) => + { + if (exception.Message == nameof(HandlerTests) || exception.InnerException.Message == nameof(HandlerTests)) + { + didReport = true; + } + }); + + var response = Task.FromException(new OperationCanceledException(nameof(HandlerTests))); + TestConfigurableDocumentHandler.ConfigureHandler(server, mutatesSolutionState: true, requiresLspSolution: true, response); + + await Assert.ThrowsAnyAsync(async () + => await server.ExecuteRequestAsync(TestConfigurableDocumentHandler.MethodName, request, CancellationToken.None)); + + Assert.False(didReport); + } + internal record TestRequestTypeOne([property: JsonPropertyName("textDocument"), JsonRequired] TextDocumentIdentifier TextDocumentIdentifier); internal record TestRequestTypeTwo([property: JsonPropertyName("textDocument"), JsonRequired] TextDocumentIdentifier TextDocumentIdentifier); diff --git a/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs b/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs index 402d309db5426..bea12674040c8 100644 --- a/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs @@ -263,7 +263,7 @@ Remarks are cool too\. var results = await RunGetHoverAsync( testLspServer, expectedLocation).ConfigureAwait(false); - Assert.Equal(expectedMarkdown, results.Contents.Value.Fourth.Value); + Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value); } [Theory, CombinatorialData] @@ -330,7 +330,7 @@ a string var results = await RunGetHoverAsync( testLspServer, expectedLocation).ConfigureAwait(false); - Assert.Equal(expectedText, results.Contents.Value.Fourth.Value); + Assert.Equal(expectedText, results.Contents.Fourth.Value); } [Theory, CombinatorialData] @@ -384,7 +384,7 @@ void A.AMethod(int i) var results = await RunGetHoverAsync( testLspServer, expectedLocation).ConfigureAwait(false); - Assert.Equal(expectedMarkdown, results.Contents.Value.Fourth.Value); + Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value); } [Theory, CombinatorialData] @@ -421,7 +421,49 @@ void A.AMethod(int i) var results = await RunGetHoverAsync( testLspServer, expectedLocation).ConfigureAwait(false); - Assert.Equal(expectedMarkdown, results.Contents.Value.Fourth.Value); + Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value); + } + + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/75181")] + public async Task TestGetHoverAsync_UsingMarkupContentDoesNotEscapeCodeBlock(bool mutatingLspWorkspace) + { + var markup = +@"class A +{ + /// + /// + /// if (true) { + /// Console.WriteLine(""hello""); + /// } + /// + /// + void {|caret:AMethod|}(int i) + { + } +}"; + var clientCapabilities = new LSP.ClientCapabilities + { + TextDocument = new LSP.TextDocumentClientCapabilities { Hover = new LSP.HoverSetting { ContentFormat = [LSP.MarkupKind.Markdown] } } + }; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, clientCapabilities); + var expectedLocation = testLspServer.GetLocations("caret").Single(); + + var expectedMarkdown = @"```csharp +void A.AMethod(int i) +``` + + +```text +if (true) { + Console.WriteLine(""hello""); +} +``` +"; + + var results = await RunGetHoverAsync( + testLspServer, + expectedLocation).ConfigureAwait(false); + Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/vscode-csharp/issues/6577")] @@ -449,7 +491,7 @@ public async Task DoAsync() var results = await RunGetHoverAsync( testLspServer, expectedLocation).ConfigureAwait(false); - Assert.Equal(expectedMarkdown, results.Contents.Value.Fourth.Value); + Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value); } private static async Task RunGetHoverAsync( diff --git a/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs b/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs index cf44a18869abb..b709ade88f520 100644 --- a/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs @@ -248,8 +248,6 @@ void M() await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var locationTyped = testLspServer.GetLocations("tab").Single(); - var document = testLspServer.GetCurrentSolution().GetDocuments(locationTyped.Uri).Single(); - // Verify we haven't parsed snippets until asked. var snippetParser = testLspServer.TestWorkspace.ExportProvider.GetExportedValue(); Assert.Equal(0, snippetParser.GetTestAccessor().GetCachedSnippetsCount()); @@ -273,7 +271,7 @@ private async Task VerifyMarkupAndExpected(string markup, string expected, bool await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var locationTyped = testLspServer.GetLocations("tab").Single(); - var document = testLspServer.GetCurrentSolution().GetDocuments(locationTyped.Uri).Single(); + var document = testLspServer.GetDocumentAsync(locationTyped.Uri); var result = await GetInlineCompletionsAsync(testLspServer, locationTyped, options ?? new LSP.FormattingOptions { InsertSpaces = true, TabSize = 4 }); diff --git a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs index bc094576d5ddb..e48b9fdc934f0 100644 --- a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs @@ -121,7 +121,7 @@ static void Main(string[] args) var textDocumentEdits = results.DocumentChanges!.Value.First.Single(); Assert.Equal(textDocumentEdits.TextDocument.Uri, mapCodeParams.Mappings.Single().TextDocument!.Uri); - edits = textDocumentEdits.Edits; + edits = textDocumentEdits.Edits.Select(e => e.Unify()).ToArray(); } else { diff --git a/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs b/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs new file mode 100644 index 0000000000000..36e37923ab780 --- /dev/null +++ b/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs @@ -0,0 +1,140 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.MetadataAsSource; +using Roslyn.Test.Utilities; +using Roslyn.Utilities; +using Xunit; +using Xunit.Abstractions; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.Metadata; + +public sealed class LspMetadataAsSourceWorkspaceTests : AbstractLanguageServerProtocolTests +{ + public LspMetadataAsSourceWorkspaceTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) + { + } + + [Theory, CombinatorialData] + public async Task TestMetadataFile_OpenClosed(bool mutatingLspWorkspace) + { + var source = + """ + using System; + class A + { + void M() + { + Console.{|definition:WriteLine|}("Hello, World!"); + } + } + """; + + // Create a server with LSP misc file workspace and metadata service. + await using var testLspServer = await CreateTestLspServerAsync(source, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); + + // Get the metadata definition. + var location = testLspServer.GetLocations("definition").Single(); + var definition = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentDefinitionName, + CreateTextDocumentPositionParams(location), CancellationToken.None); + + // Open the metadata file and verify it gets added to the metadata workspace. + await testLspServer.OpenDocumentAsync(definition.Single().Uri, text: string.Empty).ConfigureAwait(false); + + Assert.Equal(WorkspaceKind.MetadataAsSource, (await GetWorkspaceForDocument(testLspServer, definition.Single().Uri)).Kind); + AssertMiscFileWorkspaceEmpty(testLspServer); + + // Close the metadata file and verify it gets removed from the metadata workspace. + await testLspServer.CloseDocumentAsync(definition.Single().Uri).ConfigureAwait(false); + + AssertMetadataFileWorkspaceEmpty(testLspServer); + } + + [Theory, CombinatorialData] + public async Task TestMetadataFile_LanguageFeatures(bool mutatingLspWorkspace) + { + var source = + """ + using System; + class A + { + void M() + { + Console.{|definition:WriteLine|}("Hello, World!"); + } + } + """; + + var metadataSource = + """ + namespace System + { + public class Console + { + public static void WriteLine(string value) {} + } + } + """; + + // Create a server with LSP misc file workspace and metadata service. + await using var testLspServer = await CreateTestLspServerAsync(source, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); + + // Get the metadata definition. + var location = testLspServer.GetLocations("definition").Single(); + var definition = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentDefinitionName, + CreateTextDocumentPositionParams(location), CancellationToken.None); + + // Open the metadata file and verify it gets added to the metadata workspace. + // We don't have the real metadata source, so just populate it with our fake metadata source. + await testLspServer.OpenDocumentAsync(definition.Single().Uri, text: metadataSource).ConfigureAwait(false); + var workspaceForDocument = await GetWorkspaceForDocument(testLspServer, definition.Single().Uri); + Assert.Equal(WorkspaceKind.MetadataAsSource, workspaceForDocument.Kind); + AssertMiscFileWorkspaceEmpty(testLspServer); + + // Manually register the workspace for followup requests - the workspace event listener that + // normally registers it on creation is not running in test code. + testLspServer.TestWorkspace.ExportProvider.GetExportedValue().Register(workspaceForDocument); + + var locationOfStringKeyword = new LSP.Location + { + Uri = definition.Single().Uri, + Range = new LSP.Range + { + Start = new LSP.Position { Line = 4, Character = 40 }, + End = new LSP.Position { Line = 4, Character = 40 } + } + }; + + var definitionFromMetadata = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentDefinitionName, + CreateTextDocumentPositionParams(locationOfStringKeyword), CancellationToken.None); + + Assert.NotNull(definitionFromMetadata); + Assert.NotEmpty(definitionFromMetadata); + Assert.Contains("String.cs", definitionFromMetadata.Single().Uri.LocalPath); + } + + private static async Task GetWorkspaceForDocument(TestLspServer testLspServer, Uri fileUri) + { + var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = fileUri }, CancellationToken.None); + return lspWorkspace!; + } + + private static void AssertMiscFileWorkspaceEmpty(TestLspServer testLspServer) + { + var doc = testLspServer.GetManagerAccessor().GetLspMiscellaneousFilesWorkspace()!.CurrentSolution.Projects.SingleOrDefault()?.Documents.SingleOrDefault(); + Assert.Null(doc); + } + + private static void AssertMetadataFileWorkspaceEmpty(TestLspServer testLspServer) + { + var provider = testLspServer.TestWorkspace.ExportProvider.GetExportedValue(); + var metadataDocument = provider.TryGetWorkspace()?.CurrentSolution.Projects.SingleOrDefault()?.Documents.SingleOrDefault(); + Assert.Null(metadataDocument); + } +} diff --git a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs index 8374320d9f140..be2a76a84c976 100644 --- a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs @@ -76,7 +76,7 @@ void M() await testLspServer.InsertTextAsync(looseFileUri, (0, 0, source)).ConfigureAwait(false); var caret = new LSP.Location { Range = new() { Start = new(0, 6), End = new(0, 7) }, Uri = looseFileUri }; var hover = await RunGetHoverAsync(testLspServer, caret).ConfigureAwait(false); - Assert.Contains("class A", hover.Contents!.Value.Fourth.Value); + Assert.Contains("class A", hover.Contents.Fourth.Value); await AssertFileInMiscWorkspaceAsync(testLspServer, looseFileUri).ConfigureAwait(false); // Assert that the misc workspace contains the updated document. diff --git a/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs b/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs index 8d486e0c11af7..c0d60cc1c5588 100644 --- a/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs @@ -404,7 +404,7 @@ private async Task VerifyMarkupAndExpected( await using var testLspServer = await testLspServerTask; var locationTyped = testLspServer.GetLocations("type").Single(); - var document = testLspServer.GetCurrentSolution().GetDocuments(locationTyped.Uri).Single(); + var document = await testLspServer.GetDocumentAsync(locationTyped.Uri); var documentText = await document.GetTextAsync(); var result = await RunOnAutoInsertAsync(testLspServer, characterTyped, locationTyped, insertSpaces, tabSize); @@ -419,7 +419,7 @@ private async Task VerifyNoResult(string characterTyped, string markup, bool mut { await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var locationTyped = testLspServer.GetLocations("type").Single(); - var documentText = await testLspServer.GetCurrentSolution().GetDocuments(locationTyped.Uri).Single().GetTextAsync(); + var documentText = await (await testLspServer.GetDocumentAsync(locationTyped.Uri)).GetTextAsync(); var result = await RunOnAutoInsertAsync(testLspServer, characterTyped, locationTyped, insertSpaces, tabSize); diff --git a/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs b/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs index a9d20fa0ccee6..d093833d00971 100644 --- a/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs @@ -167,27 +167,6 @@ public void CreateAbsoluteUri_Urls(string url) Assert.Equal(url, ProtocolConversions.CreateAbsoluteUri(url).AbsoluteUri); } - [ConditionalTheory(typeof(WindowsOnly))] - [InlineData("a\\b", "source-generated:///a/b")] - [InlineData("a//b", "source-generated:///a//b")] - [InlineData("a/b", "source-generated:///a/b")] - [InlineData("%25\ue25b//\u0089\uC7BD/a", "source-generated:///%2525%EE%89%9B//%C2%89%EC%9E%BD/a")] - [InlineData("%25\ue25b\\\u0089\uC7BD", "source-generated:///%2525%EE%89%9B/%C2%89%EC%9E%BD")] - public void GetUriFromSourceGeneratedFilePath_Windows(string filePath, string expectedAbsoluteUri) - { - var url = ProtocolConversions.CreateUriFromSourceGeneratedFilePath(filePath); - Assert.Equal(expectedAbsoluteUri, url.AbsoluteUri); - } - - [ConditionalTheory(typeof(UnixLikeOnly))] - [InlineData("a/b", "source-generated:///a/b")] - [InlineData("%25\ue25b/\u0089\uC7BD", "source-generated:///%2525%EE%89%9B/%C2%89%EC%9E%BD")] - public void GetUriFromSourceGeneratedFilePath_Unix(string filePath, string expectedAbsoluteUri) - { - var url = ProtocolConversions.CreateUriFromSourceGeneratedFilePath(filePath); - Assert.Equal(expectedAbsoluteUri, url.AbsoluteUri); - } - [Fact] public void CompletionItemKind_DoNotUseMethodAndFunction() { diff --git a/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerFeaturesTests.cs b/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerFeaturesTests.cs index d0b34c6580445..8fda99724efe7 100644 --- a/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerFeaturesTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerFeaturesTests.cs @@ -12,12 +12,9 @@ using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.References; -public class FindAllReferencesHandlerFeaturesTests : AbstractLanguageServerProtocolTests +public sealed class FindAllReferencesHandlerFeaturesTests(ITestOutputHelper? testOutputHelper) + : AbstractLanguageServerProtocolTests(testOutputHelper) { - public FindAllReferencesHandlerFeaturesTests(ITestOutputHelper? testOutputHelper) : base(testOutputHelper) - { - } - protected override TestComposition Composition => LspTestCompositions.LanguageServerProtocol .AddParts(typeof(TestDocumentTrackingService)) .AddParts(typeof(TestWorkspaceRegistrationService)); @@ -26,25 +23,143 @@ public FindAllReferencesHandlerFeaturesTests(ITestOutputHelper? testOutputHelper public async Task TestFindAllReferencesAsync_DoesNotUseVSTypes(bool mutatingLspWorkspace) { var markup = -@"class A -{ - public int {|reference:someInt|} = 1; - void M() - { - var i = {|reference:someInt|} + 1; + """ + class A + { + public int {|reference:someInt|} = 1; + void M() + { + var i = {|reference:someInt|} + 1; + } + } + class B + { + int someInt = A.{|reference:someInt|} + 1; + void M2() + { + var j = someInt + A.{|caret:|}{|reference:someInt|}; + } + } + """; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, new LSP.ClientCapabilities()); + + var results = await FindAllReferencesHandlerTests.RunFindAllReferencesNonVSAsync(testLspServer, testLspServer.GetLocations("caret").First()); + AssertLocationsEqual(testLspServer.GetLocations("reference"), results.Select(result => result)); } -} -class B -{ - int someInt = A.{|reference:someInt|} + 1; - void M2() + + [Theory, CombinatorialData] + public async Task TestFindAllReferencesAsync_LargeNumberOfReferences(bool mutatingLspWorkspace) { - var j = someInt + A.{|caret:|}{|reference:someInt|}; - } -}"; + var markup = + """ + using System.Threading.Tasks + class A + { + private {|caret:Task|} someTask = Task.CompletedTask; + } + """; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, new LSP.ClientCapabilities()); + for (var i = 0; i < 100; i++) + { + var source = $$""" + using System.Threading.Tasks + class SomeClass{{i}} + { + private Task someTask; + } + """; + + var testDocument = new EditorTestHostDocument(text: source, displayName: @$"C:\SomeFile{i}.cs", exportProvider: testLspServer.TestWorkspace.ExportProvider, filePath: @$"C:\SomeFile{i}.cs"); + testLspServer.TestWorkspace.AddTestProject(new EditorTestHostProject(testLspServer.TestWorkspace, documents: [testDocument])); + } + + await WaitForWorkspaceOperationsAsync(testLspServer.TestWorkspace); + var results = await FindAllReferencesHandlerTests.RunFindAllReferencesNonVSAsync(testLspServer, testLspServer.GetLocations("caret").First()); - AssertLocationsEqual(testLspServer.GetLocations("reference"), results.Select(result => result)); + Assert.Equal(103, results.Length); + } + + [Theory, CombinatorialData] + public async Task TestFindAllReferencesAsync_LinkedFile(bool mutatingLspWorkspace, [CombinatorialRange(0, 10)] int iteration) + { + _ = iteration; + var markup = + """ + using System.Threading.Tasks + class A + { + private void SomeMethod() + { + Do({|caret:Task|}.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + Do(Task.CompletedTask); + } + } + """; + + var workspaceXml = + $""" + + + {markup} + + + + + + """; + + await using var testLspServer = await CreateXmlTestLspServerAsync(workspaceXml, mutatingLspWorkspace, initializationOptions: new InitializationOptions + { + ClientCapabilities = new LSP.ClientCapabilities() + }); + + await WaitForWorkspaceOperationsAsync(testLspServer.TestWorkspace); + + var results = await FindAllReferencesHandlerTests.RunFindAllReferencesNonVSAsync(testLspServer, testLspServer.GetLocations("caret").First()); + Assert.Equal(46, results.Length); } } diff --git a/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs b/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs new file mode 100644 index 0000000000000..2cc292339e553 --- /dev/null +++ b/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs @@ -0,0 +1,177 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Roslyn.LanguageServer.Protocol; +using Roslyn.Test.Utilities; +using Roslyn.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.RelatedDocuments; + +public sealed class RelatedDocumentsTests(ITestOutputHelper testOutputHelper) + : AbstractLanguageServerProtocolTests(testOutputHelper) +{ + private static async Task RunGetRelatedDocumentsAsync( + TestLspServer testLspServer, + Uri uri, + bool useProgress = false) + { + BufferedProgress? progress = useProgress ? BufferedProgress.Create(null) : null; + var spans = await testLspServer.ExecuteRequestAsync( + VSInternalMethods.CopilotRelatedDocumentsName, + new VSInternalRelatedDocumentParams + { + TextDocument = new TextDocumentIdentifier { Uri = uri }, + PartialResultToken = progress, + }, + CancellationToken.None).ConfigureAwait(false); + + if (useProgress) + { + Assert.Null(spans); + spans = progress!.Value.GetFlattenedValues(); + } + + AssertEx.NotNull(spans); + return spans; + } + + [Theory, CombinatorialData] + public async Task ReferenceNoDocuments(bool mutatingLspWorkspace, bool useProgress) + { + var markup1 = """ + class X + { + } + """; + + var markup2 = """ + class Y + { + } + """; + + await using var testLspServer = await CreateTestLspServerAsync([markup1, markup2], mutatingLspWorkspace); + + var project = testLspServer.TestWorkspace.CurrentSolution.Projects.Single(); + var results = await RunGetRelatedDocumentsAsync( + testLspServer, + project.Documents.First().GetURI(), + useProgress: useProgress); + + Assert.Equal(0, results.Length); + } + + [Theory, CombinatorialData] + public async Task ReferenceSingleOtherDocument(bool mutatingLspWorkspace, bool useProgress) + { + var markup1 = """ + class X + { + Y y; + } + """; + + var markup2 = """ + class Y + { + } + """; + + await using var testLspServer = await CreateTestLspServerAsync([markup1, markup2], mutatingLspWorkspace); + + var project = testLspServer.TestWorkspace.CurrentSolution.Projects.Single(); + var results = await RunGetRelatedDocumentsAsync( + testLspServer, + project.Documents.First().GetURI(), + useProgress: useProgress); + + Assert.Equal(1, results.Length); + Assert.Equal(project.Documents.Last().FilePath, results[0].FilePaths.Single()); + } + + [Theory, CombinatorialData] + public async Task ReferenceMultipleOtherDocument(bool mutatingLspWorkspace, bool useProgress) + { + var markup1 = """ + class X + { + Y y; + Z z; + } + """; + + var markup2 = """ + class Y + { + } + """; + + var markup3 = """ + class Z + { + } + """; + + await using var testLspServer = await CreateTestLspServerAsync([markup1, markup2, markup3], mutatingLspWorkspace); + + var project = testLspServer.TestWorkspace.CurrentSolution.Projects.Single(); + var results = await RunGetRelatedDocumentsAsync( + testLspServer, + project.Documents.First().GetURI(), + useProgress: useProgress); + + Assert.Equal(2, results.SelectMany(r => r.FilePaths).Count()); + AssertEx.SetEqual([.. project.Documents.Skip(1).Select(d => d.FilePath)], results.SelectMany(r => r.FilePaths)); + } + + [Theory, CombinatorialData] + public async Task TestRepeatInvocations(bool mutatingLspWorkspace, bool useProgress) + { + var markup1 = """ + class X + { + Y y; + } + """; + + var markup2 = """ + class Y + { + } + """; + + await using var testLspServer = await CreateTestLspServerAsync([markup1, markup2], mutatingLspWorkspace); + + var project = testLspServer.TestWorkspace.CurrentSolution.Projects.Single(); + var results1 = await RunGetRelatedDocumentsAsync( + testLspServer, + project.Documents.First().GetURI(), + useProgress: useProgress); + + var expectedResult = new VSInternalRelatedDocumentReport[] + { + new() + { + FilePaths = [project.Documents.Last().FilePath!], + } + }; + + AssertJsonEquals(results1, expectedResult); + + // Calling again, without a change, should return the old result id and no filepaths. + var results2 = await RunGetRelatedDocumentsAsync( + testLspServer, + project.Documents.First().GetURI(), + useProgress: useProgress); + + AssertJsonEquals(results2, expectedResult); + } +} diff --git a/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs b/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs index 6a7550ab424e0..68c71fadb2528 100644 --- a/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs @@ -182,8 +182,8 @@ void M2() var documentEdit = results.DocumentChanges.Value.First.Single(); Assert.Equal(expectedMappedDocument, documentEdit.TextDocument.Uri); - Assert.Equal(expectedMappedRanges, documentEdit.Edits.Select(edit => edit.Range)); - Assert.True(documentEdit.Edits.All(edit => edit.NewText == renameText)); + Assert.Equal(expectedMappedRanges, documentEdit.Edits.Select(edit => edit.Unify().Range)); + Assert.True(documentEdit.Edits.All(edit => edit.Unify().NewText == renameText)); } private static LSP.RenameParams CreateRenameParams(LSP.Location location, string newName) diff --git a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs index 775d6669a6b43..4f882cdbe5239 100644 --- a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs @@ -18,11 +18,9 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.SpellCheck { - public class SpellCheckTests : AbstractLanguageServerProtocolTests + public sealed class SpellCheckTests(ITestOutputHelper testOutputHelper) + : AbstractLanguageServerProtocolTests(testOutputHelper) { - public SpellCheckTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) - { - } #region Document @@ -337,7 +335,7 @@ public async Task TestWorkspaceResultsForClosedFiles(bool mutatingLspWorkspace) { }"; var markup2 = ""; - await using var testLspServer = await CreateTestLspServerAsync(new[] { markup1, markup2 }, mutatingLspWorkspace); + await using var testLspServer = await CreateTestLspServerAsync([markup1, markup2], mutatingLspWorkspace); var results = await RunGetWorkspaceSpellCheckSpansAsync(testLspServer); @@ -351,7 +349,7 @@ public async Task TestWorkspaceResultsForClosedFiles(bool mutatingLspWorkspace) ResultId = "WorkspaceSpellCheckHandler:0", Ranges = GetRanges(testLspServer.TestWorkspace.Documents.First().AnnotatedSpans), }); - Assert.Empty(results[1].Ranges); + AssertEx.Empty(results[1].Ranges); } [Theory, CombinatorialData] @@ -410,7 +408,7 @@ public async Task TestWorkspaceResultsForRemovedDocument(bool mutatingLspWorkspa { }"; var markup2 = ""; - await using var testLspServer = await CreateTestLspServerAsync(new[] { markup1, markup2 }, mutatingLspWorkspace); + await using var testLspServer = await CreateTestLspServerAsync([markup1, markup2], mutatingLspWorkspace); var results = await RunGetWorkspaceSpellCheckSpansAsync(testLspServer); @@ -424,7 +422,7 @@ public async Task TestWorkspaceResultsForRemovedDocument(bool mutatingLspWorkspa ResultId = "WorkspaceSpellCheckHandler:0", Ranges = GetRanges(testLspServer.TestWorkspace.Documents.First().AnnotatedSpans), }); - Assert.Empty(results[1].Ranges); + AssertEx.Empty(results[1].Ranges); testLspServer.TestWorkspace.OnDocumentRemoved(testLspServer.TestWorkspace.Documents.First().Id); @@ -436,7 +434,7 @@ public async Task TestWorkspaceResultsForRemovedDocument(bool mutatingLspWorkspa Assert.Null(results2[0].ResultId); // Second doc should be unchanged - Assert.Empty(results[1].Ranges); + AssertEx.Empty(results[1].Ranges); Assert.Equal(results[1].ResultId, results2[1].ResultId); } @@ -448,7 +446,7 @@ public async Task TestNoChangeIfWorkspaceResultsCalledTwice(bool mutatingLspWork { }"; var markup2 = ""; - await using var testLspServer = await CreateTestLspServerAsync(new[] { markup1, markup2 }, mutatingLspWorkspace); + await using var testLspServer = await CreateTestLspServerAsync([markup1, markup2], mutatingLspWorkspace); var results = await RunGetWorkspaceSpellCheckSpansAsync(testLspServer); @@ -462,7 +460,7 @@ public async Task TestNoChangeIfWorkspaceResultsCalledTwice(bool mutatingLspWork ResultId = "WorkspaceSpellCheckHandler:0", Ranges = GetRanges(testLspServer.TestWorkspace.Documents.First().AnnotatedSpans), }); - Assert.Empty(results[1].Ranges); + AssertEx.Empty(results[1].Ranges); var results2 = await RunGetWorkspaceSpellCheckSpansAsync(testLspServer, previousResults: CreateParamsFromPreviousReports(results)); @@ -484,7 +482,7 @@ public async Task TestWorkspaceResultUpdatedAfterEdit(bool mutatingLspWorkspace) "; var markup2 = ""; - await using var testLspServer = await CreateTestLspServerAsync(new[] { markup1, markup2 }, mutatingLspWorkspace); + await using var testLspServer = await CreateTestLspServerAsync([markup1, markup2], mutatingLspWorkspace); var results = await RunGetWorkspaceSpellCheckSpansAsync(testLspServer); @@ -498,7 +496,7 @@ public async Task TestWorkspaceResultUpdatedAfterEdit(bool mutatingLspWorkspace) ResultId = "WorkspaceSpellCheckHandler:0", Ranges = GetRanges(testLspServer.TestWorkspace.Documents.First().AnnotatedSpans), }); - Assert.Empty(results[1].Ranges); + AssertEx.Empty(results[1].Ranges); var buffer = testLspServer.TestWorkspace.Documents.First().GetTextBuffer(); buffer.Insert(buffer.CurrentSnapshot.Length, "// comment"); @@ -537,7 +535,7 @@ public async Task TestStreamingWorkspaceResults(bool mutatingLspWorkspace) { }"; var markup2 = ""; - await using var testLspServer = await CreateTestLspServerAsync(new[] { markup1, markup2 }, mutatingLspWorkspace); + await using var testLspServer = await CreateTestLspServerAsync([markup1, markup2], mutatingLspWorkspace); var results = await RunGetWorkspaceSpellCheckSpansAsync(testLspServer); @@ -551,7 +549,7 @@ public async Task TestStreamingWorkspaceResults(bool mutatingLspWorkspace) ResultId = "WorkspaceSpellCheckHandler:0", Ranges = GetRanges(testLspServer.TestWorkspace.Documents.First().AnnotatedSpans), }); - Assert.Empty(results[1].Ranges); + AssertEx.Empty(results[1].Ranges); results = await RunGetWorkspaceSpellCheckSpansAsync(testLspServer, CreateParamsFromPreviousReports(results), useProgress: true); diff --git a/src/LanguageServer/ProtocolUnitTests/Symbols/DocumentSymbolsTests.cs b/src/LanguageServer/ProtocolUnitTests/Symbols/DocumentSymbolsTests.cs index 738c127bcc2be..b7c02a130b7ae 100644 --- a/src/LanguageServer/ProtocolUnitTests/Symbols/DocumentSymbolsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Symbols/DocumentSymbolsTests.cs @@ -48,7 +48,11 @@ public async Task TestGetDocumentSymbolsAsync(bool mutatingLspWorkspace) CreateDocumentSymbol(LSP.SymbolKind.Method, "M", "M()", testLspServer.GetLocations("method").Single(), testLspServer.GetLocations("methodSelection").Single(), expected.First()); var results = await RunGetDocumentSymbolsAsync(testLspServer); - AssertJsonEquals(expected, results); + Assert.Equal(expected.Length, results.Length); + for (var i = 0; i < results.Length; i++) + { + AssertDocumentSymbolEquals(expected[i], results[i]); + } } [Theory, CombinatorialData] @@ -61,7 +65,7 @@ public async Task TestGetDocumentSymbolsAsync_WithoutHierarchicalSupport(bool mu { } }"; - await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, CapabilitiesWithVSExtensions); var expected = new LSP.SymbolInformation[] { CreateSymbolInformation(LSP.SymbolKind.Class, "A", testLspServer.GetLocations("class").Single(), Glyph.ClassInternal), @@ -101,7 +105,9 @@ public class await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var results = await RunGetDocumentSymbolsAsync(testLspServer).ConfigureAwait(false); +#pragma warning disable CS0618 // Type or member is obsolete Assert.Equal(".", results.First().Name); +#pragma warning restore CS0618 } [Theory, CombinatorialData] @@ -126,7 +132,10 @@ public class await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, clientCapabilities); var results = await RunGetDocumentSymbolsAsync(testLspServer).ConfigureAwait(false); +#pragma warning disable CS0618 // Type or member is obsolete + Assert.Equal(".", results.First().Name); +#pragma warning restore CS0618 } [Theory, CombinatorialData] @@ -172,7 +181,9 @@ private static LSP.DocumentSymbol CreateDocumentSymbol(LSP.SymbolKind kind, stri Range = location.Range, Children = new LSP.DocumentSymbol[0], Detail = detail, +#pragma warning disable 618 // obsolete member Deprecated = false, +#pragma warning restore 618 SelectionRange = selection.Range }; diff --git a/src/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs b/src/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs index 11db567b17042..3a90b5d341ab6 100644 --- a/src/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs @@ -72,13 +72,13 @@ void M() CreateSymbolInformation(LSP.SymbolKind.Class, "A", testLspServer.GetLocations("class").Single(), Glyph.ClassInternal, GetContainerName(testLspServer.GetCurrentSolution())) }; - using var progress = BufferedProgress.Create(null); + using var progress = BufferedProgress.Create>(null); var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "A", progress).ConfigureAwait(false); Assert.Null(results); - results = progress.GetFlattenedValues(); + results = progress.GetValues()?.SelectMany(v => v.First).ToArray(); AssertSetEquals(expected, results); } @@ -208,7 +208,7 @@ void M() await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "NonExistingSymbol").ConfigureAwait(false); - Assert.Empty(results); + AssertEx.Empty(results); } [Theory, CombinatorialData] @@ -231,7 +231,7 @@ End Class AssertSetEquals(expected, results); } - private static Task RunGetWorkspaceSymbolsAsync(TestLspServer testLspServer, string query, IProgress? progress = null) + private static Task RunGetWorkspaceSymbolsAsync(TestLspServer testLspServer, string query, IProgress>? progress = null) { var request = new LSP.WorkspaceSymbolParams { diff --git a/src/LanguageServer/ProtocolUnitTests/TestConfigurableDocumentHandler.cs b/src/LanguageServer/ProtocolUnitTests/TestConfigurableDocumentHandler.cs new file mode 100644 index 0000000000000..30c853f44cc77 --- /dev/null +++ b/src/LanguageServer/ProtocolUnitTests/TestConfigurableDocumentHandler.cs @@ -0,0 +1,67 @@ +// 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.Text.Json.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CommonLanguageServerProtocol.Framework; +using Roslyn.LanguageServer.Protocol; +using Roslyn.Utilities; +using static Roslyn.Test.Utilities.AbstractLanguageServerProtocolTests; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; + +internal record TestRequestWithDocument([property: JsonPropertyName("textDocument"), JsonRequired] TextDocumentIdentifier TextDocumentIdentifier); + +internal record TestConfigurableResponse([property: JsonPropertyName("response"), JsonRequired] string Response); + +[ExportCSharpVisualBasicStatelessLspService(typeof(TestConfigurableDocumentHandler)), PartNotDiscoverable, Shared] +[LanguageServerEndpoint(MethodName, LanguageServerConstants.DefaultLanguageName)] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class TestConfigurableDocumentHandler() : ILspServiceDocumentRequestHandler +{ + public const string MethodName = nameof(TestConfigurableDocumentHandler); + + private bool? _mutatesSolutionState; + private bool? _requiresLSPSolution; + private Task? _response; + + public bool MutatesSolutionState => _mutatesSolutionState ?? throw new InvalidOperationException($"{nameof(ConfigureHandler)} has not been called"); + public bool RequiresLSPSolution => _requiresLSPSolution ?? throw new InvalidOperationException($"{nameof(ConfigureHandler)} has not been called"); + + public void ConfigureHandler(bool mutatesSolutionState, bool requiresLspSolution, Task response) + { + if (_mutatesSolutionState is not null || _requiresLSPSolution is not null || _response is not null) + { + throw new InvalidOperationException($"{nameof(ConfigureHandler)} has already been called"); + } + + _mutatesSolutionState = mutatesSolutionState; + _requiresLSPSolution = requiresLspSolution; + _response = response; + } + + public TextDocumentIdentifier GetTextDocumentIdentifier(TestRequestWithDocument request) + { + return request.TextDocumentIdentifier; + } + + public Task HandleRequestAsync(TestRequestWithDocument request, RequestContext context, CancellationToken cancellationToken) + { + Contract.ThrowIfNull(_response, $"{nameof(ConfigureHandler)} has not been called"); + return _response; + } + + public static void ConfigureHandler(TestLspServer server, bool mutatesSolutionState, bool requiresLspSolution, Task response) + { + var handler = (TestConfigurableDocumentHandler)server.GetQueueAccessor()!.Value.GetHandlerProvider().GetMethodHandler(TestConfigurableDocumentHandler.MethodName, + TypeRef.From(typeof(TestRequestWithDocument)), TypeRef.From(typeof(TestConfigurableResponse)), LanguageServerConstants.DefaultLanguageName); + handler.ConfigureHandler(mutatesSolutionState, requiresLspSolution, response); + } +} diff --git a/src/LanguageServer/ProtocolUnitTests/UriTests.cs b/src/LanguageServer/ProtocolUnitTests/UriTests.cs index 96a748f5bb508..8ad1df6cca445 100644 --- a/src/LanguageServer/ProtocolUnitTests/UriTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/UriTests.cs @@ -3,9 +3,16 @@ // See the LICENSE file in the project root for more information. using System; +using System.Composition; using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CommonLanguageServerProtocol.Framework; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -18,6 +25,8 @@ public UriTests(ITestOutputHelper? testOutputHelper) : base(testOutputHelper) { } + protected override TestComposition Composition => base.Composition.AddParts(typeof(CustomResolveHandler)); + [Theory, CombinatorialData] [WorkItem("https://github.com/dotnet/runtime/issues/89538")] public async Task TestMiscDocument_WithFileScheme(bool mutatingLspWorkspace) @@ -150,4 +159,159 @@ public async Task TestWorkspaceDocument_WithFileAndGitScheme(bool mutatingLspWor Assert.Equal(gitDocumentUri, gitDocument.GetURI()); Assert.Equal(gitDocumentText, gitText.ToString()); } + + [Theory, CombinatorialData] + public async Task TestFindsExistingDocumentWhenUriHasDifferentEncodingAsync(bool mutatingLspWorkspace) + { + await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); + + // Execute the request as JSON directly to avoid the test client serializing System.Uri using the encoded Uri to send to the server. + var requestJson = """ + { + "textDocument": { + "uri": "git:/c:/Users/dabarbet/source/repos/ConsoleApp10/ConsoleApp10/Program.cs?{{\"path\":\"c:\\\\Users\\\\dabarbet\\\\source\\\\repos\\\\ConsoleApp10\\\\ConsoleApp10\\\\Program.cs\",\"ref\":\"~\"}}", + "languageId": "csharp", + "text": "LSP text" + } + } + """; + var jsonDocument = JsonDocument.Parse(requestJson); + await testLspServer.ExecutePreSerializedRequestAsync(LSP.Methods.TextDocumentDidOpenName, jsonDocument); + + // Retrieve the URI from the json - this is the unencoded (and not JSON escaped) version of the URI. + var unencodedUri = JsonSerializer.Deserialize(jsonDocument, JsonSerializerOptions)!.TextDocument.Uri; + + // Access the document using the unencoded URI to make sure we find it in the C# misc files. + var (workspace, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = unencodedUri }, CancellationToken.None).ConfigureAwait(false); + AssertEx.NotNull(lspDocument); + Assert.Equal(WorkspaceKind.MiscellaneousFiles, workspace?.Kind); + Assert.Equal(LanguageNames.CSharp, lspDocument.Project.Language); + var originalText = await lspDocument.GetTextAsync(CancellationToken.None); + Assert.Equal("LSP text", originalText.ToString()); + + // Now make a request using the encoded document to ensure the server is able to find the document in misc C# files. + var encodedUriString = @"git:/c:/Users/dabarbet/source/repos/ConsoleApp10/ConsoleApp10/Program.cs?%7B%7B%22path%22:%22c:%5C%5CUsers%5C%5Cdabarbet%5C%5Csource%5C%5Crepos%5C%5CConsoleApp10%5C%5CConsoleApp10%5C%5CProgram.cs%22,%22ref%22:%22~%22%7D%7D"; +#pragma warning disable RS0030 // Do not use banned APIs + var encodedUri = new Uri(encodedUriString, UriKind.Absolute); +#pragma warning restore RS0030 // Do not use banned APIs + var info = await testLspServer.ExecuteRequestAsync(CustomResolveHandler.MethodName, + new CustomResolveParams(new LSP.TextDocumentIdentifier { Uri = encodedUri }), CancellationToken.None); + Assert.Equal(WorkspaceKind.MiscellaneousFiles, workspace?.Kind); + Assert.Equal(LanguageNames.CSharp, lspDocument.Project.Language); + + var (encodedWorkspace, _, encodedDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = encodedUri }, CancellationToken.None).ConfigureAwait(false); + Assert.Same(workspace, encodedWorkspace); + AssertEx.NotNull(encodedDocument); + Assert.Equal(LanguageNames.CSharp, encodedDocument.Project.Language); + var encodedText = await encodedDocument.GetTextAsync(CancellationToken.None); + Assert.Equal("LSP text", encodedText.ToString()); + + // The text we get back should be the exact same instance that was originally saved by the unencoded request. + Assert.Same(originalText, encodedText); + } + + [Theory, CombinatorialData, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2208409")] + public async Task TestFindsExistingDocumentWhenUriHasDifferentCasingForCaseInsensitiveUriAsync(bool mutatingLspWorkspace) + { + await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); + +#pragma warning disable RS0030 // Do not use banned APIs + var upperCaseUri = new Uri(@"file:///C:/Users/dabarbet/source/repos/XUnitApp1/UnitTest1.cs", UriKind.Absolute); + var lowerCaseUri = new Uri(@"file:///c:/Users/dabarbet/source/repos/XUnitApp1/UnitTest1.cs", UriKind.Absolute); +#pragma warning restore RS0030 // Do not use banned APIs + + // Execute the request as JSON directly to avoid the test client serializing System.Uri. + var requestJson = $$$""" + { + "textDocument": { + "uri": "{{{upperCaseUri.OriginalString}}}", + "languageId": "csharp", + "text": "LSP text" + } + } + """; + var jsonDocument = JsonDocument.Parse(requestJson); + await testLspServer.ExecutePreSerializedRequestAsync(LSP.Methods.TextDocumentDidOpenName, jsonDocument); + + // Access the document using the upper case to make sure we find it in the C# misc files. + var (workspace, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = upperCaseUri }, CancellationToken.None).ConfigureAwait(false); + AssertEx.NotNull(lspDocument); + Assert.Equal(WorkspaceKind.MiscellaneousFiles, workspace?.Kind); + Assert.Equal(LanguageNames.CSharp, lspDocument.Project.Language); + var originalText = await lspDocument.GetTextAsync(CancellationToken.None); + Assert.Equal("LSP text", originalText.ToString()); + + // Now make a request using different case. + var info = await testLspServer.ExecuteRequestAsync(CustomResolveHandler.MethodName, + new CustomResolveParams(new LSP.TextDocumentIdentifier { Uri = lowerCaseUri }), CancellationToken.None); + Assert.Equal(WorkspaceKind.MiscellaneousFiles, workspace?.Kind); + Assert.Equal(LanguageNames.CSharp, lspDocument.Project.Language); + + var (lowerCaseWorkspace, _, lowerCaseDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = lowerCaseUri }, CancellationToken.None).ConfigureAwait(false); + Assert.Same(workspace, lowerCaseWorkspace); + AssertEx.NotNull(lowerCaseDocument); + Assert.Equal(LanguageNames.CSharp, lowerCaseDocument.Project.Language); + var lowerCaseText = await lowerCaseDocument.GetTextAsync(CancellationToken.None); + Assert.Equal("LSP text", lowerCaseText.ToString()); + + // The text we get back should be the exact same instance that was originally saved by the unencoded request. + Assert.Same(originalText, lowerCaseText); + } + + [Theory, CombinatorialData, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2208409")] + public async Task TestUsesDifferentDocumentForDifferentCaseWithNonUncUriAsync(bool mutatingLspWorkspace) + { + await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); + +#pragma warning disable RS0030 // Do not use banned APIs + var upperCaseUri = new Uri(@"git:/Blah", UriKind.Absolute); + var lowerCaseUri = new Uri(@"git:/blah", UriKind.Absolute); +#pragma warning restore RS0030 // Do not use banned APIs + + // Execute the request as JSON directly to avoid the test client serializing System.Uri. + var requestJson = $$$""" + { + "textDocument": { + "uri": "{{{upperCaseUri.OriginalString}}}", + "languageId": "csharp", + "text": "LSP text" + } + } + """; + var jsonDocument = JsonDocument.Parse(requestJson); + await testLspServer.ExecutePreSerializedRequestAsync(LSP.Methods.TextDocumentDidOpenName, jsonDocument); + + // Access the document using the upper case to make sure we find it in the C# misc files. + var (workspace, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = upperCaseUri }, CancellationToken.None).ConfigureAwait(false); + AssertEx.NotNull(lspDocument); + Assert.Equal(WorkspaceKind.MiscellaneousFiles, workspace?.Kind); + Assert.Equal(LanguageNames.CSharp, lspDocument.Project.Language); + var originalText = await lspDocument.GetTextAsync(CancellationToken.None); + Assert.Equal("LSP text", originalText.ToString()); + + // Now make a request using different case. This should throw since we have not opened a document with the URI with different case (and not UNC). + await Assert.ThrowsAnyAsync(async () + => await testLspServer.ExecuteRequestAsync(CustomResolveHandler.MethodName, + new CustomResolveParams(new LSP.TextDocumentIdentifier { Uri = lowerCaseUri }), CancellationToken.None)); + } + + private record class ResolvedDocumentInfo(string WorkspaceKind, string ProjectLanguage); + private record class CustomResolveParams([property: JsonPropertyName("textDocument")] LSP.TextDocumentIdentifier TextDocument); + + [ExportCSharpVisualBasicStatelessLspService(typeof(CustomResolveHandler)), PartNotDiscoverable, Shared] + [LanguageServerEndpoint(MethodName, LanguageServerConstants.DefaultLanguageName)] + [method: ImportingConstructor] + [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + private class CustomResolveHandler() : ILspServiceDocumentRequestHandler + { + public const string MethodName = nameof(CustomResolveHandler); + + public bool MutatesSolutionState => false; + public bool RequiresLSPSolution => true; + public LSP.TextDocumentIdentifier GetTextDocumentIdentifier(CustomResolveParams request) => request.TextDocument; + public Task HandleRequestAsync(CustomResolveParams request, RequestContext context, CancellationToken cancellationToken) + { + return Task.FromResult(new ResolvedDocumentInfo(context.Workspace!.Kind!, context.GetRequiredDocument().Project.Language)); + } + } } diff --git a/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs index 31c6ceb43706a..6093ca628acc8 100644 --- a/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs @@ -69,7 +69,7 @@ public async Task TestRoslynTypeScriptHandlerInvoked() }; var response = await testLspServer.ExecuteRequestAsync(VSInternalMethods.DocumentPullDiagnosticName, documentPullRequest, CancellationToken.None); - Assert.Empty(response); + AssertEx.Empty(response); } [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1901118")] diff --git a/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs b/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs index ae4fc945289ff..c82af271ddc77 100644 --- a/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs @@ -11,8 +11,10 @@ using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; +using Roslyn.Test.Utilities.TestGenerators; using Xunit; using Xunit.Abstractions; @@ -55,7 +57,7 @@ public async Task TestLspUsesWorkspaceInstanceOnChangesAsync(bool mutatingLspWor { var markupOne = "One"; var markupTwo = "Two"; - await using var testLspServer = await CreateTestLspServerAsync(new string[] { markupOne, markupTwo }, mutatingLspWorkspace); + await using var testLspServer = await CreateTestLspServerAsync([markupOne, markupTwo], mutatingLspWorkspace); var firstDocumentUri = testLspServer.GetCurrentSolution().Projects.First().Documents.Single(d => d.FilePath!.Contains("test1")).GetURI(); var secondDocumentUri = testLspServer.GetCurrentSolution().Projects.First().Documents.Single(d => d.FilePath!.Contains("test2")).GetURI(); @@ -107,7 +109,7 @@ public async Task TestLspHasClosedDocumentChangesAsync(bool mutatingLspWorkspace { var markupOne = "One"; var markupTwo = "Two"; - await using var testLspServer = await CreateTestLspServerAsync(new string[] { markupOne, markupTwo }, mutatingLspWorkspace); + await using var testLspServer = await CreateTestLspServerAsync([markupOne, markupTwo], mutatingLspWorkspace); var firstDocumentUri = testLspServer.GetCurrentSolution().Projects.First().Documents.Single(d => d.FilePath!.Contains("test1")).GetURI(); var secondDocument = testLspServer.GetCurrentSolution().Projects.First().Documents.Single(d => d.FilePath!.Contains("test2")); @@ -468,11 +470,6 @@ public async Task TestSeparateWorkspaceManagerPerServerAsync(bool mutatingLspWor using var testWorkspace = CreateWorkspace(options: null, workspaceKind: null, mutatingLspWorkspace); testWorkspace.InitializeDocuments(XElement.Parse(workspaceXml)); - // Wait for workspace creation operations to complete. - await WaitForWorkspaceOperationsAsync(testWorkspace); - - var documentUri = testWorkspace.CurrentSolution.Projects.First().Documents.First().GetURI(); - await using var testLspServerOne = await TestLspServer.CreateAsync(testWorkspace, new InitializationOptions(), TestOutputLspLogger); await using var testLspServerTwo = await TestLspServer.CreateAsync(testWorkspace, new InitializationOptions(), TestOutputLspLogger); @@ -483,6 +480,7 @@ public async Task TestSeparateWorkspaceManagerPerServerAsync(bool mutatingLspWor Assert.True(IsWorkspaceRegistered(testWorkspace, testLspServerTwo)); // Verify that the LSP solution uses the correct text for each server. + var documentUri = testWorkspace.CurrentSolution.Projects.First().Documents.First().GetURI(); var documentServerOne = await OpenDocumentAndVerifyLspTextAsync(documentUri, testLspServerOne, "Server one text"); var (_, documentServerTwo) = await GetLspWorkspaceAndDocumentAsync(documentUri, testLspServerTwo).ConfigureAwait(false); @@ -690,6 +688,68 @@ await testLspServer.ReplaceTextAsync(documentUri, Assert.True(oldMethodDeclarations[2].IsIncrementallyIdenticalTo(newMethodDeclarations[2])); } + [Theory, CombinatorialData] + public async Task TestDoesNotUseForkForUnchangedGeneratedFileAsync(bool mutatingLspWorkspace) + { + var generatorText = "// Hello World!"; + await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace); + await AddGeneratorAsync(new SingleFileTestGenerator(generatorText), testLspServer.TestWorkspace); + + var sourceGeneratedDocuments = await testLspServer.GetCurrentSolution().Projects.Single().GetSourceGeneratedDocumentsAsync(); + var sourceGeneratedDocumentIdentity = sourceGeneratedDocuments.Single().Identity; + var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); + + // The workspace manager calls WithFrozenSourceGeneratedDocuments with the current DateTime. If that date time + // is the same as the generation date time, it does not fork. To ensure that it is not the same in tests, we explicitly + // wait a second to ensure the request datetime does not match the generated datetime. + await Task.Delay(TimeSpan.FromSeconds(1)); + + var sourceGeneratedDocument = await OpenDocumentAndVerifyLspTextAsync(sourceGeneratorDocumentUri, testLspServer, generatorText) as SourceGeneratedDocument; + AssertEx.NotNull(sourceGeneratedDocument); + Assert.Same(testLspServer.TestWorkspace.CurrentSolution, sourceGeneratedDocument.Project.Solution); + } + + [Theory, CombinatorialData] + public async Task TestForksWithDifferentGeneratedContentsAsync(bool mutatingLspWorkspace) + { + var workspaceGeneratedText = "// Hello World!"; + var lspGeneratedText = "// Hello LSP!"; + await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace); + await AddGeneratorAsync(new SingleFileTestGenerator(workspaceGeneratedText), testLspServer.TestWorkspace); + + var sourceGeneratedDocuments = await testLspServer.GetCurrentSolution().Projects.Single().GetSourceGeneratedDocumentsAsync(); + var sourceGeneratedDocumentIdentity = sourceGeneratedDocuments.Single().Identity; + var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); + + var sourceGeneratedDocument = await OpenDocumentAndVerifyLspTextAsync(sourceGeneratorDocumentUri, testLspServer, lspGeneratedText) as SourceGeneratedDocument; + AssertEx.NotNull(sourceGeneratedDocument); + Assert.NotSame(testLspServer.TestWorkspace.CurrentSolution, sourceGeneratedDocument.Project.Solution); + } + + [Theory, CombinatorialData] + public async Task TestForksWithRemovedGeneratorAsync(bool mutatingLspWorkspace) + { + var generatorText = "// Hello World!"; + await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace); + var generatorReference = await AddGeneratorAsync(new SingleFileTestGenerator(generatorText), testLspServer.TestWorkspace); + + var sourceGeneratedDocuments = await testLspServer.GetCurrentSolution().Projects.Single().GetSourceGeneratedDocumentsAsync(); + var sourceGeneratedDocumentIdentity = sourceGeneratedDocuments.Single().Identity; + var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); + + var sourceGeneratedDocument = await OpenDocumentAndVerifyLspTextAsync(sourceGeneratorDocumentUri, testLspServer, generatorText) as SourceGeneratedDocument; + AssertEx.NotNull(sourceGeneratedDocument); + Assert.Same(testLspServer.TestWorkspace.CurrentSolution, sourceGeneratedDocument.Project.Solution); + + // Remove the generator and verify the document is forked. + await RemoveGeneratorAsync(generatorReference, testLspServer.TestWorkspace); + + var (_, removedSourceGeneratorDocument) = await GetLspWorkspaceAndDocumentAsync(sourceGeneratorDocumentUri, testLspServer).ConfigureAwait(false); + AssertEx.NotNull(sourceGeneratedDocument as SourceGeneratedDocument); + Assert.Equal(generatorText, (await sourceGeneratedDocument.GetTextAsync(CancellationToken.None)).ToString()); + Assert.NotSame(testLspServer.TestWorkspace.CurrentSolution, sourceGeneratedDocument.Project.Solution); + } + private static async Task OpenDocumentAndVerifyLspTextAsync(Uri documentUri, TestLspServer testLspServer, string openText = "LSP text") { await testLspServer.OpenDocumentAsync(documentUri, openText); diff --git a/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs new file mode 100644 index 0000000000000..1889e398f460e --- /dev/null +++ b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Roslyn.Test.Utilities; +using Roslyn.Test.Utilities.TestGenerators; +using Xunit; +using Xunit.Abstractions; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.Workspaces; + +public class SourceGeneratedDocumentTests(ITestOutputHelper? testOutputHelper) : AbstractLanguageServerProtocolTests(testOutputHelper) +{ + [Theory, CombinatorialData] + public async Task ReturnsTextForSourceGeneratedDocument(bool mutatingLspWorkspace) + { + await using var testLspServer = await CreateTestLspServerWithGeneratorAsync(mutatingLspWorkspace, "// Hello, World"); + + var sourceGeneratedDocuments = await testLspServer.GetCurrentSolution().Projects.Single().GetSourceGeneratedDocumentsAsync(); + var sourceGeneratedDocumentIdentity = sourceGeneratedDocuments.Single().Identity; + var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); + + var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }), CancellationToken.None); + + AssertEx.NotNull(text); + Assert.Equal("// Hello, World", text.Text); + } + + [Theory, CombinatorialData] + public async Task OpenCloseSourceGeneratedDocument(bool mutatingLspWorkspace) + { + await using var testLspServer = await CreateTestLspServerWithGeneratorAsync(mutatingLspWorkspace, "// Hello, World"); + + var sourceGeneratedDocuments = await testLspServer.GetCurrentSolution().Projects.Single().GetSourceGeneratedDocumentsAsync(); + var sourceGeneratedDocumentIdentity = sourceGeneratedDocuments.Single().Identity; + var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); + + var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }), CancellationToken.None); + + AssertEx.NotNull(text); + Assert.Equal("// Hello, World", text.Text); + + // Verifying opening and closing the document doesn't cause any issues. + await testLspServer.OpenDocumentAsync(sourceGeneratorDocumentUri, text.Text); + await testLspServer.CloseDocumentAsync(sourceGeneratorDocumentUri); + } + + [Theory, CombinatorialData] + public async Task OpenMultipleSourceGeneratedDocument(bool mutatingLspWorkspace) + { + await using var testLspServer = await CreateTestLspServerWithGeneratorAsync(mutatingLspWorkspace, "// Hello, World"); + + await AddGeneratorAsync(new SingleFileTestGenerator2("// Goodbye"), testLspServer.TestWorkspace); + + var sourceGeneratedDocuments = await testLspServer.GetCurrentSolution().Projects.Single().GetSourceGeneratedDocumentsAsync(); + var sourceGeneratorDocumentUris = sourceGeneratedDocuments.Select(s => SourceGeneratedDocumentUri.Create(s.Identity)); + + Assert.Equal(2, sourceGeneratorDocumentUris.Count()); + + foreach (var sourceGeneratorDocumentUri in sourceGeneratorDocumentUris) + { + var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }), CancellationToken.None); + AssertEx.NotNull(text?.Text); + await testLspServer.OpenDocumentAsync(sourceGeneratorDocumentUri, text.Text); + } + + foreach (var sourceGeneratorDocumentUri in sourceGeneratorDocumentUris) + { + await testLspServer.CloseDocumentAsync(sourceGeneratorDocumentUri); + } + } + + [Theory, CombinatorialData] + public async Task RequestOnSourceGeneratedDocument(bool mutatingLspWorkspace) + { + await using var testLspServer = await CreateTestLspServerWithGeneratorAsync(mutatingLspWorkspace, "class A { }"); + + var sourceGeneratedDocuments = await testLspServer.GetCurrentSolution().Projects.Single().GetSourceGeneratedDocumentsAsync(); + var sourceGeneratedDocumentIdentity = sourceGeneratedDocuments.Single().Identity; + var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); + + var location = new LSP.Location { Uri = sourceGeneratorDocumentUri, Range = new LSP.Range { Start = new LSP.Position(0, 6), End = new LSP.Position(0, 6) } }; + + var hover = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentHoverName, + CreateTextDocumentPositionParams(location), CancellationToken.None); + + AssertEx.NotNull(hover); + Assert.Contains("class A", hover.Contents.Fourth.Value); + } + + private async Task CreateTestLspServerWithGeneratorAsync(bool mutatingLspWorkspace, string generatedDocumentText) + { + var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace); + await AddGeneratorAsync(new SingleFileTestGenerator(generatedDocumentText), testLspServer.TestWorkspace); + return testLspServer; + } +} diff --git a/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentUriTests.cs b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentUriTests.cs new file mode 100644 index 0000000000000..e71bedfbdb23e --- /dev/null +++ b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentUriTests.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Threading.Tasks; +using Roslyn.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.Workspaces; + +public class SourceGeneratedDocumentUrisTests : AbstractLanguageServerProtocolTests +{ + public SourceGeneratedDocumentUrisTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) + { + } + + [Fact] + public async Task UrisRoundTrip() + { + await using var testLspServer = await CreateTestLspServerAsync("", false); + + // Create up an identity to test with; we'll use the real project ID since we implicitly look for that when deserializing to get the + // project's debug name, but everything else we'll generate here to ensure we don't assume it exists during deserialization. + const string HintName = "HintName.cs"; + + var generatedDocumentId = DocumentId.CreateFromSerialized(testLspServer.TestWorkspace.Projects.Single().Id, Guid.NewGuid(), isSourceGenerated: true, debugName: HintName); + + var identity = new SourceGeneratedDocumentIdentity(generatedDocumentId, HintName, + new SourceGeneratorIdentity("GeneratorAssembly", "Generator.dll", new Version(1, 0), "GeneratorType"), HintName); + + var uri = SourceGeneratedDocumentUri.Create(identity); + Assert.Equal(SourceGeneratedDocumentUri.Scheme, uri.Scheme); + var deserialized = SourceGeneratedDocumentUri.DeserializeIdentity(testLspServer.TestWorkspace.CurrentSolution, uri); + + AssertEx.NotNull(deserialized); + Assert.Equal(identity, deserialized.Value); + + // Debug name is not considered as a the usual part of equality, but we want to ensure we pass this through too + Assert.Equal(generatedDocumentId.DebugName, deserialized.Value.DocumentId.DebugName); + } +} \ No newline at end of file diff --git a/src/NuGet/Microsoft.CodeAnalysis.Compilers.Package/Microsoft.CodeAnalysis.Compilers.Package.csproj b/src/NuGet/Microsoft.CodeAnalysis.Compilers.Package/Microsoft.CodeAnalysis.Compilers.Package.csproj index 6b130f797f52a..bf4a4b759328c 100644 --- a/src/NuGet/Microsoft.CodeAnalysis.Compilers.Package/Microsoft.CodeAnalysis.Compilers.Package.csproj +++ b/src/NuGet/Microsoft.CodeAnalysis.Compilers.Package/Microsoft.CodeAnalysis.Compilers.Package.csproj @@ -5,7 +5,7 @@ true - true + true Microsoft.CodeAnalysis.Compilers false diff --git a/src/NuGet/Microsoft.CodeAnalysis.EditorFeatures.Package/Microsoft.CodeAnalysis.EditorFeatures.Package.csproj b/src/NuGet/Microsoft.CodeAnalysis.EditorFeatures.Package/Microsoft.CodeAnalysis.EditorFeatures.Package.csproj index 36d3803cbc3b6..3b21088976dfd 100644 --- a/src/NuGet/Microsoft.CodeAnalysis.EditorFeatures.Package/Microsoft.CodeAnalysis.EditorFeatures.Package.csproj +++ b/src/NuGet/Microsoft.CodeAnalysis.EditorFeatures.Package/Microsoft.CodeAnalysis.EditorFeatures.Package.csproj @@ -5,7 +5,7 @@ true - true + true Microsoft.CodeAnalysis.EditorFeatures false diff --git a/src/NuGet/Microsoft.CodeAnalysis.Scripting.Package/Microsoft.CodeAnalysis.Scripting.Package.csproj b/src/NuGet/Microsoft.CodeAnalysis.Scripting.Package/Microsoft.CodeAnalysis.Scripting.Package.csproj index c35c54b8798e6..8a8d04d61b1ed 100644 --- a/src/NuGet/Microsoft.CodeAnalysis.Scripting.Package/Microsoft.CodeAnalysis.Scripting.Package.csproj +++ b/src/NuGet/Microsoft.CodeAnalysis.Scripting.Package/Microsoft.CodeAnalysis.Scripting.Package.csproj @@ -5,7 +5,7 @@ true - true + true Microsoft.CodeAnalysis.Scripting false diff --git a/src/NuGet/Microsoft.Net.Compilers.Toolset/DesktopCompilerArtifacts.targets b/src/NuGet/Microsoft.Net.Compilers.Toolset/DesktopCompilerArtifacts.targets index 7008b7b87c2f6..3a2eb7c1ea3fa 100644 --- a/src/NuGet/Microsoft.Net.Compilers.Toolset/DesktopCompilerArtifacts.targets +++ b/src/NuGet/Microsoft.Net.Compilers.Toolset/DesktopCompilerArtifacts.targets @@ -24,7 +24,7 @@ VS training data to the assemblies they produce. --> - + @@ -34,9 +34,9 @@ - - - + + + diff --git a/src/NuGet/Microsoft.Net.Compilers.Toolset/Framework/Microsoft.Net.Compilers.Toolset.Framework.Package.csproj b/src/NuGet/Microsoft.Net.Compilers.Toolset/Framework/Microsoft.Net.Compilers.Toolset.Framework.Package.csproj index ca1b19d9d1209..a907edcd53777 100644 --- a/src/NuGet/Microsoft.Net.Compilers.Toolset/Framework/Microsoft.Net.Compilers.Toolset.Framework.Package.csproj +++ b/src/NuGet/Microsoft.Net.Compilers.Toolset/Framework/Microsoft.Net.Compilers.Toolset.Framework.Package.csproj @@ -7,7 +7,7 @@ Microsoft.Net.Compilers.Toolset.Framework false true - true + true .NET Framework Compilers Toolset Package diff --git a/src/NuGet/Microsoft.Net.Compilers.Toolset/arm64/Microsoft.Net.Compilers.Toolset.Arm64.Package.csproj b/src/NuGet/Microsoft.Net.Compilers.Toolset/arm64/Microsoft.Net.Compilers.Toolset.Arm64.Package.csproj index 5a824c5b6fb90..51c21a5b9d6f0 100644 --- a/src/NuGet/Microsoft.Net.Compilers.Toolset/arm64/Microsoft.Net.Compilers.Toolset.Arm64.Package.csproj +++ b/src/NuGet/Microsoft.Net.Compilers.Toolset/arm64/Microsoft.Net.Compilers.Toolset.Arm64.Package.csproj @@ -8,7 +8,7 @@ Microsoft.Net.Compilers.Toolset.Arm64 false true - true + true .NET Compilers Toolset Package. Referencing this package will cause the project to be built using the C# and Visual Basic compilers contained in the package, as opposed to the version installed with MSBuild. diff --git a/src/NuGet/VS.Tools.Roslyn.Package/Directory.Build.props b/src/NuGet/VS.Tools.Roslyn.Package/Directory.Build.props index 6eef643958f56..9dd0ddea9df26 100644 --- a/src/NuGet/VS.Tools.Roslyn.Package/Directory.Build.props +++ b/src/NuGet/VS.Tools.Roslyn.Package/Directory.Build.props @@ -1,6 +1,6 @@ - true + true diff --git a/src/NuGet/VS.Tools.Roslyn.Package/VS.Tools.Roslyn.Package.csproj b/src/NuGet/VS.Tools.Roslyn.Package/VS.Tools.Roslyn.Package.csproj index 5a7283350c3c1..01e1c7eb73eaf 100644 --- a/src/NuGet/VS.Tools.Roslyn.Package/VS.Tools.Roslyn.Package.csproj +++ b/src/NuGet/VS.Tools.Roslyn.Package/VS.Tools.Roslyn.Package.csproj @@ -51,7 +51,7 @@ AfterTargets="Build" Inputs="$(ArtifactsBinDir)csc\$(Configuration)\net472\csc.exe" Outputs="$(IntermediateOutputPath)csc.exe" - Condition="'$(DotNetBuildFromSource)' != 'true'"> + Condition="'$(DotNetBuildSourceOnly)' != 'true'"> diff --git a/src/Scripting/CSharpTest.Desktop/InteractiveSessionReferencesTests.cs b/src/Scripting/CSharpTest.Desktop/InteractiveSessionReferencesTests.cs index c236c73222d8f..56c62ee5d48b5 100644 --- a/src/Scripting/CSharpTest.Desktop/InteractiveSessionReferencesTests.cs +++ b/src/Scripting/CSharpTest.Desktop/InteractiveSessionReferencesTests.cs @@ -25,7 +25,6 @@ using TestBase = PortableTestUtils::Roslyn.Test.Utilities.TestBase; using WorkItemAttribute = PortableTestUtils::Roslyn.Test.Utilities.WorkItemAttribute; using static Microsoft.CodeAnalysis.Scripting.TestCompilationFactory; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.Scripting.Test { @@ -374,10 +373,10 @@ public void References_Versioning_StrongNames2() public void References_Versioning_WeakNames1() { var c1 = Temp.CreateFile(extension: ".dll").WriteAllBytes( - CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class C {}", new[] { Net451.mscorlib }, assemblyName: "C").EmitToArray()); + CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class C {}", new[] { NetFramework.mscorlib }, assemblyName: "C").EmitToArray()); var c2 = Temp.CreateFile(extension: ".dll").WriteAllBytes( - CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class C {}", new[] { Net451.mscorlib }, assemblyName: "C").EmitToArray()); + CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class C {}", new[] { NetFramework.mscorlib }, assemblyName: "C").EmitToArray()); var result = CSharpScript.EvaluateAsync($@" #r ""{c1.Path}"" @@ -393,10 +392,10 @@ public void References_Versioning_WeakNames1() public void References_Versioning_WeakNames2() { var c1 = Temp.CreateFile(extension: ".dll").WriteAllBytes( - CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class C {}", new[] { Net451.mscorlib }, assemblyName: "C").EmitToArray()); + CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class C {}", new[] { NetFramework.mscorlib }, assemblyName: "C").EmitToArray()); var c2 = Temp.CreateFile(extension: ".dll").WriteAllBytes( - CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class C {}", new[] { Net451.mscorlib }, assemblyName: "C").EmitToArray()); + CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class C {}", new[] { NetFramework.mscorlib }, assemblyName: "C").EmitToArray()); var result = CSharpScript.Create($@" #r ""{c1.Path}"" @@ -413,10 +412,10 @@ public void References_Versioning_WeakNames2() public void References_Versioning_WeakNames3() { var c1 = Temp.CreateFile(extension: ".dll").WriteAllBytes( - CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class C {}", new[] { Net451.mscorlib }, assemblyName: "C").EmitToArray()); + CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] public class C {}", new[] { NetFramework.mscorlib }, assemblyName: "C").EmitToArray()); var c2 = Temp.CreateFile(extension: ".dll").WriteAllBytes( - CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class C {}", new[] { Net451.mscorlib }, assemblyName: "C").EmitToArray()); + CreateCSharpCompilation(@"[assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] public class C {}", new[] { NetFramework.mscorlib }, assemblyName: "C").EmitToArray()); var script0 = CSharpScript.Create($@" #r ""{c1.Path}"" @@ -565,7 +564,7 @@ public async Task MissingRefrencesAutoResolution() [Fact] public void HostObjectInInMemoryAssembly() { - var lib = CreateCSharpCompilation("public class C { public int X = 1, Y = 2; }", new[] { Net451.mscorlib }, "HostLib"); + var lib = CreateCSharpCompilation("public class C { public int X = 1, Y = 2; }", new[] { NetFramework.mscorlib }, "HostLib"); var libImage = lib.EmitToArray(); var libRef = MetadataImageReference.CreateFromImage(libImage); @@ -600,21 +599,21 @@ public class LibBase { public readonly int X = 1; } -", new[] { Net451.mscorlib }, libBaseName); +", new[] { NetFramework.mscorlib }, libBaseName); var lib1 = CreateCSharpCompilation(@" public class Lib1 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase.ToMetadataReference() }, lib1Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase.ToMetadataReference() }, lib1Name); var lib2 = CreateCSharpCompilation(@" public class Lib2 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase.ToMetadataReference() }, lib2Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase.ToMetadataReference() }, lib2Name); var libBaseImage = libBase.EmitToArray(); var lib1Image = lib1.EmitToArray(); @@ -658,21 +657,21 @@ public class LibBase { public readonly int X = 1; } -", new[] { Net451.mscorlib }, libBaseName, s_signedDll); +", new[] { NetFramework.mscorlib }, libBaseName, s_signedDll); var lib1 = CreateCSharpCompilation(@" public class Lib1 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase.ToMetadataReference() }, lib1Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase.ToMetadataReference() }, lib1Name); var lib2 = CreateCSharpCompilation(@" public class Lib2 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase.ToMetadataReference() }, lib2Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase.ToMetadataReference() }, lib2Name); var libBaseImage = libBase.EmitToArray(); var lib1Image = lib1.EmitToArray(); @@ -716,28 +715,28 @@ public class LibBase { public readonly int X = 1; } -", new[] { Net451.mscorlib }, libBaseName); +", new[] { NetFramework.mscorlib }, libBaseName); var libBase2 = CreateCSharpCompilation(@" public class LibBase { public readonly int X = 2; } -", new[] { Net451.mscorlib }, libBaseName); +", new[] { NetFramework.mscorlib }, libBaseName); var lib1 = CreateCSharpCompilation(@" public class Lib1 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib1Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib1Name); var lib2 = CreateCSharpCompilation(@" public class Lib2 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib2Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib2Name); var libBase1Image = libBase1.EmitToArray(); var libBase2Image = libBase2.EmitToArray(); @@ -783,7 +782,7 @@ public class LibBase { public readonly int X = 1; } -", new[] { Net451.mscorlib }, libBaseName, s_signedDll); +", new[] { NetFramework.mscorlib }, libBaseName, s_signedDll); var libBase2 = CreateCSharpCompilation(@" [assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] @@ -791,21 +790,21 @@ public class LibBase { public readonly int X = 2; } -", new[] { Net451.mscorlib }, libBaseName, s_signedDll); +", new[] { NetFramework.mscorlib }, libBaseName, s_signedDll); var lib1 = CreateCSharpCompilation(@" public class Lib1 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib1Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib1Name); var lib2 = CreateCSharpCompilation(@" public class Lib2 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib2Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib2Name); var libBase1Image = libBase1.EmitToArray(); var libBase2Image = libBase2.EmitToArray(); @@ -851,7 +850,7 @@ public class LibBase { public readonly int X = 1; } -", new[] { Net451.mscorlib }, libBaseName, s_signedDll); +", new[] { NetFramework.mscorlib }, libBaseName, s_signedDll); var libBase2 = CreateCSharpCompilation(@" [assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] @@ -859,21 +858,21 @@ public class LibBase { public readonly int X = 2; } -", new[] { Net451.mscorlib }, libBaseName); +", new[] { NetFramework.mscorlib }, libBaseName); var lib1 = CreateCSharpCompilation(@" public class Lib1 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib1Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib1Name); var lib2 = CreateCSharpCompilation(@" public class Lib2 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib2Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib2Name); var libBase1Image = libBase1.EmitToArray(); var libBase2Image = libBase2.EmitToArray(); @@ -919,7 +918,7 @@ public class LibBase { public readonly int X = 1; } -", new[] { Net451.mscorlib }, libBaseName, s_signedDll); +", new[] { NetFramework.mscorlib }, libBaseName, s_signedDll); var libBase2 = CreateCSharpCompilation(@" [assembly: System.Reflection.AssemblyVersion(""1.0.0.0"")] @@ -927,21 +926,21 @@ public class LibBase { public readonly int X = 2; } -", new[] { Net451.mscorlib }, libBaseName, s_signedDll2); +", new[] { NetFramework.mscorlib }, libBaseName, s_signedDll2); var lib1 = CreateCSharpCompilation(@" public class Lib1 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib1Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib1Name); var lib2 = CreateCSharpCompilation(@" public class Lib2 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib2Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib2Name); var libBase1Image = libBase1.EmitToArray(); var libBase2Image = libBase2.EmitToArray(); @@ -987,7 +986,7 @@ public class LibBase { public readonly int X = 1; } -", new[] { Net451.mscorlib }, libBaseName); +", new[] { NetFramework.mscorlib }, libBaseName); var libBase2 = CreateCSharpCompilation(@" [assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] @@ -995,21 +994,21 @@ public class LibBase { public readonly int X = 2; } -", new[] { Net451.mscorlib }, libBaseName); +", new[] { NetFramework.mscorlib }, libBaseName); var lib1 = CreateCSharpCompilation(@" public class Lib1 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib1Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib1Name); var lib2 = CreateCSharpCompilation(@" public class Lib2 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase2.ToMetadataReference() }, lib2Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase2.ToMetadataReference() }, lib2Name); var libBase1Image = libBase1.EmitToArray(); var libBase2Image = libBase2.EmitToArray(); @@ -1055,7 +1054,7 @@ public class LibBase { public readonly int X = 1; } -", new[] { Net451.mscorlib }, libBaseName, s_signedDll); +", new[] { NetFramework.mscorlib }, libBaseName, s_signedDll); var libBase2 = CreateCSharpCompilation(@" [assembly: System.Reflection.AssemblyVersion(""2.0.0.0"")] @@ -1063,21 +1062,21 @@ public class LibBase { public readonly int X = 2; } -", new[] { Net451.mscorlib }, libBaseName, s_signedDll); +", new[] { NetFramework.mscorlib }, libBaseName, s_signedDll); var lib1 = CreateCSharpCompilation(@" public class Lib1 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib1Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib1Name); var lib2 = CreateCSharpCompilation(@" public class Lib2 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase2.ToMetadataReference() }, lib2Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase2.ToMetadataReference() }, lib2Name); var libBase1Image = libBase1.EmitToArray(); var libBase2Image = libBase2.EmitToArray(); @@ -1114,7 +1113,7 @@ public class C var lib = CSharpCompilation.Create( "Lib", new[] { SyntaxFactory.ParseSyntaxTree(source) }, - new[] { Net451.mscorlib, Net451.System }, + new[] { NetFramework.mscorlib, NetFramework.System }, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); var libFile = Temp.CreateFile("lib").WriteAllBytes(lib.EmitToArray()); diff --git a/src/Scripting/CSharpTest/CommandLineRunnerTests.cs b/src/Scripting/CSharpTest/CommandLineRunnerTests.cs index bdf2e78cd6788..11459d0f58e4b 100644 --- a/src/Scripting/CSharpTest/CommandLineRunnerTests.cs +++ b/src/Scripting/CSharpTest/CommandLineRunnerTests.cs @@ -18,7 +18,6 @@ using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; -using static Roslyn.Test.Utilities.TestMetadata; namespace Microsoft.CodeAnalysis.CSharp.Scripting.UnitTests { @@ -869,28 +868,28 @@ public class LibBase { public readonly int X = 1; } -", new[] { Net451.mscorlib }, libBaseName); +", new[] { NetFramework.mscorlib }, libBaseName); var libBase2 = TestCompilationFactory.CreateCSharpCompilation(@" public class LibBase { public readonly int X = 2; } -", new[] { Net451.mscorlib }, libBaseName); +", new[] { NetFramework.mscorlib }, libBaseName); var lib1 = TestCompilationFactory.CreateCSharpCompilation(@" public class Lib1 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib1Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib1Name); var lib2 = TestCompilationFactory.CreateCSharpCompilation(@" public class Lib2 { public LibBase libBase = new LibBase(); } -", new MetadataReference[] { Net451.mscorlib, libBase1.ToMetadataReference() }, lib2Name); +", new MetadataReference[] { NetFramework.mscorlib, libBase1.ToMetadataReference() }, lib2Name); var libBase1Image = libBase1.EmitToArray(); var libBase2Image = libBase2.EmitToArray(); diff --git a/src/Scripting/CSharpTest/ObjectFormatterTests.cs b/src/Scripting/CSharpTest/ObjectFormatterTests.cs index 07201a7ada581..2f5baa40fb5c2 100644 --- a/src/Scripting/CSharpTest/ObjectFormatterTests.cs +++ b/src/Scripting/CSharpTest/ObjectFormatterTests.cs @@ -861,7 +861,7 @@ public void DebuggerProxy_DiagnosticBag() [Fact] public void DebuggerProxy_ArrayBuilder() { - var obj = new ArrayBuilder(); + var obj = ArrayBuilder.GetInstance(); obj.AddRange(new[] { 1, 2, 3, 4, 5 }); var str = s_formatter.FormatObject(obj, SingleLineOptions); @@ -875,6 +875,8 @@ public void DebuggerProxy_ArrayBuilder() "4", "5" ); + + obj.Free(); } [Fact, WorkItem(8542, "https://github.com/dotnet/roslyn/issues/8452")] diff --git a/src/Scripting/Core/CoreLightup.cs b/src/Scripting/Core/CoreLightup.cs deleted file mode 100644 index 7af9ded1629c8..0000000000000 --- a/src/Scripting/Core/CoreLightup.cs +++ /dev/null @@ -1,127 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Reflection; - -namespace Roslyn.Utilities -{ - /// - /// This type contains the light up scenarios for various platform and runtimes. Any function - /// in this type can, and is expected to, fail on various platforms. These are light up scenarios - /// only. - /// - internal static class CoreLightup - { - internal static class Desktop - { - private static class _Assembly - { - internal static readonly Type Type = typeof(Assembly); - - internal static readonly Func get_GlobalAssemblyCache = Type - .GetTypeInfo() - .GetDeclaredMethod("get_GlobalAssemblyCache") - .CreateDelegate>(); - } - - private static class _ResolveEventArgs - { - internal static readonly Type Type = ReflectionUtilities.TryGetType("System.ResolveEventArgs"); - - internal static readonly MethodInfo get_Name = Type - .GetTypeInfo() - .GetDeclaredMethod("get_Name"); - - internal static readonly MethodInfo get_RequestingAssembly = Type - .GetTypeInfo() - .GetDeclaredMethod("get_RequestingAssembly"); - } - - private static class _AppDomain - { - internal static readonly Type Type = ReflectionUtilities.TryGetType("System.AppDomain"); - internal static readonly Type ResolveEventHandlerType = ReflectionUtilities.TryGetType("System.ResolveEventHandler"); - - internal static readonly MethodInfo get_CurrentDomain = Type - .GetTypeInfo() - .GetDeclaredMethod("get_CurrentDomain"); - - internal static readonly MethodInfo add_AssemblyResolve = Type - .GetTypeInfo() - .GetDeclaredMethod("add_AssemblyResolve", ResolveEventHandlerType); - - internal static readonly MethodInfo remove_AssemblyResolve = Type - .GetTypeInfo() - .GetDeclaredMethod("remove_AssemblyResolve", ResolveEventHandlerType); - } - - internal static bool IsAssemblyFromGlobalAssemblyCache(Assembly assembly) - { - if (_Assembly.get_GlobalAssemblyCache == null) - { - throw new PlatformNotSupportedException(); - } - - return _Assembly.get_GlobalAssemblyCache(assembly); - } - - private sealed class AssemblyResolveWrapper - { - private readonly Func _handler; - private static readonly MethodInfo s_stubInfo = typeof(AssemblyResolveWrapper).GetTypeInfo().GetDeclaredMethod("Stub"); - - public AssemblyResolveWrapper(Func handler) - { - _handler = handler; - } - -#pragma warning disable IDE0051 // Remove unused private members - Reflection (s_stubInfo) -#pragma warning disable IDE0060 // Remove unused parameter - private Assembly Stub(object sender, object resolveEventArgs) -#pragma warning restore IDE0051 // Remove unused private members -#pragma warning restore IDE0060 // Remove unused parameter - { - var name = (string)_ResolveEventArgs.get_Name.Invoke(resolveEventArgs, Array.Empty()); - var requestingAssembly = (Assembly)_ResolveEventArgs.get_RequestingAssembly.Invoke(resolveEventArgs, Array.Empty()); - - return _handler(name, requestingAssembly); - } - - public object GetHandler() - { - return s_stubInfo.CreateDelegate(_AppDomain.ResolveEventHandlerType, this); - } - } - - internal static void GetOrRemoveAssemblyResolveHandler(Func handler, MethodInfo handlerOperation) - { - if (_AppDomain.add_AssemblyResolve == null) - { - throw new PlatformNotSupportedException(); - } - - var currentAppDomain = AppDomain.CurrentDomain; - object resolveEventHandler = new AssemblyResolveWrapper(handler).GetHandler(); - - handlerOperation.Invoke(currentAppDomain, [resolveEventHandler]); - } - - internal static void AddAssemblyResolveHandler(Func handler) - { - GetOrRemoveAssemblyResolveHandler(handler, _AppDomain.add_AssemblyResolve); - } - - internal static void RemoveAssemblyResolveHandler(Func handler) - { - GetOrRemoveAssemblyResolveHandler(handler, _AppDomain.remove_AssemblyResolve); - } - } - } -} diff --git a/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyAndLocation.cs b/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyAndLocation.cs index e67168a9500b2..9fb3f7022c9b6 100644 --- a/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyAndLocation.cs +++ b/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyAndLocation.cs @@ -2,42 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System; -using System.Diagnostics; using System.Reflection; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Scripting.Hosting -{ - internal readonly struct AssemblyAndLocation : IEquatable - { - public Assembly Assembly { get; } - public string Location { get; } - public bool GlobalAssemblyCache { get; } - - internal AssemblyAndLocation(Assembly assembly, string location, bool fromGac) - { - Debug.Assert(assembly != null && location != null); - Assembly = assembly; - Location = location; - GlobalAssemblyCache = fromGac; - } +namespace Microsoft.CodeAnalysis.Scripting.Hosting; - public bool IsDefault => Assembly == null; - - public bool Equals(AssemblyAndLocation other) - => Assembly == other.Assembly && Location == other.Location && GlobalAssemblyCache == other.GlobalAssemblyCache; - - public override int GetHashCode() - => Hash.Combine(Assembly, Hash.Combine(Location, Hash.Combine(GlobalAssemblyCache, 0))); - - public override bool Equals(object obj) - => obj is AssemblyAndLocation && Equals((AssemblyAndLocation)obj); +internal readonly record struct AssemblyAndLocation(Assembly Assembly, string Location, bool GlobalAssemblyCache) +{ + public bool IsDefault => Assembly == null; - public override string ToString() - => Assembly + " @ " + (GlobalAssemblyCache ? "" : Location); - } + public override string ToString() + => Assembly + " @ " + (GlobalAssemblyCache ? "" : Location); } diff --git a/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyLoadResult.cs b/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyLoadResult.cs index 75dd78620b83d..7589e3b503749 100644 --- a/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyLoadResult.cs +++ b/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyLoadResult.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 - namespace Microsoft.CodeAnalysis.Scripting.Hosting { /// diff --git a/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyLoaderImpl.cs b/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyLoaderImpl.cs index d7d8401ecd2b8..18cd4541c49e7 100644 --- a/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyLoaderImpl.cs +++ b/src/Scripting/Core/Hosting/AssemblyLoader/AssemblyLoaderImpl.cs @@ -2,43 +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. -#nullable disable - using System; using System.IO; using System.Reflection; -using System.Runtime.CompilerServices; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Scripting.Hosting { - internal abstract class AssemblyLoaderImpl : IDisposable + internal abstract class AssemblyLoaderImpl(InteractiveAssemblyLoader loader) : IDisposable { - internal readonly InteractiveAssemblyLoader Loader; - - protected AssemblyLoaderImpl(InteractiveAssemblyLoader loader) - { - Loader = loader; - } + internal readonly InteractiveAssemblyLoader Loader = loader; public static AssemblyLoaderImpl Create(InteractiveAssemblyLoader loader) - { - if (CoreClrShim.AssemblyLoadContext.Type != null) - { - return CreateCoreImpl(loader); - } - else - { - return new DesktopAssemblyLoaderImpl(loader); - } - } - - // NoInlining to avoid loading AssemblyLoadContext if not available. - [MethodImpl(MethodImplOptions.NoInlining)] - private static AssemblyLoaderImpl CreateCoreImpl(InteractiveAssemblyLoader loader) - { - return new CoreAssemblyLoaderImpl(loader); - } +#if NET + => new CoreAssemblyLoaderImpl(loader); +#else + => new DesktopAssemblyLoaderImpl(loader); +#endif public abstract Assembly LoadFromStream(Stream peStream, Stream pdbStream); public abstract AssemblyAndLocation LoadFromPath(string path); diff --git a/src/Scripting/Core/Hosting/AssemblyLoader/CoreAssemblyLoaderImpl.cs b/src/Scripting/Core/Hosting/AssemblyLoader/CoreAssemblyLoaderImpl.cs index baeb4f0e2c690..e539846aded3f 100644 --- a/src/Scripting/Core/Hosting/AssemblyLoader/CoreAssemblyLoaderImpl.cs +++ b/src/Scripting/Core/Hosting/AssemblyLoader/CoreAssemblyLoaderImpl.cs @@ -2,10 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable +#if NET -using System; -using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.Loader; @@ -34,7 +32,7 @@ public override AssemblyAndLocation LoadFromPath(string path) // but there is no need to reuse contexts. var assembly = new LoadContext(Loader, Path.GetDirectoryName(path)).LoadFromAssemblyPath(path); - return new AssemblyAndLocation(assembly, path, fromGac: false); + return new AssemblyAndLocation(assembly, path, GlobalAssemblyCache: false); } public override void Dispose() @@ -44,15 +42,13 @@ public override void Dispose() private sealed class LoadContext : AssemblyLoadContext { - private readonly string _loadDirectoryOpt; + private readonly string? _loadDirectory; private readonly InteractiveAssemblyLoader _loader; - internal LoadContext(InteractiveAssemblyLoader loader, string loadDirectoryOpt) + internal LoadContext(InteractiveAssemblyLoader loader, string? loadDirectory) { - Debug.Assert(loader != null); - _loader = loader; - _loadDirectoryOpt = loadDirectoryOpt; + _loadDirectory = loadDirectory; // CoreCLR resolves assemblies in steps: // @@ -68,10 +64,11 @@ internal LoadContext(InteractiveAssemblyLoader loader, string loadDirectoryOpt) // This order is necessary to avoid loading assemblies twice (by the host App and by interactive loader). Resolving += (_, assemblyName) => - _loader.ResolveAssembly(AssemblyIdentity.FromAssemblyReference(assemblyName), _loadDirectoryOpt); + _loader.ResolveAssembly(AssemblyIdentity.FromAssemblyReference(assemblyName), _loadDirectory); } - protected override Assembly Load(AssemblyName assemblyName) => null; + protected override Assembly? Load(AssemblyName assemblyName) => null; } } } +#endif diff --git a/src/Scripting/Core/Hosting/AssemblyLoader/DesktopAssemblyLoaderImpl.cs b/src/Scripting/Core/Hosting/AssemblyLoader/DesktopAssemblyLoaderImpl.cs index 3fedb5a7cd172..e84fb9395ec6a 100644 --- a/src/Scripting/Core/Hosting/AssemblyLoader/DesktopAssemblyLoaderImpl.cs +++ b/src/Scripting/Core/Hosting/AssemblyLoader/DesktopAssemblyLoaderImpl.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable +#if !NET using System; using System.IO; @@ -13,31 +13,28 @@ namespace Microsoft.CodeAnalysis.Scripting.Hosting { internal sealed class DesktopAssemblyLoaderImpl : AssemblyLoaderImpl { - private readonly Func _assemblyResolveHandlerOpt; - public DesktopAssemblyLoaderImpl(InteractiveAssemblyLoader loader) : base(loader) { - _assemblyResolveHandlerOpt = loader.ResolveAssembly; - CoreLightup.Desktop.AddAssemblyResolveHandler(_assemblyResolveHandlerOpt); + AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; } public override void Dispose() { - if (_assemblyResolveHandlerOpt != null) - { - CoreLightup.Desktop.RemoveAssemblyResolveHandler(_assemblyResolveHandlerOpt); - } + AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve; } + private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) + => Loader.ResolveAssembly(args.Name, args.RequestingAssembly); + public override Assembly LoadFromStream(Stream peStream, Stream pdbStream) { - byte[] peImage = new byte[peStream.Length]; + var peImage = new byte[peStream.Length]; peStream.TryReadAll(peImage, 0, peImage.Length); if (pdbStream != null) { - byte[] pdbImage = new byte[pdbStream.Length]; + var pdbImage = new byte[pdbStream.Length]; pdbStream.TryReadAll(pdbImage, 0, pdbImage.Length); return Assembly.Load(peImage, pdbImage); @@ -52,9 +49,8 @@ public override AssemblyAndLocation LoadFromPath(string path) // Assembly.LoadFile(string) automatically redirects to GAC if the assembly has a strong name and there is an equivalent assembly in GAC. var assembly = Assembly.LoadFile(path); - var location = assembly.Location; - var fromGac = CoreLightup.Desktop.IsAssemblyFromGlobalAssemblyCache(assembly); - return new AssemblyAndLocation(assembly, location, fromGac); + return new AssemblyAndLocation(assembly, assembly.Location, assembly.GlobalAssemblyCache); } } } +#endif diff --git a/src/Scripting/Core/Hosting/AssemblyLoader/InteractiveAssemblyLoader.cs b/src/Scripting/Core/Hosting/AssemblyLoader/InteractiveAssemblyLoader.cs index bff59c9770b35..6d55c480fdcad 100644 --- a/src/Scripting/Core/Hosting/AssemblyLoader/InteractiveAssemblyLoader.cs +++ b/src/Scripting/Core/Hosting/AssemblyLoader/InteractiveAssemblyLoader.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.Diagnostics; @@ -13,7 +11,6 @@ using System.Reflection; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; -using System.Runtime.CompilerServices; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Scripting.Hosting @@ -34,12 +31,12 @@ private class LoadedAssembly /// The original path of the assembly before it was shadow-copied. /// For GAC'd assemblies, this is equal to Assembly.Location no matter what path was used to load them. /// - public string OriginalPath { get; set; } + public string? OriginalPath { get; set; } } private readonly AssemblyLoaderImpl _runtimeAssemblyLoader; - private readonly MetadataShadowCopyProvider _shadowCopyProvider; + private readonly MetadataShadowCopyProvider? _shadowCopyProvider; // Synchronizes assembly reference tracking. // Needs to be thread-safe since assembly loading may be triggered at any time by CLR type loader. @@ -66,8 +63,6 @@ private readonly struct AssemblyIdentityAndLocation public AssemblyIdentityAndLocation(AssemblyIdentity identity, string location) { - Debug.Assert(identity != null && location != null); - Identity = identity; Location = location; } @@ -76,26 +71,18 @@ public AssemblyIdentityAndLocation(AssemblyIdentity identity, string location) } [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] - private readonly struct LoadedAssemblyInfo + private readonly struct LoadedAssemblyInfo(Assembly assembly, AssemblyIdentity identity, string? location) { - public readonly Assembly Assembly; - public readonly AssemblyIdentity Identity; - public readonly string LocationOpt; - - public LoadedAssemblyInfo(Assembly assembly, AssemblyIdentity identity, string locationOpt) - { - Debug.Assert(assembly != null && identity != null); - - Assembly = assembly; - Identity = identity; - LocationOpt = locationOpt; - } + public readonly Assembly Assembly = assembly; + public readonly AssemblyIdentity Identity = identity; + public readonly string? Location = location; public bool IsDefault => Assembly == null; - private string GetDebuggerDisplay() => IsDefault ? "uninitialized" : Identity.GetDisplayName() + (LocationOpt != null ? " @ " + LocationOpt : ""); + + private string GetDebuggerDisplay() => IsDefault ? "uninitialized" : Identity.GetDisplayName() + (Location != null ? " @ " + Location : ""); } - public InteractiveAssemblyLoader(MetadataShadowCopyProvider shadowCopyProvider = null) + public InteractiveAssemblyLoader(MetadataShadowCopyProvider? shadowCopyProvider = null) { _shadowCopyProvider = shadowCopyProvider; @@ -121,7 +108,7 @@ internal Assembly LoadAssemblyFromStream(Stream peStream, Stream pdbStream) private AssemblyAndLocation Load(string reference) { - MetadataShadowCopy copy = null; + MetadataShadowCopy? copy = null; try { if (_shadowCopyProvider != null) @@ -144,7 +131,7 @@ private AssemblyAndLocation Load(string reference) } catch (FileNotFoundException) { - return default(AssemblyAndLocation); + return default; } finally { @@ -201,17 +188,16 @@ public void RegisterDependency(Assembly dependency) lock (_referencesLock) { - RegisterLoadedAssemblySimpleNameNoLock(dependency, locationOpt: null); + RegisterLoadedAssemblySimpleNameNoLock(dependency, location: null); } } - private void RegisterLoadedAssemblySimpleNameNoLock(Assembly assembly, string locationOpt) + private void RegisterLoadedAssemblySimpleNameNoLock(Assembly assembly, string? location) { var identity = AssemblyIdentity.FromAssemblyDefinition(assembly); - var info = new LoadedAssemblyInfo(assembly, identity, locationOpt); + var info = new LoadedAssemblyInfo(assembly, identity, location); - List existingInfos; - if (_loadedAssembliesBySimpleName.TryGetValue(identity.Name, out existingInfos)) + if (_loadedAssembliesBySimpleName.TryGetValue(identity.Name, out var existingInfos)) { existingInfos.Add(info); } @@ -223,9 +209,8 @@ private void RegisterLoadedAssemblySimpleNameNoLock(Assembly assembly, string lo private void RegisterDependencyNoLock(AssemblyIdentityAndLocation dependency) { - List sameSimpleNameAssemblyIdentities; string simpleName = dependency.Identity.Name; - if (_dependenciesWithLocationBySimpleName.TryGetValue(simpleName, out sameSimpleNameAssemblyIdentities)) + if (_dependenciesWithLocationBySimpleName.TryGetValue(simpleName, out var sameSimpleNameAssemblyIdentities)) { sameSimpleNameAssemblyIdentities.Add(dependency); } @@ -235,53 +220,50 @@ private void RegisterDependencyNoLock(AssemblyIdentityAndLocation dependency) } } - internal Assembly ResolveAssembly(string assemblyDisplayName, Assembly requestingAssemblyOpt) + internal Assembly? ResolveAssembly(string assemblyDisplayName, Assembly? requestingAssembly) { - AssemblyIdentity identity; - if (!AssemblyIdentity.TryParseDisplayName(assemblyDisplayName, out identity)) + if (!AssemblyIdentity.TryParseDisplayName(assemblyDisplayName, out var identity)) { return null; } - string loadDirectoryOpt; + string? loadDirectory; lock (_referencesLock) { - LoadedAssembly loadedAssembly; - if (requestingAssemblyOpt != null && - _assembliesLoadedFromLocation.TryGetValue(requestingAssemblyOpt, out loadedAssembly)) + if (requestingAssembly != null && + _assembliesLoadedFromLocation.TryGetValue(requestingAssembly, out var loadedAssembly)) { - loadDirectoryOpt = Path.GetDirectoryName(loadedAssembly.OriginalPath); + loadDirectory = Path.GetDirectoryName(loadedAssembly.OriginalPath); } else { - loadDirectoryOpt = null; + loadDirectory = null; } } - return ResolveAssembly(identity, loadDirectoryOpt); + return ResolveAssembly(identity, loadDirectory); } - internal Assembly ResolveAssembly(AssemblyIdentity identity, string loadDirectoryOpt) + internal Assembly? ResolveAssembly(AssemblyIdentity identity, string? loadDirectory) { // if the referring assembly is already loaded by our loader, load from its directory: - if (loadDirectoryOpt != null) + if (loadDirectory != null) { - Assembly assembly; + Assembly? assembly; var conflictingLoadedAssemblyOpt = default(LoadedAssemblyInfo); var loadedAssemblyWithEqualNameAndVersionOpt = default(LoadedAssemblyInfo); lock (_referencesLock) { // Has the file already been loaded? - assembly = TryGetAssemblyLoadedFromPath(identity, loadDirectoryOpt); + assembly = TryGetAssemblyLoadedFromPath(identity, loadDirectory); if (assembly != null) { return assembly; } // Has an assembly with the same name and version been loaded (possibly from a different directory)? - List loadedInfos; - if (_loadedAssembliesBySimpleName.TryGetValue(identity.Name, out loadedInfos)) + if (_loadedAssembliesBySimpleName.TryGetValue(identity.Name, out var loadedInfos)) { // Desktop FX: A weak-named assembly conflicts with another weak-named assembly of the same simple name, // unless we find an assembly whose identity matches exactly and whose content is exactly the same. @@ -298,14 +280,13 @@ internal Assembly ResolveAssembly(AssemblyIdentity identity, string loadDirector } } - string assemblyFilePathOpt = FindExistingAssemblyFile(identity.Name, loadDirectoryOpt); - if (assemblyFilePathOpt != null) + var assemblyFilePath = FindExistingAssemblyFile(identity.Name, loadDirectory); + if (assemblyFilePath != null) { // TODO: Stop using reflection once ModuleVersionId property once is available in Core contract. - if (!loadedAssemblyWithEqualNameAndVersionOpt.IsDefault) + if (loadedAssemblyWithEqualNameAndVersionOpt.Assembly != null) { - Guid mvid; - if (TryReadMvid(assemblyFilePathOpt, out mvid) && + if (TryReadMvid(assemblyFilePath, out var mvid) && loadedAssemblyWithEqualNameAndVersionOpt.Assembly.ManifestModule.ModuleVersionId == mvid) { return loadedAssemblyWithEqualNameAndVersionOpt.Assembly; @@ -316,8 +297,8 @@ internal Assembly ResolveAssembly(AssemblyIdentity identity, string loadDirector string.Format(null, ScriptingResources.AssemblyAlreadyLoaded, identity.Name, identity.Version, - loadedAssemblyWithEqualNameAndVersionOpt.LocationOpt, - assemblyFilePathOpt) + loadedAssemblyWithEqualNameAndVersionOpt.Location, + assemblyFilePath) ); } @@ -328,12 +309,12 @@ internal Assembly ResolveAssembly(AssemblyIdentity identity, string loadDirector throw new InteractiveAssemblyLoaderException( string.Format(null, ScriptingResources.AssemblyAlreadyLoadedNotSigned, identity.Name, - conflictingLoadedAssemblyOpt.LocationOpt, - assemblyFilePathOpt) + conflictingLoadedAssemblyOpt.Location, + assemblyFilePath) ); } - assembly = ShadowCopyAndLoadDependency(assemblyFilePathOpt).Assembly; + assembly = ShadowCopyAndLoadDependency(assemblyFilePath).Assembly; if (assembly != null) { return assembly; @@ -344,7 +325,7 @@ internal Assembly ResolveAssembly(AssemblyIdentity identity, string loadDirector return GetOrLoadKnownAssembly(identity); } - private static string FindExistingAssemblyFile(string simpleName, string directory) + private static string? FindExistingAssemblyFile(string simpleName, string directory) { string pathWithoutExtension = Path.Combine(directory, simpleName); foreach (var extension in RuntimeMetadataReferenceResolver.AssemblyExtensions) @@ -359,7 +340,7 @@ private static string FindExistingAssemblyFile(string simpleName, string directo return null; } - private Assembly TryGetAssemblyLoadedFromPath(AssemblyIdentity identity, string directory) + private Assembly? TryGetAssemblyLoadedFromPath(AssemblyIdentity identity, string directory) { string pathWithoutExtension = Path.Combine(directory, identity.Name); @@ -397,17 +378,16 @@ private static bool TryReadMvid(string filePath, out Guid mvid) } } - private Assembly GetOrLoadKnownAssembly(AssemblyIdentity identity) + private Assembly? GetOrLoadKnownAssembly(AssemblyIdentity identity) { - Assembly assembly = null; - string assemblyFileToLoad = null; + Assembly? assembly = null; + string? assemblyFileToLoad = null; // Try to find the assembly among assemblies that we loaded, comparing its identity with the requested one. lock (_referencesLock) { // already loaded assemblies: - List infos; - if (_loadedAssembliesBySimpleName.TryGetValue(identity.Name, out infos)) + if (_loadedAssembliesBySimpleName.TryGetValue(identity.Name, out var infos)) { assembly = FindHighestVersionOrFirstMatchingIdentity(identity, infos); if (assembly != null) @@ -417,8 +397,7 @@ private Assembly GetOrLoadKnownAssembly(AssemblyIdentity identity) } // names: - List sameSimpleNameIdentities; - if (_dependenciesWithLocationBySimpleName.TryGetValue(identity.Name, out sameSimpleNameIdentities)) + if (_dependenciesWithLocationBySimpleName.TryGetValue(identity.Name, out var sameSimpleNameIdentities)) { var identityAndLocation = FindHighestVersionOrFirstMatchingIdentity(identity, sameSimpleNameIdentities); if (identityAndLocation.Identity != null) @@ -446,7 +425,7 @@ private AssemblyAndLocation ShadowCopyAndLoadDependency(string originalPath) AssemblyAndLocation assemblyAndLocation = Load(originalPath); if (assemblyAndLocation.IsDefault) { - return default(AssemblyAndLocation); + return default; } lock (_referencesLock) @@ -454,8 +433,7 @@ private AssemblyAndLocation ShadowCopyAndLoadDependency(string originalPath) // Always remember the path. The assembly might have been loaded from another path or not loaded yet. _assembliesLoadedFromLocationByFullPath[originalPath] = assemblyAndLocation; - LoadedAssembly loadedAssembly; - if (_assembliesLoadedFromLocation.TryGetValue(assemblyAndLocation.Assembly, out loadedAssembly)) + if (_assembliesLoadedFromLocation.TryGetValue(assemblyAndLocation.Assembly, out var loadedAssembly)) { return assemblyAndLocation; } @@ -470,10 +448,10 @@ private AssemblyAndLocation ShadowCopyAndLoadDependency(string originalPath) return assemblyAndLocation; } - private static Assembly FindHighestVersionOrFirstMatchingIdentity(AssemblyIdentity identity, IEnumerable infos) + private static Assembly? FindHighestVersionOrFirstMatchingIdentity(AssemblyIdentity identity, IEnumerable infos) { - Assembly candidate = null; - Version candidateVersion = null; + Assembly? candidate = null; + Version? candidateVersion = null; foreach (var info in infos) { if (DesktopAssemblyIdentityComparer.Default.ReferenceMatchesDefinition(identity, info.Identity)) diff --git a/src/Scripting/Core/Hosting/CommandLine/CommandLineRunner.cs b/src/Scripting/Core/Hosting/CommandLine/CommandLineRunner.cs index d4cd9a8baf048..369e4c2ddf217 100644 --- a/src/Scripting/Core/Hosting/CommandLine/CommandLineRunner.cs +++ b/src/Scripting/Core/Hosting/CommandLine/CommandLineRunner.cs @@ -22,8 +22,6 @@ namespace Microsoft.CodeAnalysis.Scripting.Hosting { internal sealed class CommandLineRunner { - private readonly ConsoleIO _console; - private readonly CommonCompiler _compiler; private readonly ScriptCompiler _scriptCompiler; private readonly ObjectFormatter _objectFormatter; @@ -34,15 +32,15 @@ internal CommandLineRunner(ConsoleIO console, CommonCompiler compiler, ScriptCom Debug.Assert(scriptCompiler != null); Debug.Assert(objectFormatter != null); - _console = console; - _compiler = compiler; + Console = console; + Compiler = compiler; _scriptCompiler = scriptCompiler; _objectFormatter = objectFormatter; } // for testing: - internal ConsoleIO Console => _console; - internal CommonCompiler Compiler => _compiler; + internal ConsoleIO Console { get; } + internal CommonCompiler Compiler { get; } /// /// csi.exe and vbi.exe entry point. @@ -50,9 +48,9 @@ internal CommandLineRunner(ConsoleIO console, CommonCompiler compiler, ScriptCom internal int RunInteractive() { SarifErrorLogger errorLogger = null; - if (_compiler.Arguments.ErrorLogOptions?.Path != null) + if (Compiler.Arguments.ErrorLogOptions?.Path != null) { - errorLogger = _compiler.GetErrorLogger(_console.Error); + errorLogger = Compiler.GetErrorLogger(Console.Error); if (errorLogger == null) { return CommonCompiler.Failed; @@ -70,35 +68,35 @@ internal int RunInteractive() /// private int RunInteractiveCore(ErrorLogger errorLogger) { - Debug.Assert(_compiler.Arguments.IsScriptRunner); + Debug.Assert(Compiler.Arguments.IsScriptRunner); - var sourceFiles = _compiler.Arguments.SourceFiles; + var sourceFiles = Compiler.Arguments.SourceFiles; - if (_compiler.Arguments.DisplayVersion) + if (Compiler.Arguments.DisplayVersion) { - _compiler.PrintVersion(_console.Out); + Compiler.PrintVersion(Console.Out); return 0; } - if (_compiler.Arguments.DisplayLangVersions) + if (Compiler.Arguments.DisplayLangVersions) { - _compiler.PrintLangVersions(_console.Out); + Compiler.PrintLangVersions(Console.Out); return 0; } - if (sourceFiles.IsEmpty && _compiler.Arguments.DisplayLogo) + if (sourceFiles.IsEmpty && Compiler.Arguments.DisplayLogo) { - _compiler.PrintLogo(_console.Out); + Compiler.PrintLogo(Console.Out); - if (!_compiler.Arguments.DisplayHelp) + if (!Compiler.Arguments.DisplayHelp) { - _console.Out.WriteLine(ScriptingResources.HelpPrompt); + Console.Out.WriteLine(ScriptingResources.HelpPrompt); } } - if (_compiler.Arguments.DisplayHelp) + if (Compiler.Arguments.DisplayHelp) { - _compiler.PrintHelp(_console.Out); + Compiler.PrintHelp(Console.Out); return 0; } @@ -110,29 +108,29 @@ private int RunInteractiveCore(ErrorLogger errorLogger) { if (sourceFiles.Length > 1 || !sourceFiles[0].IsScript) { - diagnosticsInfos.Add(new DiagnosticInfo(_compiler.MessageProvider, _compiler.MessageProvider.ERR_ExpectedSingleScript)); + diagnosticsInfos.Add(new DiagnosticInfo(Compiler.MessageProvider, Compiler.MessageProvider.ERR_ExpectedSingleScript)); } else { - code = _compiler.TryReadFileContent(sourceFiles[0], diagnosticsInfos); + code = Compiler.TryReadFileContent(sourceFiles[0], diagnosticsInfos); } } // only emit symbols for non-interactive mode, - var emitDebugInformation = !_compiler.Arguments.InteractiveMode; + var emitDebugInformation = !Compiler.Arguments.InteractiveMode; var scriptPathOpt = sourceFiles.IsEmpty ? null : sourceFiles[0].Path; - var scriptOptions = GetScriptOptions(_compiler.Arguments, scriptPathOpt, _compiler.MessageProvider, diagnosticsInfos, emitDebugInformation); + var scriptOptions = GetScriptOptions(Compiler.Arguments, scriptPathOpt, Compiler.MessageProvider, diagnosticsInfos, emitDebugInformation); - var errors = _compiler.Arguments.Errors.Concat(diagnosticsInfos.Select(Diagnostic.Create)); - if (_compiler.ReportDiagnostics(errors, _console.Error, errorLogger, compilation: null)) + var errors = Compiler.Arguments.Errors.Concat(diagnosticsInfos.Select(Diagnostic.Create)); + if (Compiler.ReportDiagnostics(errors, Console.Error, errorLogger, compilation: null)) { return CommonCompiler.Failed; } var cancellationToken = new CancellationToken(); - if (_compiler.Arguments.InteractiveMode) + if (Compiler.Arguments.InteractiveMode) { RunInteractiveLoop(scriptOptions, code?.ToString(), cancellationToken); return CommonCompiler.Succeeded; @@ -191,8 +189,8 @@ internal static SourceReferenceResolver GetSourceReferenceResolver(CommandLineAr private int RunScript(ScriptOptions options, SourceText code, ErrorLogger errorLogger, CancellationToken cancellationToken) { - var globals = new CommandLineScriptGlobals(_console.Out, _objectFormatter); - globals.Args.AddRange(_compiler.Arguments.ScriptArguments); + var globals = new CommandLineScriptGlobals(Console.Out, _objectFormatter); + globals.Args.AddRange(Compiler.Arguments.ScriptArguments); var script = Script.CreateInitialScript(_scriptCompiler, code, options, globals.GetType(), assemblyLoaderOpt: null); try @@ -201,7 +199,7 @@ private int RunScript(ScriptOptions options, SourceText code, ErrorLogger errorL } catch (CompilationErrorException e) { - _compiler.ReportDiagnostics(e.Diagnostics, _console.Error, errorLogger, compilation: null); + Compiler.ReportDiagnostics(e.Diagnostics, Console.Error, errorLogger, compilation: null); return CommonCompiler.Failed; } catch (Exception e) @@ -213,8 +211,8 @@ private int RunScript(ScriptOptions options, SourceText code, ErrorLogger errorL private void RunInteractiveLoop(ScriptOptions options, string initialScriptCodeOpt, CancellationToken cancellationToken) { - var globals = new InteractiveScriptGlobals(_console.Out, _objectFormatter); - globals.Args.AddRange(_compiler.Arguments.ScriptArguments); + var globals = new InteractiveScriptGlobals(Console.Out, _objectFormatter); + globals.Args.AddRange(Compiler.Arguments.ScriptArguments); ScriptState state = null; @@ -226,14 +224,14 @@ private void RunInteractiveLoop(ScriptOptions options, string initialScriptCodeO while (true) { - _console.Out.Write("> "); + Console.Out.Write("> "); var input = new StringBuilder(); string line; bool cancelSubmission = false; while (true) { - line = _console.In.ReadLine(); + line = Console.In.ReadLine(); if (line == null) { if (input.Length == 0) @@ -253,7 +251,7 @@ private void RunInteractiveLoop(ScriptOptions options, string initialScriptCodeO break; } - _console.Out.Write(". "); + Console.Out.Write(". "); } if (cancelSubmission) @@ -335,20 +333,20 @@ private void DisplayException(Exception e) { try { - _console.SetForegroundColor(ConsoleColor.Red); + Console.SetForegroundColor(ConsoleColor.Red); if (e is FileLoadException && e.InnerException is InteractiveAssemblyLoaderException) { - _console.Error.WriteLine(e.InnerException.Message); + Console.Error.WriteLine(e.InnerException.Message); } else { - _console.Error.Write(_objectFormatter.FormatException(e)); + Console.Error.Write(_objectFormatter.FormatException(e)); } } finally { - _console.ResetColor(); + Console.ResetColor(); } } @@ -361,8 +359,8 @@ private static bool IsHelpCommand(string text) private void DisplayHelpText() { - _console.Out.Write(ScriptingResources.HelpText); - _console.Out.WriteLine(); + Console.Out.Write(ScriptingResources.HelpText); + Console.Out.WriteLine(); } private void DisplayDiagnostics(ImmutableArray diagnostics) @@ -380,20 +378,20 @@ private void DisplayDiagnostics(ImmutableArray diagnostics) { foreach (var diagnostic in ordered.Take(MaxDisplayCount)) { - _console.SetForegroundColor(diagnostic.Severity == DiagnosticSeverity.Error ? ConsoleColor.Red : ConsoleColor.Yellow); - _console.Error.WriteLine(diagnostic.ToString()); + Console.SetForegroundColor(diagnostic.Severity == DiagnosticSeverity.Error ? ConsoleColor.Red : ConsoleColor.Yellow); + Console.Error.WriteLine(diagnostic.ToString()); } if (diagnostics.Length > MaxDisplayCount) { int notShown = diagnostics.Length - MaxDisplayCount; - _console.SetForegroundColor(ConsoleColor.DarkRed); - _console.Error.WriteLine(string.Format(ScriptingResources.PlusAdditionalError, notShown)); + Console.SetForegroundColor(ConsoleColor.DarkRed); + Console.Error.WriteLine(string.Format(ScriptingResources.PlusAdditionalError, notShown)); } } finally { - _console.ResetColor(); + Console.ResetColor(); } } } diff --git a/src/Scripting/Core/Microsoft.CodeAnalysis.Scripting.csproj b/src/Scripting/Core/Microsoft.CodeAnalysis.Scripting.csproj index ca855a03458bf..127c5b51a41dc 100644 --- a/src/Scripting/Core/Microsoft.CodeAnalysis.Scripting.csproj +++ b/src/Scripting/Core/Microsoft.CodeAnalysis.Scripting.csproj @@ -20,10 +20,6 @@ - - - - Hosting\Resolvers\RelativePathResolver.cs diff --git a/src/Scripting/Core/ScriptExecutionState.cs b/src/Scripting/Core/ScriptExecutionState.cs index 2b6ebd767d63d..e2f9fcf43aefb 100644 --- a/src/Scripting/Core/ScriptExecutionState.cs +++ b/src/Scripting/Core/ScriptExecutionState.cs @@ -21,13 +21,12 @@ namespace Microsoft.CodeAnalysis.Scripting internal sealed class ScriptExecutionState { private object[] _submissionStates; - private int _count; private int _frozen; private ScriptExecutionState(object[] submissionStates, int count) { _submissionStates = submissionStates; - _count = count; + SubmissionStateCount = count; } public static ScriptExecutionState Create(object globals) @@ -47,22 +46,22 @@ public ScriptExecutionState FreezeAndClone() { // since only one state can add to the submissions, if its already been frozen and clone before // make a copy of the visible contents for the new state. - var copy = new object[_count]; - Array.Copy(_submissionStates, copy, _count); - return new ScriptExecutionState(copy, _count); + var copy = new object[SubmissionStateCount]; + Array.Copy(_submissionStates, copy, SubmissionStateCount); + return new ScriptExecutionState(copy, SubmissionStateCount); } else { // cloned state can continue to add submission states - return new ScriptExecutionState(_submissionStates, _count); + return new ScriptExecutionState(_submissionStates, SubmissionStateCount); } } - public int SubmissionStateCount => _count; + public int SubmissionStateCount { get; private set; } public object GetSubmissionState(int index) { - Debug.Assert(index >= 0 && index < _count); + Debug.Assert(index >= 0 && index < SubmissionStateCount); return _submissionStates[index]; } @@ -158,18 +157,18 @@ internal async Task RunSubmissionsAsync( private void EnsureStateCapacity() { // make sure there is enough free space for the submission to add its state - if (_count >= _submissionStates.Length) + if (SubmissionStateCount >= _submissionStates.Length) { - Array.Resize(ref _submissionStates, Math.Max(_count, _submissionStates.Length * 2)); + Array.Resize(ref _submissionStates, Math.Max(SubmissionStateCount, _submissionStates.Length * 2)); } } private void AdvanceStateCounter() { // check to see if state was added (submissions that don't make declarations don't add state) - if (_submissionStates[_count] != null) + if (_submissionStates[SubmissionStateCount] != null) { - _count++; + SubmissionStateCount++; } } } diff --git a/src/Scripting/Core/Utilities/PdbHelpers.cs b/src/Scripting/Core/Utilities/PdbHelpers.cs index fe8f6747b2a88..a4d1b5ea0e52b 100644 --- a/src/Scripting/Core/Utilities/PdbHelpers.cs +++ b/src/Scripting/Core/Utilities/PdbHelpers.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 Microsoft.CodeAnalysis.Emit; @@ -13,14 +11,19 @@ internal static class PdbHelpers { public static DebugInformationFormat GetPlatformSpecificDebugInformationFormat() { - // for CoreCLR & Mono, use PortablePdb - if (CoreClrShim.AssemblyLoadContext.Type != null || Type.GetType("Mono.Runtime") != null) +#if NET + // Use PortablePdb for .NET + return DebugInformationFormat.PortablePdb; +#else + // Use PortablePdb for Mono + if (Type.GetType("Mono.Runtime") != null) { return DebugInformationFormat.PortablePdb; } // otherwise standard PDB return DebugInformationFormat.Pdb; +#endif } } } diff --git a/src/Scripting/CoreTestUtilities/Microsoft.CodeAnalysis.Scripting.TestUtilities.csproj b/src/Scripting/CoreTestUtilities/Microsoft.CodeAnalysis.Scripting.TestUtilities.csproj index 8f4f5897a7906..4a8e63bf4da65 100644 --- a/src/Scripting/CoreTestUtilities/Microsoft.CodeAnalysis.Scripting.TestUtilities.csproj +++ b/src/Scripting/CoreTestUtilities/Microsoft.CodeAnalysis.Scripting.TestUtilities.csproj @@ -7,7 +7,7 @@ net472;$(NetRoslyn) true false - true + true true diff --git a/src/Scripting/VisualBasicTest/ScriptTests.vb b/src/Scripting/VisualBasicTest/ScriptTests.vb index e1a903ddca8a4..093475ccfb7d5 100644 --- a/src/Scripting/VisualBasicTest/ScriptTests.vb +++ b/src/Scripting/VisualBasicTest/ScriptTests.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Threading.Tasks +Imports Basic.Reference.Assemblies Imports Microsoft.CodeAnalysis.Scripting Imports Roslyn.Test.Utilities Imports Xunit @@ -17,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.UnitTests ''' will attempt to validate file paths and one does not exist for this reference as it's an in ''' memory item. ''' - Private Shared ReadOnly s_msvbReference As PortableExecutableReference = AssemblyMetadata.CreateFromImage(TestMetadata.ResourcesNet451.MicrosoftVisualBasic).GetReference() + Private Shared ReadOnly s_msvbReference As PortableExecutableReference = AssemblyMetadata.CreateFromImage(Net461.Resources.MicrosoftVisualBasic).GetReference() ' It shouldn't be necessary to include VB runtime assembly ' explicitly in VisualBasicScript.Create. diff --git a/src/Setup/DevDivVsix/CompilersPackage/CompilersPackage.targets b/src/Setup/DevDivVsix/CompilersPackage/CompilersPackage.targets index bec9c7c8e1d33..b398c100c0065 100644 --- a/src/Setup/DevDivVsix/CompilersPackage/CompilersPackage.targets +++ b/src/Setup/DevDivVsix/CompilersPackage/CompilersPackage.targets @@ -47,7 +47,7 @@ BeforeTargets="SwixBuild" DependsOnTargets="_SetSwrFilePath;InitializeDesktopCompilerArtifacts;_PrepareDesktopCompilerArtifactsForOptimization;ApplyOptimizations" Outputs="$(_SwrFilePath)" - Condition="'$(DotNetBuildFromSource)' != 'true'"> + Condition="'$(DotNetBuildSourceOnly)' != 'true'"> <_File Include="@(DesktopCompilerArtifact)"> diff --git a/src/Setup/Directory.Build.props b/src/Setup/Directory.Build.props index 50fecf188a03e..394b128ba0fb3 100644 --- a/src/Setup/Directory.Build.props +++ b/src/Setup/Directory.Build.props @@ -1,7 +1,7 @@ - true + true true diff --git a/src/Setup/Installer/Installer.Package.csproj b/src/Setup/Installer/Installer.Package.csproj index 52641789c8dee..4cd2da2a01854 100644 --- a/src/Setup/Installer/Installer.Package.csproj +++ b/src/Setup/Installer/Installer.Package.csproj @@ -24,7 +24,7 @@ DependsOnTargets="_CalculateInputsOutputs;ResolveProjectReferences" Inputs="$(MSBuildAllProjects);$(_DeploymentVsixPath)" Outputs="$(_InstallerFilePath)" - Condition="'$(DotNetBuildFromSource)' != 'true' and '$(MSBuildRuntimeType)' != 'Core'"> + Condition="'$(DotNetBuildSourceOnly)' != 'true' and '$(MSBuildRuntimeType)' != 'Core'"> <_Files Include="$(MSBuildProjectDirectory)\tools\*.*" TargetDir="tools"/> <_Files Include="$(MSBuildProjectDirectory)\scripts\*.*" TargetDir=""/> diff --git a/src/Test/Directory.Build.props b/src/Test/Directory.Build.props index 6eef643958f56..9dd0ddea9df26 100644 --- a/src/Test/Directory.Build.props +++ b/src/Test/Directory.Build.props @@ -1,6 +1,6 @@ - true + true diff --git a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs index e1da918c194b7..222a9f07b76fc 100644 --- a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs +++ b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs @@ -11,6 +11,7 @@ using System.Reflection.Metadata.Ecma335; using Microsoft.CodeAnalysis.Symbols; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Utilities; using Roslyn.Test.Utilities; namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests @@ -127,14 +128,7 @@ public void VerifySynthesizedMembers(params string[] expected) => VerifySynthesizedMembers(displayTypeKind: false, expected); public void VerifySynthesizedMembers(bool displayTypeKind, params string[] expected) - => Verify(() => - { - var actual = GetSynthesizedMembers().Select(e => - $"{(displayTypeKind && e.Key is INamedTypeSymbolInternal type ? (type.TypeKind == TypeKind.Struct ? "struct " : "class ") : "")}{e.Key}: " + - $"{{{string.Join(", ", e.Value.Select(v => v.Name))}}}"); - - AssertEx.SetEqual(expected, actual, itemSeparator: ",\r\n", itemInspector: s => $"\"{s}\""); - }); + => Verify(() => CompilationDifference.VerifySynthesizedMembers(GetSynthesizedMembers(), displayTypeKind, expected)); public void VerifySynthesizedFields(string typeName, params string[] expectedSynthesizedTypesAndMemberCounts) => Verify(() => @@ -161,7 +155,23 @@ public void VerifyChangedTypeNames(params string[] expectedTypeNames) }); internal void VerifyMethodBody(string qualifiedMemberName, string expectedILWithSequencePoints) - => Verify(() => generationInfo.CompilationVerifier!.VerifyMethodBody(qualifiedMemberName, expectedILWithSequencePoints)); + => Verify(() => + { + if (generationInfo.CompilationVerifier != null) + { + generationInfo.CompilationVerifier.VerifyMethodBody(qualifiedMemberName, expectedILWithSequencePoints); + } + else + { + Debug.Assert(generationInfo.CompilationDifference != null); + var updatedMethods = generationInfo.CompilationDifference.EmitResult.UpdatedMethods; + + Debug.Assert(updatedMethods.Length == 1, "Only supported for a single method update"); + var updatedMethodToken = updatedMethods.Single(); + + generationInfo.CompilationDifference.VerifyIL(qualifiedMemberName, expectedILWithSequencePoints, methodToken: updatedMethodToken); + } + }); internal void VerifyPdb(IEnumerable methodTokens, string expectedPdb) => Verify(() => generationInfo.CompilationDifference!.VerifyPdb(methodTokens, expectedPdb, expectedIsRawXml: true)); @@ -192,6 +202,15 @@ internal void VerifyIL(string qualifiedMemberName, string expectedIL) generationInfo.CompilationDifference.VerifyIL(qualifiedMemberName, expectedIL); } }); + + public void VerifyLocalSignature(string qualifiedMethodName, string expectedSignature) + => Verify(() => + { + var testData = generationInfo.CompilationVerifier?.TestData ?? generationInfo.CompilationDifference!.TestData; + var ilBuilder = testData.GetMethodData(qualifiedMethodName).ILBuilder; + var actualSignature = ILBuilderVisualizer.LocalSignatureToString(ilBuilder); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedSignature, actualSignature, escapeQuotes: true); + }); } } } diff --git a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs index 638b2dfcf3d6c..f51868ce67eab 100644 --- a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs +++ b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs @@ -13,11 +13,13 @@ using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; +using Roslyn.Utilities; using Xunit; +using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests { - internal abstract partial class EditAndContinueTest(Verification? verification = null) : IDisposable + internal abstract partial class EditAndContinueTest(ITestOutputHelper? output = null, Verification? verification = null) : IDisposable where TSelf : EditAndContinueTest { private readonly Verification _verification = verification ?? Verification.Passes; @@ -33,7 +35,7 @@ internal abstract partial class EditAndContinueTest(Verification? verific private TSelf This => (TSelf)this; - internal TSelf AddBaseline(string source, Action? validator = null) + internal TSelf AddBaseline(string source, Action? validator = null, Func? debugInformationProvider = null) { _hasVerified = false; @@ -45,20 +47,22 @@ internal TSelf AddBaseline(string source, Action? validator var verifier = new CompilationVerifier(compilation); + output?.WriteLine($"Emitting baseline"); + verifier.Emit( expectedOutput: null, trimOutput: false, expectedReturnCode: null, args: null, manifestResources: null, - emitOptions: EmitOptions.Default, + emitOptions: EmitOptions.Default.WithDebugInformationFormat(DebugInformationFormat.PortablePdb), peVerify: _verification, expectedSignatures: null); var md = ModuleMetadata.CreateFromImage(verifier.EmittedAssemblyData); _disposables.Add(md); - var baseline = EditAndContinueTestUtilities.CreateInitialBaseline(compilation, md, verifier.CreateSymReader().GetEncMethodDebugInfo); + var baseline = EditAndContinueTestUtilities.CreateInitialBaseline(compilation, md, debugInformationProvider ?? verifier.CreateSymReader().GetEncMethodDebugInfo); _generations.Add(new GenerationInfo(compilation, md.MetadataReader, diff: null, verifier, baseline, validator ?? new(x => { }))); _sources.Add(markedSource); @@ -70,6 +74,12 @@ internal TSelf AddGeneration(string source, SemanticEditDescription[] edits, Act => AddGeneration(source, _ => edits, validator); internal TSelf AddGeneration(string source, Func edits, Action validator) + => AddGeneration(source, edits, validator, expectedErrors: []); + + internal TSelf AddGeneration(string source, SemanticEditDescription[] edits, DiagnosticDescription[] expectedErrors) + => AddGeneration(source, _ => edits, validator: static _ => { }, expectedErrors); + + private TSelf AddGeneration(string source, Func edits, Action validator, DiagnosticDescription[] expectedErrors) { _hasVerified = false; @@ -85,9 +95,15 @@ internal TSelf AddGeneration(string source, Func d.Severity == DiagnosticSeverity.Error)); + diff.EmitResult.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).Verify(expectedErrors); + if (expectedErrors is not []) + { + return This; + } var md = diff.GetMetadata(); _disposables.Add(md); diff --git a/src/Tools/AnalyzerRunner/PerformanceTracker.cs b/src/Tools/AnalyzerRunner/PerformanceTracker.cs index 8fe321588d85d..9bc2328e99921 100644 --- a/src/Tools/AnalyzerRunner/PerformanceTracker.cs +++ b/src/Tools/AnalyzerRunner/PerformanceTracker.cs @@ -12,13 +12,13 @@ namespace AnalyzerRunner internal sealed class PerformanceTracker { private readonly Stopwatch _stopwatch; -#if NETCOREAPP +#if NET private readonly long _initialTotalAllocatedBytes; #endif public PerformanceTracker(Stopwatch stopwatch, long initialTotalAllocatedBytes) { -#if NETCOREAPP +#if NET _initialTotalAllocatedBytes = initialTotalAllocatedBytes; #endif _stopwatch = stopwatch; @@ -26,7 +26,7 @@ public PerformanceTracker(Stopwatch stopwatch, long initialTotalAllocatedBytes) public static PerformanceTracker StartNew(bool preciseMemory = true) { -#if NETCOREAPP +#if NET var initialTotalAllocatedBytes = GC.GetTotalAllocatedBytes(preciseMemory); #else var initialTotalAllocatedBytes = 0L; @@ -37,7 +37,7 @@ public static PerformanceTracker StartNew(bool preciseMemory = true) public TimeSpan Elapsed => _stopwatch.Elapsed; -#if NETCOREAPP +#if NET public long AllocatedBytes => GC.GetTotalAllocatedBytes(true) - _initialTotalAllocatedBytes; #else public long AllocatedBytes => 0; @@ -45,7 +45,7 @@ public static PerformanceTracker StartNew(bool preciseMemory = true) public string GetSummary(bool preciseMemory = true) { -#if NETCOREAPP +#if NET var elapsedTime = Elapsed; var allocatedBytes = GC.GetTotalAllocatedBytes(preciseMemory) - _initialTotalAllocatedBytes; diff --git a/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs b/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs index 23717503f643f..d1f46f1ddbfb0 100644 --- a/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs +++ b/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs @@ -330,8 +330,8 @@ private static string GetChecksum(string filePath) private static string GetChecksum(Stream stream) { - using var md5 = MD5.Create(); - return BitConverter.ToString(md5.ComputeHash(stream)); + using var hash = SHA256.Create(); + return BitConverter.ToString(hash.ComputeHash(stream)); } /// diff --git a/src/Tools/BuildValidator/BuildValidator.csproj b/src/Tools/BuildValidator/BuildValidator.csproj index 3800558e4d50f..24eefed6e66e3 100644 --- a/src/Tools/BuildValidator/BuildValidator.csproj +++ b/src/Tools/BuildValidator/BuildValidator.csproj @@ -9,6 +9,7 @@ enable true false + true AnyCPU diff --git a/src/Tools/BuildValidator/IldasmUtilities.cs b/src/Tools/BuildValidator/IldasmUtilities.cs index b617c37ff759b..3f22c5d7e6299 100644 --- a/src/Tools/BuildValidator/IldasmUtilities.cs +++ b/src/Tools/BuildValidator/IldasmUtilities.cs @@ -12,6 +12,15 @@ namespace BuildValidator { internal static class IldasmUtilities { + private static string GetArchitecture() + { +#if NET8_0_OR_GREATER + return RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(); +#else + return "x64"; +#endif + } + private static string GetIldasmPath() { var ildasmExeName = PlatformInformation.IsWindows ? "ildasm.exe" : "ildasm"; @@ -27,7 +36,7 @@ private static string GetIldasmPath() } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - ridName = "linux-x64"; + ridName = $"linux-{GetArchitecture()}"; } else { diff --git a/src/Tools/Directory.Build.props b/src/Tools/Directory.Build.props index 6eef643958f56..9dd0ddea9df26 100644 --- a/src/Tools/Directory.Build.props +++ b/src/Tools/Directory.Build.props @@ -1,6 +1,6 @@ - true + true diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Completion.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Completion.cs new file mode 100644 index 0000000000000..3e284056947b0 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Completion.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.LanguageServer.Handler.Completion; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; + +internal static class Completion +{ + private static CompletionListCache? s_completionListCache; + + private static CompletionListCache GetCache() + => s_completionListCache ??= InterlockedOperations.Initialize(ref s_completionListCache, () => new()); + + public static async Task GetCompletionListAsync( + Document document, + LinePosition linePosition, + LSP.CompletionContext? completionContext, + bool supportsVSExtensions, + LSP.CompletionSetting completionCapabilities, + CancellationToken cancellationToken) + { + var cache = GetCache(); + + var position = await document + .GetPositionFromLinePositionAsync(linePosition, cancellationToken) + .ConfigureAwait(false); + + var globalOptions = document.Project.Solution.Services.ExportProvider.GetService(); + var capabilityHelper = new CompletionCapabilityHelper(supportsVSExtensions, completionCapabilities); + + return await CompletionHandler.GetCompletionListAsync( + document, + position, + completionContext, + globalOptions, + capabilityHelper, + cache, + cancellationToken).ConfigureAwait(false); + } + + public static Task ResolveCompletionItemAsync( + LSP.CompletionItem completionItem, + Document document, + bool supportsVSExtensions, + LSP.CompletionSetting completionCapabilities, + CancellationToken cancellationToken) + { + var cache = GetCache(); + + var globalOptions = document.Project.Solution.Services.ExportProvider.GetService(); + var capabilityHelper = new CompletionCapabilityHelper(supportsVSExtensions, completionCapabilities); + + return CompletionResolveHandler.ResolveCompletionItemAsync( + completionItem, document, globalOptions, capabilityHelper, cache, cancellationToken); + } +} diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Diagnostics.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Diagnostics.cs new file mode 100644 index 0000000000000..b0313ab63e20e --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Diagnostics.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PooledObjects; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; + +internal static class Diagnostics +{ + public static async Task> GetDocumentDiagnosticsAsync(Document document, bool supportsVisualStudioExtensions, CancellationToken cancellationToken) + { + var globalOptionsService = document.Project.Solution.Services.ExportProvider.GetService(); + var diagnosticAnalyzerService = document.Project.Solution.Services.ExportProvider.GetService(); + + var diagnostics = await diagnosticAnalyzerService.GetDiagnosticsForSpanAsync(document, range: null, cancellationToken).ConfigureAwait(false); + + var project = document.Project; + // isLiveSource means build might override a diagnostics, but this method is only used by tooling, so builds aren't relevant + const bool IsLiveSource = false; + // Potential duplicate is only set for workspace diagnostics + const bool PotentialDuplicate = false; + + var result = ArrayBuilder.GetInstance(capacity: diagnostics.Length); + foreach (var diagnostic in diagnostics) + { + result.AddRange(ProtocolConversions.ConvertDiagnostic(diagnostic, supportsVisualStudioExtensions, project, IsLiveSource, PotentialDuplicate, globalOptionsService)); + } + + return result.ToImmutableAndFree(); + } +} diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSpellCheck.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSpellCheck.cs new file mode 100644 index 0000000000000..c1d9310d3cd6a --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSpellCheck.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.SpellCheck; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; + +internal static class SpellCheck +{ + public readonly record struct SpellCheckSpan(int StartIndex, int Length, VSInternalSpellCheckableRangeKind Kind); + + public static async Task> GetSpellCheckSpansAsync(Document document, CancellationToken cancellationToken) + { + var service = document.GetLanguageService(); + if (service is null) + { + return []; + } + + var spans = await service.GetSpansAsync(document, cancellationToken).ConfigureAwait(false); + + using var _ = ArrayBuilder.GetInstance(spans.Length, out var razorSpans); + foreach (var span in spans) + { + var kind = ProtocolConversions.SpellCheckSpanKindToSpellCheckableRangeKind(span.Kind); + razorSpans.Add(new SpellCheckSpan(span.TextSpan.Start, span.TextSpan.Length, kind)); + } + + return razorSpans.ToImmutable(); + } +} diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSymbols.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSymbols.cs new file mode 100644 index 0000000000000..51db13bc8f38b --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/DocumentSymbols.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; + +internal static class DocumentSymbols +{ + public static Task> GetDocumentSymbolsAsync( + Document document, bool useHierarchicalSymbols, bool supportsVSExtensions, CancellationToken cancellationToken) + { + // supportsVSExtensions controls whether or not any SymbolInformation that's returned is a VSSymbolInformation + // with a VSImageId. This value should be retrieved from the language server's client capabilities. + return DocumentSymbolsHandler.GetDocumentSymbolsAsync(document, useHierarchicalSymbols, supportsVSExtensions, cancellationToken); + } + + [Obsolete("Update to call overload that takes 'supportsVSExtensions' argument.")] + public static Task> GetDocumentSymbolsAsync( + Document document, bool useHierarchicalSymbols, CancellationToken cancellationToken) + => GetDocumentSymbolsAsync(document, useHierarchicalSymbols, supportsVSExtensions: false, cancellationToken); +} diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/GoToImplementation.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/GoToImplementation.cs new file mode 100644 index 0000000000000..6124fb821981a --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/GoToImplementation.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; + +using Location = Roslyn.LanguageServer.Protocol.Location; + +internal static class GoToImplementation +{ + public static Task FindImplementationsAsync(Document document, LinePosition linePosition, bool supportsVisualStudioExtensions, CancellationToken cancellationToken) + { + var globalOptions = document.Project.Solution.Services.ExportProvider.GetService(); + var classificationOptions = globalOptions.GetClassificationOptionsProvider(); + + return FindImplementationsHandler.FindImplementationsAsync(document, linePosition, classificationOptions, supportsVisualStudioExtensions, cancellationToken); + } +} diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Hover.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Hover.cs new file mode 100644 index 0000000000000..241a80db42a5c --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/Hover.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers; + +internal static class Hover +{ + public static Task GetHoverAsync( + Document document, + LinePosition linePosition, + bool supportsVSExtensions, + bool supportsMarkdown, + CancellationToken cancellationToken) + { + var globalOptions = document.Project.Solution.Services.ExportProvider.GetService(); + + return HoverHandler.GetHoverAsync( + document, linePosition, globalOptions, supportsVSExtensions, supportsMarkdown, cancellationToken); + } +} diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/InlayHints.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/InlayHints.cs new file mode 100644 index 0000000000000..1c7fe47a2ea68 --- /dev/null +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/InlayHints.cs @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.InlineHints; +using Microsoft.CodeAnalysis.LanguageServer.Handler.InlayHint; +using Roslyn.LanguageServer.Protocol; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers +{ + internal static class InlayHints + { + // In the Roslyn LSP server this cache has the same lifetime as the LSP server. For Razor, running OOP, we don't have + // that same lifetime anywhere, everything is just static. This is likely not ideal, but the inlay hint cache has a + // max size of 3 items, so it's not a huge deal. + private static InlayHintCache? s_resolveCache; + + public static Task GetInlayHintsAsync(Document document, TextDocumentIdentifier textDocumentIdentifier, Range range, bool displayAllOverride, CancellationToken cancellationToken) + { + s_resolveCache ??= new(); + + // Currently Roslyn options don't sync to OOP so trying to get the real options out of IGlobalOptionsService will + // always just result in the defaults, which for inline hints are to not show anything. However, the editor has a + // setting for LSP inlay hints, so we can assume that if we get a request from the client, the user wants hints. + // When overriding however, Roslyn does a nicer job if type hints are off. + var options = InlineHintsOptions.Default; + if (!displayAllOverride) + { + options = options with + { + TypeOptions = options.TypeOptions with { EnabledForTypes = true }, + ParameterOptions = options.ParameterOptions with { EnabledForParameters = true }, + }; + } + + return InlayHintHandler.GetInlayHintsAsync(document, textDocumentIdentifier, range, options, displayAllOverride, s_resolveCache, cancellationToken); + } + + public static Task ResolveInlayHintAsync(Document document, InlayHint request, CancellationToken cancellationToken) + { + Contract.ThrowIfNull(s_resolveCache, "Cache should never be null for resolve, since it should have been created by the original request"); + + return InlayHintResolveHandler.ResolveInlayHintAsync(document, request, s_resolveCache, cancellationToken); + } + } +} diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/SemanticTokensRange.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/SemanticTokensRange.cs index 2358c142b3c61..357fd8cbe5821 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/SemanticTokensRange.cs +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/SemanticTokensRange.cs @@ -20,11 +20,11 @@ public static Task GetSemanticTokensAsync( CancellationToken cancellationToken) { var tokens = SemanticTokensHelpers.HandleRequestHelperAsync( - document, - spans, - supportsVisualStudioExtensions, - ClassificationOptions.Default, - cancellationToken); + document, + spans, + supportsVisualStudioExtensions, + ClassificationOptions.Default, + cancellationToken); // The above call to get semantic tokens may be inaccurate (because we use frozen partial semantics). Kick // off a request to ensure that the OOP side gets a fully up to compilation for this project. Once it does diff --git a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/SignatureHelp.cs b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/SignatureHelp.cs index bcc8cfb0b9a52..37ab5d4cd24e5 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/Handlers/SignatureHelp.cs +++ b/src/Tools/ExternalAccess/Razor/Cohost/Handlers/SignatureHelp.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer.Handler; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.SignatureHelp; using Microsoft.CodeAnalysis.Text; using LSP = Roslyn.LanguageServer.Protocol; diff --git a/src/Tools/ExternalAccess/Razor/Cohost/RazorDynamicRegistrationServiceFactory.cs b/src/Tools/ExternalAccess/Razor/Cohost/RazorDynamicRegistrationServiceFactory.cs index 8891b52c7c275..3b12143b2c23a 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/RazorDynamicRegistrationServiceFactory.cs +++ b/src/Tools/ExternalAccess/Razor/Cohost/RazorDynamicRegistrationServiceFactory.cs @@ -36,9 +36,12 @@ private class RazorDynamicRegistrationService( IClientLanguageServerManager? clientLanguageServerManager) : ILspService, IOnInitialized, IDisposable { private readonly CancellationTokenSource _disposalTokenSource = new(); + private IDisposable? _activation; public void Dispose() { + _activation?.Dispose(); + _activation = null; _disposalTokenSource.Cancel(); } @@ -56,7 +59,7 @@ public Task OnInitializedAsync(ClientCapabilities clientCapabilities, RequestCon } else { - uIContextActivationService.ExecuteWhenActivated(Constants.RazorCohostingUIContext, InitializeRazor); + _activation = uIContextActivationService.ExecuteWhenActivated(Constants.RazorCohostingUIContext, InitializeRazor); } return Task.CompletedTask; diff --git a/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj b/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj index 41dd9af02dfb1..6164b50074dd8 100644 --- a/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj +++ b/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj @@ -31,6 +31,7 @@ + diff --git a/src/Tools/ExternalAccess/Razor/RazorCSharpInterceptionMiddleLayer.cs b/src/Tools/ExternalAccess/Razor/RazorCSharpInterceptionMiddleLayer.cs index 5b274b59a765f..5330a42dd0147 100644 --- a/src/Tools/ExternalAccess/Razor/RazorCSharpInterceptionMiddleLayer.cs +++ b/src/Tools/ExternalAccess/Razor/RazorCSharpInterceptionMiddleLayer.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Editor.Implementation.LanguageClient; -using Newtonsoft.Json.Linq; +using System.Text.Json; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor { @@ -27,10 +27,17 @@ public RazorCSharpInterceptionMiddleLayerWrapper(IRazorCSharpInterceptionMiddleL public override bool CanHandle(string methodName) => _razorCSharpInterceptionMiddleLayer.CanHandle(methodName); - public override Task HandleNotificationAsync(string methodName, JToken methodParam, Func sendNotification) - => _razorCSharpInterceptionMiddleLayer.HandleNotificationAsync(methodName, methodParam, sendNotification); + public override Task HandleNotificationAsync(string methodName, JsonElement methodParam, Func sendNotification) + { + // Razor only ever looks at the method name, so it is safe to pass null for all the Newtonsoft JToken params. + return _razorCSharpInterceptionMiddleLayer.HandleNotificationAsync(methodName, null!, null!); + } - public override Task HandleRequestAsync(string methodName, JToken methodParam, Func> sendRequest) - => _razorCSharpInterceptionMiddleLayer.HandleRequestAsync(methodName, methodParam, sendRequest); + public override Task HandleRequestAsync(string methodName, JsonElement methodParam, Func> sendRequest) + { + // Razor only implements a middlelayer for semantic tokens refresh, which is a notification. + // Cohosting makes all this unnecessary, so keeping this as minimal as possible until then. + throw new NotImplementedException(); + } } } diff --git a/src/Tools/ExternalAccess/RazorCompiler/GeneratorExtensions.cs b/src/Tools/ExternalAccess/RazorCompiler/GeneratorExtensions.cs index bc7d9f43af7be..57346d1dd157f 100644 --- a/src/Tools/ExternalAccess/RazorCompiler/GeneratorExtensions.cs +++ b/src/Tools/ExternalAccess/RazorCompiler/GeneratorExtensions.cs @@ -4,21 +4,38 @@ using System; using System.Collections.Immutable; +using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler { + /// + /// Nothing should be using these extensions, but they are kept here for now for back compat + /// in case an older razor generator is using a newer Roslyn. + /// internal static partial class GeneratorExtensions { +#pragma warning disable RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + public static void RegisterHostOutput(ref this IncrementalGeneratorInitializationContext @this, IncrementalValuesProvider source, Action action) { - _ = @this; - source.Node.RegisterOutput(new HostOutputNode(source.Node, action)); + @this.RegisterHostOutput(source, (ctx, source) => + { + var outputs = ArrayBuilder<(string, string)>.GetInstance(); + var hpc = new HostProductionContext(outputs); + action(hpc, source, CancellationToken.None); + foreach (var output in outputs) + { + ctx.AddOutput(output.Item1, output.Item2); + } + outputs.Free(); + }); } - public static ImmutableArray<(string Key, string Value)> GetHostOutputs(this GeneratorRunResult runResult) => runResult.HostOutputs; + public static ImmutableArray<(string Key, string Value)> GetHostOutputs(this GeneratorRunResult runResult) => runResult.HostOutputs.ToImmutableArray().SelectAsArray(a => (a.Key, a.Value.ToString() ?? "")); } +#pragma warning restore RSEXPERIMENTAL004 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. internal readonly struct HostProductionContext { diff --git a/src/Tools/ExternalAccess/RazorCompiler/Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj b/src/Tools/ExternalAccess/RazorCompiler/Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj index f41f08081f772..88b3a3f943dbe 100644 --- a/src/Tools/ExternalAccess/RazorCompiler/Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj +++ b/src/Tools/ExternalAccess/RazorCompiler/Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.csproj @@ -7,7 +7,7 @@ $(NetRoslynSourceBuild);netstandard2.0 - false + false true diff --git a/src/Tools/ExternalAccess/Xaml/External/ExportXamlLspServiceFactoryAttribute.cs b/src/Tools/ExternalAccess/Xaml/External/ExportXamlLspServiceFactoryAttribute.cs index 86c2e477dc98a..7dbb80bea82d5 100644 --- a/src/Tools/ExternalAccess/Xaml/External/ExportXamlLspServiceFactoryAttribute.cs +++ b/src/Tools/ExternalAccess/Xaml/External/ExportXamlLspServiceFactoryAttribute.cs @@ -14,8 +14,14 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.Xaml; [AttributeUsage(AttributeTargets.Class, AllowMultiple = false), MetadataAttribute] internal sealed class ExportXamlLspServiceFactoryAttribute : ExportLspServiceFactoryAttribute { - public ExportXamlLspServiceFactoryAttribute(Type type, WellKnownLspServerKinds serverKind = WellKnownLspServerKinds.Any) + [Obsolete("Use the constructor that takes only a type")] + public ExportXamlLspServiceFactoryAttribute(Type type, WellKnownLspServerKinds serverKind) : base(type, ProtocolConstants.RoslynLspLanguagesContract, serverKind) { } + + public ExportXamlLspServiceFactoryAttribute(Type type) + : base(type, ProtocolConstants.RoslynLspLanguagesContract) + { + } } diff --git a/src/Tools/ExternalAccess/Xaml/External/IInitializationService.cs b/src/Tools/ExternalAccess/Xaml/External/IInitializationService.cs index ae64f59cd5e32..79f20a112d286 100644 --- a/src/Tools/ExternalAccess/Xaml/External/IInitializationService.cs +++ b/src/Tools/ExternalAccess/Xaml/External/IInitializationService.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.Threading; using System.Threading.Tasks; @@ -10,6 +11,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.Xaml; /// /// Represents a service to be exported via MEF for language server initialization. /// +[Obsolete("Use IOnInitializedService instead.")] internal interface IInitializationService { /// diff --git a/src/Tools/ExternalAccess/Xaml/External/IOnInitializedService.cs b/src/Tools/ExternalAccess/Xaml/External/IOnInitializedService.cs new file mode 100644 index 0000000000000..257932731290a --- /dev/null +++ b/src/Tools/ExternalAccess/Xaml/External/IOnInitializedService.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using LSP = Roslyn.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.ExternalAccess.Xaml; + +/// +/// Represents a service to be exported via MEF for language server initialization. +/// +internal interface IOnInitializedService +{ + /// + /// Called when the language server is being initialized. + /// + Task OnInitializedAsync(IClientRequestManager clientRequestManager, LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken); +} diff --git a/src/Tools/ExternalAccess/Xaml/External/XamlRequestContext.cs b/src/Tools/ExternalAccess/Xaml/External/XamlRequestContext.cs index 2953e18dc8727..2daefd1be36d9 100644 --- a/src/Tools/ExternalAccess/Xaml/External/XamlRequestContext.cs +++ b/src/Tools/ExternalAccess/Xaml/External/XamlRequestContext.cs @@ -20,10 +20,11 @@ private XamlRequestContext(RequestContext context) _context = context; } - internal readonly LSP.ClientCapabilities ClientCapabilities => _context.GetRequiredClientCapabilities(); + public readonly LSP.ClientCapabilities ClientCapabilities => _context.GetRequiredClientCapabilities(); public readonly TextDocument? TextDocument => _context.TextDocument; + [Obsolete("Use ClientCapabilities instead.")] public readonly IClientCapabilityProvider ClientCapabilityProvider => new ClientCapabilityProvider(_context.GetRequiredClientCapabilities()); public object ToCachedResolveData(object data, Uri uri) diff --git a/src/Tools/ExternalAccess/Xaml/Internal/ClientCapabilityProvider.cs b/src/Tools/ExternalAccess/Xaml/Internal/ClientCapabilityProvider.cs index 812a79e593eef..db26259d5643d 100644 --- a/src/Tools/ExternalAccess/Xaml/Internal/ClientCapabilityProvider.cs +++ b/src/Tools/ExternalAccess/Xaml/Internal/ClientCapabilityProvider.cs @@ -79,6 +79,8 @@ public bool IsDynamicRegistrationSupported(string methodName) return internalTextDocumentClientCapabilities.OnAutoInsert?.DynamicRegistration == true; } return false; + case LSP.Methods.TextDocumentDocumentColorName: + return _clientCapabilities?.TextDocument?.ColorProvider?.DynamicRegistration == true; default: throw new InvalidOperationException($"Unsupported dynamic registration method: {methodName}"); } diff --git a/src/Tools/ExternalAccess/Xaml/Internal/OnInitializedServiceFactory.cs b/src/Tools/ExternalAccess/Xaml/Internal/OnInitializedServiceFactory.cs index 8b4d2325a6aee..e6646ca9bbd0a 100644 --- a/src/Tools/ExternalAccess/Xaml/Internal/OnInitializedServiceFactory.cs +++ b/src/Tools/ExternalAccess/Xaml/Internal/OnInitializedServiceFactory.cs @@ -15,41 +15,56 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.Xaml; [ExportCSharpVisualBasicLspServiceFactory(typeof(OnInitializedService)), Shared] internal sealed class OnInitializedServiceFactory : ILspServiceFactory { +#pragma warning disable CS0618 // Type or member is obsolete private readonly IInitializationService? _initializationService; +#pragma warning restore CS0618 // Type or member is obsolete + private readonly IOnInitializedService? _onInitializedService; [ImportingConstructor] [Obsolete(StringConstants.ImportingConstructorMessage, error: true)] - public OnInitializedServiceFactory([Import(AllowDefault = true)] IInitializationService? initializationService) + public OnInitializedServiceFactory( + [Import(AllowDefault = true)] IInitializationService? initializationService, + [Import(AllowDefault = true)] IOnInitializedService? onInitializedService) { _initializationService = initializationService; + _onInitializedService = onInitializedService; } public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) { var clientLanguageServerManager = lspServices.GetRequiredService(); - return new OnInitializedService(_initializationService, clientLanguageServerManager); + return new OnInitializedService(_initializationService, _onInitializedService, clientLanguageServerManager); } private class OnInitializedService : ILspService, IOnInitialized { +#pragma warning disable CS0618 // Type or member is obsolete private readonly IInitializationService? _initializationService; +#pragma warning restore CS0618 // Type or member is obsolete + private readonly IOnInitializedService? _onInitializedService; private readonly IClientLanguageServerManager _clientLanguageServerManager; - public OnInitializedService(IInitializationService? initializationService, IClientLanguageServerManager clientLanguageServerManager) +#pragma warning disable CS0618 // Type or member is obsolete + public OnInitializedService(IInitializationService? initializationService, IOnInitializedService? onInitializedService, IClientLanguageServerManager clientLanguageServerManager) +#pragma warning restore CS0618 // Type or member is obsolete { _initializationService = initializationService; + _onInitializedService = onInitializedService; _clientLanguageServerManager = clientLanguageServerManager; } public async Task OnInitializedAsync(LSP.ClientCapabilities clientCapabilities, RequestContext context, CancellationToken cancellationToken) { - if (_initializationService is null) + if (_initializationService is not null) { - return; + await _initializationService.OnInitializedAsync(new ClientRequestManager(_clientLanguageServerManager), new ClientCapabilityProvider(clientCapabilities), cancellationToken).ConfigureAwait(false); } - await _initializationService.OnInitializedAsync(new ClientRequestManager(_clientLanguageServerManager), new ClientCapabilityProvider(clientCapabilities), cancellationToken).ConfigureAwait(false); + if (_onInitializedService is not null) + { + await _onInitializedService.OnInitializedAsync(new ClientRequestManager(_clientLanguageServerManager), clientCapabilities, cancellationToken).ConfigureAwait(false); + } } private class ClientRequestManager : IClientRequestManager diff --git a/src/Tools/ExternalAccess/Xaml/InternalAPI.Unshipped.txt b/src/Tools/ExternalAccess/Xaml/InternalAPI.Unshipped.txt index 70cc3d4b4e678..a135ca4112674 100644 --- a/src/Tools/ExternalAccess/Xaml/InternalAPI.Unshipped.txt +++ b/src/Tools/ExternalAccess/Xaml/InternalAPI.Unshipped.txt @@ -17,7 +17,8 @@ Microsoft.CodeAnalysis.ExternalAccess.Xaml.DescriptionService.DescriptionService Microsoft.CodeAnalysis.ExternalAccess.Xaml.DescriptionService.GetDescriptionAsync(Microsoft.CodeAnalysis.ISymbol! symbol, Microsoft.CodeAnalysis.Project! project, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!>! Microsoft.CodeAnalysis.ExternalAccess.Xaml.DescriptionService.GetMarkupContent(System.Collections.Immutable.ImmutableArray tags, string! language, bool featureSupportsMarkdown) -> (string! content, bool isMarkdown) Microsoft.CodeAnalysis.ExternalAccess.Xaml.ExportXamlLspServiceFactoryAttribute -Microsoft.CodeAnalysis.ExternalAccess.Xaml.ExportXamlLspServiceFactoryAttribute.ExportXamlLspServiceFactoryAttribute(System.Type! type, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind = Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds.Any) -> void +Microsoft.CodeAnalysis.ExternalAccess.Xaml.ExportXamlLspServiceFactoryAttribute.ExportXamlLspServiceFactoryAttribute(System.Type! type) -> void +Microsoft.CodeAnalysis.ExternalAccess.Xaml.ExportXamlLspServiceFactoryAttribute.ExportXamlLspServiceFactoryAttribute(System.Type! type, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> void Microsoft.CodeAnalysis.ExternalAccess.Xaml.ExportXamlStatelessLspServiceAttribute Microsoft.CodeAnalysis.ExternalAccess.Xaml.ExportXamlStatelessLspServiceAttribute.ExportXamlStatelessLspServiceAttribute(System.Type! handlerType) -> void Microsoft.CodeAnalysis.ExternalAccess.Xaml.IClientCapabilityProvider @@ -36,6 +37,8 @@ Microsoft.CodeAnalysis.ExternalAccess.Xaml.IInitializationService.OnInitializedA Microsoft.CodeAnalysis.ExternalAccess.Xaml.ILocationService Microsoft.CodeAnalysis.ExternalAccess.Xaml.ILocationService.GetLocationAsync(Microsoft.CodeAnalysis.TextDocument! document, Microsoft.CodeAnalysis.Text.TextSpan textSpan, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.Xaml.ILocationService.GetSymbolLocationsAsync(Microsoft.CodeAnalysis.ISymbol! symbol, Microsoft.CodeAnalysis.Project! project, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task! +Microsoft.CodeAnalysis.ExternalAccess.Xaml.IOnInitializedService +Microsoft.CodeAnalysis.ExternalAccess.Xaml.IOnInitializedService.OnInitializedAsync(Microsoft.CodeAnalysis.ExternalAccess.Xaml.IClientRequestManager! clientRequestManager, Roslyn.LanguageServer.Protocol.ClientCapabilities! clientCapabilities, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task! Microsoft.CodeAnalysis.ExternalAccess.Xaml.IResolveCachedDataService Microsoft.CodeAnalysis.ExternalAccess.Xaml.IResolveCachedDataService.FromResolveData(object? resolveData) -> (object? data, System.Uri? uri) Microsoft.CodeAnalysis.ExternalAccess.Xaml.IResolveCachedDataService.ToResolveData(object! data, System.Uri! uri) -> object! @@ -50,7 +53,7 @@ Microsoft.CodeAnalysis.ExternalAccess.Xaml.LocationService.GetSymbolLocationsAsy Microsoft.CodeAnalysis.ExternalAccess.Xaml.LocationService.LocationService(Microsoft.CodeAnalysis.MetadataAsSource.IMetadataAsSourceFileService! metadataAsSourceFileService, Microsoft.CodeAnalysis.Options.IGlobalOptionService! globalOptions) -> void Microsoft.CodeAnalysis.ExternalAccess.Xaml.OnInitializedServiceFactory Microsoft.CodeAnalysis.ExternalAccess.Xaml.OnInitializedServiceFactory.CreateILspService(Microsoft.CodeAnalysis.LanguageServer.LspServices! lspServices, Microsoft.CodeAnalysis.LanguageServer.WellKnownLspServerKinds serverKind) -> Microsoft.CodeAnalysis.LanguageServer.ILspService! -Microsoft.CodeAnalysis.ExternalAccess.Xaml.OnInitializedServiceFactory.OnInitializedServiceFactory(Microsoft.CodeAnalysis.ExternalAccess.Xaml.IInitializationService? initializationService) -> void +Microsoft.CodeAnalysis.ExternalAccess.Xaml.OnInitializedServiceFactory.OnInitializedServiceFactory(Microsoft.CodeAnalysis.ExternalAccess.Xaml.IInitializationService? initializationService, Microsoft.CodeAnalysis.ExternalAccess.Xaml.IOnInitializedService? onInitializedService) -> void Microsoft.CodeAnalysis.ExternalAccess.Xaml.ResolveDataConversions Microsoft.CodeAnalysis.ExternalAccess.Xaml.StringConstants Microsoft.CodeAnalysis.ExternalAccess.Xaml.XamlCommandAttribute diff --git a/src/Tools/Replay/Replay.csproj b/src/Tools/Replay/Replay.csproj index 79a6869497ece..0d6c48af4cd98 100644 --- a/src/Tools/Replay/Replay.csproj +++ b/src/Tools/Replay/Replay.csproj @@ -14,6 +14,8 @@ + + diff --git a/src/Tools/SemanticSearch/ReferenceAssemblies/SemanticSearch.ReferenceAssemblies.csproj b/src/Tools/SemanticSearch/ReferenceAssemblies/SemanticSearch.ReferenceAssemblies.csproj index 12f985c4d121b..445516a39de98 100644 --- a/src/Tools/SemanticSearch/ReferenceAssemblies/SemanticSearch.ReferenceAssemblies.csproj +++ b/src/Tools/SemanticSearch/ReferenceAssemblies/SemanticSearch.ReferenceAssemblies.csproj @@ -61,10 +61,8 @@ - + - - <_PublishProjectOutputGroupOutput Include="@(_OutputFile)" /> - - + + diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CSharpSyntaxGenerator.csproj b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CSharpSyntaxGenerator.csproj index e1794e71faf05..20219430450e9 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CSharpSyntaxGenerator.csproj +++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CSharpSyntaxGenerator.csproj @@ -9,7 +9,7 @@ Exe $(RoslynPortableRuntimeIdentifiers) false - false + false diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Grammar/GrammarGenerator.cs b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Grammar/GrammarGenerator.cs index 5748e2260fd13..dd6d963192773 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Grammar/GrammarGenerator.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Grammar/GrammarGenerator.cs @@ -5,7 +5,7 @@ #nullable disable // We only support grammar generation in the command line version for now which is the netcoreapp target -#if NETCOREAPP +#if NET using System; using System.Collections.Generic; diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Program.cs b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Program.cs index 6039621972b7d..1b580c4d3a6ff 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Program.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/Program.cs @@ -5,7 +5,7 @@ #nullable disable // We only include this file in the command line version for now which is the netcoreapp target -#if NETCOREAPP +#if NET using System; using System.IO; diff --git a/src/Tools/Source/RunTests/Options.cs b/src/Tools/Source/RunTests/Options.cs index ecc626feb0aa4..40460d1e477c9 100644 --- a/src/Tools/Source/RunTests/Options.cs +++ b/src/Tools/Source/RunTests/Options.cs @@ -141,7 +141,7 @@ public Options( internal static Options? Parse(string[] args) { string? dotnetFilePath = null; - var architecture = "x64"; + var architecture = Microsoft.CodeAnalysis.Test.Utilities.IlasmUtilities.Architecture; var includeHtml = false; var testRuntime = TestRuntime.Both; var configuration = "Debug"; diff --git a/src/Tools/Source/RunTests/RunTests.csproj b/src/Tools/Source/RunTests/RunTests.csproj index 2ef5a300de578..c3c7c14e08d87 100644 --- a/src/Tools/Source/RunTests/RunTests.csproj +++ b/src/Tools/Source/RunTests/RunTests.csproj @@ -31,4 +31,4 @@ - \ No newline at end of file + diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs index c64de1c39082b..39bcd183ae1fe 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.cs @@ -3596,7 +3596,7 @@ private static bool IsPartialMethod(MethodDeclarationSyntax methodDeclaration) => methodDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword); public override string[] GetFunctionExtenderNames() - => new[] { ExtenderNames.ExtensionMethod, ExtenderNames.PartialMethod }; + => [ExtenderNames.ExtensionMethod, ExtenderNames.PartialMethod]; public override object GetFunctionExtender(string name, SyntaxNode node, ISymbol symbol) { @@ -3636,7 +3636,7 @@ public override object GetFunctionExtender(string name, SyntaxNode node, ISymbol } public override string[] GetPropertyExtenderNames() - => new[] { ExtenderNames.AutoImplementedProperty }; + => [ExtenderNames.AutoImplementedProperty]; public override object GetPropertyExtender(string name, SyntaxNode node, ISymbol symbol) { @@ -3658,7 +3658,7 @@ public override object GetPropertyExtender(string name, SyntaxNode node, ISymbol } public override string[] GetExternalTypeExtenderNames() - => new[] { ExtenderNames.ExternalLocation }; + => [ExtenderNames.ExternalLocation]; public override object GetExternalTypeExtender(string name, string externalLocation) { diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/AutoImplementedPropertyExtender.cs b/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/AutoImplementedPropertyExtender.cs index 722218c561308..b7eec5e7fbfb2 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/AutoImplementedPropertyExtender.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/AutoImplementedPropertyExtender.cs @@ -20,14 +20,9 @@ internal static ICSAutoImplementedPropertyExtender Create(bool isAutoImplemented return (ICSAutoImplementedPropertyExtender)ComAggregate.CreateAggregatedObject(result); } - private readonly bool _isAutoImplemented; - private AutoImplementedPropertyExtender(bool isAutoImplemented) - => _isAutoImplemented = isAutoImplemented; + => IsAutoImplemented = isAutoImplemented; - public bool IsAutoImplemented - { - get { return _isAutoImplemented; } - } + public bool IsAutoImplemented { get; } } } diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/CodeTypeLocationExtender.cs b/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/CodeTypeLocationExtender.cs index 9defa5438d855..bcb5d6af00886 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/CodeTypeLocationExtender.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/CodeTypeLocationExtender.cs @@ -20,17 +20,9 @@ internal static ICSCodeTypeLocation Create(string externalLocation) return (ICSCodeTypeLocation)ComAggregate.CreateAggregatedObject(result); } - private readonly string _externalLocation; - private CodeTypeLocationExtender(string externalLocation) - => _externalLocation = externalLocation; + => ExternalLocation = externalLocation; - public string ExternalLocation - { - get - { - return _externalLocation; - } - } + public string ExternalLocation { get; } } } diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/ExtensionMethodExtender.cs b/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/ExtensionMethodExtender.cs index 606dac5fd40dc..776328a706952 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/ExtensionMethodExtender.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/ExtensionMethodExtender.cs @@ -20,14 +20,9 @@ internal static ICSExtensionMethodExtender Create(bool isExtension) return (ICSExtensionMethodExtender)ComAggregate.CreateAggregatedObject(result); } - private readonly bool _isExtension; - private ExtensionMethodExtender(bool isExtension) - => _isExtension = isExtension; + => IsExtension = isExtension; - public bool IsExtension - { - get { return _isExtension; } - } + public bool IsExtension { get; } } } diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/PartialMethodExtender.cs b/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/PartialMethodExtender.cs index 227dbd70997c5..17d3914f76d49 100644 --- a/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/PartialMethodExtender.cs +++ b/src/VisualStudio/CSharp/Impl/CodeModel/Extenders/PartialMethodExtender.cs @@ -20,26 +20,18 @@ internal static ICSPartialMethodExtender Create(bool isPartial, bool isDeclarati return (ICSPartialMethodExtender)ComAggregate.CreateAggregatedObject(result); } - private readonly bool _isPartial; - private readonly bool _isDeclaration; private readonly bool _hasOtherPart; private PartialMethodExtender(bool isPartial, bool isDeclaration, bool hasOtherPart) { - _isPartial = isPartial; - _isDeclaration = isDeclaration; + IsPartial = isPartial; + IsDeclaration = isDeclaration; _hasOtherPart = hasOtherPart; } - public bool IsPartial - { - get { return _isPartial; } - } + public bool IsPartial { get; } - public bool IsDeclaration - { - get { return _isDeclaration; } - } + public bool IsDeclaration { get; } public bool HasOtherPart { diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodeCleanupFixer.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodeCleanupFixer.cs index 07fc6cd967c95..95869ad79ed84 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodeCleanupFixer.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpCodeCleanupFixer.cs @@ -21,8 +21,8 @@ internal sealed class CSharpCodeCleanUpFixer : AbstractCodeCleanUpFixer { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpCodeCleanUpFixer(IThreadingContext threadingContext, VisualStudioWorkspaceImpl workspace, IVsHierarchyItemManager vsHierarchyItemManager, IGlobalOptionService globalOptions) - : base(threadingContext, workspace, vsHierarchyItemManager, globalOptions) + public CSharpCodeCleanUpFixer(IThreadingContext threadingContext, VisualStudioWorkspaceImpl workspace, IVsHierarchyItemManager vsHierarchyItemManager) + : base(threadingContext, workspace, vsHierarchyItemManager) { } } diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpDebuggerIntelliSenseContext.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpDebuggerIntelliSenseContext.cs index d772cb40c1af8..cc232ea5b71fc 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpDebuggerIntelliSenseContext.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpDebuggerIntelliSenseContext.cs @@ -93,7 +93,7 @@ protected override ITrackingSpan GetPreviousStatementBufferAndSpan(int contextPo // terminate the previous expression/statement var buffer = ProjectionBufferFactoryService.CreateProjectionBuffer( projectionEditResolver: null, - sourceSpans: new object[] { previousTrackingSpan, this.StatementTerminator }, + sourceSpans: [previousTrackingSpan, this.StatementTerminator], options: ProjectionBufferOptions.None, contentType: this.ContentType); diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs index bc1f1776e0b25..e440ed8430a4b 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs @@ -221,7 +221,7 @@ internal override void OnLoad() (await _colorSchemeApplier.IsSupportedThemeAsync(cancellationToken).ConfigureAwait(false), await _colorSchemeApplier.IsThemeCustomizedAsync(cancellationToken).ConfigureAwait(false))); - Editor_color_scheme.Visibility = isSupportedTheme ? Visibility.Visible : Visibility.Collapsed; + Editor_color_scheme.IsEnabled = isSupportedTheme; Customized_Theme_Warning.Visibility = isSupportedTheme && isThemeCustomized ? Visibility.Visible : Visibility.Collapsed; Custom_VS_Theme_Warning.Visibility = isSupportedTheme ? Visibility.Collapsed : Visibility.Visible; diff --git a/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioCopilotOptionsService.cs b/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioCopilotOptionsService.cs index f5fcb69f0bb5f..d815050c1e954 100644 --- a/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioCopilotOptionsService.cs +++ b/src/VisualStudio/CSharp/Impl/Options/CSharpVisualStudioCopilotOptionsService.cs @@ -40,9 +40,11 @@ internal sealed class CSharpVisualStudioCopilotOptionsService : ICopilotOptionsS private const string GitHubAccountStatusIsCopilotEntitled = "3DE3FA6E-91B2-46C1-9E9E-DD04975BB890"; private const string CopilotOptionNamePrefix = "Microsoft.VisualStudio.Conversations"; - private const string CopilotCodeAnalysisOptionName = "EnableCSharpCodeAnalysis"; - private const string CopilotRefineOptionName = "EnableCSharpRefineQuickActionSuggestion"; - private const string CopilotOnTheFlyDocsOptionName = "EnableCSharpOnTheFlyDocs"; + + // Default value must reflect their default values in ConversationsOptions in Copilot repo. + private readonly CopilotOption _copilotCodeAnalysisOption = new("EnableCSharpCodeAnalysis", false); + private readonly CopilotOption _copilotRefineOption = new("EnableCSharpRefineQuickActionSuggestion", false); + private readonly CopilotOption _copilotOnTheFlyDocsOption = new("EnableOnTheFlyDocs", true); private static readonly UIContext s_copilotHasLoadedUIContext = UIContext.FromUIContextGuid(new Guid(CopilotHasLoadedGuid)); private static readonly UIContext s_gitHubAccountStatusDeterminedContext = UIContext.FromUIContextGuid(new Guid(GitHubAccountStatusDetermined)); @@ -69,23 +71,26 @@ public CSharpVisualStudioCopilotOptionsService( _settingsManagerTask = settingsManagerService.GetValueAsync(threadingContext.DisposalToken); } - public async Task IsCopilotOptionEnabledAsync(string optionName) + private async Task IsCopilotOptionEnabledAsync(CopilotOption option) { if (!IsGithubCopilotLoadedAndSignedIn) return false; var settingManager = await _settingsManagerTask.ConfigureAwait(false); // The bool setting is persisted as 0=None, 1=True, 2=False, so it needs to be retrieved as an int. - return settingManager.TryGetValue($"{CopilotOptionNamePrefix}.{optionName}", out int isEnabled) == GetValueResult.Success - && isEnabled == 1; + // If isEnabled is 0 or the value is not persisted, we should return the default value for the option. + var isEnabled = settingManager.GetValueOrDefault($"{CopilotOptionNamePrefix}.{option.Name}", 0); + return isEnabled == 1 || (isEnabled == 0 && option.DefaultValue); } public Task IsCodeAnalysisOptionEnabledAsync() - => IsCopilotOptionEnabledAsync(CopilotCodeAnalysisOptionName); + => IsCopilotOptionEnabledAsync(_copilotCodeAnalysisOption); public Task IsRefineOptionEnabledAsync() - => IsCopilotOptionEnabledAsync(CopilotRefineOptionName); + => IsCopilotOptionEnabledAsync(_copilotRefineOption); public Task IsOnTheFlyDocsOptionEnabledAsync() - => IsCopilotOptionEnabledAsync(CopilotOnTheFlyDocsOptionName); + => IsCopilotOptionEnabledAsync(_copilotOnTheFlyDocsOption); + + private record struct CopilotOption(string Name, bool DefaultValue); } diff --git a/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs b/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs index ece1c3379fd94..5b549fcc253d8 100644 --- a/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs +++ b/src/VisualStudio/CSharp/Test/DocumentOutline/DocumentOutlineTestsBase.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.Test; using Microsoft.CodeAnalysis.Editor.UnitTests; +using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.LanguageServer.UnitTests; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -43,7 +44,7 @@ protected class DocumentOutlineTestMocks : IAsyncDisposable private readonly IAsyncDisposable _disposable; internal DocumentOutlineTestMocks( - LanguageServiceBrokerCallback languageServiceBrokerCallback, + LanguageServiceBrokerCallback languageServiceBrokerCallback, IThreadingContext threadingContext, EditorTestWorkspace workspace, IAsyncDisposable disposable) @@ -55,7 +56,7 @@ internal DocumentOutlineTestMocks( TextBuffer = workspace.Documents.Single().GetTextBuffer(); } - internal LanguageServiceBrokerCallback LanguageServiceBrokerCallback { get; } + internal LanguageServiceBrokerCallback LanguageServiceBrokerCallback { get; } internal IThreadingContext ThreadingContext { get; } @@ -78,30 +79,22 @@ protected async Task CreateMocksAsync(string code) var workspace = EditorTestWorkspace.CreateCSharp(code, composition: s_composition); var threadingContext = workspace.GetService(); - var testLspServer = await CreateTestLspServerAsync(workspace, new InitializationOptions - { - // Set the message formatter to use newtonsoft on the client side to match real behavior. - // Also avoid calling initialize / initialized as the test harness uses types only compatible with STJ. - // TODO - switch back to STJ with https://github.com/dotnet/roslyn/issues/73317 - ClientMessageFormatter = new JsonMessageFormatter(), - CallInitialize = false, - CallInitialized = false - }); + var testLspServer = await CreateTestLspServerAsync(workspace); var mocks = new DocumentOutlineTestMocks(RequestAsync, threadingContext, workspace, testLspServer); return mocks; - async Task RequestAsync(Request request, CancellationToken cancellationToken) + async Task RequestAsync(Request request, CancellationToken cancellationToken) { - var docRequest = (DocumentRequest)request; + var docRequest = (DocumentRequest)request; var parameters = docRequest.ParameterFactory(docRequest.TextBuffer.CurrentSnapshot); - var response = await testLspServer.ExecuteRequestAsync(request.Method, parameters, cancellationToken); + var response = await testLspServer.ExecuteRequestAsync(request.Method, parameters, cancellationToken); return response; } } - private async Task CreateTestLspServerAsync(EditorTestWorkspace workspace, InitializationOptions initializationOptions) + private async Task CreateTestLspServerAsync(EditorTestWorkspace workspace) { var solution = workspace.CurrentSolution; @@ -122,23 +115,10 @@ private async Task CreateTestLspServerAsync(EditorTestWorkspace w solution = solution.WithProjectFilePath(project.Id, PathRoot + project.Name); } - solution = solution.WithAnalyzerReferences(new[] { new TestAnalyzerReferenceByLanguage(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap()) }); + solution = solution.WithAnalyzerReferences([new TestAnalyzerReferenceByLanguage(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap())]); await workspace.ChangeSolutionAsync(solution); - // Important: We must wait for workspace creation operations to finish. - // Otherwise we could have a race where workspace change events triggered by creation are changing the state - // created by the initial test steps. This can interfere with the expected test state. - var operations = workspace.ExportProvider.GetExportedValue(); - var workspaceWaiter = operations.GetWaiter(FeatureAttribute.Workspace); - await workspaceWaiter.ExpeditedWaitAsync(); - - var server = await TestLspServer.CreateAsync(workspace, initializationOptions, _logger); - - // We disable the default test initialize call because the default test harness intialize types only support STJ (not newtonsoft). - // We only care that initialize has been called with some capability, so call with simple objects. - // TODO - remove with switch to STJ in https://github.com/dotnet/roslyn/issues/73317 - await server.ExecuteRequestAsync(Roslyn.LanguageServer.Protocol.Methods.InitializeName, new NewtonsoftInitializeParams() { Capabilities = new object() }, CancellationToken.None); - + var server = await TestLspServer.CreateAsync(workspace, new InitializationOptions(), _logger); return server; } diff --git a/src/VisualStudio/CSharp/Test/Interactive/Commands/InteractiveCommandHandlerTests.cs b/src/VisualStudio/CSharp/Test/Interactive/Commands/InteractiveCommandHandlerTests.cs index a38008bf4f4b8..62f2d535fe082 100644 --- a/src/VisualStudio/CSharp/Test/Interactive/Commands/InteractiveCommandHandlerTests.cs +++ b/src/VisualStudio/CSharp/Test/Interactive/Commands/InteractiveCommandHandlerTests.cs @@ -37,12 +37,12 @@ void goo() { [WpfFact] public void TestExecuteInInteractiveWithoutSelection() { - AssertExecuteInInteractive(Caret, new string[0]); + AssertExecuteInInteractive(Caret, []); AssertExecuteInInteractive( @"var x = 1; $$ -var y = 2;", new string[0]); +var y = 2;", []); AssertExecuteInInteractive(ExampleCode1 + Caret, ExampleCode1); AssertExecuteInInteractive(ExampleCode1.Insert(3, Caret), ExampleCode1); @@ -55,7 +55,7 @@ public void TestExecuteInInteractiveWithEmptyBuffer() { AssertExecuteInInteractive( @"{|Selection:|}var x = 1; -{|Selection:$$|}var y = 2;", new string[0]); +{|Selection:$$|}var y = 2;", []); AssertExecuteInInteractive($@"{{|Selection:{ExampleCode1}$$|}}", ExampleCode1); @@ -170,7 +170,7 @@ private static void AssertCopyToInteractive(string code, string expectedBufferTe private static void AssertExecuteInInteractive(string code, string expectedSubmission, string submissionBuffer = null) { - AssertExecuteInInteractive(code, new string[] { expectedSubmission }, submissionBuffer); + AssertExecuteInInteractive(code, [expectedSubmission], submissionBuffer); } private static void AssertExecuteInInteractive(string code, string[] expectedSubmissions, string submissionBuffer = null) diff --git a/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs b/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs index 19e955da84b13..dad950009f4dc 100644 --- a/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs +++ b/src/VisualStudio/CSharp/Test/PersistentStorage/AbstractPersistentStorageTests.cs @@ -1045,16 +1045,15 @@ private class MockPersistentStorageConfiguration : IPersistentStorageConfigurati { private readonly SolutionId _solutionId; private readonly string _storageLocation; - private readonly bool _throwOnFailure; public MockPersistentStorageConfiguration(SolutionId solutionId, string storageLocation, bool throwOnFailure) { _solutionId = solutionId; _storageLocation = storageLocation; - _throwOnFailure = throwOnFailure; + ThrowOnFailure = throwOnFailure; } - public bool ThrowOnFailure => _throwOnFailure; + public bool ThrowOnFailure { get; } public string? TryGetStorageLocation(SolutionKey solutionKey) => solutionKey.Id == _solutionId ? _storageLocation : null; diff --git a/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/SourceFileHandlingTests.cs b/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/SourceFileHandlingTests.cs index 9d9f47ecca6c2..3aac00458cfa1 100644 --- a/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/SourceFileHandlingTests.cs +++ b/src/VisualStudio/CSharp/Test/ProjectSystemShim/CPS/SourceFileHandlingTests.cs @@ -89,11 +89,11 @@ public async Task ReorderSourceFiles_CPS() var oldVersion = GetVersion(); - project.ReorderSourceFiles(new[] { sourceFileFullPath5, sourceFileFullPath4, sourceFileFullPath3, sourceFileFullPath2, sourceFileFullPath1 }); + project.ReorderSourceFiles([sourceFileFullPath5, sourceFileFullPath4, sourceFileFullPath3, sourceFileFullPath2, sourceFileFullPath1]); var newVersion = GetVersion(); - project.ReorderSourceFiles(new[] { sourceFileFullPath5, sourceFileFullPath4, sourceFileFullPath3, sourceFileFullPath2, sourceFileFullPath1 }); + project.ReorderSourceFiles([sourceFileFullPath5, sourceFileFullPath4, sourceFileFullPath3, sourceFileFullPath2, sourceFileFullPath1]); var newSameVersion = GetVersion(); @@ -142,7 +142,7 @@ public async Task ReorderSourceFilesBatch_CPS() // Removing path4 to test remove of a file when it was also added in a batch. project.RemoveSourceFile(sourceFileFullPath4); - project.ReorderSourceFiles(new[] { sourceFileFullPath5, sourceFileFullPath3, sourceFileFullPath1 }); + project.ReorderSourceFiles([sourceFileFullPath5, sourceFileFullPath3, sourceFileFullPath1]); } var documents = GetCurrentDocuments().ToArray(); @@ -184,7 +184,7 @@ public async Task ReorderSourceFilesBatchWithReAdding_CPS() // Removing path4 to test remove of a file when it was also added in a batch. project.RemoveSourceFile(sourceFileFullPath4); - project.ReorderSourceFiles(new[] { sourceFileFullPath5, sourceFileFullPath3, sourceFileFullPath1 }); + project.ReorderSourceFiles([sourceFileFullPath5, sourceFileFullPath3, sourceFileFullPath1]); // Re-adding / re-removing / re-adding again. project.AddSourceFile(sourceFileFullPath2); @@ -194,7 +194,7 @@ public async Task ReorderSourceFilesBatchWithReAdding_CPS() project.AddSourceFile(sourceFileFullPath2); project.AddSourceFile(sourceFileFullPath4); - project.ReorderSourceFiles(new[] { sourceFileFullPath5, sourceFileFullPath4, sourceFileFullPath3, sourceFileFullPath2, sourceFileFullPath1 }); + project.ReorderSourceFiles([sourceFileFullPath5, sourceFileFullPath4, sourceFileFullPath3, sourceFileFullPath2, sourceFileFullPath1]); } var documents = GetCurrentDocuments().ToArray(); @@ -227,14 +227,14 @@ public async Task ReorderSourceFilesBatchAddAfterReorder_CPS() project.AddSourceFile(sourceFileFullPath1); project.AddSourceFile(sourceFileFullPath2); - project.ReorderSourceFiles(new[] { sourceFileFullPath2, sourceFileFullPath1 }); + project.ReorderSourceFiles([sourceFileFullPath2, sourceFileFullPath1]); project.AddSourceFile(sourceFileFullPath3); project.AddSourceFile(sourceFileFullPath4); project.AddSourceFile(sourceFileFullPath5); } - project.ReorderSourceFiles(new[] { sourceFileFullPath5, sourceFileFullPath4, sourceFileFullPath3, sourceFileFullPath2, sourceFileFullPath1 }); + project.ReorderSourceFiles([sourceFileFullPath5, sourceFileFullPath4, sourceFileFullPath3, sourceFileFullPath2, sourceFileFullPath1]); var documents = GetCurrentDocuments().ToArray(); @@ -269,14 +269,14 @@ public async Task ReorderSourceFilesBatchRemoveAfterReorder_CPS() project.AddSourceFile(sourceFileFullPath4); project.AddSourceFile(sourceFileFullPath5); - project.ReorderSourceFiles(new[] { sourceFileFullPath5, sourceFileFullPath4, sourceFileFullPath3, sourceFileFullPath2, sourceFileFullPath1 }); + project.ReorderSourceFiles([sourceFileFullPath5, sourceFileFullPath4, sourceFileFullPath3, sourceFileFullPath2, sourceFileFullPath1]); project.RemoveSourceFile(sourceFileFullPath3); project.RemoveSourceFile(sourceFileFullPath4); project.RemoveSourceFile(sourceFileFullPath5); } - project.ReorderSourceFiles(new[] { sourceFileFullPath2, sourceFileFullPath1 }); + project.ReorderSourceFiles([sourceFileFullPath2, sourceFileFullPath1]); var documents = GetCurrentDocuments().ToArray(); @@ -311,10 +311,10 @@ public async Task ReorderSourceFilesExceptions_CPS() project.AddSourceFile(sourceFileFullPath4); // This should throw due to not passing all of the files. - Assert.Throws(() => project.ReorderSourceFiles(new[] { sourceFileFullPath4, sourceFileFullPath5 })); + Assert.Throws(() => project.ReorderSourceFiles([sourceFileFullPath4, sourceFileFullPath5])); // This should throw because the path does not exist in the project. - Assert.Throws(() => project.ReorderSourceFiles(new[] { @"C:\invalid source file", sourceFileFullPath2, sourceFileFullPath3, sourceFileFullPath4, sourceFileFullPath5 })); + Assert.Throws(() => project.ReorderSourceFiles([@"C:\invalid source file", sourceFileFullPath2, sourceFileFullPath3, sourceFileFullPath4, sourceFileFullPath5])); Assert.Throws(() => project.ReorderSourceFiles(new List())); Assert.Throws(() => project.ReorderSourceFiles(null)); @@ -338,16 +338,16 @@ public async Task ReorderSourceFilesBatchExceptions_CPS() var disposableBatchScope = await project.CreateBatchScopeAsync(CancellationToken.None).ConfigureAwait(false); await using var _ = disposableBatchScope.ConfigureAwait(false); - Assert.Throws(() => project.ReorderSourceFiles(new[] { sourceFileFullPath4, sourceFileFullPath5 })); - Assert.Throws(() => project.ReorderSourceFiles(new[] { @"C:\invalid source file" })); // no files were added, therefore we should get an argument exception + Assert.Throws(() => project.ReorderSourceFiles([sourceFileFullPath4, sourceFileFullPath5])); + Assert.Throws(() => project.ReorderSourceFiles([@"C:\invalid source file"])); // no files were added, therefore we should get an argument exception Assert.Throws(() => project.ReorderSourceFiles(new List())); Assert.Throws(() => project.ReorderSourceFiles(null)); project.AddSourceFile(sourceFileFullPath1); // Test before we add/remove the rest of source files in the batch. - Assert.Throws(() => project.ReorderSourceFiles(new[] { sourceFileFullPath4, sourceFileFullPath5 })); - Assert.Throws(() => project.ReorderSourceFiles(new[] { @"C:\invalid source file" })); + Assert.Throws(() => project.ReorderSourceFiles([sourceFileFullPath4, sourceFileFullPath5])); + Assert.Throws(() => project.ReorderSourceFiles([@"C:\invalid source file"])); Assert.Throws(() => project.ReorderSourceFiles(new List())); Assert.Throws(() => project.ReorderSourceFiles(null)); @@ -362,8 +362,8 @@ public async Task ReorderSourceFilesBatchExceptions_CPS() project.RemoveSourceFile(sourceFileFullPath4); project.AddSourceFile(sourceFileFullPath4); - Assert.Throws(() => project.ReorderSourceFiles(new[] { sourceFileFullPath4, sourceFileFullPath5 })); - Assert.Throws(() => project.ReorderSourceFiles(new[] { @"C:\invalid source file", sourceFileFullPath2, sourceFileFullPath3, sourceFileFullPath4, sourceFileFullPath5 })); + Assert.Throws(() => project.ReorderSourceFiles([sourceFileFullPath4, sourceFileFullPath5])); + Assert.Throws(() => project.ReorderSourceFiles([@"C:\invalid source file", sourceFileFullPath2, sourceFileFullPath3, sourceFileFullPath4, sourceFileFullPath5])); Assert.Throws(() => project.ReorderSourceFiles(new List())); Assert.Throws(() => project.ReorderSourceFiles(null)); } @@ -387,7 +387,7 @@ public async Task ReorderSourceFilesBatchExceptionRemoveFile_CPS() await using (disposableBatchScope.ConfigureAwait(false)) { project.RemoveSourceFile(sourceFileFullPath2); - Assert.Throws(() => project.ReorderSourceFiles(new[] { sourceFileFullPath2 })); + Assert.Throws(() => project.ReorderSourceFiles([sourceFileFullPath2])); } var documents = GetCurrentDocuments().ToArray(); diff --git a/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/SourceFileHandlingTests.cs b/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/SourceFileHandlingTests.cs index 6b4c2570db7ec..33d42c2dff4b1 100644 --- a/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/SourceFileHandlingTests.cs +++ b/src/VisualStudio/CSharp/Test/ProjectSystemShim/LegacyProject/SourceFileHandlingTests.cs @@ -42,7 +42,7 @@ public void AddFileExWithLinkPathUsesThatAsAFolder() var document = environment.Workspace.CurrentSolution.Projects.Single().Documents.Single(); - Assert.Equal(new[] { "LinkFolder" }, document.Folders); + Assert.Equal(["LinkFolder"], document.Folders); } [WpfFact] @@ -83,7 +83,7 @@ public void AddFileExWithNoLinkPathComputesRelativeFolderPath() var document = environment.Workspace.CurrentSolution.Projects.Single().Documents.Single(); - Assert.Equal(new[] { "RelativeFolder" }, document.Folders); + Assert.Equal(["RelativeFolder"], document.Folders); } } } diff --git a/src/VisualStudio/CSharp/Test/ProjectSystemShim/TempPECompilerServiceTests.cs b/src/VisualStudio/CSharp/Test/ProjectSystemShim/TempPECompilerServiceTests.cs index 40b16cbe0dde0..93f4deaf967bf 100644 --- a/src/VisualStudio/CSharp/Test/ProjectSystemShim/TempPECompilerServiceTests.cs +++ b/src/VisualStudio/CSharp/Test/ProjectSystemShim/TempPECompilerServiceTests.cs @@ -34,7 +34,7 @@ public void TempPECompilationWithInvalidReferenceDoesNotCrash() fileContents: [], optionCount: 1, optionNames: ["r"], - optionValues: new[] { Path.Combine(directory.Path, "MissingReference.dll") }); + optionValues: [Path.Combine(directory.Path, "MissingReference.dll")]); Assert.Equal(VSConstants.S_FALSE, hr); } diff --git a/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs b/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs index 738861c3e31d7..22e4fa8171da8 100644 --- a/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs +++ b/src/VisualStudio/CodeLens/ReferenceCodeLensProvider.cs @@ -105,7 +105,7 @@ private async Task PollForUpdatesAsync() var projectVersions = await _lazyCodeLensCallbackService.Value.InvokeAsync>( this, nameof(ICodeLensContext.GetProjectVersionsAsync), - new object[] { keys }, + [keys], _cancellationTokenSource.Token).ConfigureAwait(false); lock (_dataPoints) @@ -201,7 +201,7 @@ public void Dispose() var referenceCountOpt = await _callbackService.InvokeAsync( _owner, nameof(ICodeLensContext.GetReferenceCountAsync), - new object?[] { Descriptor, descriptorContext, _calculatedReferenceCount }, + [Descriptor, descriptorContext, _calculatedReferenceCount], cancellationToken).ConfigureAwait(false); if (!referenceCountOpt.HasValue) @@ -244,7 +244,7 @@ public async Task GetDetailsAsync(CodeLensDescriptorC var referenceLocationDescriptors = await _callbackService.InvokeAsync<(string projectVersion, ImmutableArray references)?>( _owner, nameof(ICodeLensContext.FindReferenceLocationsAsync), - new object[] { Descriptor, descriptorContext }, + [Descriptor, descriptorContext], cancellationToken).ConfigureAwait(false); // Keep track of the exact reference count diff --git a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyDetail.cs b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyDetail.cs index e9346e436a2fb..025e7da51bf41 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyDetail.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyDetail.cs @@ -21,13 +21,6 @@ internal class CallHierarchyDetail : ICallHierarchyItemDetails private readonly DocumentId _documentId; private readonly Workspace _workspace; - private readonly int _endColumn; - private readonly int _endLine; - private readonly string _sourceFile; - private readonly int _startColumn; - private readonly int _startLine; - private readonly string _text; - public CallHierarchyDetail( CallHierarchyProvider provider, Location location, @@ -37,12 +30,12 @@ public CallHierarchyDetail( _span = location.SourceSpan; _documentId = workspace.CurrentSolution.GetDocumentId(location.SourceTree); _workspace = workspace; - _endColumn = location.GetLineSpan().Span.End.Character; - _endLine = location.GetLineSpan().EndLinePosition.Line; - _sourceFile = location.SourceTree.FilePath; - _startColumn = location.GetLineSpan().StartLinePosition.Character; - _startLine = location.GetLineSpan().StartLinePosition.Line; - _text = ComputeText(location); + EndColumn = location.GetLineSpan().Span.End.Character; + EndLine = location.GetLineSpan().EndLinePosition.Line; + File = location.SourceTree.FilePath; + StartColumn = location.GetLineSpan().StartLinePosition.Character; + StartLine = location.GetLineSpan().StartLinePosition.Line; + Text = ComputeText(location); } private static string ComputeText(Location location) @@ -53,14 +46,14 @@ private static string ComputeText(Location location) return location.SourceTree.GetText().GetSubText(TextSpan.FromBounds(start, end)).ToString(); } - public string File => _sourceFile; - public string Text => _text; + public string File { get; } + public string Text { get; } public bool SupportsNavigateTo => true; - public int EndColumn => _endColumn; - public int EndLine => _endLine; - public int StartColumn => _startColumn; - public int StartLine => _startLine; + public int EndColumn { get; } + public int EndLine { get; } + public int StartColumn { get; } + public int StartLine { get; } public void NavigateTo() { diff --git a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs index 055fd1752ed34..dd9c5604304b8 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/CallHierarchyItem.cs @@ -22,15 +22,11 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.CallHierarchy; internal class CallHierarchyItem : ICallHierarchyMemberItem { private readonly Workspace _workspace; - private readonly string _containingNamespaceName; - private readonly string _containingTypeName; private readonly INavigableLocation _navigableLocation; private readonly IEnumerable _callsites; private readonly IEnumerable _finders; private readonly Func _glyphCreator; - private readonly string _name; private readonly CallHierarchyProvider _provider; - private readonly string _sortText; public CallHierarchyItem( CallHierarchyProvider provider, @@ -45,12 +41,12 @@ public CallHierarchyItem( _provider = provider; _navigableLocation = navigableLocation; _finders = finders; - _containingTypeName = symbol.ContainingType.ToDisplayString(ContainingTypeFormat); - _containingNamespaceName = symbol.ContainingNamespace.ToDisplayString(ContainingNamespaceFormat); + ContainingTypeName = symbol.ContainingType.ToDisplayString(ContainingTypeFormat); + ContainingNamespaceName = symbol.ContainingNamespace.ToDisplayString(ContainingNamespaceFormat); _glyphCreator = glyphCreator; - _name = symbol.ToDisplayString(MemberNameFormat); + MemberName = symbol.ToDisplayString(MemberNameFormat); _callsites = callsites.SelectAsArray(loc => new CallHierarchyDetail(provider, loc, _workspace)); - _sortText = symbol.ToDisplayString(); + SortText = symbol.ToDisplayString(); ProjectName = project.Name; } @@ -83,9 +79,9 @@ public CallHierarchyItem( public string ProjectName { get; } - public string ContainingNamespaceName => _containingNamespaceName; + public string ContainingNamespaceName { get; } - public string ContainingTypeName => _containingTypeName; + public string ContainingTypeName { get; } public IEnumerable Details => _callsites; @@ -97,11 +93,11 @@ public ImageSource DisplayGlyph } } - public string MemberName => _name; + public string MemberName { get; } public string NameSeparator => "."; - public string SortText => _sortText; + public string SortText { get; } public IEnumerable SupportedSearchCategories { diff --git a/src/VisualStudio/Core/Def/CallHierarchy/FieldInitializerItem.cs b/src/VisualStudio/Core/Def/CallHierarchy/FieldInitializerItem.cs index 616dc50bb5d3f..d05deb2230de3 100644 --- a/src/VisualStudio/Core/Def/CallHierarchy/FieldInitializerItem.cs +++ b/src/VisualStudio/Core/Def/CallHierarchy/FieldInitializerItem.cs @@ -12,24 +12,19 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.CallHierarchy; internal class FieldInitializerItem : ICallHierarchyNameItem { - private readonly IEnumerable _details; - private readonly ImageSource _displayGlyph; - private readonly string _name; - private readonly string _sortText; - public FieldInitializerItem(string name, string sortText, ImageSource displayGlyph, IEnumerable details) { - _name = name; - _sortText = sortText; - _displayGlyph = displayGlyph; - _details = details; + Name = name; + SortText = sortText; + DisplayGlyph = displayGlyph; + Details = details; } - public IEnumerable Details => _details; + public IEnumerable Details { get; } - public ImageSource DisplayGlyph => _displayGlyph; + public ImageSource DisplayGlyph { get; } - public string Name => _name; + public string Name { get; } - public string SortText => _sortText; + public string SortText { get; } } diff --git a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs index 7de89e094a3b5..34c60b0c81683 100644 --- a/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/ChangeSignature/ChangeSignatureDialogViewModel.cs @@ -39,7 +39,6 @@ internal partial class ChangeSignatureDialogViewModel : AbstractNotifyPropertyCh private readonly HashSet _disabledParameters = []; private readonly ImmutableArray _declarationParts; - private bool _previewChanges; /// /// The document where the symbol we are changing signature is defined. @@ -172,18 +171,7 @@ public int GetStartingSelectionIndex() return -1; } - public bool PreviewChanges - { - get - { - return _previewChanges; - } - - set - { - _previewChanges = value; - } - } + public bool PreviewChanges { get; set; } public bool CanRemove { diff --git a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs index 705ad57775991..407b0d6dffce1 100644 --- a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs +++ b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs @@ -39,18 +39,15 @@ internal abstract partial class AbstractCodeCleanUpFixer : ICodeCleanUpFixer private readonly IThreadingContext _threadingContext; private readonly VisualStudioWorkspaceImpl _workspace; private readonly IVsHierarchyItemManager _vsHierarchyItemManager; - private readonly IGlobalOptionService _globalOptions; protected AbstractCodeCleanUpFixer( IThreadingContext threadingContext, VisualStudioWorkspaceImpl workspace, - IVsHierarchyItemManager vsHierarchyItemManager, - IGlobalOptionService globalOptions) + IVsHierarchyItemManager vsHierarchyItemManager) { _threadingContext = threadingContext; _workspace = workspace; _vsHierarchyItemManager = vsHierarchyItemManager; - _globalOptions = globalOptions; } public Task FixAsync(ICodeCleanUpScope scope, ICodeCleanUpExecutionContext context) @@ -71,7 +68,7 @@ private async Task FixHierarchyContentAsync(IVsHierarchyCodeCleanupScope h _workspace, // Just defer to FixProjectsAsync, passing in all fixable projects in the solution. (progress, cancellationToken) => FixProjectsAsync( - _globalOptions, solution, solution.Projects.Where(p => p.SupportsCompilation).ToImmutableArray(), context.EnabledFixIds, progress, cancellationToken), + solution, solution.Projects.Where(p => p.SupportsCompilation).ToImmutableArray(), context.EnabledFixIds, progress, cancellationToken), context).ConfigureAwait(false); } @@ -109,7 +106,7 @@ private async Task FixHierarchyContentAsync(IVsHierarchyCodeCleanupScope h _workspace, // Just defer to FixProjectsAsync, passing in this single project to fix. (progress, cancellationToken) => FixProjectsAsync( - _globalOptions, project.Solution, [project], context.EnabledFixIds, progress, cancellationToken), + project.Solution, [project], context.EnabledFixIds, progress, cancellationToken), context).ConfigureAwait(false); } else if (hierarchy.GetCanonicalName(itemId, out var path) == 0) @@ -133,13 +130,12 @@ private async Task FixHierarchyContentAsync(IVsHierarchyCodeCleanupScope h return false; var document = solution.GetRequiredDocument(documentId); - var options = _globalOptions.GetCodeActionOptions(document.Project.Services); return await FixAsync( _workspace, async (progress, cancellationToken) => { - var newDocument = await FixDocumentAsync(document, context.EnabledFixIds, progress, options, cancellationToken).ConfigureAwait(true); + var newDocument = await FixDocumentAsync(document, context.EnabledFixIds, progress, cancellationToken).ConfigureAwait(true); return newDocument.Project.Solution; }, context).ConfigureAwait(false); @@ -175,8 +171,7 @@ async Task ApplyFixAsync(IProgress progress, Can var document = buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); Contract.ThrowIfNull(document); - var options = _globalOptions.GetCodeActionOptions(document.Project.Services); - var newDoc = await FixDocumentAsync(document, context.EnabledFixIds, progress, options, cancellationToken).ConfigureAwait(true); + var newDoc = await FixDocumentAsync(document, context.EnabledFixIds, progress, cancellationToken).ConfigureAwait(true); return newDoc.Project.Solution; } } @@ -207,7 +202,6 @@ private async Task FixAsync( } private static async Task FixProjectsAsync( - IGlobalOptionService globalOptions, Solution solution, ImmutableArray projects, FixIdContainer enabledFixIds, @@ -224,11 +218,9 @@ private static async Task FixProjectsAsync( { Contract.ThrowIfFalse(project.SupportsCompilation); - var (globalOptions, solution, enabledFixIds, progressTracker) = args; + var (solution, enabledFixIds, progressTracker) = args; cancellationToken.ThrowIfCancellationRequested(); - var ideOptions = globalOptions.GetCodeActionOptions(project.Services); - // And for each project, process all the documents in parallel. await RoslynParallel.ForEachAsync( source: project.Documents, @@ -240,14 +232,14 @@ await RoslynParallel.ForEachAsync( // FixDocumentAsync reports progress within a document, but we only want to report progress at // the document granularity. So we pass CodeAnalysisProgress.None here so that inner progress // updates don't affect us. - var fixedDocument = await FixDocumentAsync(document, enabledFixIds, CodeAnalysisProgress.None, ideOptions, cancellationToken).ConfigureAwait(false); + var fixedDocument = await FixDocumentAsync(document, enabledFixIds, CodeAnalysisProgress.None, cancellationToken).ConfigureAwait(false); if (fixedDocument == document) return; callback((document.Id, await fixedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false))); }).ConfigureAwait(false); }, - args: (globalOptions, solution, enabledFixIds, progressTracker), + args: (solution, enabledFixIds, progressTracker), cancellationToken).ConfigureAwait(false); return solution.WithDocumentSyntaxRoots(changedRoots); @@ -257,7 +249,6 @@ private static async Task FixDocumentAsync( Document document, FixIdContainer enabledFixIds, IProgress progressTracker, - CodeActionOptions ideOptions, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -270,6 +261,6 @@ private static async Task FixDocumentAsync( enabledDiagnostics = AdjustDiagnosticOptions(enabledDiagnostics, enabledFixIds.IsFixIdEnabled); return await codeCleanupService.CleanupAsync( - document, enabledDiagnostics, progressTracker, ideOptions.CreateProvider(), cancellationToken).ConfigureAwait(false); + document, enabledDiagnostics, progressTracker, cancellationToken).ConfigureAwait(false); } } diff --git a/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs b/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs index b8a2b7c50f717..702de2078b64f 100644 --- a/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs +++ b/src/VisualStudio/Core/Def/CodeLens/RemoteCodeLensReferencesService.cs @@ -150,7 +150,7 @@ private async Task> FixUpDescriptors continue; } - var spanMapper = document.Services.GetService(); + var spanMapper = document.DocumentServiceProvider.GetService(); if (spanMapper == null) { // for normal document, just add one as they are @@ -173,7 +173,7 @@ private async Task> FixUpDescriptors continue; } - var excerpter = document.Services.GetService(); + var excerpter = document.DocumentServiceProvider.GetService(); if (excerpter == null) { continue; diff --git a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs index 31770172cdfab..c77d5f9293384 100644 --- a/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs +++ b/src/VisualStudio/Core/Def/ColorSchemes/ColorSchemeApplier.cs @@ -13,12 +13,15 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio; using Microsoft.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Threading; +using Microsoft.Win32; +using Roslyn.Utilities; using Task = System.Threading.Tasks.Task; namespace Microsoft.CodeAnalysis.ColorSchemes; @@ -35,6 +38,7 @@ internal sealed partial class ColorSchemeApplier private readonly ColorSchemeSettings _settings; private readonly ClassificationVerifier _classificationVerifier; private readonly ImmutableDictionary _colorSchemes; + private readonly AsyncBatchingWorkQueue _workQueue; private readonly object _gate = new(); @@ -47,7 +51,8 @@ public ColorSchemeApplier( IThreadingContext threadingContext, IVsService fontAndColorStorage, IGlobalOptionService globalOptions, - SVsServiceProvider serviceProvider) + SVsServiceProvider serviceProvider, + IAsynchronousOperationListenerProvider listenerProvider) { _threadingContext = threadingContext; _serviceProvider = serviceProvider; @@ -56,6 +61,11 @@ public ColorSchemeApplier( _settings = new ColorSchemeSettings(threadingContext, _serviceProvider, globalOptions); _colorSchemes = ColorSchemeSettings.GetColorSchemes(); _classificationVerifier = new ClassificationVerifier(threadingContext, fontAndColorStorage, _colorSchemes); + _workQueue = new( + DelayTimeSpan.Idle, + QueueColorSchemeUpdateAsync, + listenerProvider.GetListener(FeatureAttribute.ColorScheme), + threadingContext.DisposalToken); } public async Task InitializeAsync(CancellationToken cancellationToken) @@ -106,15 +116,18 @@ await _settings.ApplyColorSchemeAsync( } private void VSColorTheme_ThemeChanged(ThemeChangedEventArgs e) - => QueueColorSchemeUpdateAsync().Forget(); + => _workQueue.AddWork(); private Task ColorSchemeChangedAsync(object sender, PropertyChangedEventArgs args) - => QueueColorSchemeUpdateAsync(); + { + _workQueue.AddWork(); + return Task.CompletedTask; + } - private async Task QueueColorSchemeUpdateAsync() + private async ValueTask QueueColorSchemeUpdateAsync(CancellationToken cancellationToken) { // Wait until things have settled down from the theme change, since we will potentially be changing theme colors. - await VsTaskLibraryHelper.StartOnIdle(_threadingContext.JoinableTaskFactory, () => UpdateColorSchemeAsync(_threadingContext.DisposalToken)); + await VsTaskLibraryHelper.StartOnIdle(_threadingContext.JoinableTaskFactory, () => UpdateColorSchemeAsync(cancellationToken)); } /// @@ -171,7 +184,27 @@ private async Task GetThemeIdAsync(CancellationToken cancellationToken) return KnownColorThemes.Blue; } - return Guid.Parse(currentThemeString); + var themeId = Guid.Parse(currentThemeString); + + if (themeId == KnownColorThemes.System) + { + themeId = ShouldAppsUseLightTheme() + ? KnownColorThemes.Light + : KnownColorThemes.Dark; + } + + return themeId; + } + + private static bool ShouldAppsUseLightTheme() + { + const string PersonalizeKey = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"; + const string AppsUseLightThemeValue = "AppsUseLightTheme"; + const string appsUseDarkTheme = "0"; + + using var personalizeKey = Registry.CurrentUser.OpenSubKey(PersonalizeKey, writable: false); + var appsThemeValue = personalizeKey?.GetValue(AppsUseLightThemeValue)?.ToString(); + return appsThemeValue != appsUseDarkTheme; } // NOTE: This service is not public or intended for use by teams/individuals outside of Microsoft. Any data stored is subject to deletion without warning. diff --git a/src/VisualStudio/Core/Def/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs b/src/VisualStudio/Core/Def/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs index c3eb55de82d67..9459a5d3ecff1 100644 --- a/src/VisualStudio/Core/Def/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs +++ b/src/VisualStudio/Core/Def/DebuggerIntelliSense/AbstractDebuggerIntelliSenseContext.cs @@ -21,11 +21,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelli internal abstract class AbstractDebuggerIntelliSenseContext : IDisposable { private readonly IWpfTextView _textView; - private readonly IContentType _contentType; private readonly IContentType _originalContentType; protected readonly IProjectionBufferFactoryService ProjectionBufferFactoryService; protected readonly TextManager.Interop.TextSpan CurrentStatementSpan; - private readonly IVsTextLines _debuggerTextLines; private IProjectionBuffer _projectionBuffer; private DebuggerTextView _debuggerTextView; private DebuggerIntelliSenseWorkspace _workspace; @@ -52,10 +50,10 @@ protected AbstractDebuggerIntelliSenseContext( IContentType contentType) { _textView = wpfTextView; - _debuggerTextLines = vsDebuggerTextLines; + DebuggerTextLines = vsDebuggerTextLines; this.ContextBuffer = contextBuffer; this.CurrentStatementSpan = currentStatementSpan[0]; - _contentType = contentType; + ContentType = contentType; _originalContentType = _textView.TextBuffer.ContentType; this.ProjectionBufferFactoryService = componentModel.GetService(); _bufferGraphFactoryService = componentModel.GetService(); @@ -74,19 +72,19 @@ protected AbstractDebuggerIntelliSenseContext( _textView = wpfTextView; this.ContextBuffer = contextBuffer; this.CurrentStatementSpan = currentStatementSpan[0]; - _contentType = contentType; + ContentType = contentType; this.ProjectionBufferFactoryService = componentModel.GetService(); _bufferGraphFactoryService = componentModel.GetService(); _isImmediateWindow = isImmediateWindow; } - public IVsTextLines DebuggerTextLines { get { return _debuggerTextLines; } } + public IVsTextLines DebuggerTextLines { get; } public ITextView DebuggerTextView { get { return _debuggerTextView; } } public ITextBuffer Buffer { get { return _projectionBuffer; } } - public IContentType ContentType { get { return _contentType; } } + public IContentType ContentType { get; } protected bool InImmediateWindow { get { return _immediateWindowContext != null; } } @@ -145,7 +143,7 @@ private bool TrySetContext( // Wrap the original ContextBuffer in a projection buffer that we can make read-only this.ContextBuffer = this.ProjectionBufferFactoryService.CreateProjectionBuffer(null, - new object[] { this.ContextBuffer.CurrentSnapshot.CreateFullTrackingSpan(SpanTrackingMode.EdgeInclusive) }, ProjectionBufferOptions.None, _contentType); + [this.ContextBuffer.CurrentSnapshot.CreateFullTrackingSpan(SpanTrackingMode.EdgeInclusive)], ProjectionBufferOptions.None, ContentType); // Make projection readonly so we can't edit it by mistake. using (var regionEdit = this.ContextBuffer.CreateReadOnlyRegionEdit()) @@ -168,7 +166,7 @@ private bool TrySetContext( // Put it all into a projection buffer _projectionBuffer = this.ProjectionBufferFactoryService.CreateProjectionBuffer(null, - new object[] { previousStatementSpan, debuggerMappedSpan, this.StatementTerminator, restOfFileSpan }, ProjectionBufferOptions.None, _contentType); + [previousStatementSpan, debuggerMappedSpan, this.StatementTerminator, restOfFileSpan], ProjectionBufferOptions.None, ContentType); // Fork the solution using this new primary buffer for the document and all of its linked documents. var forkedSolution = solution.WithDocumentText(document.Id, _projectionBuffer.CurrentSnapshot.AsText(), PreservationMode.PreserveIdentity); @@ -189,17 +187,17 @@ private bool TrySetContext( // Start getting the compilation so the PartialSolution will be ready when the user starts typing in the window document.Project.GetCompilationAsync(System.Threading.CancellationToken.None); - _textView.TextBuffer.ChangeContentType(_contentType, null); + _textView.TextBuffer.ChangeContentType(ContentType, null); var bufferGraph = _bufferGraphFactoryService.CreateBufferGraph(_projectionBuffer); - _debuggerTextView = new DebuggerTextView(_textView, bufferGraph, _debuggerTextLines, InImmediateWindow); + _debuggerTextView = new DebuggerTextView(_textView, bufferGraph, DebuggerTextLines, InImmediateWindow); return true; } internal void SetContentType(bool install) { - var contentType = install ? _contentType : _originalContentType; + var contentType = install ? ContentType : _originalContentType; _textView.TextBuffer.ChangeContentType(contentType, null); } @@ -210,14 +208,14 @@ private ITrackingSpan CreateImmediateWindowProjectionMapping(out ImmediateWindow var debuggerMappedSpan = _textView.TextSnapshot.CreateFullTrackingSpan(SpanTrackingMode.EdgeInclusive); var projectionBuffer = this.ProjectionBufferFactoryService.CreateProjectionBuffer(null, - new object[] { debuggerMappedSpan }, ProjectionBufferOptions.PermissiveEdgeInclusiveSourceSpans, _contentType); + [debuggerMappedSpan], ProjectionBufferOptions.PermissiveEdgeInclusiveSourceSpans, ContentType); // There's currently a bug in the editor (515925) where an elision buffer can't be projected into // another projection buffer. So workaround by using a second projection buffer that only // projects the text we care about var elisionProjectionBuffer = this.ProjectionBufferFactoryService.CreateProjectionBuffer(null, - new object[] { projectionBuffer.CurrentSnapshot.CreateFullTrackingSpan(SpanTrackingMode.EdgeInclusive) }, - ProjectionBufferOptions.None, _contentType); + [projectionBuffer.CurrentSnapshot.CreateFullTrackingSpan(SpanTrackingMode.EdgeInclusive)], + ProjectionBufferOptions.None, ContentType); immediateWindowContext = new ImmediateWindowContext() { diff --git a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.cs b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.cs index a3f63f04f316d..c44d0d2a07eca 100644 --- a/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.cs +++ b/src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerProvider.cs @@ -56,8 +56,8 @@ internal VisualStudioDiagnosticAnalyzerProvider(object extensionManager, Type ty // var enabledExtensions = extensionManager.GetEnabledExtensions(AnalyzerContentTypeName); var extensionManagerType = _extensionManager.GetType(); - var extensionManager_GetEnabledExtensionsMethod = extensionManagerType.GetRuntimeMethod("GetEnabledExtensions", new Type[] { typeof(string) }); - var enabledExtensions = (IEnumerable)extensionManager_GetEnabledExtensionsMethod.Invoke(_extensionManager, new object[] { AnalyzerContentTypeName }); + var extensionManager_GetEnabledExtensionsMethod = extensionManagerType.GetRuntimeMethod("GetEnabledExtensions", [typeof(string)]); + var enabledExtensions = (IEnumerable)extensionManager_GetEnabledExtensionsMethod.Invoke(_extensionManager, [AnalyzerContentTypeName]); foreach (var extension in enabledExtensions) { @@ -78,8 +78,8 @@ internal VisualStudioDiagnosticAnalyzerProvider(object extensionManager, Type ty continue; } - var extensionType_GetContentMethod = extensionType.GetRuntimeMethod("GetContentLocation", new Type[] { _typeIExtensionContent }); - if (extensionType_GetContentMethod?.Invoke(extension, new object[] { content }) is not string assemblyPath || + var extensionType_GetContentMethod = extensionType.GetRuntimeMethod("GetContentLocation", [_typeIExtensionContent]); + if (extensionType_GetContentMethod?.Invoke(extension, [content]) is not string assemblyPath || string.IsNullOrEmpty(assemblyPath)) { continue; diff --git a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs index 4874c749f4682..0559d1c49b659 100644 --- a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs +++ b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.PatternMatching; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; @@ -25,15 +26,15 @@ internal sealed partial class DocumentOutlineViewModel /// Makes an LSP document symbol request and returns the response and the text snapshot used at /// the time the LSP client sends the request to the server. /// - public static async Task<(DocumentSymbolNewtonsoft.NewtonsoftRoslynDocumentSymbol[] response, ITextSnapshot snapshot)?> DocumentSymbolsRequestAsync( + public static async Task<(RoslynDocumentSymbol[] response, ITextSnapshot snapshot)?> DocumentSymbolsRequestAsync( ITextBuffer textBuffer, - LanguageServiceBrokerCallback callbackAsync, + LanguageServiceBrokerCallback callbackAsync, string textViewFilePath, CancellationToken cancellationToken) { ITextSnapshot? requestSnapshot = null; - var request = new DocumentRequest() + var request = new DocumentRequest() { Method = Methods.TextDocumentDocumentSymbolName, LanguageServerName = WellKnownLspServerKinds.AlwaysActiveVSLspServer.ToUserVisibleString(), @@ -41,9 +42,14 @@ internal sealed partial class DocumentOutlineViewModel ParameterFactory = (snapshot) => { requestSnapshot = snapshot; - return new DocumentSymbolNewtonsoft.NewtonsoftRoslynDocumentSymbolParams( - new DocumentSymbolNewtonsoft.NewtonsoftTextDocumentIdentifier(ProtocolConversions.CreateAbsoluteUri(textViewFilePath)), - UseHierarchicalSymbols: true); + return new RoslynDocumentSymbolParams + { + TextDocument = new TextDocumentIdentifier + { + Uri = ProtocolConversions.CreateAbsoluteUri(textViewFilePath), + }, + UseHierarchicalSymbols = true + }; } }; @@ -88,7 +94,7 @@ internal sealed partial class DocumentOutlineViewModel /// ] /// } /// ] - public static ImmutableArray CreateDocumentSymbolData(DocumentSymbolNewtonsoft.NewtonsoftRoslynDocumentSymbol[] documentSymbols, ITextSnapshot textSnapshot) + public static ImmutableArray CreateDocumentSymbolData(RoslynDocumentSymbol[] documentSymbols, ITextSnapshot textSnapshot) { // Obtain a flat list of all the document symbols sorted by location in the document. var allSymbols = documentSymbols @@ -108,7 +114,7 @@ public static ImmutableArray CreateDocumentSymbolData(Docume // Returns the symbol in the list at index start (the parent symbol) with the following symbols in the list // (descendants) appropriately nested into the parent. - DocumentSymbolData NestDescendantSymbols(ImmutableArray allSymbols, int start, out int newStart) + DocumentSymbolData NestDescendantSymbols(ImmutableArray allSymbols, int start, out int newStart) { var currentParent = allSymbols[start]; start++; @@ -141,18 +147,20 @@ DocumentSymbolData NestDescendantSymbols(ImmutableArray parentRange.Start && childRange.End <= parentRange.End; - static LinePositionSpan RangeToLinePositionSpan(DocumentSymbolNewtonsoft.NewtonsoftRange range) - => new(new LinePosition(range.Start.Line, range.Start.Character), new LinePosition(range.End.Line, range.End.Character)); + static LinePositionSpan RangeToLinePositionSpan(Range range) + { + return new(new LinePosition(range.Start.Line, range.Start.Character), new LinePosition(range.End.Line, range.End.Character)); + } } // Converts a Document Symbol Range to a SnapshotSpan within the text snapshot used for the LSP request. - SnapshotSpan GetSymbolRangeSpan(DocumentSymbolNewtonsoft.NewtonsoftRange symbolRange) + SnapshotSpan GetSymbolRangeSpan(Range symbolRange) { var originalStartPosition = textSnapshot.GetLineFromLineNumber(symbolRange.Start.Line).Start.Position + symbolRange.Start.Character; var originalEndPosition = textSnapshot.GetLineFromLineNumber(symbolRange.End.Line).Start.Position + symbolRange.End.Character; diff --git a/src/VisualStudio/Core/Def/DocumentOutline/DocumentSymbolNewtonsoft.cs b/src/VisualStudio/Core/Def/DocumentOutline/DocumentSymbolNewtonsoft.cs deleted file mode 100644 index 962a451c2c5a5..0000000000000 --- a/src/VisualStudio/Core/Def/DocumentOutline/DocumentSymbolNewtonsoft.cs +++ /dev/null @@ -1,127 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Globalization; -using System.Runtime.Serialization; -using Microsoft.CodeAnalysis.LanguageServer; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Microsoft.VisualStudio.LanguageServices.DocumentOutline; - -/// -/// These are very temporary types that we need in order to serialize document symbol data -/// using Newtonsoft instead of System.Text.Json -/// -/// We currently must support Newtonsoft serialization here because we have not yet opted into using STJ -/// in the VS language server client (and so the client will serialize the request using Newtonsoft). -/// -/// https://github.com/dotnet/roslyn/pull/72675 tracks opting in the client to STJ. -/// TODO - everything in this type should be deleted once the client side is using STJ. -/// -internal class DocumentSymbolNewtonsoft -{ - private class NewtonsoftDocumentUriConverter : JsonConverter - { - /// - public override bool CanConvert(Type objectType) - { - return true; - } - - /// - public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) - { - reader = reader ?? throw new ArgumentNullException(nameof(reader)); - if (reader.TokenType == JsonToken.String) - { - var token = JToken.ReadFrom(reader); - var uri = new Uri(token.ToObject()); - - return uri; - } - else if (reader.TokenType == JsonToken.Null) - { - return null; - } - - throw new JsonSerializationException(string.Format(CultureInfo.InvariantCulture, LanguageServerProtocolResources.DocumentUriSerializationError, reader.Value)); - } - - /// - public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) - { - writer = writer ?? throw new ArgumentNullException(nameof(writer)); - - if (value is Uri uri) - { - var token = JToken.FromObject(uri.AbsoluteUri); - token.WriteTo(writer); - } - else - { - throw new ArgumentException($"{nameof(value)} must be of type {nameof(Uri)}"); - } - } - } - - [DataContract] - internal record NewtonsoftTextDocumentIdentifier([property: DataMember(Name = "uri"), JsonConverter(typeof(NewtonsoftDocumentUriConverter))] Uri Uri); - - [DataContract] - internal record NewtonsoftRoslynDocumentSymbolParams( - [property: DataMember(Name = "textDocument")] NewtonsoftTextDocumentIdentifier TextDocument, - [property: DataMember(Name = "useHierarchicalSymbols"), JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] bool UseHierarchicalSymbols); - - [DataContract] - internal record NewtonsoftRoslynDocumentSymbol( - [property: DataMember(IsRequired = true, Name = "name")] string Name, - [property: DataMember(Name = "detail")][property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] string? Detail, - [property: DataMember(Name = "kind")] NewtonsoftSymbolKind Kind, - [property: DataMember(Name = "deprecated")][property: JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] bool Deprecated, - [property: DataMember(IsRequired = true, Name = "range")] NewtonsoftRange Range, - [property: DataMember(IsRequired = true, Name = "selectionRange")] NewtonsoftRange SelectionRange, - [property: DataMember(Name = "children")][property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] NewtonsoftRoslynDocumentSymbol[]? Children, - [property: DataMember(Name = "glyph")] int Glyph); - - [DataContract] - internal record NewtonsoftRange( - [property: DataMember(Name = "start"), JsonProperty(Required = Required.Always)] NewtonsoftPosition Start, - [property: DataMember(Name = "end"), JsonProperty(Required = Required.Always)] NewtonsoftPosition End); - - [DataContract] - internal record NewtonsoftPosition([property: DataMember(Name = "line")] int Line, [property: DataMember(Name = "character")] int Character); - - [DataContract] - internal enum NewtonsoftSymbolKind - { - File = 1, - Module = 2, - Namespace = 3, - Package = 4, - Class = 5, - Method = 6, - Property = 7, - Field = 8, - Constructor = 9, - Enum = 10, - Interface = 11, - Function = 12, - Variable = 13, - Constant = 14, - String = 15, - Number = 16, - Boolean = 17, - Array = 18, - Object = 19, - Key = 20, - Null = 21, - EnumMember = 22, - Struct = 23, - Event = 24, - Operator = 25, - TypeParameter = 26, - } -} diff --git a/src/VisualStudio/Core/Def/EditAndContinue/EditAndContinueFeedbackDiagnosticFileProvider.cs b/src/VisualStudio/Core/Def/EditAndContinue/EditAndContinueFeedbackDiagnosticFileProvider.cs index 864cd41eeef90..cd7540be5d53a 100644 --- a/src/VisualStudio/Core/Def/EditAndContinue/EditAndContinueFeedbackDiagnosticFileProvider.cs +++ b/src/VisualStudio/Core/Def/EditAndContinue/EditAndContinueFeedbackDiagnosticFileProvider.cs @@ -99,7 +99,7 @@ private string GetZipFilePath() public IReadOnlyCollection GetFiles() => _vsFeedbackSemaphoreFileWatcher is null ? Array.Empty() - : (IReadOnlyCollection)(new[] { GetZipFilePath() }); + : (IReadOnlyCollection)([GetZipFilePath()]); private void OnFeedbackSemaphoreCreatedOrChanged() { diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.cs index 13456ad8241e9..3ac3d2db61275 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.cs @@ -41,13 +41,12 @@ protected override IEnumerable GetInitialColumnStates() }; protected override string[] GetFixedColumns() - => new[] - { + => [ ColumnDefinitions.Analyzer.Category, ColumnDefinitions.Analyzer.Id, ColumnDefinitions.Analyzer.Title, ColumnDefinitions.Analyzer.Description, ColumnDefinitions.Analyzer.Severity, ColumnDefinitions.Analyzer.Location, - }; + ]; } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.cs index 294e6573478f0..1f478ba44041c 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.cs @@ -39,12 +39,11 @@ protected override IEnumerable GetInitialColumnStates() }; protected override string[] GetFixedColumns() - => new[] - { + => [ ColumnDefinitions.CodeStyle.Category, ColumnDefinitions.CodeStyle.Description, ColumnDefinitions.CodeStyle.Value, ColumnDefinitions.CodeStyle.Severity, ColumnDefinitions.CodeStyle.Location - }; + ]; } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/ViewModel/NamingStyleSettingsViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/ViewModel/NamingStyleSettingsViewModel.cs index a7eab95c680dd..3622274b45702 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/ViewModel/NamingStyleSettingsViewModel.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/NamingStyle/ViewModel/NamingStyleSettingsViewModel.cs @@ -38,11 +38,10 @@ protected override IEnumerable GetInitialColumnStates() }; protected override string[] GetFixedColumns() - => new[] - { + => [ ColumnDefinitions.NamingStyle.Type, ColumnDefinitions.NamingStyle.Style, ColumnDefinitions.NamingStyle.Severity, ColumnDefinitions.NamingStyle.Location - }; + ]; } diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml.cs index c5481121e2963..f9b33536b10dc 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/SettingsEditorControl.xaml.cs @@ -82,7 +82,10 @@ internal void SynchronizeSettings() var solution = _workspace.CurrentSolution; var analyzerConfigDocument = solution.Projects - .Select(p => p.TryGetExistingAnalyzerConfigDocumentAtPath(_filepath)).FirstOrDefault(); + .Select(p => p.TryGetExistingAnalyzerConfigDocumentAtPath(_filepath)) + .WhereNotNull() + .FirstOrDefault(); + if (analyzerConfigDocument is null) { return; diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/ViewModel/WhitespaceViewModel.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/ViewModel/WhitespaceViewModel.cs index f2ba855794564..20f0a2b01f127 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/ViewModel/WhitespaceViewModel.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/ViewModel/WhitespaceViewModel.cs @@ -38,11 +38,10 @@ protected override IEnumerable GetInitialColumnStates() }; protected override string[] GetFixedColumns() - => new[] - { + => [ ColumnDefinitions.Whitespace.Category, ColumnDefinitions.Whitespace.Description, ColumnDefinitions.Whitespace.Value, ColumnDefinitions.Whitespace.Location - }; + ]; } diff --git a/src/VisualStudio/Core/Def/ErrorReporting/VisualStudioInfoBar.cs b/src/VisualStudio/Core/Def/ErrorReporting/VisualStudioInfoBar.cs index b138103b89a10..03ed5ca6fc273 100644 --- a/src/VisualStudio/Core/Def/ErrorReporting/VisualStudioInfoBar.cs +++ b/src/VisualStudio/Core/Def/ErrorReporting/VisualStudioInfoBar.cs @@ -97,7 +97,7 @@ public void ShowInfoBarMessageFromAnyThread( } var infoBarModel = new InfoBarModel( - new[] { new InfoBarTextSpan(message) }, + [new InfoBarTextSpan(message)], actionItems, imageMoniker, isCloseButtonVisible); diff --git a/src/VisualStudio/Core/Def/External/UnitTesting/UnitTestingReferencesService.cs b/src/VisualStudio/Core/Def/External/UnitTesting/UnitTestingReferencesService.cs index f86bcdb38e6df..23fc4f16d43fd 100644 --- a/src/VisualStudio/Core/Def/External/UnitTesting/UnitTestingReferencesService.cs +++ b/src/VisualStudio/Core/Def/External/UnitTesting/UnitTestingReferencesService.cs @@ -31,7 +31,7 @@ internal class UnitTestingReferencesService var callerMethods = await callbackService.InvokeAsync?>( provider, nameof(ICodeLensContext.FindReferenceMethodsAsync), - new object[] { descriptor, descriptorContext }, + [descriptor, descriptorContext], cancellationToken).ConfigureAwait(false); if (!callerMethods.HasValue || callerMethods.Value.IsEmpty) diff --git a/src/VisualStudio/Core/Def/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs b/src/VisualStudio/Core/Def/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs index bb341e4867e58..a4a0895b1616d 100644 --- a/src/VisualStudio/Core/Def/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs +++ b/src/VisualStudio/Core/Def/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs @@ -109,8 +109,8 @@ private abstract class AbstractTableDataSourceFindUsagesContext : /// private bool _currentlyGroupingByDefinition; - protected readonly List EntriesWhenNotGroupingByDefinition = []; - protected readonly List EntriesWhenGroupingByDefinition = []; + protected readonly (List primary, List nonPrimary) EntriesWhenNotGroupingByDefinition = ([], []); + protected readonly (List primary, List nonPrimary) EntriesWhenGroupingByDefinition = ([], []); private TableEntriesSnapshot? _lastSnapshot; public int CurrentVersionNumber { get; protected set; } @@ -182,9 +182,17 @@ protected AbstractTableDataSourceFindUsagesContext( protected abstract ValueTask OnDefinitionFoundWorkerAsync(DefinitionItem definition, CancellationToken cancellationToken); protected abstract ValueTask OnReferenceFoundWorkerAsync(SourceReferenceItem reference, CancellationToken cancellationToken); - protected static void AddRange(List list, ArrayBuilder builder) + protected static void Add((List primary, List nonPrimary) entries, T item, bool isPrimary) { + var list = isPrimary ? entries.primary : entries.nonPrimary; + list.Add(item); + } + + protected static void AddRange((List primary, List nonPrimary) entries, ArrayBuilder builder, bool isPrimary) + { + var list = isPrimary ? entries.primary : entries.nonPrimary; list.Capacity = list.Count + builder.Count; + foreach (var item in builder) list.Add(item); } @@ -462,7 +470,7 @@ protected async Task AddDocumentSpanEntriesAsync( var document = documentSpan.Document; var sourceSpan = documentSpan.SourceSpan; - var excerptService = document.Services.GetService(); + var excerptService = document.DocumentServiceProvider.GetService(); // Fetching options is expensive enough to try to avoid it if we can. So only fetch this if absolutely necessary. ClassificationOptions? options = null; @@ -589,8 +597,8 @@ public ITableEntriesSnapshot GetCurrentSnapshot() var entries = _cleared ? [] : _currentlyGroupingByDefinition - ? EntriesWhenGroupingByDefinition.ToImmutableArray() - : EntriesWhenNotGroupingByDefinition.ToImmutableArray(); + ? ToImmutableArray(EntriesWhenGroupingByDefinition) + : ToImmutableArray(EntriesWhenNotGroupingByDefinition); _lastSnapshot = new TableEntriesSnapshot(entries, CurrentVersionNumber); } @@ -599,6 +607,21 @@ public ITableEntriesSnapshot GetCurrentSnapshot() } } + private static ImmutableArray ToImmutableArray((List primary, List nonPrimary) entries) + { + // When returning the final list of entries to the UI layer, we want primary entries to come first, followed + // by non-primary ones. + + var result = new FixedSizeArrayBuilder(entries.nonPrimary.Count + entries.primary.Count); + foreach (var entry in entries.primary) + result.Add(entry); + + foreach (var entry in entries.nonPrimary) + result.Add(entry); + + return result.MoveToImmutable(); + } + public ITableEntriesSnapshot? GetSnapshot(int versionNumber) { lock (Gate) diff --git a/src/VisualStudio/Core/Def/FindReferences/Contexts/WithReferencesFindUsagesContext.cs b/src/VisualStudio/Core/Def/FindReferences/Contexts/WithReferencesFindUsagesContext.cs index 7d451d702441e..86c24274ff923 100644 --- a/src/VisualStudio/Core/Def/FindReferences/Contexts/WithReferencesFindUsagesContext.cs +++ b/src/VisualStudio/Core/Def/FindReferences/Contexts/WithReferencesFindUsagesContext.cs @@ -28,20 +28,23 @@ internal partial class StreamingFindUsagesPresenter /// This context supports showing reference items, and will display appropriate messages /// about no-references being found for a definition at the end of the search. /// - private sealed class WithReferencesFindUsagesContext : AbstractTableDataSourceFindUsagesContext + private sealed class WithReferencesFindUsagesContext( + StreamingFindUsagesPresenter presenter, + IFindAllReferencesWindow findReferencesWindow, + ImmutableArray customColumns, + IGlobalOptionService globalOptions, + bool includeContainingTypeAndMemberColumns, + bool includeKindColumn, + IThreadingContext threadingContext) + : AbstractTableDataSourceFindUsagesContext( + presenter, + findReferencesWindow, + customColumns, + globalOptions, + includeContainingTypeAndMemberColumns, + includeKindColumn, + threadingContext) { - public WithReferencesFindUsagesContext( - StreamingFindUsagesPresenter presenter, - IFindAllReferencesWindow findReferencesWindow, - ImmutableArray customColumns, - IGlobalOptionService globalOptions, - bool includeContainingTypeAndMemberColumns, - bool includeKindColumn, - IThreadingContext threadingContext) - : base(presenter, findReferencesWindow, customColumns, globalOptions, includeContainingTypeAndMemberColumns, includeKindColumn, threadingContext) - { - } - protected override async ValueTask OnDefinitionFoundWorkerAsync(DefinitionItem definition, CancellationToken cancellationToken) { // If this is a definition we always want to show, then create entries for all the declaration locations @@ -75,6 +78,7 @@ private async Task AddDeclarationEntriesAsync(DefinitionItem definition, bool ex await AddDocumentSpanEntriesAsync(entries, definitionBucket, definition, cancellationToken).ConfigureAwait(false); var changed = false; + var isPrimary = IsPrimary(definition); lock (Gate) { // Do one final check to ensure that no other thread beat us here. @@ -82,7 +86,7 @@ private async Task AddDeclarationEntriesAsync(DefinitionItem definition, bool ex { // We only include declaration entries in the entries we show when // not grouping by definition. - AddRange(EntriesWhenNotGroupingByDefinition, entries); + AddRange(EntriesWhenNotGroupingByDefinition, entries, isPrimary); CurrentVersionNumber++; changed = true; } @@ -99,7 +103,13 @@ private bool HasDeclarationEntries(DefinitionItem definition) { lock (Gate) { - foreach (var entry in EntriesWhenNotGroupingByDefinition) + foreach (var entry in EntriesWhenNotGroupingByDefinition.primary) + { + if (entry.DefinitionBucket.DefinitionItem == definition) + return true; + } + + foreach (var entry in EntriesWhenNotGroupingByDefinition.nonPrimary) { if (entry.DefinitionBucket.DefinitionItem == definition) return true; @@ -151,16 +161,17 @@ private async ValueTask OnEntryFoundAsync( // Proceed, even if we didn't create an entry. It's possible that we augmented // an existing entry and we want the UI to refresh to show the results of that. + var isPrimary = IsPrimary(definition); lock (Gate) { if (entry != null) { // Once we can make the new entry, add it to the appropriate list. if (addToEntriesWhenGroupingByDefinition) - EntriesWhenGroupingByDefinition.Add(entry); + Add(EntriesWhenGroupingByDefinition, entry, isPrimary); if (addToEntriesWhenNotGroupingByDefinition) - EntriesWhenNotGroupingByDefinition.Add(entry); + Add(EntriesWhenNotGroupingByDefinition, entry, isPrimary); } CurrentVersionNumber++; @@ -228,7 +239,7 @@ private ImmutableArray GetDefinitionsToCreateMissingReferenceIte { lock (Gate) { - var entries = whenGroupingByDefinition + var (primary, nonPrimary) = whenGroupingByDefinition ? EntriesWhenGroupingByDefinition : EntriesWhenNotGroupingByDefinition; @@ -236,7 +247,9 @@ private ImmutableArray GetDefinitionsToCreateMissingReferenceIte // them if they want to be displayed without any references. This will // ensure that we still see things like overrides and whatnot, but we // won't show property-accessors. - var seenDefinitions = entries.Select(r => r.DefinitionBucket.DefinitionItem).ToSet(); + var seenDefinitions = primary.Concat(nonPrimary) + .Select(r => r.DefinitionBucket.DefinitionItem) + .ToSet(); var q = from definition in Definitions where !seenDefinitions.Contains(definition) && definition.DisplayIfNoReferences @@ -245,19 +258,15 @@ private ImmutableArray GetDefinitionsToCreateMissingReferenceIte // If we find at least one of these types of definitions, then just return those. var result = ImmutableArray.CreateRange(q); if (result.Length > 0) - { return result; - } - // We found no definitions that *want* to be displayed. However, we still - // want to show something. So, if necessary, show at lest the first definition - // even if we found no references and even if it would prefer to not be seen. - if (entries.Count == 0 && Definitions.Count > 0) - { + // We found no definitions that *want* to be displayed. However, we still want to show something. So, + // if necessary, show at lest the first definition even if we found no references and even if it would + // prefer to not be seen. + if (primary.Count == 0 && nonPrimary.Count == 0 && Definitions.Count > 0) return [Definitions.First()]; - } - return ImmutableArray.Empty; + return []; } } diff --git a/src/VisualStudio/Core/Def/FindReferences/Contexts/WithoutReferencesFindUsagesContext.cs b/src/VisualStudio/Core/Def/FindReferences/Contexts/WithoutReferencesFindUsagesContext.cs index 3a66ce6fdfe2d..c433614329a37 100644 --- a/src/VisualStudio/Core/Def/FindReferences/Contexts/WithoutReferencesFindUsagesContext.cs +++ b/src/VisualStudio/Core/Def/FindReferences/Contexts/WithoutReferencesFindUsagesContext.cs @@ -23,19 +23,23 @@ internal partial class StreamingFindUsagesPresenter /// This context will not group entries by definition, and will instead just create /// entries for the definitions themselves. /// - private sealed class WithoutReferencesFindUsagesContext : AbstractTableDataSourceFindUsagesContext + private sealed class WithoutReferencesFindUsagesContext( + StreamingFindUsagesPresenter presenter, + IFindAllReferencesWindow findReferencesWindow, + ImmutableArray customColumns, + IGlobalOptionService globalOptions, + bool includeContainingTypeAndMemberColumns, + bool includeKindColumn, + IThreadingContext threadingContext) + : AbstractTableDataSourceFindUsagesContext( + presenter, + findReferencesWindow, + customColumns, + globalOptions, + includeContainingTypeAndMemberColumns, + includeKindColumn, + threadingContext) { - public WithoutReferencesFindUsagesContext( - StreamingFindUsagesPresenter presenter, - IFindAllReferencesWindow findReferencesWindow, - ImmutableArray customColumns, - IGlobalOptionService globalOptions, - bool includeContainingTypeAndMemberColumns, - bool includeKindColumn, - IThreadingContext threadingContext) - : base(presenter, findReferencesWindow, customColumns, globalOptions, includeContainingTypeAndMemberColumns, includeKindColumn, threadingContext) - { - } // We should never be called in a context where we get references. protected override ValueTask OnReferenceFoundWorkerAsync(SourceReferenceItem reference, CancellationToken cancellationToken) @@ -60,10 +64,13 @@ private async Task CreateNoResultsFoundEntryIfNecessaryAsync() var definitionBucket = GetOrCreateDefinitionBucket(CreateNoResultsDefinitionItem(message), expandedByDefault: true); var entry = await SimpleMessageEntry.CreateAsync(definitionBucket, navigationBucket: null, message).ConfigureAwait(false); + var isPrimary = IsPrimary(definitionBucket.DefinitionItem); + lock (Gate) { - EntriesWhenGroupingByDefinition.Add(entry); - EntriesWhenNotGroupingByDefinition.Add(entry); + Add(EntriesWhenGroupingByDefinition, entry, isPrimary); + Add(EntriesWhenNotGroupingByDefinition, entry, isPrimary); + CurrentVersionNumber++; } @@ -105,10 +112,12 @@ protected override async ValueTask OnDefinitionFoundWorkerAsync(DefinitionItem d if (entries.Count > 0) { + var isPrimary = IsPrimary(definition); + lock (Gate) { - AddRange(EntriesWhenGroupingByDefinition, entries); - AddRange(EntriesWhenNotGroupingByDefinition, entries); + AddRange(EntriesWhenGroupingByDefinition, entries, isPrimary); + AddRange(EntriesWhenNotGroupingByDefinition, entries, isPrimary); CurrentVersionNumber++; } diff --git a/src/VisualStudio/Core/Def/FindReferences/Entries/AbstractDocumentSpanEntry.cs b/src/VisualStudio/Core/Def/FindReferences/Entries/AbstractDocumentSpanEntry.cs index eb3f0f84da2c4..b5cd1fd9c0cab 100644 --- a/src/VisualStudio/Core/Def/FindReferences/Entries/AbstractDocumentSpanEntry.cs +++ b/src/VisualStudio/Core/Def/FindReferences/Entries/AbstractDocumentSpanEntry.cs @@ -75,7 +75,7 @@ await documentNavigationService.TryNavigateToSpanAsync( public static async Task TryMapAndGetFirstAsync(DocumentSpan documentSpan, SourceText sourceText, CancellationToken cancellationToken) { - var service = documentSpan.Document.Services.GetService(); + var service = documentSpan.Document.DocumentServiceProvider.GetService(); if (service == null) { return new MappedSpanResult(documentSpan.Document.FilePath, sourceText.Lines.GetLinePositionSpan(documentSpan.SourceSpan), documentSpan.SourceSpan); diff --git a/src/VisualStudio/Core/Def/FindReferences/Entries/DocumentSpanEntry.cs b/src/VisualStudio/Core/Def/FindReferences/Entries/DocumentSpanEntry.cs index 1b730d1c38127..7b69f24be8945 100644 --- a/src/VisualStudio/Core/Def/FindReferences/Entries/DocumentSpanEntry.cs +++ b/src/VisualStudio/Core/Def/FindReferences/Entries/DocumentSpanEntry.cs @@ -183,7 +183,7 @@ private DisposableToolTip CreateDisposableToolTip(Document document, TextSpan so var controlService = document.Project.Solution.Services.GetRequiredService(); var sourceText = document.GetTextSynchronously(CancellationToken.None); - var excerptService = document.Services.GetService(); + var excerptService = document.DocumentServiceProvider.GetService(); if (excerptService != null) { var classificationOptions = Presenter._globalOptions.GetClassificationOptions(document.Project.Language); diff --git a/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs b/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs index 8f3dd6c8c4920..b3873f7f49ab3 100644 --- a/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs +++ b/src/VisualStudio/Core/Def/FindReferences/StreamingFindUsagesPresenter.cs @@ -134,6 +134,9 @@ private StreamingFindUsagesPresenter( public IClassificationFormatMap ClassificationFormatMap => _lazyClassificationFormatMap.Value; + private static bool IsPrimary(DefinitionItem definition) + => definition.Properties.ContainsKey(DefinitionItem.Primary); + private static IEnumerable GetCustomColumns(IEnumerable> columns) { foreach (var column in columns) diff --git a/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialogViewModel.cs b/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialogViewModel.cs index 3f969740852c3..b7fd599a1c4e6 100644 --- a/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/GenerateType/GenerateTypeDialogViewModel.cs @@ -784,64 +784,42 @@ internal GenerateTypeDialogViewModel( public class ProjectSelectItem { - private readonly Project _project; - public string Name { get { - return _project.Name; + return Project.Name; } } - public Project Project - { - get - { - return _project; - } - } + public Project Project { get; } public ProjectSelectItem(Project project) - => _project = project; + => Project = project; } public class DocumentSelectItem { - private readonly Document _document; - public Document Document - { - get - { - return _document; - } - } + public Document Document { get; } - private readonly string _name; - public string Name - { - get - { - return _name; - } - } + public string Name { get; } public DocumentSelectItem(Document document, string documentName) { - _document = document; - _name = documentName; + Document = document; + Name = documentName; } public DocumentSelectItem(Document document) { - _document = document; + Document = document; if (document.Folders.Count == 0) { - _name = document.Name; + Name = document.Name; } else { - _name = string.Join("\\", document.Folders) + "\\" + document.Name; + Name = string.Join("\\", document.Folders) + "\\" + document.Name; } } } diff --git a/src/VisualStudio/Core/Def/Implementation/VisualStudioUIContextActivationService.cs b/src/VisualStudio/Core/Def/Implementation/VisualStudioUIContextActivationService.cs index d04d43a5cd83c..41b73f8a55c5c 100644 --- a/src/VisualStudio/Core/Def/Implementation/VisualStudioUIContextActivationService.cs +++ b/src/VisualStudio/Core/Def/Implementation/VisualStudioUIContextActivationService.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.Shell; +using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation; @@ -15,9 +16,60 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation; [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] internal sealed class VisualStudioUIContextActivationService() : IUIContextActivationService { - public void ExecuteWhenActivated(Guid uiContext, Action action) + public IDisposable ExecuteWhenActivated(Guid uiContext, Action action) { var context = UIContext.FromUIContextGuid(uiContext); - context.WhenActivated(action); + if (context.IsActive) + { + action(); + return EmptyDisposable.Instance; + } + else + { + return new WhenActivatedHandler(context, action); + } + } + + private sealed class EmptyDisposable : IDisposable + { + public static EmptyDisposable Instance = new(); + + public void Dispose() + { + } + } + + private sealed class WhenActivatedHandler : IDisposable + { + private readonly Action _action; + private UIContext? _context; + + public WhenActivatedHandler(UIContext context, Action action) + { + _context = context; + _action = action; + _context.UIContextChanged += OnContextChanged; + } + + public void Dispose() + { + if (_context is not null) + { + _context.UIContextChanged -= OnContextChanged; + } + + _context = null; + } + + private void OnContextChanged(object sender, UIContextChangedEventArgs e) + { + Contract.ThrowIfNull(_context); + + if (e.Activated) + { + _action(); + Dispose(); + } + } } } diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/DisambiguousTargetMenuItemViewModel.cs b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/DisambiguousTargetMenuItemViewModel.cs index 22da492537d65..1bb43a47827bc 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/DisambiguousTargetMenuItemViewModel.cs +++ b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/DisambiguousTargetMenuItemViewModel.cs @@ -11,12 +11,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.InheritanceMarg /// /// The View Model would be used when there are multiple targets with same name in the group. -/// It contains an addtional image moniker represents the source language in the UI. +/// It contains an additional image moniker represents the source language in the UI. /// internal class DisambiguousTargetMenuItemViewModel : TargetMenuItemViewModel { /// - /// Icon represets the source language of this target. + /// Icon represents the source language of this target. /// public ImageMoniker LanguageMoniker { get; } diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml index 874af870668a3..19b3669728231 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml +++ b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml @@ -13,6 +13,7 @@ UsesItemContainerTemplate="True" MaxHeight="400" StaysOpen="True" + x:Name="InheritanceContextMenu" Background="{DynamicResource {x:Static vsfx:VsBrushes.CommandBarMenuBackgroundGradientKey}}" FontFamily="{DynamicResource {x:Static vsfx:VsFonts.EnvironmentFontFamilyKey}}" FontSize="{DynamicResource {x:Static vsfx:VsFonts.EnvironmentFontSizeKey}}" @@ -21,7 +22,7 @@ d:DesignHeight="450" d:DesignWidth="800"> - + @@ -112,7 +113,7 @@ SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Content="{TemplateBinding MenuItem.Icon}" /> + SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Moniker="{Binding LanguageMoniker}" imaging:CrispImage.ScaleFactor="{Binding DataContext.ScaleFactor, ElementName=InheritanceContextMenu}" /> @@ -234,7 +235,7 @@ - + diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml.cs b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml.cs index 15f4d538e4585..35cc5b6662da4 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml.cs +++ b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; +using System.Windows.Media; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -31,7 +32,8 @@ public InheritanceMarginContextMenu( IStreamingFindUsagesPresenter streamingFindUsagesPresenter, IUIThreadOperationExecutor operationExecutor, Workspace workspace, - IAsynchronousOperationListener listener) + IAsynchronousOperationListener listener, + double scaleFactor) { _threadingContext = threadingContext; _streamingFindUsagesPresenter = streamingFindUsagesPresenter; @@ -39,6 +41,8 @@ public InheritanceMarginContextMenu( _operationExecutor = operationExecutor; _listener = listener; InitializeComponent(); + LayoutTransform = new ScaleTransform(scaleFactor, scaleFactor); + LayoutTransform.Freeze(); } private void TargetMenuItem_OnClick(object sender, RoutedEventArgs e) diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginGlyph.cs b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginGlyph.cs index 9a6ea06bacea1..6b3efdb443d9c 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginGlyph.cs +++ b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginGlyph.cs @@ -120,7 +120,13 @@ private void LazyInitializeContextMenu() { var viewModel = (InheritanceMarginGlyphViewModel)DataContext; - ContextMenu = new InheritanceMarginContextMenu(_threadingContext, _streamingFindUsagesPresenter, _operationExecutor, _workspace, _listener); + ContextMenu = new InheritanceMarginContextMenu( + _threadingContext, + _streamingFindUsagesPresenter, + _operationExecutor, + _workspace, + _listener, + viewModel.ScaleFactor); ContextMenu.DataContext = viewModel; ContextMenu.ItemsSource = viewModel.MenuItemViewModels; ContextMenu.Opened += ContextMenu_OnOpen; diff --git a/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowPackage.cs b/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowPackage.cs index e15f21c189799..c9f7e2dcc5490 100644 --- a/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowPackage.cs +++ b/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowPackage.cs @@ -33,7 +33,6 @@ protected virtual void InitializeMenuCommands(OleMenuCommandService menuCommandS protected abstract Guid ToolWindowId { get; } private IComponentModel _componentModel; - private TVsInteractiveWindowProvider _interactiveWindowProvider; protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { @@ -61,7 +60,7 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke SetErrorHandlers(typeof(IInteractiveWindow).Assembly, fatalHandler, nonFatalHandler); SetErrorHandlers(typeof(IVsInteractiveWindow).Assembly, fatalHandler, nonFatalHandler); - _interactiveWindowProvider = _componentModel.DefaultExportProvider.GetExportedValue(); + InteractiveWindowProvider = _componentModel.DefaultExportProvider.GetExportedValue(); InitializeMenuCommands(menuCommandService); } @@ -77,10 +76,7 @@ private static void SetErrorHandlers(Assembly assembly, Action fatalH nonFatalHandlerSetter.Invoke(null, [nonFatalHandler]); } - protected TVsInteractiveWindowProvider InteractiveWindowProvider - { - get { return _interactiveWindowProvider; } - } + protected TVsInteractiveWindowProvider InteractiveWindowProvider { get; private set; } /// /// When a VSPackage supports multi-instance tool windows, each window uses the same rguidPersistenceSlot. @@ -90,7 +86,7 @@ int IVsToolWindowFactory.CreateToolWindow(ref Guid rguidPersistenceSlot, uint id { if (rguidPersistenceSlot == ToolWindowId) { - _interactiveWindowProvider.Create((int)id); + InteractiveWindowProvider.Create((int)id); return VSConstants.S_OK; } diff --git a/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs b/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs index 0f914aac74f1b..44603eea333e1 100644 --- a/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs +++ b/src/VisualStudio/Core/Def/Interactive/VsInteractiveWindowProvider.cs @@ -32,8 +32,6 @@ internal abstract class VsInteractiveWindowProvider private readonly VisualStudioWorkspace _vsWorkspace; private readonly IViewClassifierAggregatorService _classifierAggregator; private readonly IContentTypeRegistryService _contentTypeRegistry; - private readonly IInteractiveWindowCommandsFactory _commandsFactory; - private readonly ImmutableArray _commands; // TODO: support multi-instance windows // single instance of the Interactive Window @@ -52,10 +50,10 @@ public VsInteractiveWindowProvider( _classifierAggregator = classifierAggregator; _contentTypeRegistry = contentTypeRegistry; _vsWorkspace = workspace; - _commands = GetApplicableCommands(commands, coreContentType: PredefinedInteractiveCommandsContentTypes.InteractiveCommandContentTypeName, + Commands = GetApplicableCommands(commands, coreContentType: PredefinedInteractiveCommandsContentTypes.InteractiveCommandContentTypeName, specializedContentType: InteractiveWindowContentTypes.CommandContentTypeName); _vsInteractiveWindowFactory = interactiveWindowFactory; - _commandsFactory = commandsFactory; + CommandsFactory = commandsFactory; } protected abstract CSharpInteractiveEvaluator CreateInteractiveEvaluator( @@ -69,21 +67,9 @@ protected abstract CSharpInteractiveEvaluator CreateInteractiveEvaluator( protected abstract string Title { get; } protected abstract FunctionId InteractiveWindowFunctionId { get; } - protected IInteractiveWindowCommandsFactory CommandsFactory - { - get - { - return _commandsFactory; - } - } + protected IInteractiveWindowCommandsFactory CommandsFactory { get; } - protected ImmutableArray Commands - { - get - { - return _commands; - } - } + protected ImmutableArray Commands { get; } public void Create(int instanceId) { diff --git a/src/VisualStudio/Core/Def/Interop/CleanableWeakComHandleTable.cs b/src/VisualStudio/Core/Def/Interop/CleanableWeakComHandleTable.cs index 94d7f017396c4..a35dcfb97dcb9 100644 --- a/src/VisualStudio/Core/Def/Interop/CleanableWeakComHandleTable.cs +++ b/src/VisualStudio/Core/Def/Interop/CleanableWeakComHandleTable.cs @@ -42,9 +42,8 @@ internal sealed class CleanableWeakComHandleTable where TValue : c public TimeSpan CleanUpTimeSlice { get; } private int _itemsAddedSinceLastCleanUp; - private bool _needsCleanUp; - public bool NeedsCleanUp => _needsCleanUp; + public bool NeedsCleanUp { get; private set; } public CleanableWeakComHandleTable(IThreadingContext threadingContext, int? cleanUpThreshold = null, TimeSpan? cleanUpTimeSlice = null) { @@ -67,13 +66,13 @@ public async Task CleanUpDeadObjectsAsync(IAsynchronousOperationListener listene await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(_threadingContext.DisposalToken); - if (!_needsCleanUp) + if (!NeedsCleanUp) { return; } // Immediately mark as not needing cleanup; this operation will clean up the table by the time it returns. - _needsCleanUp = false; + NeedsCleanUp = false; var timeSlice = new TimeSlice(CleanUpTimeSlice); @@ -159,7 +158,7 @@ public void Add(TKey key, TValue value) _itemsAddedSinceLastCleanUp++; if (_itemsAddedSinceLastCleanUp >= CleanUpThreshold) { - _needsCleanUp = true; + NeedsCleanUp = true; _itemsAddedSinceLastCleanUp = 0; } diff --git a/src/VisualStudio/Core/Def/Interop/ComHandle.cs b/src/VisualStudio/Core/Def/Interop/ComHandle.cs index 6c3519e03f84a..80b4f5047e1ab 100644 --- a/src/VisualStudio/Core/Def/Interop/ComHandle.cs +++ b/src/VisualStudio/Core/Def/Interop/ComHandle.cs @@ -20,7 +20,6 @@ internal readonly struct ComHandle where TObject : class, THandle { private readonly THandle _handle; - private readonly TObject _managedObject; /// /// Create an instance from a "ComObject" or from a managed object. @@ -30,17 +29,17 @@ public ComHandle(THandle handleOrManagedObject) if (handleOrManagedObject == null) { _handle = null; - _managedObject = null; + Object = null; } else if (Marshal.IsComObject(handleOrManagedObject)) { _handle = handleOrManagedObject; - _managedObject = ComAggregate.GetManagedObject(handleOrManagedObject); + Object = ComAggregate.GetManagedObject(handleOrManagedObject); } else { _handle = (THandle)ComAggregate.TryGetWrapper(handleOrManagedObject); - _managedObject = (TObject)handleOrManagedObject; + Object = (TObject)handleOrManagedObject; } } @@ -49,7 +48,7 @@ public ComHandle(THandle handle, TObject managedObject) if (handle == null && managedObject == null) { _handle = null; - _managedObject = null; + Object = null; } else { @@ -62,7 +61,7 @@ public ComHandle(THandle handle, TObject managedObject) } _handle = handle; - _managedObject = managedObject; + Object = managedObject; } } @@ -77,7 +76,7 @@ public THandle Handle if (_handle == null) { - return _managedObject; + return Object; } else { @@ -89,13 +88,7 @@ public THandle Handle /// /// Return the managed object /// - public TObject Object - { - get - { - return _managedObject; - } - } + public TObject Object { get; } public ComHandle Cast() where TNewHandle : class diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs index a5de30141b25e..8d05193d1b33e 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs @@ -38,8 +38,6 @@ internal abstract partial class AbstractObjectBrowserLibraryManager : AbstractLi private uint _classVersion; private uint _membersVersion; - private uint _packageVersion; - private ObjectListItem _activeListItem; private AbstractListItemFactory _listItemFactory; private readonly object _classMemberGate = new(); @@ -150,10 +148,7 @@ internal uint MembersVersion } } - internal uint PackageVersion - { - get { return _packageVersion; } - } + internal uint PackageVersion { get; private set; } internal void UpdateClassAndMemberVersions() { @@ -171,7 +166,7 @@ private void UpdateMembersVersion() => _membersVersion = unchecked(_membersVersion + 1); internal void UpdatePackageVersion() - => _packageVersion = unchecked(_packageVersion + 1); + => PackageVersion = unchecked(PackageVersion + 1); internal void SetActiveListItem(ObjectListItem listItem) => _activeListItem = listItem; @@ -327,7 +322,7 @@ protected override IVsSimpleObjectList2 GetList(uint listType, uint flags, VSOBS } protected override uint GetUpdateCounter() - => _packageVersion; + => PackageVersion; protected override int CreateNavInfo(SYMBOL_DESCRIPTION_NODE[] rgSymbolNodes, uint ulcNodes, out IVsNavInfo ppNavInfo) { diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/MemberListItem.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/MemberListItem.cs index 6882f30c0ce35..a68f9f5dcce40 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/MemberListItem.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/MemberListItem.cs @@ -11,29 +11,26 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectB internal class MemberListItem : SymbolListItem { - private readonly MemberKind _kind; - private readonly bool _isInherited; - internal MemberListItem(ProjectId projectId, ISymbol symbol, string displayText, string fullNameText, string searchText, bool isHidden, bool isInherited) : base(projectId, symbol, displayText, fullNameText, searchText, isHidden) { - _isInherited = isInherited; + IsInherited = isInherited; switch (symbol.Kind) { case SymbolKind.Event: - _kind = MemberKind.Event; + Kind = MemberKind.Event; break; case SymbolKind.Field: var fieldSymbol = (IFieldSymbol)symbol; if (fieldSymbol.ContainingType.TypeKind == TypeKind.Enum) { - _kind = MemberKind.EnumMember; + Kind = MemberKind.EnumMember; } else { - _kind = fieldSymbol.IsConst + Kind = fieldSymbol.IsConst ? MemberKind.Constant : MemberKind.Field; } @@ -42,7 +39,7 @@ internal MemberListItem(ProjectId projectId, ISymbol symbol, string displayText, case SymbolKind.Method: var methodSymbol = (IMethodSymbol)symbol; - _kind = methodSymbol.MethodKind is MethodKind.Conversion or + Kind = methodSymbol.MethodKind is MethodKind.Conversion or MethodKind.UserDefinedOperator ? MemberKind.Operator : MemberKind.Method; @@ -50,23 +47,17 @@ internal MemberListItem(ProjectId projectId, ISymbol symbol, string displayText, break; case SymbolKind.Property: - _kind = MemberKind.Property; + Kind = MemberKind.Property; break; default: Debug.Fail("Unsupported symbol for member: " + symbol.Kind.ToString()); - _kind = MemberKind.None; + Kind = MemberKind.None; break; } } - public bool IsInherited - { - get { return _isInherited; } - } + public bool IsInherited { get; } - public MemberKind Kind - { - get { return _kind; } - } + public MemberKind Kind { get; } } diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/ReferenceListItem.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/ReferenceListItem.cs index ff520fa87762e..d0464aa342ae1 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/ReferenceListItem.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/ReferenceListItem.cs @@ -12,13 +12,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectB internal class ReferenceListItem : ObjectListItem { private readonly string _name; - private readonly MetadataReference _reference; public ReferenceListItem(ProjectId projectId, string name, MetadataReference reference) : base(projectId, StandardGlyphGroup.GlyphAssembly) { _name = name; - _reference = reference; + MetadataReference = reference; } public override string DisplayText @@ -36,11 +35,8 @@ public override string SearchText get { return _name; } } - public MetadataReference MetadataReference - { - get { return _reference; } - } + public MetadataReference MetadataReference { get; } public IAssemblySymbol GetAssembly(Compilation compilation) - => compilation.GetAssemblyOrModuleSymbol(_reference) as IAssemblySymbol; + => compilation.GetAssemblyOrModuleSymbol(MetadataReference) as IAssemblySymbol; } diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/SymbolListItem.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/SymbolListItem.cs index 1126bd3ec4c80..0e226236a61c5 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/SymbolListItem.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/SymbolListItem.cs @@ -13,7 +13,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectB internal abstract class SymbolListItem : ObjectListItem { private readonly SymbolKey _symbolKey; - private readonly Accessibility _accessibility; private readonly string _displayText; private readonly string _fullNameText; private readonly string _searchText; @@ -25,7 +24,7 @@ protected SymbolListItem(ProjectId projectId, ISymbol symbol, string displayText : base(projectId, symbol.GetGlyph().GetStandardGlyphGroup(), symbol.GetGlyph().GetStandardGlyphItem(), isHidden) { _symbolKey = symbol.GetSymbolKey(); - _accessibility = symbol.DeclaredAccessibility; + Accessibility = symbol.DeclaredAccessibility; _displayText = displayText; _fullNameText = fullNameText; _searchText = searchText; @@ -34,10 +33,7 @@ protected SymbolListItem(ProjectId projectId, ISymbol symbol, string displayText _supportsFindAllReferences = symbol.Kind != SymbolKind.Namespace; } - public Accessibility Accessibility - { - get { return _accessibility; } - } + public Accessibility Accessibility { get; } public override string DisplayText { diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/TypeListItem.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/TypeListItem.cs index b4a5f109a6528..4cbd1a1cfde19 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/TypeListItem.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/Lists/TypeListItem.cs @@ -10,16 +10,11 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectB internal class TypeListItem : SymbolListItem { - private readonly TypeKind _typeKind; - internal TypeListItem(ProjectId projectId, INamedTypeSymbol typeSymbol, string displayText, string fullNameText, string searchText, bool isHidden) : base(projectId, typeSymbol, displayText, fullNameText, searchText, isHidden) { - _typeKind = typeSymbol.TypeKind; + Kind = typeSymbol.TypeKind; } - public TypeKind Kind - { - get { return _typeKind; } - } + public TypeKind Kind { get; } } diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectList.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectList.cs index f04628339efba..afbabdf35f36d 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectList.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectList.cs @@ -22,9 +22,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectB internal class ObjectList : AbstractObjectList { - private readonly ObjectListKind _kind; private readonly ObjectList _parentList; - private readonly ObjectListItem _parentListItem; private readonly uint _flags; private readonly ImmutableArray _items; @@ -46,10 +44,10 @@ public ObjectList( ImmutableArray items) : base(manager) { - _kind = kind; + Kind = kind; _flags = flags; _parentList = parentList; - _parentListItem = parentListItem; + ParentListItem = parentListItem; _items = items; @@ -77,7 +75,7 @@ private string GetDisplayText(uint index, VSTREETEXTOPTIONS textOptions) { case VSTREETEXTOPTIONS.TTO_SORTTEXT: case VSTREETEXTOPTIONS.TTO_DISPLAYTEXT: - switch (_kind) + switch (Kind) { case ObjectListKind.BaseTypes: case ObjectListKind.Hierarchy: @@ -116,7 +114,7 @@ protected override bool TryGetCapabilities(out uint capabilities) private bool TryGetListType(out uint categoryField) { - switch (_kind) + switch (Kind) { case ObjectListKind.BaseTypes: categoryField = (uint)_LIB_LISTTYPE.LLT_CLASSES | (uint)_LIB_LISTTYPE.LLT_MEMBERS; @@ -359,7 +357,7 @@ protected override bool TryGetCategoryField(uint index, int category, out uint c return TryGetClassType(index, out categoryField); case (int)_LIB_CATEGORY2.LC_HIERARCHYTYPE: - if (_kind == ObjectListKind.Hierarchy) + if (Kind == ObjectListKind.Hierarchy) { categoryField = this.ParentKind == ObjectListKind.Projects ? (uint)_LIBCAT_HIERARCHYTYPE.LCHT_PROJECTREFERENCES @@ -400,7 +398,7 @@ protected override void GetDisplayData(uint index, ref VSTREEDISPLAYDATA data) protected override bool GetExpandable(uint index, uint listTypeExcluded) { - switch (_kind) + switch (Kind) { case ObjectListKind.Hierarchy: case ObjectListKind.Namespaces: @@ -463,7 +461,7 @@ protected override IVsSimpleObjectList2 GetList(uint index, uint listType, uint var listItem = GetListItem(index); // We need to do a little massaging of the list type and parent item in a couple of cases. - switch (_kind) + switch (Kind) { case ObjectListKind.Hierarchy: // LLT_USESCLASSES is for displaying base classes and interfaces @@ -473,7 +471,7 @@ protected override IVsSimpleObjectList2 GetList(uint index, uint listType, uint : Helpers.LLT_PROJREF; // Use the parent of this list as the parent of the new list. - listItem = listItem.ParentList._parentListItem; + listItem = listItem.ParentList.ParentListItem; break; @@ -577,7 +575,7 @@ protected override IVsNavInfoNode GetNavInfoNode(uint index) var listItem = GetListItem(index); var name = listItem.DisplayText; - var type = Helpers.ObjectListKindToListType(_kind); + var type = Helpers.ObjectListKindToListType(Kind); if (type == (uint)_LIB_LISTTYPE.LLT_USESCLASSES) { @@ -611,7 +609,7 @@ protected override bool TryLocateNavInfoNode(IVsNavInfoNode pNavInfoNode, out ui { var name = GetText(i, VSTREETEXTOPTIONS.TTO_DISPLAYTEXT); - if (_kind is ObjectListKind.Types or + if (Kind is ObjectListKind.Types or ObjectListKind.Namespaces or ObjectListKind.Members) { @@ -628,7 +626,7 @@ ObjectListKind.Namespaces or index = i; break; } - else if (_kind == ObjectListKind.Projects) + else if (Kind == ObjectListKind.Projects) { if (matchName.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0) { @@ -767,7 +765,7 @@ protected override async Task GoToSourceAsync(uint index, VSOBJGOTOSRCTYPE srcTy protected override uint GetUpdateCounter() { - switch (_kind) + switch (Kind) { case ObjectListKind.Projects: case ObjectListKind.References: @@ -782,7 +780,7 @@ protected override uint GetUpdateCounter() return LibraryManager.ClassVersion | LibraryManager.MembersVersion; default: - Debug.Fail("Unsupported object list kind: " + _kind.ToString()); + Debug.Fail("Unsupported object list kind: " + Kind.ToString()); throw new InvalidOperationException(); } } @@ -804,7 +802,7 @@ protected override bool TryGetContextMenu(uint index, out Guid menuGuid, out int const int IDM_VS_CTXT_CV_GROUPINGFOLDER = 0x0435; const int IDM_VS_CTXT_CV_MEMBER = 0x0438; - switch (_kind) + switch (Kind) { case ObjectListKind.Projects: menuId = IDM_VS_CTXT_CV_PROJECT; @@ -949,10 +947,7 @@ protected override bool TryGetBrowseContainerData(uint index, ref VSCOMPONENTSEL return true; } - public ObjectListKind Kind - { - get { return _kind; } - } + public ObjectListKind Kind { get; } public ObjectListKind ParentKind { @@ -964,8 +959,5 @@ public ObjectListKind ParentKind } } - public ObjectListItem ParentListItem - { - get { return _parentListItem; } - } + public ObjectListItem ParentListItem { get; } } diff --git a/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectListItem.cs b/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectListItem.cs index bebdc890be102..3621441506afc 100644 --- a/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectListItem.cs +++ b/src/VisualStudio/Core/Def/Library/ObjectBrowser/ObjectListItem.cs @@ -15,30 +15,25 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectB internal abstract class ObjectListItem { - private readonly ProjectId _projectId; - private ObjectList _parentList; - private readonly ushort _glyphIndex; - private readonly bool _isHidden; - protected ObjectListItem( ProjectId projectId, StandardGlyphGroup glyphGroup, StandardGlyphItem glyphItem = StandardGlyphItem.GlyphItemPublic, bool isHidden = false) { - _projectId = projectId; + ProjectId = projectId; - _glyphIndex = glyphGroup < StandardGlyphGroup.GlyphGroupError + GlyphIndex = glyphGroup < StandardGlyphGroup.GlyphGroupError ? (ushort)((int)glyphGroup + (int)glyphItem) : (ushort)glyphGroup; - _isHidden = isHidden; + IsHidden = isHidden; } internal void SetParentList(ObjectList parentList) { - Debug.Assert(_parentList == null); - _parentList = parentList; + Debug.Assert(ParentList == null); + ParentList = parentList; } public virtual bool SupportsGoToDefinition @@ -60,32 +55,23 @@ public virtual bool SupportsFindAllReferences public override string ToString() => DisplayText; - public ObjectList ParentList - { - get { return _parentList; } - } + public ObjectList ParentList { get; private set; } public ObjectListKind ParentListKind { get { - return _parentList != null - ? _parentList.Kind + return ParentList != null + ? ParentList.Kind : ObjectListKind.None; } } - public ProjectId ProjectId - { - get - { - return _projectId; - } - } + public ProjectId ProjectId { get; } public Compilation GetCompilation(Workspace workspace) { - var project = workspace.CurrentSolution.GetProject(_projectId); + var project = workspace.CurrentSolution.GetProject(ProjectId); if (project == null) { return null; @@ -96,13 +82,7 @@ public Compilation GetCompilation(Workspace workspace) .WaitAndGetResult_ObjectBrowser(CancellationToken.None); } - public ushort GlyphIndex - { - get { return _glyphIndex; } - } + public ushort GlyphIndex { get; } - public bool IsHidden - { - get { return _isHidden; } - } + public bool IsHidden { get; } } diff --git a/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs b/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs index 9b3a2b72a5a21..c189b86b8045d 100644 --- a/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs +++ b/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs @@ -64,9 +64,9 @@ public Task> GetPreviewPanelsAsync(S return null; Uri? absoluteUri; - if (document.IsSourceGeneratedDocument) + if (document.SourceGeneratedDocumentIdentity is not null) { - absoluteUri = ProtocolConversions.CreateUriFromSourceGeneratedFilePath(filePath); + absoluteUri = SourceGeneratedDocumentUri.Create(document.SourceGeneratedDocumentIdentity.Value); } else { diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs index 37959e4c33d30..8ceae9cd6694d 100644 --- a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs +++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs @@ -317,7 +317,7 @@ public bool TryFetch(LocalUserRegistryOptionPersister persister, OptionKey2 opti {"dotnet_generate_equality_operators", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.GenerateEqualsAndGetHashCodeFromMembersOptions.GenerateOperators")}, {"dotnet_generate_iequatable_implementation", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.GenerateEqualsAndGetHashCodeFromMembersOptions.ImplementIEquatable")}, {"dotnet_generate_overrides_for_all_members", new RoamingProfileStorage("TextEditor.Specific.GenerateOverridesOptions.SelectAll")}, - {"dotnet_insertion_behavior", new RoamingProfileStorage("TextEditor.%LANGUAGE%.ImplementTypeOptions.InsertionBehavior")}, + {"dotnet_member_insertion_location", new RoamingProfileStorage("TextEditor.%LANGUAGE%.ImplementTypeOptions.InsertionBehavior")}, {"dotnet_property_generation_behavior", new RoamingProfileStorage("TextEditor.%LANGUAGE%.ImplementTypeOptions.PropertyGenerationBehavior")}, #pragma warning disable CS0612 // Type or member is obsolete {"indent_size", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Indent Size", vbKey: "TextEditor.Basic.Indent Size")}, @@ -373,6 +373,7 @@ public bool TryFetch(LocalUserRegistryOptionPersister persister, OptionKey2 opti {"dotnet_unsupported_report_invalid_json_patterns", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.ReportInvalidJsonPatterns")}, {"visual_studio_enable_key_binding_reset", new FeatureFlagStorage("Roslyn.KeybindingResetEnabled")}, {"visual_studio_enable_semantic_search", new FeatureFlagStorage("Roslyn.SemanticSearchEnabled")}, + {"visual_studio_enable_copilot_rename_context", new FeatureFlagStorage("Roslyn.CopilotRenameGetContext")}, {"visual_studio_key_binding_needs_reset", new LocalUserProfileStorage(@"Roslyn\Internal\KeybindingsStatus", "NeedsReset")}, {"visual_studio_key_binding_reset_never_show_again", new LocalUserProfileStorage(@"Roslyn\Internal\KeybindingsStatus", "NeverShowAgain")}, {"visual_studio_resharper_key_binding_status", new LocalUserProfileStorage(@"Roslyn\Internal\KeybindingsStatus", "ReSharperStatus")}, @@ -405,7 +406,7 @@ public bool TryFetch(LocalUserRegistryOptionPersister persister, OptionKey2 opti {"visual_studio_disable_document_outline_feature_flag", new FeatureFlagStorage(@"DocumentOutline.DisableFeature")}, {"visual_studio_document_outline_sort_order", new RoamingProfileStorage(@"DocumentOutline.SortOrder")}, {"visual_studio_enable_symbol_search", new LocalUserProfileStorage(@"Roslyn\Features\SymbolSearch", "Enabled")}, - {"dotnet_search_nuget_packages", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.SuggestForTypesInNuGetPackages")}, + {"dotnet_unsupported_search_nuget_packages", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.SuggestForTypesInNuGetPackages")}, {"dotnet_search_reference_assemblies", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Specific.SuggestForTypesInReferenceAssemblies")}, #pragma warning disable CS0612 // Type or member is obsolete {"tab_width", new RoamingProfileStorage("TextEditor.%LANGUAGE%.Tab Size", "TextEditor.Basic.Tab Size")}, diff --git a/src/VisualStudio/Core/Def/PackageRegistration.pkgdef b/src/VisualStudio/Core/Def/PackageRegistration.pkgdef index 25767a4f03745..aaf0e6d907cd4 100644 --- a/src/VisualStudio/Core/Def/PackageRegistration.pkgdef +++ b/src/VisualStudio/Core/Def/PackageRegistration.pkgdef @@ -45,6 +45,12 @@ "Title"="Enable C# Semantic Search" "PreviewPaneChannels"="IntPreview,int.main" +[$RootKey$\FeatureFlags\Roslyn\CopilotRenameGetContext] +"Description"="Add semantic context to Copilot Rename Suggestions in C#." +"Value"=dword:00000000 +"Title"="Semantic Context in C# Copilot Rename (requires restart)" +"PreviewPaneChannels"="IntPreview,int.main" + // Corresponds to WellKnownExperimentNames.LspPullDiagnosticsFeatureFlag [$RootKey$\FeatureFlags\Lsp\PullDiagnostics] "Description"="Enables the LSP-powered diagnostics for managed .Net projects" diff --git a/src/VisualStudio/Core/Def/PdbSourceDocument/AbstractSourceLinkService.cs b/src/VisualStudio/Core/Def/PdbSourceDocument/AbstractSourceLinkService.cs new file mode 100644 index 0000000000000..217736f81b2ce --- /dev/null +++ b/src/VisualStudio/Core/Def/PdbSourceDocument/AbstractSourceLinkService.cs @@ -0,0 +1,104 @@ +// 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.IO; +using System.Reflection.PortableExecutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.PdbSourceDocument; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.VisualStudio.Debugger.Contracts.SourceLink; +using Microsoft.VisualStudio.Debugger.Contracts.SymbolLocator; + +namespace Microsoft.VisualStudio.LanguageServices.PdbSourceDocument; + +internal abstract class AbstractSourceLinkService : ISourceLinkService +{ + public async Task GetPdbFilePathAsync(string dllPath, PEReader peReader, bool useDefaultSymbolServers, CancellationToken cancellationToken) + { + var hasCodeViewEntry = false; + uint timeStamp = 0; + CodeViewDebugDirectoryData codeViewEntry = default; + using var _ = ArrayBuilder.GetInstance(out var checksums); + foreach (var entry in peReader.ReadDebugDirectory()) + { + if (entry.Type == DebugDirectoryEntryType.PdbChecksum) + { + var checksum = peReader.ReadPdbChecksumDebugDirectoryData(entry); + checksums.Add(new PdbChecksum(checksum.AlgorithmName, checksum.Checksum)); + } + else if (entry.Type == DebugDirectoryEntryType.CodeView && entry.IsPortableCodeView) + { + hasCodeViewEntry = true; + timeStamp = entry.Stamp; + codeViewEntry = peReader.ReadCodeViewDebugDirectoryData(entry); + } + } + + if (!hasCodeViewEntry) + return null; + + var pdbInfo = new SymbolLocatorPdbInfo( + Path.GetFileName(codeViewEntry.Path), + codeViewEntry.Guid, + (uint)codeViewEntry.Age, + timeStamp, + checksums.ToImmutable(), + dllPath, + codeViewEntry.Path); + + var flags = useDefaultSymbolServers + ? SymbolLocatorSearchFlags.ForceNuGetSymbolServer | SymbolLocatorSearchFlags.ForceMsftSymbolServer + : SymbolLocatorSearchFlags.None; + var result = await LocateSymbolFileAsync(pdbInfo, flags, cancellationToken).ConfigureAwait(false); + if (result is null) + { + Logger?.Log($"{nameof(LocateSymbolFileAsync)} returned null"); + return null; + } + + if (result.Value.Found && result.Value.SymbolFilePath is not null) + { + return new PdbFilePathResult(result.Value.SymbolFilePath); + } + else if (Logger is not null) + { + // We log specific info from the debugger if there is a failure, but the caller will log general failure + // information otherwise + Logger.Log(result.Value.Status); + Logger.Log(result.Value.Log); + } + + return null; + } + + public async Task GetSourceFilePathAsync(string url, string relativePath, CancellationToken cancellationToken) + { + var result = await GetSourceLinkAsync(url, relativePath, cancellationToken).ConfigureAwait(false); + if (result is null) + { + Logger?.Log($"{nameof(GetSourceLinkAsync)} returned null"); + return null; + } + + if (result.Value.Status == SourceLinkResultStatus.Succeeded && result.Value.Path is not null) + { + return new SourceFilePathResult(result.Value.Path); + } + else if (Logger is not null && result.Value.Log is not null) + { + // We log specific info from the debugger if there is a failure, but the caller will log general failure + // information otherwise. + Logger.Log(result.Value.Log); + } + + return null; + } + + protected abstract Task LocateSymbolFileAsync(SymbolLocatorPdbInfo pdbInfo, SymbolLocatorSearchFlags flags, CancellationToken cancellationToken); + + protected abstract Task GetSourceLinkAsync(string url, string relativePath, CancellationToken cancellationToken); + + protected abstract IPdbSourceDocumentLogger? Logger { get; } +} diff --git a/src/VisualStudio/Core/Def/PdbSourceDocument/SourceLinkService.cs b/src/VisualStudio/Core/Def/PdbSourceDocument/SourceLinkService.cs index f72a9a1c1574a..88133e11292c1 100644 --- a/src/VisualStudio/Core/Def/PdbSourceDocument/SourceLinkService.cs +++ b/src/VisualStudio/Core/Def/PdbSourceDocument/SourceLinkService.cs @@ -4,20 +4,17 @@ using System; using System.Composition; -using System.IO; -using System.Reflection.PortableExecutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PdbSourceDocument; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.Debugger.Contracts.SourceLink; using Microsoft.VisualStudio.Debugger.Contracts.SymbolLocator; namespace Microsoft.VisualStudio.LanguageServices.PdbSourceDocument; [Export(typeof(ISourceLinkService)), Shared] -internal class SourceLinkService : ISourceLinkService +internal class SourceLinkService : AbstractSourceLinkService { private readonly IDebuggerSymbolLocatorService _debuggerSymbolLocatorService; private readonly IDebuggerSourceLinkService _debuggerSourceLinkService; @@ -35,74 +32,15 @@ public SourceLinkService( _logger = logger; } - public async Task GetPdbFilePathAsync(string dllPath, PEReader peReader, bool useDefaultSymbolServers, CancellationToken cancellationToken) + protected override async Task LocateSymbolFileAsync(SymbolLocatorPdbInfo pdbInfo, SymbolLocatorSearchFlags flags, CancellationToken cancellationToken) { - var hasCodeViewEntry = false; - uint timeStamp = 0; - CodeViewDebugDirectoryData codeViewEntry = default; - using var _ = ArrayBuilder.GetInstance(out var checksums); - foreach (var entry in peReader.ReadDebugDirectory()) - { - if (entry.Type == DebugDirectoryEntryType.PdbChecksum) - { - var checksum = peReader.ReadPdbChecksumDebugDirectoryData(entry); - checksums.Add(new PdbChecksum(checksum.AlgorithmName, checksum.Checksum)); - } - else if (entry.Type == DebugDirectoryEntryType.CodeView && entry.IsPortableCodeView) - { - hasCodeViewEntry = true; - timeStamp = entry.Stamp; - codeViewEntry = peReader.ReadCodeViewDebugDirectoryData(entry); - } - } - - if (!hasCodeViewEntry) - return null; - - var pdbInfo = new SymbolLocatorPdbInfo( - Path.GetFileName(codeViewEntry.Path), - codeViewEntry.Guid, - (uint)codeViewEntry.Age, - timeStamp, - checksums.ToImmutable(), - dllPath, - codeViewEntry.Path); - - var flags = useDefaultSymbolServers - ? SymbolLocatorSearchFlags.ForceNuGetSymbolServer | SymbolLocatorSearchFlags.ForceMsftSymbolServer - : SymbolLocatorSearchFlags.None; - var result = await _debuggerSymbolLocatorService.LocateSymbolFileAsync(pdbInfo, flags, progress: null, cancellationToken).ConfigureAwait(false); - - if (result.Found && result.SymbolFilePath is not null) - { - return new PdbFilePathResult(result.SymbolFilePath); - } - else if (_logger is not null) - { - // We log specific info from the debugger if there is a failure, but the caller will log general failure - // information otherwise - _logger.Log(result.Status); - _logger.Log(result.Log); - } - - return null; + return await _debuggerSymbolLocatorService.LocateSymbolFileAsync(pdbInfo, flags, progress: null, cancellationToken).ConfigureAwait(false); } - public async Task GetSourceFilePathAsync(string url, string relativePath, CancellationToken cancellationToken) + protected override async Task GetSourceLinkAsync(string url, string relativePath, CancellationToken cancellationToken) { - var result = await _debuggerSourceLinkService.GetSourceLinkAsync(url, relativePath, allowInteractiveLogin: false, cancellationToken).ConfigureAwait(false); - - if (result.Status == SourceLinkResultStatus.Succeeded && result.Path is not null) - { - return new SourceFilePathResult(result.Path); - } - else if (_logger is not null && result.Log is not null) - { - // We log specific info from the debugger if there is a failure, but the caller will log general failure - // information otherwise. - _logger.Log(result.Log); - } - - return null; + return await _debuggerSourceLinkService.GetSourceLinkAsync(url, relativePath, allowInteractiveLogin: false, cancellationToken).ConfigureAwait(false); } + + protected override IPdbSourceDocumentLogger? Logger => _logger; } diff --git a/src/VisualStudio/Core/Def/Preview/ReferenceChange.cs b/src/VisualStudio/Core/Def/Preview/ReferenceChange.cs index 17e4008908bd3..dd2f116574ff6 100644 --- a/src/VisualStudio/Core/Def/Preview/ReferenceChange.cs +++ b/src/VisualStudio/Core/Def/Preview/ReferenceChange.cs @@ -15,16 +15,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Preview; internal abstract partial class ReferenceChange : AbstractChange { - private readonly ProjectId _projectId; - private readonly string _projectName; - private readonly bool _isAddedReference; - protected ReferenceChange(ProjectId projectId, string projectName, bool isAddedReference, PreviewEngine engine) : base(engine) { - _projectId = projectId; - _projectName = projectName; - _isAddedReference = isAddedReference; + ProjectId = projectId; + ProjectName = projectName; + IsAddedReference = isAddedReference; } public static void AppendReferenceChanges(IEnumerable projectChangesList, PreviewEngine engine, ArrayBuilder builder) @@ -71,9 +67,9 @@ public static void AppendReferenceChanges(IEnumerable projectCha } } - protected ProjectId ProjectId { get { return _projectId; } } - internal bool IsAddedReference { get { return _isAddedReference; } } - protected string ProjectName { get { return _projectName; } } + protected ProjectId ProjectId { get; } + internal bool IsAddedReference { get; } + protected string ProjectName { get; } protected abstract string GetDisplayText(); internal abstract Solution AddToSolution(Solution solution); diff --git a/src/VisualStudio/Core/Def/Progression/GraphBuilder.cs b/src/VisualStudio/Core/Def/Progression/GraphBuilder.cs index 8844c23386857..47c0201ce4ad2 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphBuilder.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphBuilder.cs @@ -25,7 +25,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Progression; internal sealed partial class GraphBuilder { - private readonly Graph _graph = new(); // Our usage of SemaphoreSlim is fine. We don't perform blocking waits for it on the UI thread. #pragma warning disable RS0030 // Do not use banned APIs private readonly SemaphoreSlim _gate = new(initialCount: 1); @@ -218,7 +217,7 @@ public async Task AddNodeAsync( using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { - var node = await GetOrCreateNodeAsync(_graph, symbol, _solution, cancellationToken).ConfigureAwait(false); + var node = await GetOrCreateNodeAsync(Graph, symbol, _solution, cancellationToken).ConfigureAwait(false); node[RoslynGraphProperties.SymbolId] = (SymbolKey?)symbol.GetSymbolKey(cancellationToken); node[RoslynGraphProperties.ContextProjectId] = GetContextProjectId(contextProject, symbol); @@ -682,7 +681,7 @@ public void AddLink(GraphNode from, GraphCategory category, GraphNode to, Cancel { using (_gate.DisposableWait(cancellationToken)) { - _graph.Links.GetOrCreate(from, to).AddCategory(category); + Graph.Links.GetOrCreate(from, to).AddCategory(category); } } @@ -701,7 +700,7 @@ public void AddLink(GraphNode from, GraphCategory category, GraphNode to, Cancel { var id = GraphNodeIdCreation.GetIdForDocument(document); - var node = _graph.Nodes.GetOrCreate(id, fileName, CodeNodeCategories.ProjectItem); + var node = Graph.Nodes.GetOrCreate(id, fileName, CodeNodeCategories.ProjectItem); _nodeToContextDocumentMap[node] = document; _nodeToContextProjectMap[node] = document.Project; @@ -755,7 +754,7 @@ NavigateToItemKind.EnumItem or // If we already have a node that matches this (say there are multiple identical sibling symbols in an error // situation). We just ignore the second match. - var existing = _graph.Nodes.Get(id); + var existing = Graph.Nodes.Get(id); if (existing != null) return null; @@ -765,7 +764,7 @@ NavigateToItemKind.EnumItem or if (sourceLocation == null) return null; - var symbolNode = _graph.Nodes.GetOrCreate(id); + var symbolNode = Graph.Nodes.GetOrCreate(id); symbolNode.Label = label; symbolNode.AddCategory(category); @@ -844,13 +843,7 @@ public void AddDeferredPropertySet(GraphNode node, GraphProperty property, objec } } - public Graph Graph - { - get - { - return _graph; - } - } + public Graph Graph { get; } = new(); public ImmutableArray GetCreatedNodes(CancellationToken cancellationToken) { diff --git a/src/VisualStudio/Core/Def/Progression/GraphProvider.cs b/src/VisualStudio/Core/Def/Progression/GraphProvider.cs index 3a9ce9b855f0b..8fcf3e7e52387 100644 --- a/src/VisualStudio/Core/Def/Progression/GraphProvider.cs +++ b/src/VisualStudio/Core/Def/Progression/GraphProvider.cs @@ -185,7 +185,7 @@ public IEnumerable GetCommands(IEnumerable nodes) yield return new GraphCommand( GraphCommandDefinition.Contains, targetCategories: null, - linkCategories: new[] { GraphCommonSchema.Contains }, + linkCategories: [GraphCommonSchema.Contains], trackChanges: true); } @@ -202,13 +202,13 @@ public IEnumerable GetCommands(IEnumerable nodes) yield return new GraphCommand( GraphCommandDefinition.BaseTypes, targetCategories: null, - linkCategories: new[] { CodeLinkCategories.InheritsFrom }, + linkCategories: [CodeLinkCategories.InheritsFrom], trackChanges: true); yield return new GraphCommand( GraphCommandDefinition.DerivedTypes, targetCategories: null, - linkCategories: new[] { CodeLinkCategories.InheritsFrom }, + linkCategories: [CodeLinkCategories.InheritsFrom], trackChanges: true); } @@ -218,7 +218,7 @@ public IEnumerable GetCommands(IEnumerable nodes) yield return new GraphCommand( GraphCommandDefinition.Calls, targetCategories: null, - linkCategories: new[] { CodeLinkCategories.Calls }, + linkCategories: [CodeLinkCategories.Calls], trackChanges: true); } @@ -229,15 +229,15 @@ public IEnumerable GetCommands(IEnumerable nodes) yield return new GraphCommand( GraphCommandDefinition.IsCalledBy, targetCategories: null, - linkCategories: new[] { CodeLinkCategories.Calls }, + linkCategories: [CodeLinkCategories.Calls], trackChanges: true); } // Show 'Is Used By' yield return new GraphCommand( GraphCommandDefinition.IsUsedBy, - targetCategories: new[] { CodeNodeCategories.SourceLocation }, - linkCategories: new[] { CodeLinkCategories.SourceReferences }, + targetCategories: [CodeNodeCategories.SourceLocation], + linkCategories: [CodeLinkCategories.SourceReferences], trackChanges: true); // Show 'Implements' on a class or struct, or an applicable member in a class or struct. @@ -247,7 +247,7 @@ public IEnumerable GetCommands(IEnumerable nodes) yield return new GraphCommand( s_implementsCommandDefinition, targetCategories: null, - linkCategories: new[] { CodeLinkCategories.Implements }, + linkCategories: [CodeLinkCategories.Implements], trackChanges: true); } @@ -263,7 +263,7 @@ public IEnumerable GetCommands(IEnumerable nodes) yield return new GraphCommand( s_implementsCommandDefinition, targetCategories: null, - linkCategories: new[] { CodeLinkCategories.Implements }, + linkCategories: [CodeLinkCategories.Implements], trackChanges: true); } } @@ -275,7 +275,7 @@ public IEnumerable GetCommands(IEnumerable nodes) yield return new GraphCommand( s_implementedByCommandDefinition, targetCategories: null, - linkCategories: new[] { CodeLinkCategories.Implements }, + linkCategories: [CodeLinkCategories.Implements], trackChanges: true); } @@ -286,7 +286,7 @@ public IEnumerable GetCommands(IEnumerable nodes) yield return new GraphCommand( s_implementedByCommandDefinition, targetCategories: null, - linkCategories: new[] { CodeLinkCategories.Implements }, + linkCategories: [CodeLinkCategories.Implements], trackChanges: true); } @@ -298,7 +298,7 @@ public IEnumerable GetCommands(IEnumerable nodes) yield return new GraphCommand( s_overridesCommandDefinition, targetCategories: null, - linkCategories: new[] { RoslynGraphCategories.Overrides }, + linkCategories: [RoslynGraphCategories.Overrides], trackChanges: true); } @@ -310,7 +310,7 @@ public IEnumerable GetCommands(IEnumerable nodes) yield return new GraphCommand( s_overriddenByCommandDefinition, targetCategories: null, - linkCategories: new[] { RoslynGraphCategories.Overrides }, + linkCategories: [RoslynGraphCategories.Overrides], trackChanges: true); } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/FileChangeTracker.cs b/src/VisualStudio/Core/Def/ProjectSystem/FileChangeTracker.cs index 7963103802bbb..34db1dfbb8256 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/FileChangeTracker.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/FileChangeTracker.cs @@ -23,7 +23,6 @@ internal sealed class FileChangeTracker : IVsFreeThreadedFileChangeEvents2, IDis private static readonly AsyncLazy s_none = AsyncLazy.Create(value: (uint?)null); private readonly IVsFileChangeEx _fileChangeService; - private readonly string _filePath; private readonly _VSFILECHANGEFLAGS _fileChangeFlags; private bool _disposed; @@ -56,7 +55,7 @@ internal sealed class FileChangeTracker : IVsFreeThreadedFileChangeEvents2, IDis public FileChangeTracker(IVsFileChangeEx fileChangeService, string filePath, _VSFILECHANGEFLAGS fileChangeFlags = DefaultFileChangeFlags) { _fileChangeService = fileChangeService; - _filePath = filePath; + FilePath = filePath; _fileChangeFlags = fileChangeFlags; _fileChangeCookie = s_none; } @@ -69,10 +68,7 @@ public FileChangeTracker(IVsFileChangeEx fileChangeService, string filePath, _VS } } - public string FilePath - { - get { return _filePath; } - } + public string FilePath { get; } /// /// Returns true if a previous call to has completed. @@ -113,7 +109,7 @@ static async (self, cancellationToken) => try { // TODO: Should we pass in cancellationToken here instead of CancellationToken.None? - uint? result = await ((IVsAsyncFileChangeEx2)self._fileChangeService).AdviseFileChangeAsync(self._filePath, self._fileChangeFlags, self, CancellationToken.None).ConfigureAwait(false); + uint? result = await ((IVsAsyncFileChangeEx2)self._fileChangeService).AdviseFileChangeAsync(self.FilePath, self._fileChangeFlags, self, CancellationToken.None).ConfigureAwait(false); return result; } catch (Exception e) when (ReportException(e)) @@ -126,7 +122,7 @@ static async (self, cancellationToken) => try { Marshal.ThrowExceptionForHR( - self._fileChangeService.AdviseFileChange(self._filePath, (uint)self._fileChangeFlags, self, out var newCookie)); + self._fileChangeService.AdviseFileChange(self.FilePath, (uint)self._fileChangeFlags, self, out var newCookie)); return newCookie; } catch (Exception e) when (ReportException(e)) diff --git a/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs b/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs index c040761079007..41701d2faf735 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/FileChangeWatcher.cs @@ -83,10 +83,8 @@ static int FindCombinableRange(ImmutableSegmentedList operatio } } - public IFileChangeContext CreateContext(params WatchedDirectory[] watchedDirectories) - { - return new Context(this, watchedDirectories.ToImmutableArray()); - } + public IFileChangeContext CreateContext(ImmutableArray watchedDirectories) + => new Context(this, watchedDirectories); /// /// Represents an operation to subscribe or unsubscribe from events. The @@ -313,7 +311,7 @@ public async ValueTask ApplyAsync(IVsAsyncFileChangeEx2 service, CancellationTok _cookies.Add(cookie); if (_filter != null) - await service.FilterDirectoryChangesAsync(cookie, new[] { _filter }, cancellationToken).ConfigureAwait(false); + await service.FilterDirectoryChangesAsync(cookie, [_filter], cancellationToken).ConfigureAwait(false); return; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/IOpenTextBufferEventListener.cs b/src/VisualStudio/Core/Def/ProjectSystem/IOpenTextBufferEventListener.cs index 0cf8a090ef7d7..5fa32e500dd0d 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/IOpenTextBufferEventListener.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/IOpenTextBufferEventListener.cs @@ -29,6 +29,12 @@ internal interface IOpenTextBufferEventListener /// the moniker of the closed document. void OnCloseDocument(string moniker); + /// + /// Triggered when a document is saved. + /// + /// the moniker of the saved document. + void OnSaveDocument(string moniker); + /// /// Triggered when a document context is refreshed with a new hierarchy. /// diff --git a/src/VisualStudio/Core/Def/ProjectSystem/InvisibleEditor.cs b/src/VisualStudio/Core/Def/ProjectSystem/InvisibleEditor.cs index f2c0d304e6bd0..4a7e5a4639726 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/InvisibleEditor.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/InvisibleEditor.cs @@ -28,7 +28,6 @@ internal sealed partial class InvisibleEditor : IInvisibleEditor /// The text buffer. null if the object has been disposed. /// private ITextBuffer? _buffer; - private IVsTextLines _vsTextLines; private IVsInvisibleEditor _invisibleEditor; private OLE.Interop.IOleUndoManager? _manager; private readonly bool _needsUndoRestored; @@ -57,13 +56,13 @@ public InvisibleEditor(IServiceProvider serviceProvider, string filePath, IVsHie { _invisibleEditor = (IVsInvisibleEditor)Marshal.GetUniqueObjectForIUnknown(invisibleEditorPtr); - _vsTextLines = RetrieveDocData(_invisibleEditor, needsSave); + VsTextLines = RetrieveDocData(_invisibleEditor, needsSave); var editorAdapterFactoryService = serviceProvider.GetMefService(); - _buffer = editorAdapterFactoryService.GetDocumentBuffer(_vsTextLines); + _buffer = editorAdapterFactoryService.GetDocumentBuffer(VsTextLines); if (needsUndoDisabled) { - Marshal.ThrowExceptionForHR(_vsTextLines.GetUndoManager(out _manager)); + Marshal.ThrowExceptionForHR(VsTextLines.GetUndoManager(out _manager)); Marshal.ThrowExceptionForHR(((IVsUndoState)_manager).IsEnabled(out var isEnabled)); _needsUndoRestored = isEnabled != 0; if (_needsUndoRestored) @@ -120,13 +119,7 @@ static IVsTextLines RetrieveDocData(IVsInvisibleEditor invisibleEditor, bool nee } } - public IVsTextLines VsTextLines - { - get - { - return _vsTextLines; - } - } + public IVsTextLines VsTextLines { get; private set; } public ITextBuffer TextBuffer { @@ -149,7 +142,7 @@ public void Dispose() _threadingContext.ThrowIfNotOnUIThread(); _buffer = null; - _vsTextLines = null!; + VsTextLines = null!; try { diff --git a/src/VisualStudio/Core/Def/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs b/src/VisualStudio/Core/Def/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs index 1673d25719ea4..7e9cd704155f0 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs @@ -233,13 +233,13 @@ static void GetStorageInfoFromTemporaryStorage( // location, so we can create a metadata value wrapping that. This will also let us share the memory // for that metadata value with our OOP process. copyStream.Position = 0; - storageHandle = temporaryStorageService.WriteToTemporaryStorage(copyStream, CancellationToken.None); + storageHandle = temporaryStorageService.WriteToTemporaryStorage(copyStream); } // Now, read the data from the memory-mapped-file back into a stream that we load into the metadata value. // The ITemporaryStorageStreamHandle should have given us an UnmanagedMemoryStream // since this only runs on Windows for VS. - stream = (UnmanagedMemoryStream)storageHandle.ReadFromTemporaryStorage(CancellationToken.None); + stream = (UnmanagedMemoryStream)storageHandle.ReadFromTemporaryStorage(); // stream size must be same as what metadata reader said the size should be. Contract.ThrowIfFalse(stream.Length == size); diff --git a/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs b/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs index ace82412c8ab2..272c0e8c93bd1 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs @@ -81,17 +81,9 @@ public async Task InitializeAsync() } void IOpenTextBufferEventListener.OnOpenDocument(string moniker, ITextBuffer textBuffer, IVsHierarchy _) => TrackOpenedDocument(moniker, textBuffer); - void IOpenTextBufferEventListener.OnDocumentOpenedIntoWindowFrame(string moniker, IVsWindowFrame windowFrame) { } void IOpenTextBufferEventListener.OnCloseDocument(string moniker) => TryUntrackClosingDocument(moniker); - /// - /// File hierarchy events are not relevant to the misc workspace. - /// - void IOpenTextBufferEventListener.OnRefreshDocumentContext(string moniker, IVsHierarchy hierarchy) - { - } - void IOpenTextBufferEventListener.OnRenameDocument(string newMoniker, string oldMoniker, ITextBuffer buffer) { // We want to consider this file to be added in one of two situations: @@ -106,6 +98,21 @@ void IOpenTextBufferEventListener.OnRenameDocument(string newMoniker, string old } } + /// + /// Not relevant to the misc workspace. + /// + void IOpenTextBufferEventListener.OnRefreshDocumentContext(string moniker, IVsHierarchy hierarchy) { } + + /// + /// Not relevant to the misc workspace. + /// + void IOpenTextBufferEventListener.OnDocumentOpenedIntoWindowFrame(string moniker, IVsWindowFrame windowFrame) { } + + /// + /// Not relevant to the misc workspace. + /// + void IOpenTextBufferEventListener.OnSaveDocument(string moniker) { } + public void RegisterLanguage(Guid languageGuid, string languageName, string scriptExtension) => _languageInformationByLanguageGuid.Add(languageGuid, new LanguageInformation(languageName, scriptExtension)); @@ -259,7 +266,7 @@ private void AttachToDocument(string moniker, ITextBuffer textBuffer) { _threadingContext.ThrowIfNotOnUIThread(); - if (_fileTrackingMetadataAsSourceService.TryAddDocumentToWorkspace(moniker, textBuffer.AsTextContainer())) + if (_fileTrackingMetadataAsSourceService.TryAddDocumentToWorkspace(moniker, textBuffer.AsTextContainer(), out var _)) { // We already added it, so we will keep it excluded from the misc files workspace return; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/OpenTextBufferProvider.cs b/src/VisualStudio/Core/Def/ProjectSystem/OpenTextBufferProvider.cs index 0caeae16a529a..d874868638ae2 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/OpenTextBufferProvider.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/OpenTextBufferProvider.cs @@ -131,7 +131,15 @@ public int OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint d } public int OnAfterSave(uint docCookie) - => VSConstants.E_NOTIMPL; + { + if (_runningDocumentTable.IsDocumentInitialized(docCookie)) + { + var moniker = _runningDocumentTable.GetDocumentMoniker(docCookie); + RaiseEventForEachListener(l => l.OnSaveDocument(moniker)); + } + + return VSConstants.S_OK; + } public int OnAfterAttributeChange(uint docCookie, uint grfAttribs) => VSConstants.E_NOTIMPL; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/RuleSets/VisualStudioRuleSetManager.RuleSetFile.cs b/src/VisualStudio/Core/Def/ProjectSystem/RuleSets/VisualStudioRuleSetManager.RuleSetFile.cs index 96a60e78cb89d..2db868ee9e115 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/RuleSets/VisualStudioRuleSetManager.RuleSetFile.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/RuleSets/VisualStudioRuleSetManager.RuleSetFile.cs @@ -66,7 +66,7 @@ public void InitializeFileTracking(IFileChangeWatcher fileChangeWatcher) includes = [FilePath]; } - _fileChangeContext = fileChangeWatcher.CreateContext(); + _fileChangeContext = fileChangeWatcher.CreateContext([]); _fileChangeContext.FileChanged += IncludeUpdated; foreach (var include in includes) diff --git a/src/VisualStudio/Core/Def/ProjectSystem/ViewEventArgs.cs b/src/VisualStudio/Core/Def/ProjectSystem/ViewEventArgs.cs index 5a4ee4070ecca..f78229e628bd7 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/ViewEventArgs.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/ViewEventArgs.cs @@ -11,10 +11,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; internal class ViewEventArgs : EventArgs { - private readonly IVsTextView _textView; - public ViewEventArgs(IVsTextView textView) - => _textView = textView; + => TextView = textView; - public IVsTextView TextView { get { return _textView; } } + public IVsTextView TextView { get; } } diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs index 77f1ef30a6e9f..620d493be4cef 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioProjectFactory.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.ExternalAccess.VSTypeScript.Api; using Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics; -using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Telemetry; @@ -94,7 +93,7 @@ public async Task CreateAndAddToWorkspaceAsync( _visualStudioWorkspaceImpl.ProjectSystemProjectFactory.SolutionPath = solutionFilePath; _visualStudioWorkspaceImpl.ProjectSystemProjectFactory.SolutionTelemetryId = GetSolutionSessionId(); - var hostInfo = new ProjectSystemHostInfo(_dynamicFileInfoProviders, HostDiagnosticUpdateSource.Instance, vsixAnalyzerProvider); + var hostInfo = new ProjectSystemHostInfo(_dynamicFileInfoProviders, vsixAnalyzerProvider); var project = await _visualStudioWorkspaceImpl.ProjectSystemProjectFactory.CreateAndAddToWorkspaceAsync(projectSystemName, language, creationInfo, hostInfo); _visualStudioWorkspaceImpl.AddProjectToInternalMaps(project, creationInfo.Hierarchy, creationInfo.ProjectGuid, projectSystemName); diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs index 85c967ad738bd..364b9c2c4203a 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs @@ -31,7 +31,7 @@ internal partial class VisualStudioWorkspaceImpl /// /// Singleton the updates the workspace in response to files being opened or closed. /// - public sealed class OpenFileTracker : IOpenTextBufferEventListener + public sealed partial class OpenFileTracker : IOpenTextBufferEventListener { private readonly VisualStudioWorkspaceImpl _workspace; private readonly ProjectSystemProjectFactory _projectSystemProjectFactory; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs index 92444d1e48237..7ed72d7b19417 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl.cs @@ -78,7 +78,7 @@ internal abstract partial class VisualStudioWorkspaceImpl : VisualStudioWorkspac /// // Our usage of SemaphoreSlim is fine. We don't perform blocking waits for it on the UI thread. #pragma warning disable RS0030 // Do not use banned APIs - private readonly SemaphoreSlim _gate = new SemaphoreSlim(initialCount: 1); + private readonly SemaphoreSlim _gate = new(initialCount: 1); #pragma warning restore RS0030 // Do not use banned APIs private ImmutableDictionary _projectToHierarchyMap = ImmutableDictionary.Empty; @@ -127,7 +127,8 @@ public VisualStudioWorkspaceImpl(ExportProvider exportProvider, IAsyncServicePro FileChangeWatcher = exportProvider.GetExportedValue().Watcher; - ProjectSystemProjectFactory = new ProjectSystemProjectFactory(this, FileChangeWatcher, CheckForAddedFileBeingOpenMaybeAsync, RemoveProjectFromMaps); + ProjectSystemProjectFactory = new ProjectSystemProjectFactory( + this, FileChangeWatcher, CheckForAddedFileBeingOpenMaybeAsync, RemoveProjectFromMaps, _threadingContext.DisposalToken); InitializeUIAffinitizedServicesAsync(asyncServiceProvider).Forget(); @@ -679,7 +680,7 @@ internal override void ApplyMappedFileChanges(SolutionChanges solutionChanges) bool ShouldApplyChangesToMappedDocuments(CodeAnalysis.Document document, [NotNullWhen(true)] out ISpanMappingService? spanMappingService) { - spanMappingService = document.Services.GetService(); + spanMappingService = document.DocumentServiceProvider.GetService(); // Only consider files that are mapped and that we are unable to apply changes to. // TODO - refactor how this is determined - https://github.com/dotnet/roslyn/issues/47908 return spanMappingService != null && document?.CanApplyChange() == false; diff --git a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl_SourceGenerators.cs b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl_SourceGenerators.cs index d11f95df75d4a..a9fb0c7357be0 100644 --- a/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl_SourceGenerators.cs +++ b/src/VisualStudio/Core/Def/ProjectSystem/VisualStudioWorkspaceImpl_SourceGenerators.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.ComponentModel.Composition; using System.Linq; -using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; -using Microsoft.VisualStudio.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; @@ -69,31 +61,16 @@ public void SubscribeToSourceGeneratorImpactingEvents() this.EnqueueUpdateSourceGeneratorVersion(projectId: null, forceRegeneration: false); } - [Export(typeof(ICommandHandler))] - [ContentType(ContentTypeNames.RoslynContentType)] - [ContentType(ContentTypeNames.XamlContentType)] - [Name(PredefinedCommandHandlerNames.SourceGeneratorSave)] - [method: ImportingConstructor] - [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - internal sealed class SaveCommandHandler() : IChainedCommandHandler + public sealed partial class OpenFileTracker { - public string DisplayName => ServicesVSResources.Roslyn_save_command_handler; - - public CommandState GetCommandState(SaveCommandArgs args, Func nextCommandHandler) - => nextCommandHandler(); - - public void ExecuteCommand(SaveCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext) + void IOpenTextBufferEventListener.OnSaveDocument(string moniker) { - nextCommandHandler(); + // Note: this will find docs, additional docs, and analyzer config docs. Thats good. We do want changing + // any of those to cause rerunning generators in any affected project. + var documentIds = _workspace.CurrentSolution.GetDocumentIdsWithFilePath(moniker); - // After a save happens, enqueue a request to run generators on the projects impacted by the save. - foreach (var projectGroup in args.SubjectBuffer.GetRelatedDocuments().GroupBy(d => d.Project)) - { - if (projectGroup.Key.Solution.Workspace is VisualStudioWorkspaceImpl visualStudioWorkspace) - { - visualStudioWorkspace.EnqueueUpdateSourceGeneratorVersion(projectGroup.Key.Id, forceRegeneration: false); - } - } + foreach (var projectId in documentIds.Select(i => i.ProjectId).Distinct()) + _workspace.EnqueueUpdateSourceGeneratorVersion(projectId, forceRegeneration: false); } } } diff --git a/src/VisualStudio/Core/Def/Remote/DefaultRemoteHostClientProvider.cs b/src/VisualStudio/Core/Def/Remote/DefaultRemoteHostClientProvider.cs index bf9ffd53372d9..7635e1501ad77 100644 --- a/src/VisualStudio/Core/Def/Remote/DefaultRemoteHostClientProvider.cs +++ b/src/VisualStudio/Core/Def/Remote/DefaultRemoteHostClientProvider.cs @@ -11,13 +11,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Remote; -internal sealed class DefaultRemoteHostClientProvider : IRemoteHostClientProvider +[method: Obsolete(MefConstruction.FactoryMethodMessage, error: true)] +internal sealed class DefaultRemoteHostClientProvider() : IRemoteHostClientProvider { - [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] - public DefaultRemoteHostClientProvider() - { - } - public Task TryGetRemoteHostClientAsync(CancellationToken cancellationToken) => SpecializedTasks.Null(); + + public Task WaitForClientCreationAsync(CancellationToken cancellationToken) + => Task.CompletedTask; } diff --git a/src/VisualStudio/Core/Def/Remote/VisualStudioRemoteHostClientProvider.cs b/src/VisualStudio/Core/Def/Remote/VisualStudioRemoteHostClientProvider.cs index 4b564f439e6a9..dd71887f4dc6f 100644 --- a/src/VisualStudio/Core/Def/Remote/VisualStudioRemoteHostClientProvider.cs +++ b/src/VisualStudio/Core/Def/Remote/VisualStudioRemoteHostClientProvider.cs @@ -18,6 +18,7 @@ using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Shell.ServiceBroker; +using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; using VSThreading = Microsoft.VisualStudio.Threading; @@ -91,6 +92,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) private readonly IVsService _brokeredServiceContainer; private readonly AsynchronousOperationListenerProvider _listenerProvider; private readonly RemoteServiceCallbackDispatcherRegistry _callbackDispatchers; + private readonly TaskCompletionSource _clientCreationSource = new(TaskCreationOptions.RunContinuationsAsynchronously); private VisualStudioRemoteHostClientProvider( SolutionServices services, @@ -133,9 +135,16 @@ private VisualStudioRemoteHostClientProvider( { return null; } + finally + { + _clientCreationSource.SetResult(true); + } } public Task TryGetRemoteHostClientAsync(CancellationToken cancellationToken) => _lazyClient.GetValueAsync(cancellationToken); + + public Task WaitForClientCreationAsync(CancellationToken cancellationToken) + => _clientCreationSource.Task.WithCancellation(cancellationToken); } } diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index b68b0a9c20696..fb8f5c3696f37 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1,17 +1,17 @@ - @@ -542,11 +542,11 @@ Use the dropdown to view and switch to other projects this file may belong to. example - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' @@ -1916,9 +1916,6 @@ Additional information: {1} Balanced. Run generators after saving or building - - Roslyn save command handler - Generator running... diff --git a/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs b/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs index 05e609484355c..bbf961860df10 100644 --- a/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs +++ b/src/VisualStudio/Core/Def/SyncNamespaces/SyncNamespacesCommandHandler.cs @@ -32,7 +32,6 @@ internal sealed class SyncNamespacesCommandHandler { private readonly VisualStudioWorkspace _workspace; private readonly IUIThreadOperationExecutor _threadOperationExecutor; - private readonly IGlobalOptionService _globalOptions; private readonly IThreadingContext _threadingContext; private IServiceProvider? _serviceProvider; @@ -41,12 +40,10 @@ internal sealed class SyncNamespacesCommandHandler public SyncNamespacesCommandHandler( IUIThreadOperationExecutor threadOperationExecutor, VisualStudioWorkspace workspace, - IGlobalOptionService globalOptions, IThreadingContext threadingContext) { _threadOperationExecutor = threadOperationExecutor; _workspace = workspace; - _globalOptions = globalOptions; _threadingContext = threadingContext; } @@ -134,7 +131,6 @@ private void SyncNamespaces(ImmutableArray projects) } var syncService = projects[0].GetRequiredLanguageService(); - var options = _globalOptions.GetCodeActionOptionsProvider(); Solution? solution = null; var status = _threadOperationExecutor.Execute( @@ -142,7 +138,7 @@ private void SyncNamespaces(ImmutableArray projects) operationContext => { solution = _threadingContext.JoinableTaskFactory.Run( - () => syncService.SyncNamespacesAsync(projects, options, operationContext.GetCodeAnalysisProgress(), operationContext.UserCancellationToken)); + () => syncService.SyncNamespacesAsync(projects, operationContext.GetCodeAnalysisProgress(), operationContext.UserCancellationToken)); }); if (status != UIThreadOperationStatus.Canceled && solution is not null) diff --git a/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs b/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs index b376dc5c68319..700d475b415b7 100644 --- a/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs +++ b/src/VisualStudio/Core/Def/TableDataSource/Suppression/VisualStudioSuppressionFixService.cs @@ -270,8 +270,6 @@ private async Task ApplySuppressionFixAsync( cancellationToken.ThrowIfCancellationRequested(); var language = languageService.Language; - var options = _globalOptions.GetCodeActionOptions(languageService); - var optionsProvider = options.CreateProvider(); var documentDiagnosticsPerLanguage = GetDocumentDiagnosticsMappedToNewSolution(documentDiagnosticsToFixMap, newSolution, language); if (!documentDiagnosticsPerLanguage.IsEmpty) @@ -285,7 +283,6 @@ private async Task ApplySuppressionFixAsync( _workspace, suppressionFixer, suppressionFixAllProvider, - optionsProvider, equivalenceKey, title, waitDialogMessage, @@ -311,7 +308,6 @@ private async Task ApplySuppressionFixAsync( _workspace, suppressionFixer, suppressionFixAllProvider, - optionsProvider, equivalenceKey, title, waitDialogMessage, diff --git a/src/VisualStudio/Core/Def/TaskList/HostDiagnosticUpdateSource.cs b/src/VisualStudio/Core/Def/TaskList/HostDiagnosticUpdateSource.cs deleted file mode 100644 index 3f20d78d8cc85..0000000000000 --- a/src/VisualStudio/Core/Def/TaskList/HostDiagnosticUpdateSource.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 Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Workspaces.ProjectSystem; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; - -internal sealed class HostDiagnosticUpdateSource : IProjectSystemDiagnosticSource -{ - public static readonly HostDiagnosticUpdateSource Instance = new(); - - private HostDiagnosticUpdateSource() - { - } - - 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/VisualStudioWorkspaceTelemetryService.cs b/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs index f42319e75f069..0fb0947443a35 100644 --- a/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs +++ b/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs @@ -5,9 +5,10 @@ using System; using System.Composition; using System.Diagnostics; -using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; @@ -19,20 +20,16 @@ namespace Microsoft.VisualStudio.LanguageServices.Telemetry; [ExportWorkspaceService(typeof(IWorkspaceTelemetryService)), Shared] -internal sealed class VisualStudioWorkspaceTelemetryService : AbstractWorkspaceTelemetryService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class VisualStudioWorkspaceTelemetryService( + IThreadingContext threadingContext, + VisualStudioWorkspace workspace, + IGlobalOptionService globalOptions) : AbstractWorkspaceTelemetryService { - private readonly VisualStudioWorkspace _workspace; - private readonly IGlobalOptionService _globalOptions; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualStudioWorkspaceTelemetryService( - VisualStudioWorkspace workspace, - IGlobalOptionService globalOptions) - { - _workspace = workspace; - _globalOptions = globalOptions; - } + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly VisualStudioWorkspace _workspace = workspace; + private readonly IGlobalOptionService _globalOptions = globalOptions; protected override ILogger CreateLogger(TelemetrySession telemetrySession, bool logDelta) => AggregateLogger.Create( @@ -44,13 +41,16 @@ protected override ILogger CreateLogger(TelemetrySession telemetrySession, bool protected override void TelemetrySessionInitialized() { + var cancellationToken = _threadingContext.DisposalToken; _ = Task.Run(async () => { - var client = await RemoteHostClient.TryGetClientAsync(_workspace, CancellationToken.None).ConfigureAwait(false); + // Wait until the remote host was created by some other party (we don't want to cause it to happen ourselves + // in the call to RemoteHostClient below). + await RemoteHostClient.WaitForClientCreationAsync(_workspace, cancellationToken).ConfigureAwait(false); + + var client = await RemoteHostClient.TryGetClientAsync(_workspace, cancellationToken).ConfigureAwait(false); if (client == null) - { return; - } var settings = SerializeCurrentSessionSettings(); Contract.ThrowIfNull(settings); @@ -61,7 +61,7 @@ protected override void TelemetrySessionInitialized() // initialize session in the remote service _ = await client.TryInvokeAsync( (service, cancellationToken) => service.InitializeTelemetrySessionAsync(Process.GetCurrentProcess().Id, settings, logDelta, cancellationToken), - CancellationToken.None).ConfigureAwait(false); - }); + cancellationToken).ConfigureAwait(false); + }, cancellationToken); } } diff --git a/src/VisualStudio/Core/Def/Venus/ContainedDocument.cs b/src/VisualStudio/Core/Def/Venus/ContainedDocument.cs index 494ec8edaad02..c63a3c3cb10aa 100644 --- a/src/VisualStudio/Core/Def/Venus/ContainedDocument.cs +++ b/src/VisualStudio/Core/Def/Venus/ContainedDocument.cs @@ -807,7 +807,7 @@ private void AdjustIndentationForSpan( var services = document.Project.Solution.Services; var formatter = document.GetRequiredLanguageService(); var changes = formatter.GetFormattingResult( - root, new TextSpan[] { CommonFormattingHelpers.GetFormattingSpan(root, visibleSpan) }, + root, [CommonFormattingHelpers.GetFormattingSpan(root, visibleSpan)], options, [.. venusFormattingRules, .. Formatter.GetDefaultFormattingRules(document)], CancellationToken.None).GetTextChanges(CancellationToken.None); diff --git a/src/VisualStudio/Core/Def/Workspace/SourceGeneratedFileManager.cs b/src/VisualStudio/Core/Def/Workspace/SourceGeneratedFileManager.cs index d31b443350ebd..0af0d25e5fda4 100644 --- a/src/VisualStudio/Core/Def/Workspace/SourceGeneratedFileManager.cs +++ b/src/VisualStudio/Core/Def/Workspace/SourceGeneratedFileManager.cs @@ -224,13 +224,9 @@ void IOpenTextBufferEventListener.OnCloseDocument(string moniker) } } - void IOpenTextBufferEventListener.OnRefreshDocumentContext(string moniker, IVsHierarchy hierarchy) - { - } - - void IOpenTextBufferEventListener.OnRenameDocument(string newMoniker, string oldMoniker, ITextBuffer textBuffer) - { - } + void IOpenTextBufferEventListener.OnRefreshDocumentContext(string moniker, IVsHierarchy hierarchy) { } + void IOpenTextBufferEventListener.OnRenameDocument(string newMoniker, string oldMoniker, ITextBuffer textBuffer) { } + void IOpenTextBufferEventListener.OnSaveDocument(string moniker) { } private sealed class OpenSourceGeneratedFile : IDisposable { diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioDocumentNavigationService.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioDocumentNavigationService.cs index 293a3544daf28..64feec718b4bf 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioDocumentNavigationService.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioDocumentNavigationService.cs @@ -205,7 +205,7 @@ static VsTextSpan GetVsTextSpan(SourceText text, int position, int virtualSpace) } // Before attempting to open the document, check if the location maps to a different file that should be opened instead. - var spanMappingService = document.Services.GetService(); + var spanMappingService = document.DocumentServiceProvider.GetService(); if (spanMappingService != null) { var mappedSpan = await GetMappedSpanAsync( diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index fcfec2ad814d9..d42e11099baae 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + Preferovat System.Threading.Lock {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ Zkontrolovat změny - - Roslyn save command handler - Obslužná rutina příkazu pro uložení v Roslynu - - Run Code Analysis on {0} Spustit analýzu kódu {0} @@ -1369,7 +1364,7 @@ Show hints for collection expressions - Show hints for collection expressions + Zobrazovat tipy pro výrazy kolekce @@ -2416,13 +2411,13 @@ V rozevíracím seznamu si můžete zobrazit jiné projekty, ke kterým by tento example - příklad - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - identifikátor - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index 11ad6d1997276..740cd1c53a7b9 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + „System.Threading.Lock“ bevorzugen {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ Änderungen überprüfen - - Roslyn save command handler - Befehlshandler „Roslyn speichern“ - - Run Code Analysis on {0} Code Analysis ausführen für "{0}" @@ -1369,7 +1364,7 @@ Show hints for collection expressions - Show hints for collection expressions + Hinweise für Sammlungsausdrücke anzeigen @@ -2416,13 +2411,13 @@ Verwenden Sie die Dropdownliste, um weitere zu dieser Datei gehörige Projekte a example - Beispiel - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - Bezeichner - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 40dfa74596ba3..50d24ce4ffcff 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + Preferir "System.Threading.Lock" {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ Revisar cambios - - Roslyn save command handler - Controlador del comando Guardar de Roslyn - - Run Code Analysis on {0} Ejecutar análisis de código en {0} @@ -1369,7 +1364,7 @@ Show hints for collection expressions - Show hints for collection expressions + Mostrar sugerencias para expresiones de colecciones @@ -2416,13 +2411,13 @@ Use la lista desplegable para ver y cambiar a otros proyectos a los que puede pe example - ejemplo - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - identificador - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index bf3ccd8c0da7f..c264525387bc8 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + Préférez 'System.Threading.Lock' {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ Passer en revue les changements - - Roslyn save command handler - Gestionnaire de commandes d’enregistrement Roslyn - - Run Code Analysis on {0} Exécuter une analyse du code sur {0} @@ -2416,13 +2411,13 @@ Utilisez le menu déroulant pour afficher et basculer vers d'autres projets auqu example - exemple - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - identificateur - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index f0dd01d001d35..db4c0af37759e 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + Preferire 'System.Threading.Lock' {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ Esamina modifiche - - Roslyn save command handler - Gestore di comandi di salvataggio Roslyn - - Run Code Analysis on {0} Esegui Code Analysis su {0} @@ -1369,7 +1364,7 @@ Show hints for collection expressions - Show hints for collection expressions + Mostra hint per le espressioni di raccolta @@ -2416,13 +2411,13 @@ Usare l'elenco a discesa per visualizzare e passare ad altri progetti a cui ques example - esempio - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - identificatore - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index 45ccc91a2bf50..9ff8b237894bb 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + 'System.Threading.Lock' を優先する {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ 変更のプレビュー - - Roslyn save command handler - Roslyn 保存コマンド ハンドラー - - Run Code Analysis on {0} {0} で Code Analysis を実行 @@ -1369,7 +1364,7 @@ Show hints for collection expressions - Show hints for collection expressions + コレクション式のヒントを表示する @@ -2416,13 +2411,13 @@ Use the dropdown to view and switch to other projects this file may belong to. example - - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - 識別子 - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index 43efd7be1e16a..6afe6a18ccfab 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + 'System.Threading.Lock' 선호 {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ 변경 내용 검토 - - Roslyn save command handler - Roslyn 저장 명령 처리기 - - Run Code Analysis on {0} {0}에서 코드 분석 실행 @@ -2416,13 +2411,13 @@ Use the dropdown to view and switch to other projects this file may belong to. example - - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - 식별자 - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 147bef38e3fe2..b8a62ae9f7edb 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + Preferuj typ „System.Threading.Lock” {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ Przejrzyj zmiany - - Roslyn save command handler - Program obsługi polecenia zapisywania Roslyn - - Run Code Analysis on {0} Uruchom analizę kodu dla: {0} @@ -1369,7 +1364,7 @@ Show hints for collection expressions - Show hints for collection expressions + Pokaż wskazówki dla wyrażeń kolekcji @@ -2416,13 +2411,13 @@ Użyj listy rozwijanej, aby wyświetlać inne projekty, do których może należ example - przykład - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - identyfikator - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index 3fcb4db2d76ba..1ddd87b9b4b76 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + Preferir 'System.Threading.Lock' {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ Revisar alterações - - Roslyn save command handler - Manipulador de comandos "salvar" do Roslyn - - Run Code Analysis on {0} Executar Análise de Código em {0} @@ -2416,13 +2411,13 @@ Use a lista suspensa para exibir e mudar entre outros projetos aos quais este ar example - exemplo - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - identificador - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index 85109cd759a45..7283f6cc2fb60 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + Предпочитать "System.Threading.Lock" {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ Проверить изменения - - Roslyn save command handler - Обработчик команды сохранения Roslyn - - Run Code Analysis on {0} Запустить Code Analysis для {0} @@ -2416,13 +2411,13 @@ Use the dropdown to view and switch to other projects this file may belong to. example - пример - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - идентификатор - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index 7b3cb41e022dc..03cd3d27c361e 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + 'System.Threading.Lock' türünü tercih edin {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ Değişiklikleri Gözden Geçir - - Roslyn save command handler - Roslyn save komut işleyicisi - - Run Code Analysis on {0} {0} Öğesinde Code Analysis Çalıştır @@ -2416,13 +2411,13 @@ Bu dosyanın ait olabileceği diğer projeleri görüntülemek ve bunlara geçi example - örnek - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - tanımlayıcı - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index cf8fdedee118b..ba40bbf0e4ee1 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + 首选 'System.Threading.Lock' {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ 预览更改 - - Roslyn save command handler - Roslyn 保存命令处理程序 - - Run Code Analysis on {0} 对 {0} 运行 Code Analysis @@ -1369,7 +1364,7 @@ Show hints for collection expressions - Show hints for collection expressions + 显示集合表达式的提示 @@ -2416,13 +2411,13 @@ Use the dropdown to view and switch to other projects this file may belong to. example - 示例 - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - 标识符 - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index e1e5394876d08..9798406dd4911 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -1039,7 +1039,7 @@ Prefer 'System.Threading.Lock' - Prefer 'System.Threading.Lock' + 偏好 'System.Threading.Lock' {Locked="System.Threading.Lock"} "System.Threading.Lock" is the name of a .Net type and should not be localized. @@ -1237,11 +1237,6 @@ 檢閱變更 - - Roslyn save command handler - Roslyn 儲存命令處理常式 - - Run Code Analysis on {0} 對 {0} 執行 Code Analysis @@ -1369,7 +1364,7 @@ Show hints for collection expressions - Show hints for collection expressions + 顯示集合運算式的提示 @@ -2416,13 +2411,13 @@ Use the dropdown to view and switch to other projects this file may belong to. example - 範例 - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + example + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. identifier - 識別碼 - IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. + identifier + {Locked} IdentifierWord_Example and IdentifierWord_Identifier are combined (with prefixes, suffixes, and word separators) into an example identifier name in the NamingStyle UI. Install '{0}' diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject.cs index fda85e0d7a3ce..a2451d1add60b 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject.cs @@ -24,7 +24,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel public abstract partial class AbstractCodeModelObject : ApartmentSensitiveComObject { private CodeModelState _state; - private bool _zombied; internal AbstractCodeModelObject(CodeModelState state) { @@ -33,10 +32,7 @@ internal AbstractCodeModelObject(CodeModelState state) _state = state; } - protected bool IsZombied - { - get { return _zombied; } - } + protected bool IsZombied { get; private set; } internal CodeModelState State { @@ -80,7 +76,7 @@ internal VisualStudioWorkspace Workspace internal virtual void Shutdown() { _state = null; - _zombied = true; + IsZombied = true; } public DTE DTE diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs index 0f8b0e399d1c6..ed69e95a31aac 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs @@ -1046,7 +1046,7 @@ private Document FormatAnnotatedNode(Document document, SyntaxAnnotation annotat return await Formatter.FormatAsync( document, - new TextSpan[] { formattingSpan }, + [formattingSpan], options, formattingRules, cancellationToken).ConfigureAwait(false); diff --git a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractKeyedCodeElement.cs b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractKeyedCodeElement.cs index 5c932c90d7675..f6d3af4312603 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractKeyedCodeElement.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractKeyedCodeElement.cs @@ -18,7 +18,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.Inter /// public abstract class AbstractKeyedCodeElement : AbstractCodeElement { - private SyntaxNodeKey _nodeKey; private readonly string _name; internal AbstractKeyedCodeElement( @@ -28,7 +27,7 @@ internal AbstractKeyedCodeElement( int? nodeKind) : base(state, fileCodeModel, nodeKind) { - _nodeKey = nodeKey; + NodeKey = nodeKey; _name = null; } @@ -40,25 +39,22 @@ internal AbstractKeyedCodeElement( string name) : base(state, fileCodeModel, nodeKind) { - _nodeKey = new SyntaxNodeKey(name, -1); + NodeKey = new SyntaxNodeKey(name, -1); _name = name; } - internal SyntaxNodeKey NodeKey - { - get { return _nodeKey; } - } + internal SyntaxNodeKey NodeKey { get; private set; } internal bool IsUnknown { - get { return _nodeKey.Ordinal == -1; } + get { return NodeKey.Ordinal == -1; } } internal override SyntaxNode LookupNode() - => CodeModelService.LookupNode(_nodeKey, GetSyntaxTree()); + => CodeModelService.LookupNode(NodeKey, GetSyntaxTree()); internal override bool TryLookupNode(out SyntaxNode node) - => CodeModelService.TryLookupNode(_nodeKey, GetSyntaxTree(), out node); + => CodeModelService.TryLookupNode(NodeKey, GetSyntaxTree(), out node); /// /// This function re-acquires the key for this code element using the given syntax path. @@ -73,9 +69,9 @@ internal void ReacquireNodeKey(SyntaxPath syntaxPath, CancellationToken cancella var newNodeKey = CodeModelService.GetNodeKey(node); - FileCodeModel.UpdateCodeElementNodeKey(this, _nodeKey, newNodeKey); + FileCodeModel.UpdateCodeElementNodeKey(this, NodeKey, newNodeKey); - _nodeKey = newNodeKey; + NodeKey = newNodeKey; } protected void UpdateNodeAndReacquireNodeKey(Action updater, T value, bool trackKinds = true) @@ -97,7 +93,7 @@ protected override Document DeleteCore(Document document) { var result = base.DeleteCore(document); - FileCodeModel.OnCodeElementDeleted(_nodeKey); + FileCodeModel.OnCodeElementDeleted(NodeKey); return result; } diff --git a/src/VisualStudio/Core/Impl/CodeModel/ProjectCodeModelFactory.cs b/src/VisualStudio/Core/Impl/CodeModel/ProjectCodeModelFactory.cs index ff6bf3c323b41..e27de36eb5a39 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/ProjectCodeModelFactory.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/ProjectCodeModelFactory.cs @@ -106,7 +106,7 @@ private async ValueTask ProcessNextDocumentBatchAsync( // Keep firing events for this doc, as long as we haven't exceeded the max amount // of waiting time, and there's no user input that should take precedence. - if (stopwatch.Elapsed.Ticks > MaxTimeSlice || IsInputPending()) + if (stopwatch.Elapsed.TotalMilliseconds > MaxTimeSlice || IsInputPending()) { await this.Listener.Delay(delayBetweenProcessing, cancellationToken).ConfigureAwait(true); stopwatch = SharedStopwatch.StartNew(); diff --git a/src/VisualStudio/Core/Impl/Options/OptionPreviewControl.xaml.cs b/src/VisualStudio/Core/Impl/Options/OptionPreviewControl.xaml.cs index 49c61e07efbc1..cf151779312cf 100644 --- a/src/VisualStudio/Core/Impl/Options/OptionPreviewControl.xaml.cs +++ b/src/VisualStudio/Core/Impl/Options/OptionPreviewControl.xaml.cs @@ -48,7 +48,7 @@ internal OptionPreviewControl(IServiceProvider serviceProvider, OptionStore opti private void Options_SelectionChanged(object sender, SelectionChangedEventArgs e) { var listView = (AutomationDelegatingListView)sender; - if (listView.SelectedItem is CheckBoxOptionViewModel checkbox) + if (listView.SelectedItem is AbstractCheckBoxViewModel checkbox) { ViewModel.UpdatePreview(checkbox.GetPreview()); } 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 5726a790255ce..35616f336f077 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageControl.xaml.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/NamingStyleOptionPageControl.xaml.cs @@ -38,13 +38,13 @@ internal partial class NamingStyleOptionPageControl : AbstractOptionPageControl private readonly string _languageName; private readonly INotificationService _notificationService; - private readonly NotificationOptionViewModel[] _notifications = new[] - { + private readonly NotificationOptionViewModel[] _notifications = + [ new NotificationOptionViewModel(NotificationOption2.Silent, KnownMonikers.None), new NotificationOptionViewModel(NotificationOption2.Suggestion, KnownMonikers.StatusInformation), new NotificationOptionViewModel(NotificationOption2.Warning, KnownMonikers.StatusWarning), new NotificationOptionViewModel(NotificationOption2.Error, KnownMonikers.StatusError) - }; + ]; internal NamingStyleOptionPageControl(OptionStore optionStore, INotificationService notificationService, string languageName) : base(optionStore) diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItem.BrowseObject.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItem.BrowseObject.cs index 08c4eb4a4d305..c9a1f0862ddf5 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItem.BrowseObject.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItem.BrowseObject.cs @@ -7,52 +7,25 @@ using System.ComponentModel; using Microsoft.VisualStudio.Shell; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +internal partial class AnalyzerItem { - internal partial class AnalyzerItem + internal sealed class BrowseObject(AnalyzerItem analyzerItem) : LocalizableProperties { - internal class BrowseObject : LocalizableProperties - { - private readonly AnalyzerItem _analyzerItem; - - public BrowseObject(AnalyzerItem analyzerItem) - { - _analyzerItem = analyzerItem; - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Name))] - public string Name - { - get - { - return _analyzerItem.AnalyzerReference.Display; - } - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Path))] - public string Path - { - get - { - return _analyzerItem.AnalyzerReference.FullPath; - } - } - - public override string GetClassName() - { - return SolutionExplorerShim.Analyzer_Properties; - } - - public override string GetComponentName() - { - return _analyzerItem.Text; - } - - [Browsable(false)] - public AnalyzerItem AnalyzerItem - { - get { return _analyzerItem; } - } - } + [Browsable(false)] + public AnalyzerItem AnalyzerItem { get; } = analyzerItem; + + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Name))] + public string Name => AnalyzerItem.AnalyzerReference.Display; + + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Path))] + public string Path => AnalyzerItem.AnalyzerReference.FullPath; + + public override string GetClassName() + => SolutionExplorerShim.Analyzer_Properties; + + public override string GetComponentName() + => AnalyzerItem.Text; } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItem.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItem.cs index f076af2f03f5b..a937acffd58cd 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItem.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItem.cs @@ -2,90 +2,41 @@ // 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.Diagnostics; using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer -{ - internal partial class AnalyzerItem : BaseItem - { - private readonly AnalyzersFolderItem _analyzersFolder; - private readonly AnalyzerReference _analyzerReference; - private readonly IContextMenuController _contextMenuController; - - public AnalyzerItem(AnalyzersFolderItem analyzersFolder, AnalyzerReference analyzerReference, IContextMenuController contextMenuController) - : base(GetNameText(analyzerReference)) - { - _analyzersFolder = analyzersFolder; - _analyzerReference = analyzerReference; - _contextMenuController = contextMenuController; - } - - public override ImageMoniker IconMoniker - { - get - { - return KnownMonikers.CodeInformation; - } - } - - public override ImageMoniker OverlayIconMoniker - { - get - { - if (_analyzerReference is UnresolvedAnalyzerReference) - { - return KnownMonikers.OverlayWarning; - } - else - { - return default; - } - } - } - - public override object GetBrowseObject() - { - return new BrowseObject(this); - } +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; - public AnalyzerReference AnalyzerReference - { - get { return _analyzerReference; } - } - - public override IContextMenuController ContextMenuController - { - get { return _contextMenuController; } - } - - public AnalyzersFolderItem AnalyzersFolder - { - get { return _analyzersFolder; } - } - - /// - /// Remove this AnalyzerItem from it's folder. - /// - public void Remove() - { - _analyzersFolder.RemoveAnalyzer(_analyzerReference.FullPath); - } - - private static string GetNameText(AnalyzerReference analyzerReference) - { - if (analyzerReference is UnresolvedAnalyzerReference) - { - return analyzerReference.FullPath; - } - else - { - return analyzerReference.Display; - } - } - } +internal sealed partial class AnalyzerItem( + AnalyzersFolderItem analyzersFolder, + AnalyzerReference analyzerReference, + IContextMenuController contextMenuController) + : BaseItem(GetNameText(analyzerReference)) +{ + public AnalyzersFolderItem AnalyzersFolder { get; } = analyzersFolder; + public AnalyzerReference AnalyzerReference { get; } = analyzerReference; + public override IContextMenuController ContextMenuController { get; } = contextMenuController; + + public override ImageMoniker IconMoniker => KnownMonikers.CodeInformation; + + public override ImageMoniker OverlayIconMoniker + => this.AnalyzerReference is UnresolvedAnalyzerReference + ? KnownMonikers.OverlayWarning + : default; + + public override object GetBrowseObject() + => new BrowseObject(this); + + /// + /// Remove this AnalyzerItem from it's folder. + /// + public void Remove() + => this.AnalyzersFolder.RemoveAnalyzer(this.AnalyzerReference.FullPath); + + private static string GetNameText(AnalyzerReference analyzerReference) + => analyzerReference is UnresolvedAnalyzerReference unresolvedAnalyzerReference + ? unresolvedAnalyzerReference.FullPath + : analyzerReference.Display; } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs index c3107210dc93c..1451dca714dc9 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSource.cs @@ -2,237 +2,179 @@ // 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; using System.ComponentModel; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Remote; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.SourceGeneration; using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.Shell; +using Roslyn.Utilities; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +internal sealed class AnalyzerItemSource : IAttachedCollectionSource { - internal class AnalyzerItemSource : IAttachedCollectionSource, INotifyPropertyChanged - { - private readonly AnalyzersFolderItem _analyzersFolder; - private readonly IAnalyzersCommandHandler _commandHandler; - private IReadOnlyCollection _analyzerReferences; - private BulkObservableCollection _analyzerItems; + private readonly AnalyzersFolderItem _analyzersFolder; + private readonly IAnalyzersCommandHandler _commandHandler; - public event PropertyChangedEventHandler PropertyChanged; + private readonly BulkObservableCollection _items = []; - public AnalyzerItemSource(AnalyzersFolderItem analyzersFolder, IAnalyzersCommandHandler commandHandler) - { - _analyzersFolder = analyzersFolder; - _commandHandler = commandHandler; + private readonly CancellationTokenSource _cancellationTokenSource = new(); + private readonly AsyncBatchingWorkQueue _workQueue; - _analyzersFolder.Workspace.WorkspaceChanged += Workspace_WorkspaceChanged; - } + private IReadOnlyCollection? _analyzerReferences; - private void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs e) - { - switch (e.Kind) - { - case WorkspaceChangeKind.SolutionAdded: - case WorkspaceChangeKind.SolutionChanged: - case WorkspaceChangeKind.SolutionReloaded: - UpdateAnalyzers(); - break; - - case WorkspaceChangeKind.SolutionRemoved: - case WorkspaceChangeKind.SolutionCleared: - _analyzersFolder.Workspace.WorkspaceChanged -= Workspace_WorkspaceChanged; - break; - - case WorkspaceChangeKind.ProjectAdded: - case WorkspaceChangeKind.ProjectReloaded: - case WorkspaceChangeKind.ProjectChanged: - if (e.ProjectId == _analyzersFolder.ProjectId) - { - UpdateAnalyzers(); - } - - break; - - case WorkspaceChangeKind.ProjectRemoved: - if (e.ProjectId == _analyzersFolder.ProjectId) - { - _analyzersFolder.Workspace.WorkspaceChanged -= Workspace_WorkspaceChanged; - } - - break; - } - } + private Workspace Workspace => _analyzersFolder.Workspace; + private ProjectId ProjectId => _analyzersFolder.ProjectId; - private void UpdateAnalyzers() - { - if (_analyzerItems == null) - { - // The set of AnalyzerItems hasn't been realized yet. Just signal that HasItems - // may have changed. + public AnalyzerItemSource( + AnalyzersFolderItem analyzersFolder, + IAnalyzersCommandHandler commandHandler, + IAsynchronousOperationListenerProvider listenerProvider) + { + _analyzersFolder = analyzersFolder; + _commandHandler = commandHandler; - NotifyPropertyChanged(nameof(HasItems)); - return; - } + _workQueue = new AsyncBatchingWorkQueue( + DelayTimeSpan.Idle, + ProcessQueueAsync, + listenerProvider.GetListener(FeatureAttribute.SourceGenerators), + _cancellationTokenSource.Token); - var project = _analyzersFolder.Workspace - .CurrentSolution - .GetProject(_analyzersFolder.ProjectId); + this.Workspace.WorkspaceChanged += OnWorkspaceChanged; - if (project != null && - project.AnalyzerReferences != _analyzerReferences) - { - _analyzerReferences = project.AnalyzerReferences; + // Kick off the initial work to determine the starting set of items. + _workQueue.AddWork(); + } - _analyzerItems.BeginBulkOperation(); + public object SourceItem => _analyzersFolder; - var itemsToRemove = _analyzerItems - .Where(item => !_analyzerReferences.Contains(item.AnalyzerReference)) - .ToArray(); + // Defer actual determination and computation of the items until later. + public bool HasItems => !_cancellationTokenSource.IsCancellationRequested; - var referencesToAdd = GetFilteredAnalyzers(_analyzerReferences, project) - .Where(r => !_analyzerItems.Any(item => item.AnalyzerReference == r)) - .ToArray(); + public IEnumerable Items => _items; - foreach (var item in itemsToRemove) - { - _analyzerItems.Remove(item); - } + private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) + { + switch (e.Kind) + { + case WorkspaceChangeKind.SolutionAdded: + case WorkspaceChangeKind.SolutionChanged: + case WorkspaceChangeKind.SolutionReloaded: + case WorkspaceChangeKind.SolutionRemoved: + case WorkspaceChangeKind.SolutionCleared: + _workQueue.AddWork(); + break; + + case WorkspaceChangeKind.ProjectAdded: + case WorkspaceChangeKind.ProjectReloaded: + case WorkspaceChangeKind.ProjectChanged: + case WorkspaceChangeKind.ProjectRemoved: + if (e.ProjectId == this.ProjectId) + _workQueue.AddWork(); + + break; + } + } - foreach (var reference in referencesToAdd) - { - _analyzerItems.Add(new AnalyzerItem(_analyzersFolder, reference, _commandHandler.AnalyzerContextMenuController)); - } + private async ValueTask ProcessQueueAsync(CancellationToken cancellationToken) + { + // If the project went away, then shut ourselves down. + var project = this.Workspace.CurrentSolution.GetProject(this.ProjectId); + if (project is null) + { + this.Workspace.WorkspaceChanged -= OnWorkspaceChanged; - var sorted = _analyzerItems.OrderBy(item => item.AnalyzerReference.Display).ToArray(); - for (var i = 0; i < sorted.Length; i++) - { - _analyzerItems.Move(_analyzerItems.IndexOf(sorted[i]), i); - } + _cancellationTokenSource.Cancel(); - _analyzerItems.EndBulkOperation(); + // Note: mutating _items will be picked up automatically by clients who are bound to the collection. We do + // not need to notify them through some other mechanism. - NotifyPropertyChanged(nameof(HasItems)); + if (_items.Count > 0) + { + // Go back to UI thread to update the observable collection. Otherwise, it enqueue its own UI work that we cannot track. + await _analyzersFolder.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + _items.Clear(); } - } - private void NotifyPropertyChanged(string propertyName) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + return; } - public bool HasItems - { - get - { - if (_analyzerItems != null) - { - return _analyzerItems.Count > 0; - } - - var project = _analyzersFolder.Workspace - .CurrentSolution - .GetProject(_analyzersFolder.ProjectId); + // If nothing changed wrt analyzer references, then there's nothing we need to do. + if (project.AnalyzerReferences == _analyzerReferences) + return; - if (project != null) - { - return project.AnalyzerReferences.Count > 0; - } + // Set the new set of analyzer references we're going to have AnalyzerItems for. + _analyzerReferences = project.AnalyzerReferences; - return false; - } - } + var references = await GetAnalyzerReferencesWithAnalyzersOrGeneratorsAsync( + project, cancellationToken).ConfigureAwait(false); - public IEnumerable Items + // Go back to UI thread to update the observable collection. Otherwise, it enqueue its own UI work that we cannot track. + await _analyzersFolder.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + try { - get - { - if (_analyzerItems == null) - { - _analyzerItems = []; - - var project = _analyzersFolder.Workspace - .CurrentSolution - .GetProject(_analyzersFolder.ProjectId); - - if (project != null) - { - _analyzerReferences = project.AnalyzerReferences; - var initialSet = GetFilteredAnalyzers(_analyzerReferences, project) - .OrderBy(ar => ar.Display) - .Select(ar => new AnalyzerItem(_analyzersFolder, ar, _commandHandler.AnalyzerContextMenuController)); - _analyzerItems.AddRange(initialSet); - } - } + _items.BeginBulkOperation(); - Logger.Log( - FunctionId.SolutionExplorer_AnalyzerItemSource_GetItems, - KeyValueLogMessage.Create(m => m["Count"] = _analyzerItems.Count)); + _items.Clear(); + foreach (var analyzerReference in references.OrderBy(static r => r.Display)) + _items.Add(new AnalyzerItem(_analyzersFolder, analyzerReference, _commandHandler.AnalyzerContextMenuController)); - return _analyzerItems; - } + return; } - - public object SourceItem + finally { - get - { - return _analyzersFolder; - } + _items.EndBulkOperation(); } - private ImmutableHashSet GetAnalyzersWithLoadErrors() + async Task> GetAnalyzerReferencesWithAnalyzersOrGeneratorsAsync( + Project project, + CancellationToken cancellationToken) { - if (_analyzersFolder.Workspace is VisualStudioWorkspaceImpl) - { - /* - var vsProject = vsWorkspace.DeferredState?.ProjectTracker.GetProject(_analyzersFolder.ProjectId); - var vsAnalyzersMap = vsProject?.GetProjectAnalyzersMap(); - - if (vsAnalyzersMap != null) - { - return vsAnalyzersMap.Where(kvp => kvp.Value.HasLoadErrors).Select(kvp => kvp.Key).ToImmutableHashSet(); - } - */ - } + var client = await RemoteHostClient.TryGetClientAsync(this.Workspace, cancellationToken).ConfigureAwait(false); - return ImmutableHashSet.Empty; - } + // If we can't make a remote call. Fall back to processing in the VS host. + if (client is null) + return project.AnalyzerReferences.Where(r => r is not AnalyzerFileReference || r.HasAnalyzersOrSourceGenerators(project.Language)).ToImmutableArray(); - private ImmutableArray GetFilteredAnalyzers(IEnumerable analyzerReferences, Project project) - { - var analyzersWithLoadErrors = GetAnalyzersWithLoadErrors(); + using var connection = client.CreateConnection(callbackTarget: null); - // Filter out analyzer dependencies which have no diagnostic analyzers, but still retain the unresolved analyzers and analyzers with load errors. - var builder = ArrayBuilder.GetInstance(); - foreach (var analyzerReference in analyzerReferences) + using var _ = ArrayBuilder.GetInstance(out var builder); + foreach (var reference in project.AnalyzerReferences) { - // Analyzer dependency: - // 1. Must be an Analyzer file reference (we don't understand other analyzer dependencies). - // 2. Mush have no diagnostic analyzers. - // 3. Must have no source generators. - // 4. Must have non-null full path. - // 5. Must not have any assembly or analyzer load failures. - if (analyzerReference is AnalyzerFileReference && - analyzerReference.GetAnalyzers(project.Language).IsDefaultOrEmpty && - analyzerReference.GetGenerators(project.Language).IsDefaultOrEmpty && - analyzerReference.FullPath != null && - !analyzersWithLoadErrors.Contains(analyzerReference.FullPath)) + // Can only remote AnalyzerFileReferences over to the oop side. + if (reference is AnalyzerFileReference analyzerFileReference) { - continue; + var result = await connection.TryInvokeAsync( + project, + (service, solutionChecksum, cancellationToken) => service.HasAnalyzersOrSourceGeneratorsAsync( + solutionChecksum, project.Id, analyzerFileReference.FullPath, cancellationToken), + cancellationToken).ConfigureAwait(false); + + // If the call fails, the OOP substrate will have already reported an error + if (!result.HasValue) + return []; + + if (result.Value) + builder.Add(analyzerFileReference); + } + else if (reference.HasAnalyzersOrSourceGenerators(project.Language)) + { + builder.Add(reference); } - - builder.Add(analyzerReference); } - return builder.ToImmutableAndFree(); + return builder.ToImmutableAndClear(); } } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSourceProvider.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSourceProvider.cs index 248921a775a57..0ddc809f17ac7 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSourceProvider.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItem/AnalyzerItemSourceProvider.cs @@ -2,40 +2,28 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer -{ - [Export(typeof(IAttachedCollectionSourceProvider))] - [Name(nameof(AnalyzerItemSourceProvider))] - [Order] - [AppliesToProject("(CSharp | VB) & !CPS")] // in the CPS case, the Analyzers items are created by the project system - internal sealed class AnalyzerItemSourceProvider : AttachedCollectionSourceProvider - { - [Import(typeof(AnalyzersCommandHandler))] - private readonly IAnalyzersCommandHandler _commandHandler = null; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public AnalyzerItemSourceProvider() - { - } +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; - protected override IAttachedCollectionSource CreateCollectionSource(AnalyzersFolderItem analyzersFolder, string relationshipName) - { - if (relationshipName == KnownRelationships.Contains) - { - return new AnalyzerItemSource(analyzersFolder, _commandHandler); - } - - return null; - } - } +[Export(typeof(IAttachedCollectionSourceProvider))] +[Name(nameof(AnalyzerItemSourceProvider)), Order] +[AppliesToProject("(CSharp | VB) & !CPS")] // in the CPS case, the Analyzers items are created by the project system +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class AnalyzerItemSourceProvider( + [Import(typeof(AnalyzersCommandHandler))] IAnalyzersCommandHandler commandHandler, + IAsynchronousOperationListenerProvider listenerProvider) + : AttachedCollectionSourceProvider +{ + protected override IAttachedCollectionSource? CreateCollectionSource(AnalyzersFolderItem analyzersFolder, string relationshipName) + => relationshipName == KnownRelationships.Contains + ? new AnalyzerItemSource(analyzersFolder, commandHandler, listenerProvider) + : null; } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs index db16d7169612a..bd5c9e9a2ac0b 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs @@ -14,118 +14,112 @@ using Microsoft.VisualStudio.Shell.Interop; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +/// +/// This class listens to selection change events, and tracks which, if any, of our +/// or is selected. +/// +[Export] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class AnalyzerItemsTracker(IThreadingContext threadingContext) : IVsSelectionEvents { - /// - /// This class listens to selection change events, and tracks which, if any, of our - /// or is selected. - /// - [Export] - internal class AnalyzerItemsTracker : IVsSelectionEvents - { - private readonly IThreadingContext _threadingContext; + private readonly IThreadingContext _threadingContext = threadingContext; - private IVsMonitorSelection? _vsMonitorSelection = null; - private uint _selectionEventsCookie = 0; + private IVsMonitorSelection? _vsMonitorSelection = null; + private uint _selectionEventsCookie = 0; - public event EventHandler? SelectedHierarchyItemChanged; + public event EventHandler? SelectedHierarchyItemChanged; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public AnalyzerItemsTracker(IThreadingContext threadingContext) - { - _threadingContext = threadingContext; - } + public async Task RegisterAsync(IAsyncServiceProvider serviceProvider, CancellationToken cancellationToken) + { + _vsMonitorSelection ??= await serviceProvider.GetServiceAsync(_threadingContext.JoinableTaskFactory, throwOnFailure: false).ConfigureAwait(false); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + _vsMonitorSelection?.AdviseSelectionEvents(this, out _selectionEventsCookie); + } - public async Task RegisterAsync(IAsyncServiceProvider serviceProvider, CancellationToken cancellationToken) - { - _vsMonitorSelection ??= await serviceProvider.GetServiceAsync(_threadingContext.JoinableTaskFactory, throwOnFailure: false).ConfigureAwait(false); - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - _vsMonitorSelection?.AdviseSelectionEvents(this, out _selectionEventsCookie); - } + public void Unregister() + { + _vsMonitorSelection?.UnadviseSelectionEvents(_selectionEventsCookie); + } - public void Unregister() - { - _vsMonitorSelection?.UnadviseSelectionEvents(_selectionEventsCookie); - } + public IVsHierarchy? SelectedHierarchy { get; private set; } + public uint SelectedItemId { get; private set; } = VSConstants.VSITEMID_NIL; + public AnalyzersFolderItem? SelectedFolder { get; private set; } + public ImmutableArray SelectedAnalyzerItems { get; private set; } = ImmutableArray.Empty; + public ImmutableArray SelectedDiagnosticItems { get; private set; } = ImmutableArray.Empty; - public IVsHierarchy? SelectedHierarchy { get; private set; } - public uint SelectedItemId { get; private set; } = VSConstants.VSITEMID_NIL; - public AnalyzersFolderItem? SelectedFolder { get; private set; } - public ImmutableArray SelectedAnalyzerItems { get; private set; } = ImmutableArray.Empty; - public ImmutableArray SelectedDiagnosticItems { get; private set; } = ImmutableArray.Empty; + int IVsSelectionEvents.OnCmdUIContextChanged(uint dwCmdUICookie, int fActive) + { + return VSConstants.S_OK; + } - int IVsSelectionEvents.OnCmdUIContextChanged(uint dwCmdUICookie, int fActive) - { - return VSConstants.S_OK; - } + int IVsSelectionEvents.OnElementValueChanged(uint elementid, object varValueOld, object varValueNew) + { + return VSConstants.S_OK; + } - int IVsSelectionEvents.OnElementValueChanged(uint elementid, object varValueOld, object varValueNew) - { - return VSConstants.S_OK; - } + int IVsSelectionEvents.OnSelectionChanged( + IVsHierarchy pHierOld, + uint itemidOld, + IVsMultiItemSelect pMISOld, + ISelectionContainer pSCOld, + IVsHierarchy pHierNew, + uint itemidNew, + IVsMultiItemSelect pMISNew, + ISelectionContainer pSCNew) + { + var oldSelectedHierarchy = this.SelectedHierarchy; + var oldSelectedItemId = this.SelectedItemId; - int IVsSelectionEvents.OnSelectionChanged( - IVsHierarchy pHierOld, - uint itemidOld, - IVsMultiItemSelect pMISOld, - ISelectionContainer pSCOld, - IVsHierarchy pHierNew, - uint itemidNew, - IVsMultiItemSelect pMISNew, - ISelectionContainer pSCNew) - { - var oldSelectedHierarchy = this.SelectedHierarchy; - var oldSelectedItemId = this.SelectedItemId; + this.SelectedHierarchy = pHierNew; + this.SelectedItemId = itemidNew; - this.SelectedHierarchy = pHierNew; - this.SelectedItemId = itemidNew; + var selectedObjects = GetSelectedObjects(pSCNew); - var selectedObjects = GetSelectedObjects(pSCNew); + this.SelectedAnalyzerItems = selectedObjects + .OfType() + .Select(b => b.AnalyzerItem) + .ToImmutableArray(); - this.SelectedAnalyzerItems = selectedObjects - .OfType() - .Select(b => b.AnalyzerItem) - .ToImmutableArray(); + this.SelectedFolder = selectedObjects + .OfType() + .Select(b => b.Folder) + .FirstOrDefault(); - this.SelectedFolder = selectedObjects - .OfType() - .Select(b => b.Folder) - .FirstOrDefault(); + this.SelectedDiagnosticItems = selectedObjects + .OfType() + .Select(b => b.DiagnosticItem) + .ToImmutableArray(); - this.SelectedDiagnosticItems = selectedObjects - .OfType() - .Select(b => b.DiagnosticItem) - .ToImmutableArray(); + if (!object.ReferenceEquals(oldSelectedHierarchy, this.SelectedHierarchy) || + oldSelectedItemId != this.SelectedItemId) + { + this.SelectedHierarchyItemChanged?.Invoke(this, EventArgs.Empty); + } - if (!object.ReferenceEquals(oldSelectedHierarchy, this.SelectedHierarchy) || - oldSelectedItemId != this.SelectedItemId) - { - this.SelectedHierarchyItemChanged?.Invoke(this, EventArgs.Empty); - } + return VSConstants.S_OK; + } - return VSConstants.S_OK; + private static object[] GetSelectedObjects(ISelectionContainer? selectionContainer) + { + if (selectionContainer == null) + { + return []; } - private static object[] GetSelectedObjects(ISelectionContainer? selectionContainer) + if (selectionContainer.CountObjects((uint)Constants.GETOBJS_SELECTED, out var selectedObjectCount) < 0 || selectedObjectCount == 0) { - if (selectionContainer == null) - { - return []; - } - - if (selectionContainer.CountObjects((uint)Constants.GETOBJS_SELECTED, out var selectedObjectCount) < 0 || selectedObjectCount == 0) - { - return []; - } - - var selectedObjects = new object[selectedObjectCount]; - if (selectionContainer.GetObjects((uint)Constants.GETOBJS_SELECTED, selectedObjectCount, selectedObjects) < 0) - { - return []; - } - - return selectedObjects; + return []; } + + var selectedObjects = new object[selectedObjectCount]; + if (selectionContainer.GetObjects((uint)Constants.GETOBJS_SELECTED, selectedObjectCount, selectedObjects) < 0) + { + return []; + } + + return selectedObjects; } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItem.BrowseObject.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItem.BrowseObject.cs index 995b58af4d9fb..17e6a6639cc48 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItem.BrowseObject.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItem.BrowseObject.cs @@ -5,34 +5,19 @@ using System.ComponentModel; using Microsoft.VisualStudio.Shell; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +internal partial class AnalyzersFolderItem { - internal partial class AnalyzersFolderItem + internal sealed class BrowseObject(AnalyzersFolderItem analyzersFolderItem) : LocalizableProperties { - internal class BrowseObject : LocalizableProperties - { - private readonly AnalyzersFolderItem _analyzersFolderItem; - - public BrowseObject(AnalyzersFolderItem analyzersFolderItem) - { - _analyzersFolderItem = analyzersFolderItem; - } - - public override string GetClassName() - { - return SolutionExplorerShim.Folder_Properties; - } + [Browsable(false)] + public AnalyzersFolderItem Folder { get; } = analyzersFolderItem; - public override string GetComponentName() - { - return _analyzersFolderItem.Text; - } + public override string GetClassName() + => SolutionExplorerShim.Folder_Properties; - [Browsable(false)] - public AnalyzersFolderItem Folder - { - get { return _analyzersFolderItem; } - } - } + public override string GetComponentName() + => Folder.Text; } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItem.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItem.cs index 79d0a0b5eefd5..b2542ef39e496 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItem.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItem.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; @@ -10,97 +11,68 @@ using Microsoft.VisualStudio.Shell; using VSLangProj140; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer -{ - using Workspace = Microsoft.CodeAnalysis.Workspace; - - internal partial class AnalyzersFolderItem : BaseItem - { - private readonly IContextMenuController _contextMenuController; +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; - public AnalyzersFolderItem( - Workspace workspace, - ProjectId projectId, - IVsHierarchyItem parentItem, - IContextMenuController contextMenuController) - : base(SolutionExplorerShim.Analyzers) - { - Workspace = workspace; - ProjectId = projectId; - ParentItem = parentItem; - _contextMenuController = contextMenuController; - } - - public override ImageMoniker IconMoniker => KnownMonikers.CodeInformation; +internal sealed partial class AnalyzersFolderItem( + IThreadingContext threadingContext, + Workspace workspace, + ProjectId projectId, + IVsHierarchyItem parentItem, + IContextMenuController contextMenuController) : BaseItem(SolutionExplorerShim.Analyzers) +{ + public readonly IThreadingContext ThreadingContext = threadingContext; + public Workspace Workspace { get; } = workspace; + public ProjectId ProjectId { get; } = projectId; + public IVsHierarchyItem ParentItem { get; } = parentItem; + public override IContextMenuController ContextMenuController { get; } = contextMenuController; - public Workspace Workspace { get; } + public override ImageMoniker IconMoniker => KnownMonikers.CodeInformation; - public ProjectId ProjectId { get; } + public override object GetBrowseObject() + => new BrowseObject(this); - public IVsHierarchyItem ParentItem { get; } + /// + /// Get the DTE object for the Project. + /// + private VSProject3? GetVSProject() + { + if (Workspace is not VisualStudioWorkspace vsWorkspace) + return null; - public override object GetBrowseObject() - { - return new BrowseObject(this); - } + var hierarchy = vsWorkspace.GetHierarchy(ProjectId); + if (hierarchy == null) + return null; - public override IContextMenuController ContextMenuController + if (hierarchy.TryGetProject(out var project)) { - get { return _contextMenuController; } + var vsproject = project.Object as VSProject3; + return vsproject; } - /// - /// Get the DTE object for the Project. - /// - private VSProject3? GetVSProject() - { - var vsWorkspace = Workspace as VisualStudioWorkspace; - if (vsWorkspace == null) - { - return null; - } - - var hierarchy = vsWorkspace.GetHierarchy(ProjectId); - if (hierarchy == null) - { - return null; - } - - if (hierarchy.TryGetProject(out var project)) - { - var vsproject = project.Object as VSProject3; - return vsproject; - } - - return null; - } + return null; + } - /// - /// Add an analyzer with the given path to this folder. - /// - public void AddAnalyzer(string path) - { - var vsproject = GetVSProject(); - if (vsproject == null) - { - return; - } + /// + /// Add an analyzer with the given path to this folder. + /// + public void AddAnalyzer(string path) + { + var vsproject = GetVSProject(); + if (vsproject == null) + return; - vsproject.AnalyzerReferences.Add(path); - } + vsproject.AnalyzerReferences.Add(path); + } - /// - /// Remove an analyzer with the given path from this folder. - /// - public void RemoveAnalyzer(string path) - { - var vsproject = GetVSProject(); - if (vsproject == null) - { - return; - } + /// + /// Remove an analyzer with the given path from this folder. + /// + public void RemoveAnalyzer(string? path) + { + var vsproject = GetVSProject(); + if (vsproject == null) + return; - vsproject.AnalyzerReferences.Remove(path); - } + vsproject.AnalyzerReferences.Remove(path); } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSource.cs index b13755617c7cd..55d53a62b8c42 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSource.cs @@ -4,72 +4,30 @@ using System.Collections; using System.Collections.ObjectModel; -using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.VisualStudio.Shell; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer -{ - using Workspace = Microsoft.CodeAnalysis.Workspace; - - internal class AnalyzersFolderItemSource : IAttachedCollectionSource - { - private readonly IVsHierarchyItem _projectHierarchyItem; - private readonly Workspace _workspace; - private readonly ProjectId _projectId; - private readonly ObservableCollection _folderItems; - private readonly IAnalyzersCommandHandler _commandHandler; - - public AnalyzersFolderItemSource(Workspace workspace, ProjectId projectId, IVsHierarchyItem projectHierarchyItem, IAnalyzersCommandHandler commandHandler) - { - _workspace = workspace; - _projectId = projectId; - _projectHierarchyItem = projectHierarchyItem; - _commandHandler = commandHandler; - - _folderItems = []; +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; - Update(); - } - - public bool HasItems - { - get - { - return true; - } - } - - public IEnumerable Items - { - get - { - return _folderItems; - } - } +internal sealed class AnalyzersFolderItemSource( + IThreadingContext threadingContext, + Workspace workspace, + ProjectId projectId, + IVsHierarchyItem projectHierarchyItem, + IAnalyzersCommandHandler commandHandler) + : IAttachedCollectionSource +{ + private readonly ObservableCollection _folderItems = [new AnalyzersFolderItem( + threadingContext, + workspace, + projectId, + projectHierarchyItem, + commandHandler.AnalyzerFolderContextMenuController)]; - public object SourceItem - { - get - { - return _projectHierarchyItem; - } - } + public bool HasItems => true; - internal void Update() - { - // Don't create the item a 2nd time. - if (_folderItems.Any()) - { - return; - } + public IEnumerable Items => _folderItems; - _folderItems.Add( - new AnalyzersFolderItem( - _workspace, - _projectId, - _projectHierarchyItem, - _commandHandler.AnalyzerFolderContextMenuController)); - } - } + public object SourceItem => projectHierarchyItem; } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSourceProvider.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSourceProvider.cs index f16cbf5a29b38..2b66c8a56c5a9 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSourceProvider.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersFolderItem/AnalyzersFolderItemSourceProvider.cs @@ -7,80 +7,72 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +[Export(typeof(IAttachedCollectionSourceProvider))] +[Name(nameof(AnalyzersFolderItemSourceProvider))] +[Order(Before = HierarchyItemsProviderNames.Contains)] +[AppliesToProject("(CSharp | VB) & !CPS")] // in the CPS case, the Analyzers folder is created by the project system +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +[method: ImportingConstructor] +internal sealed class AnalyzersFolderItemSourceProvider( + IThreadingContext threadingContext, + VisualStudioWorkspace workspace, + [Import(typeof(AnalyzersCommandHandler))] IAnalyzersCommandHandler commandHandler) + : AttachedCollectionSourceProvider { - using Workspace = Microsoft.CodeAnalysis.Workspace; + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly Workspace _workspace = workspace; + private readonly IAnalyzersCommandHandler _commandHandler = commandHandler; - [Export(typeof(IAttachedCollectionSourceProvider))] - [Name(nameof(AnalyzersFolderItemSourceProvider))] - [Order(Before = HierarchyItemsProviderNames.Contains)] - [AppliesToProject("(CSharp | VB) & !CPS")] // in the CPS case, the Analyzers folder is created by the project system - internal class AnalyzersFolderItemSourceProvider : AttachedCollectionSourceProvider - { - private readonly IAnalyzersCommandHandler _commandHandler; - private IHierarchyItemToProjectIdMap? _projectMap; - private readonly Workspace _workspace; + private IHierarchyItemToProjectIdMap? _projectMap; - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - [ImportingConstructor] - public AnalyzersFolderItemSourceProvider( - VisualStudioWorkspace workspace, - [Import(typeof(AnalyzersCommandHandler))] IAnalyzersCommandHandler commandHandler) + protected override IAttachedCollectionSource? CreateCollectionSource(IVsHierarchyItem item, string relationshipName) + { + if (item != null && + item.HierarchyIdentity != null && + item.HierarchyIdentity.NestedHierarchy != null && + relationshipName == KnownRelationships.Contains) { - _workspace = workspace; - _commandHandler = commandHandler; - } + var hierarchy = item.HierarchyIdentity.NestedHierarchy; + var itemId = item.HierarchyIdentity.NestedItemID; - protected override IAttachedCollectionSource? CreateCollectionSource(IVsHierarchyItem item, string relationshipName) - { - if (item != null && - item.HierarchyIdentity != null && - item.HierarchyIdentity.NestedHierarchy != null && - relationshipName == KnownRelationships.Contains) + var projectTreeCapabilities = GetProjectTreeCapabilities(hierarchy, itemId); + if (projectTreeCapabilities.Any(static c => c.Equals("References"))) { - var hierarchy = item.HierarchyIdentity.NestedHierarchy; - var itemId = item.HierarchyIdentity.NestedItemID; - - var projectTreeCapabilities = GetProjectTreeCapabilities(hierarchy, itemId); - if (projectTreeCapabilities.Any(static c => c.Equals("References"))) + var hierarchyMapper = TryGetProjectMap(); + if (hierarchyMapper != null && + hierarchyMapper.TryGetProjectId(item.Parent, targetFrameworkMoniker: null, projectId: out var projectId)) { - var hierarchyMapper = TryGetProjectMap(); - if (hierarchyMapper != null && - hierarchyMapper.TryGetProjectId(item.Parent, targetFrameworkMoniker: null, projectId: out var projectId)) - { - return new AnalyzersFolderItemSource(_workspace, projectId, item, _commandHandler); - } - - return null; + return new AnalyzersFolderItemSource(_threadingContext, _workspace, projectId, item, _commandHandler); } - } - return null; + return null; + } } - private static ImmutableArray GetProjectTreeCapabilities(IVsHierarchy hierarchy, uint itemId) + return null; + } + + private static ImmutableArray GetProjectTreeCapabilities(IVsHierarchy hierarchy, uint itemId) + { + if (hierarchy.GetProperty(itemId, (int)__VSHPROPID7.VSHPROPID_ProjectTreeCapabilities, out var capabilitiesObj) == VSConstants.S_OK) { - if (hierarchy.GetProperty(itemId, (int)__VSHPROPID7.VSHPROPID_ProjectTreeCapabilities, out var capabilitiesObj) == VSConstants.S_OK) - { - var capabilitiesString = (string)capabilitiesObj; - return ImmutableArray.Create(capabilitiesString.Split(' ')); - } - else - { - return ImmutableArray.Empty; - } + var capabilitiesString = (string)capabilitiesObj; + return ImmutableArray.Create(capabilitiesString.Split(' ')); } - - private IHierarchyItemToProjectIdMap? TryGetProjectMap() + else { - _projectMap ??= _workspace.Services.GetService(); - - return _projectMap; + return ImmutableArray.Empty; } } + + private IHierarchyItemToProjectIdMap? TryGetProjectMap() + => _projectMap ??= _workspace.Services.GetService(); } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/BaseItem.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/BaseItem.cs index eb4e8e26026af..1d6e7acd2c146 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/BaseItem.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/BaseItem.cs @@ -33,11 +33,11 @@ internal abstract class BaseItem : { public virtual event PropertyChangedEventHandler PropertyChanged { add { } remove { } } - private readonly string _name; + protected readonly string Name; public BaseItem(string name) { - _name = name; + Name = name; } public IEnumerable Children => []; @@ -61,9 +61,9 @@ public BaseItem(string name) public virtual ImageMoniker StateIconMoniker => default; public string? StateToolTipText => null; public override string ToString() => Text; - public string Text => _name; + public string Text => Name; public object? ToolTipContent => null; - public string ToolTipText => _name; + public string ToolTipText => Name; private static readonly HashSet s_supportedPatterns = [ diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs index ef558ad59cd77..b90add845e4e1 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs @@ -5,189 +5,222 @@ using System; using System.Collections; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.SourceGeneration; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Shell; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +internal abstract partial class BaseDiagnosticAndGeneratorItemSource : IAttachedCollectionSource { - internal abstract partial class BaseDiagnosticAndGeneratorItemSource : IAttachedCollectionSource + private static readonly DiagnosticDescriptorComparer s_comparer = new(); + + private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService; + private readonly BulkObservableCollection _items = []; + + private readonly CancellationTokenSource _cancellationTokenSource = new(); + private readonly AsyncBatchingWorkQueue _workQueue; + private readonly IThreadingContext _threadingContext; + + protected Workspace Workspace { get; } + protected ProjectId ProjectId { get; } + protected IAnalyzersCommandHandler CommandHandler { get; } + + /// + /// The analyzer reference that has been found. Once it's been assigned a non-null value, it'll never be assigned + /// again. + /// + private AnalyzerReference? _analyzerReference_DoNotAccessDirectly; + + public BaseDiagnosticAndGeneratorItemSource( + IThreadingContext threadingContext, + Workspace workspace, + ProjectId projectId, + IAnalyzersCommandHandler commandHandler, + IDiagnosticAnalyzerService diagnosticAnalyzerService, + IAsynchronousOperationListenerProvider listenerProvider) { - private static readonly DiagnosticDescriptorComparer s_comparer = new DiagnosticDescriptorComparer(); + _threadingContext = threadingContext; + Workspace = workspace; + ProjectId = projectId; + CommandHandler = commandHandler; + _diagnosticAnalyzerService = diagnosticAnalyzerService; + + _workQueue = new AsyncBatchingWorkQueue( + DelayTimeSpan.Idle, + ProcessQueueAsync, + listenerProvider.GetListener(FeatureAttribute.SourceGenerators), + _cancellationTokenSource.Token); + } - private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService; + protected AnalyzerReference? AnalyzerReference + { + get => _analyzerReference_DoNotAccessDirectly; + set + { + Contract.ThrowIfTrue(_analyzerReference_DoNotAccessDirectly != null); + if (value is null) + return; - private BulkObservableCollection? _items; - private ReportDiagnostic _generalDiagnosticOption; - private ImmutableDictionary? _specificDiagnosticOptions; - private AnalyzerConfigData? _analyzerConfigOptions; + _analyzerReference_DoNotAccessDirectly = value; - public BaseDiagnosticAndGeneratorItemSource(Workspace workspace, ProjectId projectId, IAnalyzersCommandHandler commandHandler, IDiagnosticAnalyzerService diagnosticAnalyzerService) - { - Workspace = workspace; - ProjectId = projectId; - CommandHandler = commandHandler; - _diagnosticAnalyzerService = diagnosticAnalyzerService; + // Listen for changes that would affect the set of analyzers/generators in this reference, and kick off work + // to now get the items for this source. + Workspace.WorkspaceChanged += OnWorkspaceChanged; + _workQueue.AddWork(); } + } - public Workspace Workspace { get; } - public ProjectId ProjectId { get; } - protected IAnalyzersCommandHandler CommandHandler { get; } + public abstract object SourceItem { get; } - public abstract AnalyzerReference? AnalyzerReference { get; } + // Defer actual determination and computation of the items until later. + public bool HasItems => !_cancellationTokenSource.IsCancellationRequested; - public abstract object SourceItem { get; } + public IEnumerable Items => _items; - [MemberNotNullWhen(true, nameof(AnalyzerReference))] - public bool HasItems - { - get - { - if (_items != null) - { - return _items.Count > 0; - } + private async ValueTask ProcessQueueAsync(CancellationToken cancellationToken) + { + var analyzerReference = this.AnalyzerReference; - if (AnalyzerReference == null) - { - return false; - } + // If we haven't even determined which analyzer reference we're for, there's nothing to do. + if (analyzerReference is null) + return; - var project = Workspace.CurrentSolution.GetProject(ProjectId); + // If the project went away, or no longer contains this analyzer. Shut ourselves down. + var project = this.Workspace.CurrentSolution.GetProject(this.ProjectId); + if (project is null || !project.AnalyzerReferences.Contains(analyzerReference)) + { + this.Workspace.WorkspaceChanged -= OnWorkspaceChanged; - if (project == null) - { - return false; - } + _cancellationTokenSource.Cancel(); - return AnalyzerReference.GetAnalyzers(project.Language).Any() || - AnalyzerReference.GetGenerators(project.Language).Any(); + // Note: mutating _items will be picked up automatically by clients who are bound to the collection. We do + // not need to notify them through some other mechanism. + if (_items.Count > 0) + { + // Go back to UI thread to update the observable collection. Otherwise, it enqueue its own UI work that we cannot track. + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + _items.Clear(); } - } - public IEnumerable Items - { - get - { - if (_items == null) - { - var project = Workspace.CurrentSolution.GetRequiredProject(ProjectId); - _generalDiagnosticOption = project.CompilationOptions!.GeneralDiagnosticOption; - _specificDiagnosticOptions = project.CompilationOptions!.SpecificDiagnosticOptions; - _analyzerConfigOptions = project.GetAnalyzerConfigOptions(); + return; + } - _items = CreateDiagnosticAndGeneratorItems(project.Id, project.Language, project.CompilationOptions, _analyzerConfigOptions); + var newDiagnosticItems = GenerateDiagnosticItems(project, analyzerReference); + var newSourceGeneratorItems = await GenerateSourceGeneratorItemsAsync( + project, analyzerReference).ConfigureAwait(false); - Workspace.WorkspaceChanged += OnWorkspaceChangedLookForOptionsChanges; - } + // If we computed the same set of items as the last time, we can bail out now. + if (_items.SequenceEqual([.. newDiagnosticItems, .. newSourceGeneratorItems])) + return; - Logger.Log( - FunctionId.SolutionExplorer_DiagnosticItemSource_GetItems, - KeyValueLogMessage.Create(m => m["Count"] = _items.Count)); + // Go back to UI thread to update the observable collection. Otherwise, it enqueue its own UI work that we cannot track. + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - return _items; - } + _items.BeginBulkOperation(); + try + { + _items.Clear(); + _items.AddRange(newDiagnosticItems); + _items.AddRange(newSourceGeneratorItems); + } + finally + { + _items.EndBulkOperation(); } - private BulkObservableCollection CreateDiagnosticAndGeneratorItems(ProjectId projectId, string language, CompilationOptions options, AnalyzerConfigData? analyzerConfigOptions) + return; + + ImmutableArray GenerateDiagnosticItems( + Project project, + AnalyzerReference analyzerReference) { - // Within an analyzer assembly, an individual analyzer may report multiple different diagnostics - // with the same ID. Or, multiple analyzers may report diagnostics with the same ID. Or a - // combination of the two may occur. - // We only want to show one node in Solution Explorer for a given ID. So we pick one, but we need - // to be consistent in which one we pick. Diagnostics with the same ID may have different - // descriptions or messages, and it would be strange if the node's name changed from one run of - // VS to another. So we group the diagnostics by ID, sort them within a group, and take the first - // one. - - Contract.ThrowIfFalse(HasItems); - - var collection = new BulkObservableCollection(); - collection.AddRange( - AnalyzerReference.GetAnalyzers(language) + var generalDiagnosticOption = project.CompilationOptions!.GeneralDiagnosticOption; + var specificDiagnosticOptions = project.CompilationOptions!.SpecificDiagnosticOptions; + var analyzerConfigOptions = project.GetAnalyzerConfigOptions(); + + return analyzerReference.GetAnalyzers(project.Language) .SelectMany(a => _diagnosticAnalyzerService.AnalyzerInfoCache.GetDiagnosticDescriptors(a)) .GroupBy(d => d.Id) .OrderBy(g => g.Key, StringComparer.CurrentCulture) - .Select(g => + .SelectAsArray(g => { var selectedDiagnostic = g.OrderBy(d => d, s_comparer).First(); - var effectiveSeverity = selectedDiagnostic.GetEffectiveSeverity(options, analyzerConfigOptions?.ConfigOptions, analyzerConfigOptions?.TreeOptions); - return new DiagnosticItem(projectId, AnalyzerReference, selectedDiagnostic, effectiveSeverity, CommandHandler); - })); - - collection.AddRange( - AnalyzerReference.GetGenerators(language) - .Select(g => new SourceGeneratorItem(projectId, g, AnalyzerReference))); - - return collection; + var effectiveSeverity = selectedDiagnostic.GetEffectiveSeverity( + project.CompilationOptions!, + analyzerConfigOptions?.ConfigOptions, + analyzerConfigOptions?.TreeOptions); + return (BaseItem)new DiagnosticItem(project.Id, analyzerReference, selectedDiagnostic, effectiveSeverity, CommandHandler); + }); } - private void OnWorkspaceChangedLookForOptionsChanges(object sender, WorkspaceChangeEventArgs e) + async Task> GenerateSourceGeneratorItemsAsync( + Project project, + AnalyzerReference analyzerReference) { - if (e.Kind is WorkspaceChangeKind.SolutionCleared or - WorkspaceChangeKind.SolutionReloaded or - WorkspaceChangeKind.SolutionRemoved) - { - Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForOptionsChanges; - } - else if (e.ProjectId == ProjectId) - { - if (e.Kind == WorkspaceChangeKind.ProjectRemoved) - { - Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForOptionsChanges; - } - else if (e.Kind == WorkspaceChangeKind.ProjectChanged) - { - OnProjectConfigurationChanged(); - } - else if (e.DocumentId != null) - { - switch (e.Kind) - { - case WorkspaceChangeKind.AnalyzerConfigDocumentAdded: - case WorkspaceChangeKind.AnalyzerConfigDocumentChanged: - case WorkspaceChangeKind.AnalyzerConfigDocumentReloaded: - case WorkspaceChangeKind.AnalyzerConfigDocumentRemoved: - OnProjectConfigurationChanged(); - break; - } - } - } - - return; + var identifies = await GetIdentitiesAsync().ConfigureAwait(false); + return identifies.SelectAsArray( + identity => (BaseItem)new SourceGeneratorItem(project.Id, identity, analyzerReference.FullPath)); + } - // Local functions. - void OnProjectConfigurationChanged() + async Task> GetIdentitiesAsync() + { + // Can only remote AnalyzerFileReferences over to the oop side. If we have another form of reference (like + // in tests), we'll just fall back to loading these in process. + if (analyzerReference is AnalyzerFileReference analyzerFileReference) { - var project = e.NewSolution.GetRequiredProject(ProjectId); - var newGeneralDiagnosticOption = project.CompilationOptions!.GeneralDiagnosticOption; - var newSpecificDiagnosticOptions = project.CompilationOptions!.SpecificDiagnosticOptions; - var newAnalyzerConfigOptions = project.GetAnalyzerConfigOptions(); - - if (newGeneralDiagnosticOption != _generalDiagnosticOption || - !object.ReferenceEquals(newSpecificDiagnosticOptions, _specificDiagnosticOptions) || - !object.ReferenceEquals(newAnalyzerConfigOptions?.TreeOptions, _analyzerConfigOptions?.TreeOptions) || - !object.ReferenceEquals(newAnalyzerConfigOptions?.ConfigOptions, _analyzerConfigOptions?.ConfigOptions)) + var client = await RemoteHostClient.TryGetClientAsync(this.Workspace, cancellationToken).ConfigureAwait(false); + if (client is not null) { - _generalDiagnosticOption = newGeneralDiagnosticOption; - _specificDiagnosticOptions = newSpecificDiagnosticOptions; - _analyzerConfigOptions = newAnalyzerConfigOptions; + var result = await client.TryInvokeAsync>( + project, + (service, solutionChecksum, cancellationToken) => service.GetSourceGeneratorIdentitiesAsync( + solutionChecksum, project.Id, analyzerFileReference.FullPath, cancellationToken), + cancellationToken).ConfigureAwait(false); - Contract.ThrowIfNull(_items, "We only subscribe to events after we create the items, so this should not be null."); + // If the call fails, the OOP substrate will have already reported an error + if (!result.HasValue) + return []; - foreach (var item in _items.OfType()) - { - var effectiveSeverity = item.Descriptor.GetEffectiveSeverity(project.CompilationOptions, newAnalyzerConfigOptions?.ConfigOptions, newAnalyzerConfigOptions?.TreeOptions); - item.UpdateEffectiveSeverity(effectiveSeverity); - } + return result.Value; } } + + // Do the work in process. + return SourceGeneratorIdentity.GetIdentities(analyzerReference, project.Language); + } + } + + private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) + { + switch (e.Kind) + { + // Solution is going away or being reloaded. The work queue will detect this and clean up accordingly. + case WorkspaceChangeKind.SolutionCleared: + case WorkspaceChangeKind.SolutionReloaded: + case WorkspaceChangeKind.SolutionRemoved: + // The project itself is being removed. The work queue will detect this and clean up accordingly. + case WorkspaceChangeKind.ProjectRemoved: + case WorkspaceChangeKind.ProjectChanged: + // Could change the severity of an analyzer. + case WorkspaceChangeKind.AnalyzerConfigDocumentAdded: + case WorkspaceChangeKind.AnalyzerConfigDocumentChanged: + case WorkspaceChangeKind.AnalyzerConfigDocumentReloaded: + case WorkspaceChangeKind.AnalyzerConfigDocumentRemoved: + _workQueue.AddWork(); + break; + default: + break; } } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs index 41eb9357fd5c9..2d7c2aa84cc51 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs @@ -8,115 +8,119 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Shell; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +internal sealed partial class CpsDiagnosticItemSource : BaseDiagnosticAndGeneratorItemSource, INotifyPropertyChanged { - internal partial class CpsDiagnosticItemSource : BaseDiagnosticAndGeneratorItemSource, INotifyPropertyChanged + private readonly IVsHierarchyItem _item; + private readonly string _projectDirectoryPath; + + public event PropertyChangedEventHandler? PropertyChanged; + + public CpsDiagnosticItemSource( + IThreadingContext threadingContext, + Workspace workspace, + string projectPath, + ProjectId projectId, + IVsHierarchyItem item, + IAnalyzersCommandHandler commandHandler, + IDiagnosticAnalyzerService analyzerService, + IAsynchronousOperationListenerProvider listenerProvider) + : base(threadingContext, workspace, projectId, commandHandler, analyzerService, listenerProvider) { - 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; + _item = item; + _projectDirectoryPath = Path.GetDirectoryName(projectPath); - public CpsDiagnosticItemSource(Workspace workspace, string projectPath, ProjectId projectId, IVsHierarchyItem item, IAnalyzersCommandHandler commandHandler, IDiagnosticAnalyzerService analyzerService) - : base(workspace, projectId, commandHandler, analyzerService) + this.AnalyzerReference = TryGetAnalyzerReference(Workspace.CurrentSolution); + if (this.AnalyzerReference == null) { - _item = item; - _projectDirectoryPath = Path.GetDirectoryName(projectPath); - - _analyzerReference = TryGetAnalyzerReference(Workspace.CurrentSolution); - if (_analyzerReference == null) + // 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)) { - // 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; + 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); + // 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(); - } + if (analyzerReference != null) + { + this.AnalyzerReference = analyzerReference; + UnsubscribeFromEvents(); } } } + } - private void UnsubscribeFromEvents() - { - Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; - _item.PropertyChanged -= IVsHierarchyItem_PropertyChanged; - } + private void UnsubscribeFromEvents() + { + Workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer; + _item.PropertyChanged -= IVsHierarchyItem_PropertyChanged; + } - private void IVsHierarchyItem_PropertyChanged(object sender, PropertyChangedEventArgs e) + 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)) { - // IVsHierarchyItem implements ISupportDisposalNotification, which allows us to know when it's been removed - if (e.PropertyName == nameof(ISupportDisposalNotification.IsDisposed)) - { - UnsubscribeFromEvents(); - } + UnsubscribeFromEvents(); } + } - public IContextMenuController DiagnosticItemContextMenuController => CommandHandler.DiagnosticContextMenuController; + public IContextMenuController DiagnosticItemContextMenuController => CommandHandler.DiagnosticContextMenuController; - public override object SourceItem => _item; + public override object SourceItem => _item; - public override AnalyzerReference? AnalyzerReference => _analyzerReference; + private void OnWorkspaceChangedLookForAnalyzer(object sender, WorkspaceChangeEventArgs e) + { + // 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)) + { + UnsubscribeFromEvents(); + return; + } - private void OnWorkspaceChangedLookForAnalyzer(object sender, WorkspaceChangeEventArgs e) + // Was this a change to our project, or a global change? + if (e.ProjectId == ProjectId || + e.Kind == WorkspaceChangeKind.SolutionChanged) { - // 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)) + var analyzerReference = TryGetAnalyzerReference(e.NewSolution); + if (analyzerReference != null) { + this.AnalyzerReference = analyzerReference; UnsubscribeFromEvents(); - return; - } - - // Was this a change to our project, or a global change? - if (e.ProjectId == ProjectId || - e.Kind == WorkspaceChangeKind.SolutionChanged) - { - var analyzerReference = TryGetAnalyzerReference(e.NewSolution); - if (analyzerReference != null) - { - _analyzerReference = analyzerReference; - UnsubscribeFromEvents(); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasItems))); - } + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasItems))); } } + } - private AnalyzerReference? TryGetAnalyzerReference(Solution solution) - { - var project = solution.GetProject(ProjectId); - - if (project == null) - { - return null; - } + private AnalyzerReference? TryGetAnalyzerReference(Solution solution) + { + var project = solution.GetProject(ProjectId); - var canonicalName = _item.CanonicalName; - var analyzerFilePath = CpsUtilities.ExtractAnalyzerFilePath(_projectDirectoryPath, canonicalName); + if (project == null) + { + return null; + } - if (string.IsNullOrEmpty(analyzerFilePath)) - { - return null; - } + var canonicalName = _item.CanonicalName; + var analyzerFilePath = CpsUtilities.ExtractAnalyzerFilePath(_projectDirectoryPath, canonicalName); - return project.AnalyzerReferences.FirstOrDefault(r => string.Equals(r.FullPath, analyzerFilePath, StringComparison.OrdinalIgnoreCase)); + if (string.IsNullOrEmpty(analyzerFilePath)) + { + return null; } + + return project.AnalyzerReferences.FirstOrDefault(r => string.Equals(r.FullPath, analyzerFilePath, StringComparison.OrdinalIgnoreCase)); } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSourceProvider.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSourceProvider.cs index b4720a60d12de..6983a954d3f69 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSourceProvider.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSourceProvider.cs @@ -7,162 +7,162 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.ProjectSystem; using Microsoft.VisualStudio.ProjectSystem.Properties; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +using OrderAttribute = Microsoft.VisualStudio.Utilities.OrderAttribute; +using Workspace = Microsoft.CodeAnalysis.Workspace; + +[Export(typeof(IAttachedCollectionSourceProvider))] +[Name(nameof(CpsDiagnosticItemSourceProvider))] +[Order] +[AppliesToProject($"({ProjectCapabilities.CSharp} | {ProjectCapabilities.VB}) & {ProjectCapabilities.Cps}")] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CpsDiagnosticItemSourceProvider( + IThreadingContext threadingContext, + [Import(typeof(AnalyzersCommandHandler))] IAnalyzersCommandHandler commandHandler, + IDiagnosticAnalyzerService diagnosticAnalyzerService, + VisualStudioWorkspace workspace, + IAsynchronousOperationListenerProvider listenerProvider) + : AttachedCollectionSourceProvider { - using OrderAttribute = Microsoft.VisualStudio.Utilities.OrderAttribute; - using Workspace = Microsoft.CodeAnalysis.Workspace; - - [Export(typeof(IAttachedCollectionSourceProvider))] - [Name(nameof(CpsDiagnosticItemSourceProvider))] - [Order] - [AppliesToProject($"({ProjectCapabilities.CSharp} | {ProjectCapabilities.VB}) & {ProjectCapabilities.Cps}")] - internal sealed class CpsDiagnosticItemSourceProvider : AttachedCollectionSourceProvider - { - private readonly IAnalyzersCommandHandler _commandHandler; - private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService; - private readonly Workspace _workspace; - - private IHierarchyItemToProjectIdMap? _projectMap; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CpsDiagnosticItemSourceProvider( - [Import(typeof(AnalyzersCommandHandler))] IAnalyzersCommandHandler commandHandler, - IDiagnosticAnalyzerService diagnosticAnalyzerService, - VisualStudioWorkspace workspace) - { - _commandHandler = commandHandler; - _diagnosticAnalyzerService = diagnosticAnalyzerService; - _workspace = workspace; - } + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly IAnalyzersCommandHandler _commandHandler = commandHandler; + private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService = diagnosticAnalyzerService; + private readonly Workspace _workspace = workspace; + private readonly IAsynchronousOperationListenerProvider _listenerProvider = listenerProvider; - protected override IAttachedCollectionSource? CreateCollectionSource(IVsHierarchyItem? item, string relationshipName) + private IHierarchyItemToProjectIdMap? _projectMap; + + protected override IAttachedCollectionSource? CreateCollectionSource(IVsHierarchyItem? item, string relationshipName) + { + if (item?.HierarchyIdentity?.NestedHierarchy != null && + !item.IsDisposed && + relationshipName == KnownRelationships.Contains) { - if (item?.HierarchyIdentity?.NestedHierarchy != null && - !item.IsDisposed && - relationshipName == KnownRelationships.Contains) + if (NestedHierarchyHasProjectTreeCapability(item, "AnalyzerDependency")) { - if (NestedHierarchyHasProjectTreeCapability(item, "AnalyzerDependency")) + var projectRootItem = FindProjectRootItem(item, out var targetFrameworkMoniker); + if (projectRootItem != null) { - var projectRootItem = FindProjectRootItem(item, out var targetFrameworkMoniker); - if (projectRootItem != null) + var hierarchyMapper = TryGetProjectMap(); + if (hierarchyMapper != null && + hierarchyMapper.TryGetProjectId(projectRootItem, targetFrameworkMoniker, out var projectId)) { - var hierarchyMapper = TryGetProjectMap(); - if (hierarchyMapper != null && - hierarchyMapper.TryGetProjectId(projectRootItem, targetFrameworkMoniker, out var projectId)) + var hierarchy = projectRootItem.HierarchyIdentity.NestedHierarchy; + var itemId = projectRootItem.HierarchyIdentity.NestedItemID; + if (hierarchy.GetCanonicalName(itemId, out var projectCanonicalName) == VSConstants.S_OK) { - var hierarchy = projectRootItem.HierarchyIdentity.NestedHierarchy; - var itemId = projectRootItem.HierarchyIdentity.NestedItemID; - if (hierarchy.GetCanonicalName(itemId, out var projectCanonicalName) == VSConstants.S_OK) - { - return new CpsDiagnosticItemSource(_workspace, projectCanonicalName, projectId, item, _commandHandler, _diagnosticAnalyzerService); - } + return new CpsDiagnosticItemSource( + _threadingContext, _workspace, projectCanonicalName, projectId, item, _commandHandler, _diagnosticAnalyzerService, _listenerProvider); } } } } - - return null; } - /// - /// Starting at the given item, walks up the tree to find the item representing the project root. - /// If the item is located under a target-framework specific node, the corresponding - /// TargetFrameworkMoniker will be found as well. - /// - private static IVsHierarchyItem? FindProjectRootItem(IVsHierarchyItem item, out string? targetFrameworkMoniker) + return null; + } + + /// + /// Starting at the given item, walks up the tree to find the item representing the project root. + /// If the item is located under a target-framework specific node, the corresponding + /// TargetFrameworkMoniker will be found as well. + /// + private static IVsHierarchyItem? FindProjectRootItem(IVsHierarchyItem item, out string? targetFrameworkMoniker) + { + targetFrameworkMoniker = null; + + for (var parent = item; parent != null; parent = parent.Parent) { - targetFrameworkMoniker = null; + targetFrameworkMoniker ??= GetTargetFrameworkMoniker(parent); - for (var parent = item; parent != null; parent = parent.Parent) + if (NestedHierarchyHasProjectTreeCapability(parent, "ProjectRoot")) { - targetFrameworkMoniker ??= GetTargetFrameworkMoniker(parent); - - if (NestedHierarchyHasProjectTreeCapability(parent, "ProjectRoot")) - { - return parent; - } + return parent; } - - return null; } - /// - /// Given an item determines if it represents a particular target framework. - /// If so, it returns the corresponding TargetFrameworkMoniker. - /// - private static string? GetTargetFrameworkMoniker(IVsHierarchyItem item) - { - if (TryGetFlags(item, out var flags) && - flags.Contains("TargetNode")) - { - const string prefix = "$TFM:"; - var flag = flags.FirstOrDefault(f => f.StartsWith(prefix)); + return null; + } - return flag?.Substring(prefix.Length); - } + /// + /// Given an item determines if it represents a particular target framework. + /// If so, it returns the corresponding TargetFrameworkMoniker. + /// + private static string? GetTargetFrameworkMoniker(IVsHierarchyItem item) + { + if (TryGetFlags(item, out var flags) && + flags.Contains("TargetNode")) + { + const string prefix = "$TFM:"; + var flag = flags.FirstOrDefault(f => f.StartsWith(prefix)); - return null; + return flag?.Substring(prefix.Length); } - private static bool NestedHierarchyHasProjectTreeCapability(IVsHierarchyItem item, string capability) - { - if (TryGetFlags(item, out var flags)) - return flags.Contains(capability); + return null; + } - return false; - } + private static bool NestedHierarchyHasProjectTreeCapability(IVsHierarchyItem item, string capability) + { + if (TryGetFlags(item, out var flags)) + return flags.Contains(capability); + + return false; + } - public static bool TryGetFlags(IVsHierarchyItem item, out ProjectTreeFlags flags) + public static bool TryGetFlags(IVsHierarchyItem item, out ProjectTreeFlags flags) + { + if (item.HierarchyIdentity.IsRoot) { - if (item.HierarchyIdentity.IsRoot) + if (item.HierarchyIdentity.NestedHierarchy is IVsBrowseObjectContext { UnconfiguredProject.Services.ProjectTreeService.CurrentTree.Tree: { } tree }) { - if (item.HierarchyIdentity.NestedHierarchy is IVsBrowseObjectContext { UnconfiguredProject.Services.ProjectTreeService.CurrentTree.Tree: { } tree }) - { - flags = tree.Flags; - return true; - } + flags = tree.Flags; + return true; } - else + } + else + { + var itemId = item.HierarchyIdentity.ItemID; + + // Browse objects are created lazily, and we want to avoid creating them when possible. + // This method is typically invoked for every hierarchy item in the tree, via Solution Explorer APIs. + // Rather than create a browse object for every node, we find the project root node and use that. + // In this way, we only ever create one browse object per project. + var root = item; + while (!root.HierarchyIdentity.IsRoot) { - var itemId = item.HierarchyIdentity.ItemID; - - // Browse objects are created lazily, and we want to avoid creating them when possible. - // This method is typically invoked for every hierarchy item in the tree, via Solution Explorer APIs. - // Rather than create a browse object for every node, we find the project root node and use that. - // In this way, we only ever create one browse object per project. - var root = item; - while (!root.HierarchyIdentity.IsRoot) - { - root = root.Parent; - } + root = root.Parent; + } - if (root.HierarchyIdentity.NestedHierarchy is IVsBrowseObjectContext { UnconfiguredProject.Services.ProjectTreeService.CurrentTree.Tree: { } tree }) + if (root.HierarchyIdentity.NestedHierarchy is IVsBrowseObjectContext { UnconfiguredProject.Services.ProjectTreeService.CurrentTree.Tree: { } tree }) + { + if (tree?.TryFind((IntPtr)itemId, out var subtree) == true) { - if (tree?.TryFind((IntPtr)itemId, out var subtree) == true) - { - flags = subtree.Flags; - return true; - } + flags = subtree.Flags; + return true; } } - - flags = default; - return false; } - private IHierarchyItemToProjectIdMap? TryGetProjectMap() - { - _projectMap ??= _workspace.Services.GetService(); + flags = default; + return false; + } - return _projectMap; - } + private IHierarchyItemToProjectIdMap? TryGetProjectMap() + { + _projectMap ??= _workspace.Services.GetService(); + + return _projectMap; } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs index 59d281e2075bf..14e0d8ba9f9c8 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs @@ -9,146 +9,79 @@ using Microsoft.VisualStudio.Shell; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +internal sealed partial class DiagnosticItem { - internal sealed partial class DiagnosticItem + internal sealed class BrowseObject(DiagnosticItem diagnosticItem) : LocalizableProperties { - internal class BrowseObject : LocalizableProperties - { - private readonly DiagnosticItem _diagnosticItem; + [Browsable(false)] + public DiagnosticItem DiagnosticItem { get; } = diagnosticItem; - public BrowseObject(DiagnosticItem diagnosticItem) - { - _diagnosticItem = diagnosticItem; - } + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.ID))] + public string Id => DiagnosticItem.Descriptor.Id; - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.ID))] - public string Id - { - get - { - return _diagnosticItem.Descriptor.Id; - } - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Title))] - public string Title - { - get - { - return _diagnosticItem.Descriptor.Title.ToString(CultureInfo.CurrentUICulture); - } - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Description))] - public string Description - { - get - { - return _diagnosticItem.Descriptor.Description.ToString(CultureInfo.CurrentUICulture); - } - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Help_link))] - public string? HelpLink - { - get - { - return _diagnosticItem.Descriptor.GetValidHelpLinkUri()?.AbsoluteUri; - } - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Category))] - public string Category - { - get - { - return _diagnosticItem.Descriptor.Category; - } - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Default_severity))] - public string DefaultSeverity - { - get - { - return MapDiagnosticSeverityToText(_diagnosticItem.Descriptor.DefaultSeverity); - } - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Enabled_by_default))] - public bool EnabledByDefault - { - get - { - return _diagnosticItem.Descriptor.IsEnabledByDefault; - } - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Message))] - public string Message - { - get - { - return _diagnosticItem.Descriptor.MessageFormat.ToString(CultureInfo.CurrentUICulture); - } - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Tags))] - public string Tags - { - get - { - return string.Join(" ", _diagnosticItem.Descriptor.CustomTags); - } - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Effective_severity))] - public string EffectiveSeverity - { - get - { - return MapReportDiagnosticToText(_diagnosticItem.EffectiveSeverity); - } - } + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Title))] + public string Title => DiagnosticItem.Descriptor.Title.ToString(CultureInfo.CurrentUICulture); - public override string GetClassName() - { - return SolutionExplorerShim.Diagnostic_Properties; - } + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Description))] + public string Description => DiagnosticItem.Descriptor.Description.ToString(CultureInfo.CurrentUICulture); - public override string GetComponentName() - { - return _diagnosticItem.Descriptor.Id; - } + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Help_link))] + public string? HelpLink => DiagnosticItem.Descriptor.GetValidHelpLinkUri()?.AbsoluteUri; - [Browsable(false)] - public DiagnosticItem DiagnosticItem - { - get { return _diagnosticItem; } - } - - private static string MapDiagnosticSeverityToText(DiagnosticSeverity severity) - => severity switch - { - DiagnosticSeverity.Hidden => SolutionExplorerShim.Hidden, - DiagnosticSeverity.Info => SolutionExplorerShim.Info, - DiagnosticSeverity.Warning => SolutionExplorerShim.Warning, - DiagnosticSeverity.Error => SolutionExplorerShim.Error_, - _ => throw ExceptionUtilities.UnexpectedValue(severity), - }; - - private static string MapReportDiagnosticToText(ReportDiagnostic report) - => report switch - { - ReportDiagnostic.Default => SolutionExplorerShim.Default_, - ReportDiagnostic.Error => SolutionExplorerShim.Error_, - ReportDiagnostic.Warn => SolutionExplorerShim.Warning, - ReportDiagnostic.Info => SolutionExplorerShim.Info, - ReportDiagnostic.Hidden => SolutionExplorerShim.Hidden, - ReportDiagnostic.Suppress => SolutionExplorerShim.Suppressed, - _ => throw ExceptionUtilities.UnexpectedValue(report), - }; + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Category))] + public string Category => DiagnosticItem.Descriptor.Category; + + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Default_severity))] + public string DefaultSeverity + => MapDiagnosticSeverityToText(DiagnosticItem.Descriptor.DefaultSeverity); + + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Enabled_by_default))] + public bool EnabledByDefault => DiagnosticItem.Descriptor.IsEnabledByDefault; + + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Message))] + public string Message + => DiagnosticItem.Descriptor.MessageFormat.ToString(CultureInfo.CurrentUICulture); + + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Tags))] + public string Tags + => string.Join(" ", DiagnosticItem.Descriptor.CustomTags); + + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Effective_severity))] + public string EffectiveSeverity + => MapReportDiagnosticToText(DiagnosticItem._effectiveSeverity); + + public override string GetClassName() + { + return SolutionExplorerShim.Diagnostic_Properties; + } + + public override string GetComponentName() + { + return DiagnosticItem.Descriptor.Id; } + + private static string MapDiagnosticSeverityToText(DiagnosticSeverity severity) + => severity switch + { + DiagnosticSeverity.Hidden => SolutionExplorerShim.Hidden, + DiagnosticSeverity.Info => SolutionExplorerShim.Info, + DiagnosticSeverity.Warning => SolutionExplorerShim.Warning, + DiagnosticSeverity.Error => SolutionExplorerShim.Error_, + _ => throw ExceptionUtilities.UnexpectedValue(severity), + }; + + private static string MapReportDiagnosticToText(ReportDiagnostic report) + => report switch + { + ReportDiagnostic.Default => SolutionExplorerShim.Default_, + ReportDiagnostic.Error => SolutionExplorerShim.Error_, + ReportDiagnostic.Warn => SolutionExplorerShim.Warning, + ReportDiagnostic.Info => SolutionExplorerShim.Info, + ReportDiagnostic.Hidden => SolutionExplorerShim.Hidden, + ReportDiagnostic.Suppress => SolutionExplorerShim.Suppressed, + _ => throw ExceptionUtilities.UnexpectedValue(report), + }; } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.cs index 5a6eed07e4a9f..79544dd6610a0 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.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 System.ComponentModel; +using System; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; @@ -12,81 +12,77 @@ using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; +using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer -{ - internal partial class DiagnosticItem : BaseItem - { - private readonly AnalyzerReference _analyzerReference; - private readonly IAnalyzersCommandHandler _commandHandler; +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; - public ProjectId ProjectId { get; } - public DiagnosticDescriptor Descriptor { get; } - public ReportDiagnostic EffectiveSeverity { get; private set; } +internal sealed partial class DiagnosticItem( + ProjectId projectId, + AnalyzerReference analyzerReference, + DiagnosticDescriptor descriptor, + ReportDiagnostic effectiveSeverity, + IAnalyzersCommandHandler commandHandler) + : BaseItem(descriptor.Id + ": " + descriptor.Title), IEquatable +{ + private readonly AnalyzerReference _analyzerReference = analyzerReference; + private readonly IAnalyzersCommandHandler _commandHandler = commandHandler; - public override event PropertyChangedEventHandler? PropertyChanged; + public ProjectId ProjectId { get; } = projectId; + public DiagnosticDescriptor Descriptor { get; } = descriptor; + private readonly ReportDiagnostic _effectiveSeverity = effectiveSeverity; - public DiagnosticItem(ProjectId projectId, AnalyzerReference analyzerReference, DiagnosticDescriptor descriptor, ReportDiagnostic effectiveSeverity, IAnalyzersCommandHandler commandHandler) - : base(descriptor.Id + ": " + descriptor.Title) - { - ProjectId = projectId; - _analyzerReference = analyzerReference; - Descriptor = descriptor; - EffectiveSeverity = effectiveSeverity; - _commandHandler = commandHandler; - } + public override ImageMoniker IconMoniker + => MapEffectiveSeverityToIconMoniker(_effectiveSeverity); - public override ImageMoniker IconMoniker - => MapEffectiveSeverityToIconMoniker(EffectiveSeverity); + public override IContextMenuController ContextMenuController => _commandHandler.DiagnosticContextMenuController; - public override IContextMenuController ContextMenuController => _commandHandler.DiagnosticContextMenuController; + public override object GetBrowseObject() + => new BrowseObject(this); - public override object GetBrowseObject() + private static ImageMoniker MapEffectiveSeverityToIconMoniker(ReportDiagnostic effectiveSeverity) + => effectiveSeverity switch { - return new BrowseObject(this); - } + ReportDiagnostic.Error => KnownMonikers.CodeErrorRule, + ReportDiagnostic.Warn => KnownMonikers.CodeWarningRule, + ReportDiagnostic.Info => KnownMonikers.CodeInformationRule, + ReportDiagnostic.Hidden => KnownMonikers.CodeHiddenRule, + ReportDiagnostic.Suppress => KnownMonikers.CodeSuppressedRule, + _ => default, + }; + + internal void SetRuleSetSeverity(ReportDiagnostic value, string pathToRuleSet) + { + var ruleSetDocument = XDocument.Load(pathToRuleSet); - internal void UpdateEffectiveSeverity(ReportDiagnostic newEffectiveSeverity) - { - if (EffectiveSeverity != newEffectiveSeverity) - { - EffectiveSeverity = newEffectiveSeverity; - - NotifyPropertyChanged(nameof(EffectiveSeverity)); - NotifyPropertyChanged(nameof(IconMoniker)); - } - } - - private static ImageMoniker MapEffectiveSeverityToIconMoniker(ReportDiagnostic effectiveSeverity) - => effectiveSeverity switch - { - ReportDiagnostic.Error => KnownMonikers.CodeErrorRule, - ReportDiagnostic.Warn => KnownMonikers.CodeWarningRule, - ReportDiagnostic.Info => KnownMonikers.CodeInformationRule, - ReportDiagnostic.Hidden => KnownMonikers.CodeHiddenRule, - ReportDiagnostic.Suppress => KnownMonikers.CodeSuppressedRule, - _ => default, - }; - - private void NotifyPropertyChanged(string propertyName) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } + ruleSetDocument.SetSeverity(_analyzerReference.Display, Descriptor.Id, value); - internal void SetRuleSetSeverity(ReportDiagnostic value, string pathToRuleSet) - { - var ruleSetDocument = XDocument.Load(pathToRuleSet); + ruleSetDocument.Save(pathToRuleSet); + } - ruleSetDocument.SetSeverity(_analyzerReference.Display, Descriptor.Id, value); + internal Task GetSolutionWithUpdatedAnalyzerConfigSeverityAsync(ReportDiagnostic value, Project project, CancellationToken cancellationToken) + { + var effectiveSeverity = value.ToDiagnosticSeverity() ?? Descriptor.DefaultSeverity; + var diagnostic = Diagnostic.Create(Descriptor, Location.None, effectiveSeverity, additionalLocations: null, properties: null); + return ConfigurationUpdater.ConfigureSeverityAsync(value, diagnostic, project, cancellationToken); + } - ruleSetDocument.Save(pathToRuleSet); - } + public override int GetHashCode() + => Hash.Combine(this.Name, + Hash.Combine(this.ProjectId, + Hash.Combine(this.Descriptor.GetHashCode(), (int)_effectiveSeverity))); - internal Task GetSolutionWithUpdatedAnalyzerConfigSeverityAsync(ReportDiagnostic value, Project project, CancellationToken cancellationToken) - { - var effectiveSeverity = value.ToDiagnosticSeverity() ?? Descriptor.DefaultSeverity; - var diagnostic = Diagnostic.Create(Descriptor, Location.None, effectiveSeverity, additionalLocations: null, properties: null); - return ConfigurationUpdater.ConfigureSeverityAsync(value, diagnostic, project, cancellationToken); - } + public override bool Equals(object obj) + => Equals(obj as DiagnosticItem); + + public bool Equals(DiagnosticItem? other) + { + if (this == other) + return true; + + return other != null && + this.Name == other.Name && + this.ProjectId == other.ProjectId && + this.Descriptor.Equals(other.Descriptor) && + _effectiveSeverity == other._effectiveSeverity; } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/LegacyDiagnosticItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/LegacyDiagnosticItemSource.cs index 611598537081e..e88a2616faac6 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/LegacyDiagnosticItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/LegacyDiagnosticItemSource.cs @@ -3,20 +3,32 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Shared.TestHooks; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer -{ - internal partial class LegacyDiagnosticItemSource : BaseDiagnosticAndGeneratorItemSource - { - private readonly AnalyzerItem _item; +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; - public LegacyDiagnosticItemSource(AnalyzerItem item, IAnalyzersCommandHandler commandHandler, IDiagnosticAnalyzerService diagnosticAnalyzerService) - : base(item.AnalyzersFolder.Workspace, item.AnalyzersFolder.ProjectId, commandHandler, diagnosticAnalyzerService) - { - _item = item; - } +internal sealed partial class LegacyDiagnosticItemSource : BaseDiagnosticAndGeneratorItemSource +{ + private readonly AnalyzerItem _item; - public override object SourceItem => _item; - public override AnalyzerReference AnalyzerReference => _item.AnalyzerReference; + public LegacyDiagnosticItemSource( + IThreadingContext threadingContext, + AnalyzerItem item, + IAnalyzersCommandHandler commandHandler, + IDiagnosticAnalyzerService diagnosticAnalyzerService, + IAsynchronousOperationListenerProvider listenerProvider) + : base( + threadingContext, + item.AnalyzersFolder.Workspace, + item.AnalyzersFolder.ProjectId, + commandHandler, + diagnosticAnalyzerService, + listenerProvider) + { + _item = item; + this.AnalyzerReference = item.AnalyzerReference; } + + public override object SourceItem => _item; } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/LegacyDiagnosticItemSourceProvider.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/LegacyDiagnosticItemSourceProvider.cs index c48962188a1f3..f0513880d775f 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/LegacyDiagnosticItemSourceProvider.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/LegacyDiagnosticItemSourceProvider.cs @@ -5,40 +5,35 @@ using System; using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +[Export(typeof(IAttachedCollectionSourceProvider))] +[Name(nameof(LegacyDiagnosticItemSourceProvider))] +[Order] +[AppliesToProject("(CSharp | VB) & !CPS")] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class LegacyDiagnosticItemSourceProvider( + IThreadingContext threadingContext, + [Import(typeof(AnalyzersCommandHandler))] IAnalyzersCommandHandler commandHandler, + IDiagnosticAnalyzerService diagnosticAnalyzerService, + IAsynchronousOperationListenerProvider listenerProvider) : AttachedCollectionSourceProvider { - [Export(typeof(IAttachedCollectionSourceProvider))] - [Name(nameof(LegacyDiagnosticItemSourceProvider))] - [Order] - [AppliesToProject("(CSharp | VB) & !CPS")] - internal sealed class LegacyDiagnosticItemSourceProvider : AttachedCollectionSourceProvider + protected override IAttachedCollectionSource? CreateCollectionSource(AnalyzerItem item, string relationshipName) { - private readonly IAnalyzersCommandHandler _commandHandler; - private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public LegacyDiagnosticItemSourceProvider( - [Import(typeof(AnalyzersCommandHandler))] IAnalyzersCommandHandler commandHandler, - IDiagnosticAnalyzerService diagnosticAnalyzerService) + if (relationshipName == KnownRelationships.Contains) { - _commandHandler = commandHandler; - _diagnosticAnalyzerService = diagnosticAnalyzerService; + return new LegacyDiagnosticItemSource( + threadingContext, item, commandHandler, diagnosticAnalyzerService, listenerProvider); } - protected override IAttachedCollectionSource? CreateCollectionSource(AnalyzerItem item, string relationshipName) - { - if (relationshipName == KnownRelationships.Contains) - { - return new LegacyDiagnosticItemSource(item, _commandHandler, _diagnosticAnalyzerService); - } - - return null; - } + return null; } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/SourceGeneratorItem.BrowseObject.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/SourceGeneratorItem.BrowseObject.cs index 27939c54c48e2..0949019cea990 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/SourceGeneratorItem.BrowseObject.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/SourceGeneratorItem.BrowseObject.cs @@ -4,27 +4,19 @@ using Microsoft.VisualStudio.Shell; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +internal sealed partial class SourceGeneratorItem { - internal sealed partial class SourceGeneratorItem + internal sealed class BrowseObject(SourceGeneratorItem sourceGeneratorItem) : LocalizableProperties { - internal sealed class BrowseObject : LocalizableProperties - { - private readonly SourceGeneratorItem _sourceGeneratorItem; - - public BrowseObject(SourceGeneratorItem sourceGeneratorItem) - { - _sourceGeneratorItem = sourceGeneratorItem; - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Type_Name))] - public string TypeName => _sourceGeneratorItem.Identity.TypeName; + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Type_Name))] + public string TypeName => sourceGeneratorItem.Identity.TypeName; - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Path))] - public string? Path => _sourceGeneratorItem.AnalyzerReference.FullPath; + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Path))] + public string? Path => sourceGeneratorItem._path; - public override string GetClassName() => SolutionExplorerShim.Source_Generator_Properties; - public override string GetComponentName() => TypeName; - } + public override string GetClassName() => SolutionExplorerShim.Source_Generator_Properties; + public override string GetComponentName() => TypeName; } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/SourceGeneratorItem.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/SourceGeneratorItem.cs index 2728157932efc..d7a8ce4a0d773 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/SourceGeneratorItem.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/SourceGeneratorItem.cs @@ -2,33 +2,47 @@ // 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; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; +using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +internal sealed partial class SourceGeneratorItem( + ProjectId projectId, + SourceGeneratorIdentity identity, + string? path) : BaseItem(identity.TypeName), IEquatable { - internal sealed partial class SourceGeneratorItem : BaseItem + public ProjectId ProjectId { get; } = projectId; + public SourceGeneratorIdentity Identity { get; } = identity; + private readonly string? _path = path; + + // TODO: do we need an icon for our use? + public override ImageMoniker IconMoniker + => KnownMonikers.Process; + + public override object GetBrowseObject() + => new BrowseObject(this); + + public override int GetHashCode() + => Hash.Combine(this.Name, + Hash.Combine(this.ProjectId, + Hash.Combine(_path, this.Identity.GetHashCode()))); + + public override bool Equals(object obj) + => Equals(obj as SourceGeneratorItem); + + public bool Equals(SourceGeneratorItem? other) { - public ProjectId ProjectId { get; } - public SourceGeneratorIdentity Identity { get; } - public AnalyzerReference AnalyzerReference { get; } - - public SourceGeneratorItem(ProjectId projectId, ISourceGenerator generator, AnalyzerReference analyzerReference) - : base(name: SourceGeneratorIdentity.GetGeneratorTypeName(generator)) - { - ProjectId = projectId; - Identity = SourceGeneratorIdentity.Create(generator, analyzerReference); - AnalyzerReference = analyzerReference; - } - - // TODO: do we need an icon for our use? - public override ImageMoniker IconMoniker => KnownMonikers.Process; - - public override object GetBrowseObject() - { - return new BrowseObject(this); - } + if (this == other) + return true; + + return other != null && + this.Name == other.Name && + this.ProjectId == other.ProjectId && + this.Identity == other.Identity && + _path == other._path; } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/NoSourceGeneratedFilesPlaceholderItem.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/NoSourceGeneratedFilesPlaceholderItem.cs index 59bcb740f9da3..9c8b2e5cc5265 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/NoSourceGeneratedFilesPlaceholderItem.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/NoSourceGeneratedFilesPlaceholderItem.cs @@ -5,15 +5,11 @@ using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer -{ - internal sealed class NoSourceGeneratedFilesPlaceholderItem : BaseItem - { - public NoSourceGeneratedFilesPlaceholderItem() - : base(SolutionExplorerShim.This_generator_is_not_generating_files) - { - } +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; - public override ImageMoniker IconMoniker => KnownMonikers.StatusInformationNoColor; - } +internal sealed class NoSourceGeneratedFilesPlaceholderItem() + : BaseItem(SolutionExplorerShim.This_generator_is_not_generating_files) +{ + public override ImageMoniker IconMoniker + => KnownMonikers.StatusInformationNoColor; } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItem.BrowseObject.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItem.BrowseObject.cs index c137f50ce7dde..28c9a7648f966 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItem.BrowseObject.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItem.BrowseObject.cs @@ -4,24 +4,16 @@ using Microsoft.VisualStudio.Shell; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +internal sealed partial class SourceGeneratedFileItem { - internal sealed partial class SourceGeneratedFileItem + private sealed class BrowseObject(SourceGeneratedFileItem sourceGeneratedFileItem) : LocalizableProperties { - private class BrowseObject : LocalizableProperties - { - private readonly SourceGeneratedFileItem _sourceGeneratedFileItem; - - public BrowseObject(SourceGeneratedFileItem sourceGeneratedFileItem) - { - _sourceGeneratedFileItem = sourceGeneratedFileItem; - } - - [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Name))] - public string Name => _sourceGeneratedFileItem.HintName; + [BrowseObjectDisplayName(nameof(SolutionExplorerShim.Name))] + public string Name => sourceGeneratedFileItem.HintName; - public override string GetClassName() => SolutionExplorerShim.Source_Generated_File_Properties; - public override string GetComponentName() => _sourceGeneratedFileItem.HintName; - } + public override string GetClassName() => SolutionExplorerShim.Source_Generated_File_Properties; + public override string GetComponentName() => sourceGeneratedFileItem.HintName; } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItem.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItem.cs index 23e999b0d2d22..3d88e6dbcd0cf 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItem.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItem.cs @@ -12,77 +12,60 @@ using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer -{ - internal sealed partial class SourceGeneratedFileItem : BaseItem - { - private readonly IThreadingContext _threadingContext; - private readonly string _languageName; - - public SourceGeneratedFileItem( - IThreadingContext threadingContext, - DocumentId documentId, - string hintName, - string languageName, - Workspace workspace) - : base(name: hintName) - { - _threadingContext = threadingContext; - DocumentId = documentId; - HintName = hintName; - _languageName = languageName; - Workspace = workspace; - } +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; - public DocumentId DocumentId { get; } - public string HintName { get; } - public Workspace Workspace { get; } +internal sealed partial class SourceGeneratedFileItem( + IThreadingContext threadingContext, + DocumentId documentId, + string hintName, + string languageName, + Workspace workspace) + : BaseItem(name: hintName) +{ + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly string _languageName = languageName; - public override ImageMoniker IconMoniker - => _languageName switch - { - LanguageNames.CSharp => KnownMonikers.CSFileNode, - LanguageNames.VisualBasic => KnownMonikers.VBFileNode, - _ => KnownMonikers.Document - }; + public DocumentId DocumentId { get; } = documentId; + public string HintName { get; } = hintName; + public Workspace Workspace { get; } = workspace; - public override object GetBrowseObject() + public override ImageMoniker IconMoniker + => _languageName switch { - return new BrowseObject(this); - } + LanguageNames.CSharp => KnownMonikers.CSFileNode, + LanguageNames.VisualBasic => KnownMonikers.VBFileNode, + _ => KnownMonikers.Document + }; - public override IInvocationController InvocationController - => new InvocationControllerImpl(_threadingContext); + public override object GetBrowseObject() + => new BrowseObject(this); - private sealed class InvocationControllerImpl : IInvocationController - { - private readonly IThreadingContext _threadingContext; + public override IInvocationController InvocationController + => new InvocationControllerImpl(_threadingContext); - public InvocationControllerImpl(IThreadingContext threadingContext) - { - _threadingContext = threadingContext; - } + private sealed class InvocationControllerImpl(IThreadingContext threadingContext) : IInvocationController + { + private readonly IThreadingContext _threadingContext = threadingContext; - public bool Invoke(IEnumerable items, InputSource inputSource, bool preview) + public bool Invoke(IEnumerable items, InputSource inputSource, bool preview) + { + return _threadingContext.JoinableTaskFactory.Run(async () => { - return _threadingContext.JoinableTaskFactory.Run(async () => + var didNavigate = false; + foreach (var item in items.OfType()) { - var didNavigate = false; - foreach (var item in items.OfType()) + var documentNavigationService = item.Workspace.Services.GetService(); + if (documentNavigationService != null) { - var documentNavigationService = item.Workspace.Services.GetService(); - if (documentNavigationService != null) - { - // TODO: we're navigating back to the top of the file, do we have a way to just bring it to the focus and that's it? - // TODO: Use a threaded-wait-dialog here so we can cancel navigation. - didNavigate |= await documentNavigationService.TryNavigateToPositionAsync( - item._threadingContext, item.Workspace, item.DocumentId, position: 0, CancellationToken.None).ConfigureAwait(false); - } + // TODO: we're navigating back to the top of the file, do we have a way to just bring it to the focus and that's it? + // TODO: Use a threaded-wait-dialog here so we can cancel navigation. + didNavigate |= await documentNavigationService.TryNavigateToPositionAsync( + item._threadingContext, item.Workspace, item.DocumentId, position: 0, CancellationToken.None).ConfigureAwait(false); } + } - return didNavigate; - }); - } + return didNavigate; + }); } } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs index 4994510a99414..96bc24025d51c 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs @@ -10,273 +10,258 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Language.Intellisense; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; + +internal sealed class SourceGeneratedFileItemSource( + SourceGeneratorItem parentGeneratorItem, + IThreadingContext threadingContext, + Workspace workspace, + IAsynchronousOperationListener asyncListener) + : Shell.IAttachedCollectionSource, ISupportExpansionEvents { - internal class SourceGeneratedFileItemSource : Shell.IAttachedCollectionSource, ISupportExpansionEvents + private readonly SourceGeneratorItem _parentGeneratorItem = parentGeneratorItem; + private readonly IThreadingContext _threadingContext = threadingContext; + private readonly Workspace _workspace = workspace; + private readonly IAsynchronousOperationListener _asyncListener = asyncListener; + + /// + /// The returned collection of items. Can only be mutated on the UI thread, as other parts of WPF are subscribed to + /// the change events and expect that. + /// + private readonly BulkObservableCollectionWithInit _items = []; + + /// + /// Gate to guard mutation of . + /// + private readonly object _gate = new(); + + private readonly CancellationSeries _cancellationSeries = new(); + private ResettableDelay? _resettableDelay; + + public object SourceItem => _parentGeneratorItem; + + // Since we are expensive to compute, always say we have items. + public bool HasItems => true; + + public IEnumerable Items => _items; + + private async Task UpdateSourceGeneratedFileItemsAsync(Solution solution, CancellationToken cancellationToken) { - private readonly SourceGeneratorItem _parentGeneratorItem; - private readonly Workspace _workspace; - private readonly IAsynchronousOperationListener _asyncListener; - private readonly IThreadingContext _threadingContext; - - /// - /// The returned collection of items. Can only be mutated on the UI thread, as other parts of WPF are subscribed to the change - /// events and expect that. - /// - private readonly BulkObservableCollectionWithInit _items; - - /// - /// Gate to guard mutation of . - /// - private readonly object _gate = new object(); - - private readonly CancellationSeries _cancellationSeries = new(); - private ResettableDelay? _resettableDelay; - - public SourceGeneratedFileItemSource(SourceGeneratorItem parentGeneratorItem, Workspace workspace, IAsynchronousOperationListener asyncListener, IThreadingContext threadingContext) + var project = solution.GetProject(_parentGeneratorItem.ProjectId); + + if (project == null) { - // Construction of BulkObservableCollection requires the main thread - threadingContext.ThrowIfNotOnUIThread(); - _items = new BulkObservableCollectionWithInit(); - - _parentGeneratorItem = parentGeneratorItem; - _workspace = workspace; - _asyncListener = asyncListener; - _threadingContext = threadingContext; + return; } - public object SourceItem => _parentGeneratorItem; + var sourceGeneratedDocuments = await project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); + var sourceGeneratedDocumentsForGeneratorById = + sourceGeneratedDocuments.Where(d => d.Identity.Generator == _parentGeneratorItem.Identity) + .ToDictionary(d => d.Id); - public bool HasItems + // We must update the list on the UI thread, since the WPF elements bound to our list expect that + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + try { - get + // We're going to incrementally update our items, ensuring we keep the object identity for things we didn't touch. + // This is because the Solution Explorer itself will use identity to keep track of active items -- if you have an + // item selected and we were to refresh in the background we don't want to lose that selection. If we just removed + // and repopulated the list from scratch each time we'd lose the selection. + _items.BeginBulkOperation(); + + // Do we already have a "no files" placeholder item? + if (_items is [NoSourceGeneratedFilesPlaceholderItem]) { - // Since we are expensive to compute, always say we have items. - return true; + // We do -- if we have no items, we're done, since the placeholder is all that needs to be there; + // otherwise remove it since we have real files now + if (sourceGeneratedDocumentsForGeneratorById.Count == 0) + { + return; + } + else + { + _items.RemoveAt(0); + } } - } - - public IEnumerable Items => _items; - private async Task UpdateSourceGeneratedFileItemsAsync(Solution solution, CancellationToken cancellationToken) - { - var project = solution.GetProject(_parentGeneratorItem.ProjectId); + for (var i = 0; i < _items.Count; i++) + { + // If this item that we already have is still a generated document, we'll remove it from our list; the list when we're + // done is going to have the new items remaining. If it no longer exists, remove it from list. + if (!sourceGeneratedDocumentsForGeneratorById.Remove(((SourceGeneratedFileItem)_items[i]).DocumentId)) + { + _items.RemoveAt(i); + i--; + } + } - if (project == null) + // Whatever is left in sourceGeneratedDocumentsForGeneratorById we should add; if we have nothing to add and nothing + // in the list after removing anything, then we should add the placeholder. + if (sourceGeneratedDocumentsForGeneratorById.Count == 0 && _items.Count == 0) { + _items.Add(new NoSourceGeneratedFilesPlaceholderItem()); return; } - var sourceGeneratedDocuments = await project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); - var sourceGeneratedDocumentsForGeneratorById = - sourceGeneratedDocuments.Where(d => d.Identity.Generator == _parentGeneratorItem.Identity) - .ToDictionary(d => d.Id); - - // We must update the list on the UI thread, since the WPF elements bound to our list expect that - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - - try + foreach (var document in sourceGeneratedDocumentsForGeneratorById.Values) { - // We're going to incrementally update our items, ensuring we keep the object identity for things we didn't touch. - // This is because the Solution Explorer itself will use identity to keep track of active items -- if you have an - // item selected and we were to refresh in the background we don't want to lose that selection. If we just removed - // and repopulated the list from scratch each time we'd lose the selection. - _items.BeginBulkOperation(); - - // Do we already have a "no files" placeholder item? - if (_items is [NoSourceGeneratedFilesPlaceholderItem]) + // Binary search to figure out where to insert + var low = 0; + var high = _items.Count; + + while (low < high) { - // We do -- if we have no items, we're done, since the placeholder is all that needs to be there; - // otherwise remove it since we have real files now - if (sourceGeneratedDocumentsForGeneratorById.Count == 0) + var mid = (low + high) / 2; + + if (StringComparer.OrdinalIgnoreCase.Compare(document.HintName, ((SourceGeneratedFileItem)_items[mid]).HintName) < 0) { - return; + high = mid; } else { - _items.RemoveAt(0); + low = mid + 1; } } - for (var i = 0; i < _items.Count; i++) - { - // If this item that we already have is still a generated document, we'll remove it from our list; the list when we're - // done is going to have the new items remaining. If it no longer exists, remove it from list. - if (!sourceGeneratedDocumentsForGeneratorById.Remove(((SourceGeneratedFileItem)_items[i]).DocumentId)) - { - _items.RemoveAt(i); - i--; - } - } + _items.Insert(low, new SourceGeneratedFileItem( + _threadingContext, document.Id, document.HintName, document.Project.Language, _workspace)); + } + } + finally + { + _items.EndBulkOperation(); + _items.MarkAsInitialized(); + } + } - // Whatever is left in sourceGeneratedDocumentsForGeneratorById we should add; if we have nothing to add and nothing - // in the list after removing anything, then we should add the placeholder. - if (sourceGeneratedDocumentsForGeneratorById.Count == 0 && _items.Count == 0) - { - _items.Add(new NoSourceGeneratedFilesPlaceholderItem()); - return; - } + public void BeforeExpand() + { + lock (_gate) + { + // We should not have an existing computation active + Contract.ThrowIfTrue(_cancellationSeries.HasActiveToken); + + var cancellationToken = _cancellationSeries.CreateNext(); + var asyncToken = _asyncListener.BeginAsyncOperation(nameof(SourceGeneratedFileItemSource) + "." + nameof(BeforeExpand)); - foreach (var document in sourceGeneratedDocumentsForGeneratorById.Values) + Task.Run( + async () => { - // Binary search to figure out where to insert - var low = 0; - var high = _items.Count; + // Since the user just expanded this, we want to do a single population aggressively, + // where the only reason we'd cancel is if the user collapsed it again. + var solution = _workspace.CurrentSolution; + await UpdateSourceGeneratedFileItemsAsync(solution, cancellationToken).ConfigureAwait(false); - while (low < high) + // Now that we've done it the first time, we'll subscribe for future changes + lock (_gate) { - var mid = (low + high) / 2; + // It's important we check for cancellation inside our lock: if the user were to collapse + // right at this point, we don't want to have a case where we cancelled the work, unsubscribed + // in AfterCollapse, and _then_ subscribed here again. - if (StringComparer.OrdinalIgnoreCase.Compare(document.HintName, ((SourceGeneratedFileItem)_items[mid]).HintName) < 0) - { - high = mid; - } - else + cancellationToken.ThrowIfCancellationRequested(); + _workspace.WorkspaceChanged += OnWorkpaceChanged; + if (_workspace.CurrentSolution != solution) { - low = mid + 1; + // The workspace changed while we were doing our initial population, so + // refresh it. We'll just call our OnWorkspaceChanged event handler + // so this looks like any other change. + OnWorkpaceChanged(this, + new WorkspaceChangeEventArgs(WorkspaceChangeKind.SolutionChanged, solution, _workspace.CurrentSolution)); } } - - _items.Insert(low, new SourceGeneratedFileItem( - _threadingContext, document.Id, document.HintName, document.Project.Language, _workspace)); - } - } - finally - { - _items.EndBulkOperation(); - _items.MarkAsInitialized(); - } + }, + cancellationToken).CompletesAsyncOperation(asyncToken); } + } - public void BeforeExpand() - { - lock (_gate) - { - // We should not have an existing computation active - Contract.ThrowIfTrue(_cancellationSeries.HasActiveToken); - - var cancellationToken = _cancellationSeries.CreateNext(); - var asyncToken = _asyncListener.BeginAsyncOperation(nameof(SourceGeneratedFileItemSource) + "." + nameof(BeforeExpand)); - - Task.Run( - async () => - { - // Since the user just expanded this, we want to do a single population aggressively, - // where the only reason we'd cancel is if the user collapsed it again. - var solution = _workspace.CurrentSolution; - await UpdateSourceGeneratedFileItemsAsync(solution, cancellationToken).ConfigureAwait(false); + public void AfterCollapse() + { + StopUpdating(); + } - // Now that we've done it the first time, we'll subscribe for future changes - lock (_gate) - { - // It's important we check for cancellation inside our lock: if the user were to collapse - // right at this point, we don't want to have a case where we cancelled the work, unsubscribed - // in AfterCollapse, and _then_ subscribed here again. - - cancellationToken.ThrowIfCancellationRequested(); - _workspace.WorkspaceChanged += OnWorkpaceChanged; - if (_workspace.CurrentSolution != solution) - { - // The workspace changed while we were doing our initial population, so - // refresh it. We'll just call our OnWorkspaceChanged event handler - // so this looks like any other change. - OnWorkpaceChanged(this, - new WorkspaceChangeEventArgs(WorkspaceChangeKind.SolutionChanged, solution, _workspace.CurrentSolution)); - } - } - }, - cancellationToken).CompletesAsyncOperation(asyncToken); - } + private void StopUpdating() + { + lock (_gate) + { + _cancellationSeries.CreateNext(new CancellationToken(canceled: true)); + _workspace.WorkspaceChanged -= OnWorkpaceChanged; + _resettableDelay = null; } + } - public void AfterCollapse() + private void OnWorkpaceChanged(object sender, WorkspaceChangeEventArgs e) + { + if (!e.NewSolution.ContainsProject(_parentGeneratorItem.ProjectId)) { StopUpdating(); } - private void StopUpdating() + lock (_gate) { - lock (_gate) + // If we already have a ResettableDelay, just delay it further; otherwise we either have no delay + // or the actual processing began, and we need to start over + if (_resettableDelay != null) { - _cancellationSeries.CreateNext(new CancellationToken(canceled: true)); - _workspace.WorkspaceChanged -= OnWorkpaceChanged; - _resettableDelay = null; + _resettableDelay.Reset(); } - } - - private void OnWorkpaceChanged(object sender, WorkspaceChangeEventArgs e) - { - if (!e.NewSolution.ContainsProject(_parentGeneratorItem.ProjectId)) + else { - StopUpdating(); - } + // Time to start the work all over again. We'll ensure any previous work is cancelled + var cancellationToken = _cancellationSeries.CreateNext(); + var asyncToken = _asyncListener.BeginAsyncOperation(nameof(SourceGeneratedFileItemSource) + "." + nameof(OnWorkpaceChanged)); - lock (_gate) - { - // If we already have a ResettableDelay, just delay it further; otherwise we either have no delay - // or the actual processing began, and we need to start over - if (_resettableDelay != null) - { - _resettableDelay.Reset(); - } - else + // We're going to go with a really long delay: once the user expands this we will keep it updated, but it's fairly + // unlikely to change in a lot of cases if a generator only produces a stable set of names. + _resettableDelay = new ResettableDelay(delayInMilliseconds: 5000, _asyncListener, cancellationToken); + _resettableDelay.Task.ContinueWith(_ => { - // Time to start the work all over again. We'll ensure any previous work is cancelled - var cancellationToken = _cancellationSeries.CreateNext(); - var asyncToken = _asyncListener.BeginAsyncOperation(nameof(SourceGeneratedFileItemSource) + "." + nameof(OnWorkpaceChanged)); - - // We're going to go with a really long delay: once the user expands this we will keep it updated, but it's fairly - // unlikely to change in a lot of cases if a generator only produces a stable set of names. - _resettableDelay = new ResettableDelay(delayInMilliseconds: 5000, _asyncListener, cancellationToken); - _resettableDelay.Task.ContinueWith(_ => + lock (_gate) { - lock (_gate) - { - // We've started off this work, so if another change comes in we need to start a delay all over again - _resettableDelay = null; - } + // We've started off this work, so if another change comes in we need to start a delay all over again + _resettableDelay = null; + } - cancellationToken.ThrowIfCancellationRequested(); + cancellationToken.ThrowIfCancellationRequested(); - return UpdateSourceGeneratedFileItemsAsync(_workspace.CurrentSolution, cancellationToken); - }, cancellationToken, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default).Unwrap().CompletesAsyncOperation(asyncToken); - } + return UpdateSourceGeneratedFileItemsAsync(_workspace.CurrentSolution, cancellationToken); + }, cancellationToken, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Default).Unwrap().CompletesAsyncOperation(asyncToken); } } + } - /// - /// This derivation of also supports raising an initialized event through - /// . This is used to show the spinning icon in the solution explorer - /// the first time you expand it. - /// - private sealed class BulkObservableCollectionWithInit : BulkObservableCollection, ISupportInitializeNotification - { - public bool IsInitialized { get; private set; } = false; + /// + /// This derivation of also supports raising an initialized event through + /// . This is used to show the spinning icon in the solution explorer + /// the first time you expand it. + /// + private sealed class BulkObservableCollectionWithInit : BulkObservableCollection, ISupportInitializeNotification + { + public bool IsInitialized { get; private set; } = false; - public event EventHandler? Initialized; + public event EventHandler? Initialized; - void ISupportInitialize.BeginInit() - { - } + void ISupportInitialize.BeginInit() + { + } - void ISupportInitialize.EndInit() - { - } + void ISupportInitialize.EndInit() + { + } - public void MarkAsInitialized() + public void MarkAsInitialized() + { + if (!IsInitialized) { - if (!IsInitialized) - { - IsInitialized = true; - Initialized?.Invoke(this, EventArgs.Empty); - } + IsInitialized = true; + Initialized?.Invoke(this, EventArgs.Empty); } } } diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSourceProvider.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSourceProvider.cs index 5387e7674c712..a08d9aa9f0bcd 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSourceProvider.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSourceProvider.cs @@ -4,7 +4,6 @@ using System; using System.ComponentModel.Composition; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -12,35 +11,23 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer -{ - [Export(typeof(IAttachedCollectionSourceProvider))] - [Name(nameof(SourceGeneratedFileItemSourceProvider))] - [Order] - [AppliesToProject("CSharp | VB")] - internal sealed class SourceGeneratedFileItemSourceProvider : AttachedCollectionSourceProvider - { - private readonly Workspace _workspace; - private readonly IAsynchronousOperationListener _asyncListener; - private readonly IThreadingContext _threadingContext; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public SourceGeneratedFileItemSourceProvider(VisualStudioWorkspace workspace, IAsynchronousOperationListenerProvider asyncListenerProvider, IThreadingContext threadingContext) - { - _workspace = workspace; - _asyncListener = asyncListenerProvider.GetListener(FeatureAttribute.SourceGenerators); - _threadingContext = threadingContext; - } +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer; - protected override IAttachedCollectionSource? CreateCollectionSource(SourceGeneratorItem item, string relationshipName) - { - if (relationshipName == KnownRelationships.Contains) - { - return new SourceGeneratedFileItemSource(item, _workspace, _asyncListener, _threadingContext); - } +[Export(typeof(IAttachedCollectionSourceProvider))] +[Name(nameof(SourceGeneratedFileItemSourceProvider)), Order] +[AppliesToProject("CSharp | VB")] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class SourceGeneratedFileItemSourceProvider( + VisualStudioWorkspace workspace, + IAsynchronousOperationListenerProvider asyncListenerProvider, + IThreadingContext threadingContext) + : AttachedCollectionSourceProvider +{ + private readonly IAsynchronousOperationListener _asyncListener = asyncListenerProvider.GetListener(FeatureAttribute.SourceGenerators); - return null; - } - } + protected override IAttachedCollectionSource? CreateCollectionSource(SourceGeneratorItem item, string relationshipName) + => relationshipName == KnownRelationships.Contains + ? new SourceGeneratedFileItemSource(item, threadingContext, workspace, _asyncListener) + : null; } diff --git a/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs b/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs index e120803d1b302..664c25c3a3306 100644 --- a/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs +++ b/src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs @@ -64,7 +64,7 @@ internal static Solution SetFullSolution(Workspace workspace) .AddAdditionalDocument("Additional", SourceText.From("hello"), ImmutableArray.Create("test"), @".\Add").Project.Solution; return solution - .WithAnalyzerReferences(new[] { new AnalyzerFileReference(Path.Combine(TempRoot.Root, "path2"), new TestAnalyzerAssemblyLoader()) }) + .WithAnalyzerReferences([new AnalyzerFileReference(Path.Combine(TempRoot.Root, "path2"), new TestAnalyzerAssemblyLoader())]) .AddAnalyzerConfigDocuments( ImmutableArray.Create( DocumentInfo.Create( @@ -491,13 +491,13 @@ public async Task SnapshotWithIdenticalAnalyzerFiles() var analyzer1 = new AnalyzerFileReference(file1.Path, TestAnalyzerAssemblyLoader.LoadNotImplemented); var analyzer2 = new AnalyzerFileReference(file2.Path, TestAnalyzerAssemblyLoader.LoadNotImplemented); - project = project.AddAnalyzerReferences(new[] { analyzer1, analyzer2 }); + project = project.AddAnalyzerReferences([analyzer1, analyzer2]); var validator = new SerializationValidator(workspace.Services); using var snapshot = await validator.AssetStorage.StoreAssetsAsync(project.Solution, CancellationToken.None); var recovered = await validator.GetSolutionAsync(snapshot); - AssertEx.Equal(new[] { file1.Path, file2.Path }, recovered.GetProject(project.Id).AnalyzerReferences.Select(r => r.FullPath)); + AssertEx.Equal([file1.Path, file2.Path], recovered.GetProject(project.Id).AnalyzerReferences.Select(r => r.FullPath)); } [Fact] diff --git a/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs b/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs index dbac2896b8a7d..dedc0e4e8c2a1 100644 --- a/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs @@ -53,7 +53,7 @@ private static async Task TestAssetAsync(object data) var storage = new SolutionAssetCache(); var assetSource = new SimpleAssetSource(workspace.Services.GetService(), new Dictionary() { { checksum, data } }); - var provider = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.GetService()); + var provider = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.SolutionServices); var stored = await provider.GetAssetAsync(AssetPath.FullLookupForTesting, checksum, CancellationToken.None); Assert.Equal(data, stored); @@ -84,7 +84,7 @@ public async Task TestAssetSynchronization() var storage = new SolutionAssetCache(); var assetSource = new SimpleAssetSource(workspace.Services.GetService(), map); - var service = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.GetService()); + var service = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.SolutionServices); await service.GetAssetsAsync(AssetPath.FullLookupForTesting, new HashSet(map.Keys), CancellationToken.None); foreach (var kv in map) @@ -112,7 +112,7 @@ public async Task TestSolutionSynchronization() var storage = new SolutionAssetCache(); var assetSource = new SimpleAssetSource(workspace.Services.GetService(), map); - var service = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.GetService()); + var service = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.SolutionServices); await service.SynchronizeSolutionAssetsAsync(await solution.CompilationState.GetChecksumAsync(CancellationToken.None), CancellationToken.None); TestUtils.VerifyAssetStorage(map, storage); @@ -137,7 +137,7 @@ public async Task TestProjectSynchronization() var storage = new SolutionAssetCache(); var assetSource = new SimpleAssetSource(workspace.Services.GetService(), map); - var service = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.GetService()); + var service = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.SolutionServices); using var _ = ArrayBuilder.GetInstance(out var allProjectChecksums); allProjectChecksums.Add(await project.State.GetStateChecksumsAsync(CancellationToken.None)); @@ -166,7 +166,7 @@ public async Task TestAssetArrayOrdering() var storage = new SolutionAssetCache(); var assetSource = new OrderedAssetSource(workspace.Services.GetService(), map); - var service = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.GetService()); + var service = new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.SolutionServices); using var _ = ArrayBuilder.GetInstance(out var allProjectChecksums); var stateChecksums = await project.State.GetStateChecksumsAsync(CancellationToken.None); diff --git a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs index ba4f8206eae2a..7017305b4ede9 100644 --- a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs @@ -115,7 +115,7 @@ private static async Task GetAssetProviderAsync(Workspace workspa var storage = new SolutionAssetCache(); var assetSource = new SimpleAssetSource(workspace.Services.GetService(), map); - return new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.GetService()); + return new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.SolutionServices); } [Fact] @@ -352,15 +352,14 @@ public async Task TestRemoteWorkspaceCircularReferences() var solutionInfo = SolutionInfo.Create( SolutionId.CreateNewId(), VersionStamp.Create(), "", - new[] - { - ProjectInfo.Create( - p1, VersionStamp.Create(), "p1", "p1", LanguageNames.CSharp, outputFilePath: file.Path, - projectReferences: new [] { new ProjectReference(p2) }), - ProjectInfo.Create( - p2, VersionStamp.Create(), "p2", "p2", LanguageNames.CSharp, - metadataReferences: new [] { MetadataReference.CreateFromFile(file.Path) }) - }); + [ + ProjectInfo.Create( + p1, VersionStamp.Create(), "p1", "p1", LanguageNames.CSharp, outputFilePath: file.Path, + projectReferences: [new ProjectReference(p2)]), + ProjectInfo.Create( + p2, VersionStamp.Create(), "p2", "p2", LanguageNames.CSharp, + metadataReferences: [MetadataReference.CreateFromFile(file.Path)]) + ]); using var remoteWorkspace = new RemoteWorkspace(FeaturesTestCompositions.RemoteHost.GetHostServices()); diff --git a/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs b/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs index d29b517e0df49..75e0de07585db 100644 --- a/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/SolutionServiceTests.cs @@ -290,7 +290,7 @@ public async Task TestUpdateDocumentInfo() { var code = @"class Test { void Method() { } }"; - await VerifySolutionUpdate(code, s => s.WithDocumentFolders(s.Projects.First().Documents.First().Id, new[] { "test" })); + await VerifySolutionUpdate(code, s => s.WithDocumentFolders(s.Projects.First().Documents.First().Id, ["test"])); } [Fact] @@ -548,7 +548,7 @@ public async Task TestPartialProjectSync_GetSolutionFirst() var map = new Dictionary(); var assetProvider = new AssetProvider( - Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.GetService()); + Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.SolutionServices); // Do the initial full sync await solution.AppendAssetMapAsync(map, CancellationToken.None); @@ -589,7 +589,7 @@ public async Task TestPartialProjectSync_GetSolutionLast() var map = new Dictionary(); var assetProvider = new AssetProvider( - Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.GetService()); + Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.SolutionServices); // Syncing project 1 should just since it over. await solution.AppendAssetMapAsync(map, project1.Id, CancellationToken.None); @@ -631,7 +631,7 @@ public async Task TestPartialProjectSync_GetDependentProjects1() var map = new Dictionary(); var assetProvider = new AssetProvider( - Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.GetService()); + Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.SolutionServices); await solution.AppendAssetMapAsync(map, project2.Id, CancellationToken.None); var project2Checksum = await solution.CompilationState.GetChecksumAsync(project2.Id, CancellationToken.None); @@ -664,7 +664,7 @@ public async Task TestPartialProjectSync_GetDependentProjects2() var map = new Dictionary(); var assetProvider = new AssetProvider( - Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.GetService()); + Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.SolutionServices); // syncing P3 should since project P2 as well because of the p2p ref await solution.AppendAssetMapAsync(map, project3.Id, CancellationToken.None); @@ -706,7 +706,7 @@ public async Task TestPartialProjectSync_GetDependentProjects3() var map = new Dictionary(); var assetProvider = new AssetProvider( - Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.GetService()); + Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.SolutionServices); // syncing project3 should since project2 and project1 as well because of the p2p ref await solution.AppendAssetMapAsync(map, project3.Id, CancellationToken.None); @@ -746,7 +746,7 @@ public async Task TestPartialProjectSync_GetDependentProjects4() var map = new Dictionary(); var assetProvider = new AssetProvider( - Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.GetService()); + Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.SolutionServices); // syncing project3 should since project2 and project1 as well because of the p2p ref await solution.AppendAssetMapAsync(map, project3.Id, CancellationToken.None); @@ -784,7 +784,7 @@ public async Task TestPartialProjectSync_Options1() var map = new Dictionary(); var assetProvider = new AssetProvider( - Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.GetService()); + Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.SolutionServices); // Syncing over project1 should give us 1 set of options on the OOP side. await solution.AppendAssetMapAsync(map, project1.Id, CancellationToken.None); @@ -817,7 +817,7 @@ public async Task TestPartialProjectSync_DoesNotSeeChangesOutsideOfCone() var map = new Dictionary(); var assetProvider = new AssetProvider( - Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.GetService()); + Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.SolutionServices); // Do the initial full sync await solution.AppendAssetMapAsync(map, CancellationToken.None); @@ -872,7 +872,7 @@ public async Task TestPartialProjectSync_AddP2PRef() var map = new Dictionary(); var assetProvider = new AssetProvider( - Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.GetService()); + Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.SolutionServices); // Do the initial full sync await solution.AppendAssetMapAsync(map, CancellationToken.None); @@ -941,7 +941,7 @@ public async Task TestPartialProjectSync_SourceGeneratorExecutionVersion_1() var map = new Dictionary(); var assetProvider = new AssetProvider( - Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.GetService()); + Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())), new SolutionAssetCache(), new SimpleAssetSource(workspace.Services.GetService(), map), remoteWorkspace.Services.SolutionServices); // Do the initial full sync await solution.AppendAssetMapAsync(map, CancellationToken.None); @@ -1277,6 +1277,6 @@ private static async Task GetAssetProviderAsync(Workspace workspa var storage = new SolutionAssetCache(); var assetSource = new SimpleAssetSource(workspace.Services.GetRequiredService(), map); - return new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.GetRequiredService()); + return new AssetProvider(sessionId, storage, assetSource, remoteWorkspace.Services.SolutionServices); } } diff --git a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs index 075d54d66fad1..4eedc603d04e6 100644 --- a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs @@ -137,7 +137,7 @@ void Method() var analyzerType = typeof(CSharpUseExplicitTypeDiagnosticAnalyzer); var analyzerReference = new AnalyzerFileReference(analyzerType.Assembly.Location, new TestAnalyzerAssemblyLoader()); - workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(new[] { analyzerReference })); + workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference])); workspace.GlobalOptions.SetGlobalOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent, new CodeStyleOption(false, NotificationOption.Suggestion)); diff --git a/src/VisualStudio/Core/Test/Options/BasicEditorConfigGeneratorTests.vb b/src/VisualStudio/Core/Test/Options/BasicEditorConfigGeneratorTests.vb index 9239f35bce3d3..33c67f60f3bd7 100644 --- a/src/VisualStudio/Core/Test/Options/BasicEditorConfigGeneratorTests.vb +++ b/src/VisualStudio/Core/Test/Options/BasicEditorConfigGeneratorTests.vb @@ -40,6 +40,11 @@ insert_final_newline = false # Type members dotnet_hide_advanced_members = false +dotnet_member_insertion_location = with_other_members_of_the_same_kind +dotnet_property_generation_behavior = prefer_throwing_properties + +# Symbol search +dotnet_search_reference_assemblies = true #### .NET Coding Conventions #### @@ -188,6 +193,11 @@ insert_final_newline = false # Type members dotnet_hide_advanced_members = false +dotnet_member_insertion_location = with_other_members_of_the_same_kind +dotnet_property_generation_behavior = prefer_throwing_properties + +# Symbol search +dotnet_search_reference_assemblies = true #### .NET Coding Conventions #### diff --git a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb index 4ffd7d0f8026c..e3be0cb90efd8 100644 --- a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb +++ b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb @@ -38,6 +38,11 @@ insert_final_newline = false # Type members dotnet_hide_advanced_members = false +dotnet_member_insertion_location = with_other_members_of_the_same_kind +dotnet_property_generation_behavior = prefer_throwing_properties + +# Symbol search +dotnet_search_reference_assemblies = true #### .NET Coding Conventions #### @@ -292,6 +297,11 @@ insert_final_newline = false # Type members dotnet_hide_advanced_members = false +dotnet_member_insertion_location = with_other_members_of_the_same_kind +dotnet_property_generation_behavior = prefer_throwing_properties + +# Symbol search +dotnet_search_reference_assemblies = true #### .NET Coding Conventions #### diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicCompilerOptionsTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicCompilerOptionsTests.vb index 864d175cd1398..f723dceff60a8 100644 --- a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicCompilerOptionsTests.vb +++ b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicCompilerOptionsTests.vb @@ -50,7 +50,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim End Using End Sub - + Public Sub SetCompilerOptions_LangVersion14() Using environment = New TestEnvironment() Dim project = CreateVisualBasicProject(environment, "Test") @@ -73,7 +73,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim End Using End Sub - + Public Sub SetCompilerOptions_LangVersion15() Using environment = New TestEnvironment() Dim project = CreateVisualBasicProject(environment, "Test") @@ -96,7 +96,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim End Using End Sub - + Public Sub SetCompilerOptions_LangVersionDefault() Using environment = New TestEnvironment() Dim project = CreateVisualBasicProject(environment, "Test") @@ -116,7 +116,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim End Using End Sub - + Public Sub SetCompilerOptions_LangVersion15_3() Using environment = New TestEnvironment() Dim project = CreateVisualBasicProject(environment, "Test") @@ -136,7 +136,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim End Using End Sub - + Public Sub SetCompilerOptions_LangVersionLatest() Using environment = New TestEnvironment() Dim project = CreateVisualBasicProject(environment, "Test") diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicProjectTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicProjectTests.vb index f4bb0b8d96bbe..f3bbf9d5026a9 100644 --- a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicProjectTests.vb +++ b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicProjectTests.vb @@ -11,7 +11,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim <[UseExportProvider]> Public Class VisualBasicProjectTests - + Public Sub RenameProjectUpdatesWorkspace() Using environment = New TestEnvironment() Dim project = CreateVisualBasicProject(environment, "Test") @@ -27,7 +27,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim End Using End Sub - + Public Sub DisconnectingAProjectDoesNotLeak() Using environment = New TestEnvironment() Dim project = ObjectReference.CreateFromFactory(Function() CreateVisualBasicProject(environment, "Test")) diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicSpecialReferencesTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicSpecialReferencesTests.vb index ea51fa5e8856d..f55b5ee018f79 100644 --- a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicSpecialReferencesTests.vb +++ b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualBasicSpecialReferencesTests.vb @@ -12,7 +12,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim <[UseExportProvider]> Public Class VisualBasicSpecialReferencesTests - + Public Sub ProjectIncludesReferencesToMscorlibSystemAndMicrosoftVisualBasic() Using environment = New TestEnvironment() Dim project = CreateVisualBasicProject(environment, "Test") @@ -29,7 +29,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim End Using End Sub - + Public Sub ProjectWithoutStandardLibsDoesNotReferenceSystem() Using environment = New TestEnvironment() Dim project = CreateVisualBasicProject(environment, "Test") @@ -48,7 +48,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim End Using End Sub - + Public Sub ProjectWithoutVisualBasicRuntimeDoesNotReferenceMicrosoftVisualBasic() Using environment = New TestEnvironment() Dim project = CreateVisualBasicProject(environment, "Test") diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioAnalyzerTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioAnalyzerTests.vb deleted file mode 100644 index e8131e4d47625..0000000000000 --- a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioAnalyzerTests.vb +++ /dev/null @@ -1,74 +0,0 @@ -' Licensed to the .NET Foundation under one or more agreements. -' The .NET Foundation licenses this file to you under the MIT license. -' See the LICENSE file in the project root for more information. - -Imports System.Collections.Immutable -Imports System.IO -Imports System.Reflection -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Diagnostics -Imports Microsoft.CodeAnalysis.Editor.UnitTests -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.Host -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 - -Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim - - - Public Class VisualStudioAnalyzerTests - Private Shared ReadOnly s_compositionWithMockDiagnosticUpdateSourceRegistrationService As TestComposition = EditorTestCompositions.EditorFeatures - - - Public Sub GetReferenceCalledMultipleTimes() - Using workspace = New TestWorkspace(composition:=s_compositionWithMockDiagnosticUpdateSourceRegistrationService) - Dim provider = workspace.Services.GetRequiredService(Of IAnalyzerAssemblyLoaderProvider) - Dim service = provider.GetLoader(shadowCopy:=True) - Using tempRoot = New TempRoot(), analyzer = New ProjectAnalyzerReference(tempRoot.CreateFile().Path, service, HostDiagnosticUpdateSource.Instance, ProjectId.CreateNewId(), LanguageNames.VisualBasic) - Dim reference1 = analyzer.GetReference() - Dim reference2 = analyzer.GetReference() - - Assert.True(Object.ReferenceEquals(reference1, reference2)) - End Using - End Using - End Sub - - Private Class EventHandlers - Public File As String - - Public Sub New(file As String) - Me.File = file - End Sub - - Public Sub DiagnosticAddedTest(o As Object, e As ImmutableArray(Of DiagnosticsUpdatedArgs)) - Dim diagnostics = e.Single().Diagnostics - Assert.Equal(1, diagnostics.Length) - Dim diagnostic As DiagnosticData = diagnostics.First() - Assert.Equal("BC42378", diagnostic.Id) - Assert.Contains(File, diagnostic.Message, StringComparison.Ordinal) - End Sub - - Public Shared Sub DiagnosticRemovedTest(o As Object, e As ImmutableArray(Of DiagnosticsUpdatedArgs)) - Dim diagnostics = e.Single().Diagnostics - Assert.Equal(0, diagnostics.Length) - End Sub - End Class - - Private Class MockAnalyzerAssemblyLoader - Implements IAnalyzerAssemblyLoader - - Public Sub AddDependencyLocation(fullPath As String) Implements IAnalyzerAssemblyLoader.AddDependencyLocation - Throw New NotImplementedException() - End Sub - - Public Function LoadFromPath(fullPath As String) As Assembly Implements IAnalyzerAssemblyLoader.LoadFromPath - Throw New NotImplementedException() - End Function - End Class - End Class -End Namespace diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb index 47a8b12842377..a8354283cebcf 100644 --- a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb +++ b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb @@ -195,7 +195,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim Dim project = Await environment.ProjectFactory.CreateAndAddToWorkspaceAsync( "Project", LanguageNames.CSharp, CancellationToken.None) - ' add Razor source generator and a couple more other analyzer filess: + ' add Razor source generator and a couple more other analyzer files: Dim path1 = Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk.Razor", "source-generators", "Microsoft.NET.Sdk.Razor.SourceGenerators.dll") Dim path2 = Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk.Razor", "source-generators", "SdkDependency1.dll") project.AddAnalyzerReference(path1) @@ -204,5 +204,57 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim AssertEx.Equal({path1, path2}, environment.Workspace.CurrentSolution.Projects.Single().AnalyzerReferences.Select(Function(r) r.FullPath)) End Using End Function + + + Public Async Function CodeStyleAnalyzers_CSharp_FromSdk_AreIgnored() As Task + Using environment = New TestEnvironment() + Dim project = Await environment.ProjectFactory.CreateAndAddToWorkspaceAsync( + "Project", LanguageNames.CSharp, CancellationToken.None) + + ' These are the in-box C# codestyle analyzers that ship with the SDK + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CodeStyle.dll")) + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CodeStyle.Fixes.dll")) + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CSharp.CodeStyle.dll")) + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "cs", "Microsoft.CodeAnalysis.CSharp.CodeStyle.Fixes.dll")) + + ' Ensure they are not returned when getting AnalyzerReferences + Assert.Empty(environment.Workspace.CurrentSolution.Projects.Single().AnalyzerReferences) + + ' Add a non-codestyle analyzer to the project + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Dir", "File.dll")) + + ' Ensure it is returned as expected + AssertEx.Equal( + { + Path.Combine(TempRoot.Root, "Dir", "File.dll") + }, environment.Workspace.CurrentSolution.Projects.Single().AnalyzerReferences.Select(Function(r) r.FullPath)) + End Using + End Function + + + Public Async Function CodeStyleAnalyzers_VisualBasic_FromSdk_AreIgnored() As Task + Using environment = New TestEnvironment() + Dim project = Await environment.ProjectFactory.CreateAndAddToWorkspaceAsync( + "Project", LanguageNames.VisualBasic, CancellationToken.None) + + ' These are the in-box VB codestyle analyzers that ship with the SDK + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "vb", "Microsoft.CodeAnalysis.CodeStyle.dll")) + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "vb", "Microsoft.CodeAnalysis.CodeStyle.Fixes.dll")) + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "vb", "Microsoft.CodeAnalysis.VisualBasic.CodeStyle.dll")) + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Sdks", "Microsoft.NET.Sdk", "codestyle", "vb", "Microsoft.CodeAnalysis.VisualBasic.CodeStyle.Fixes.dll")) + + ' Ensure they are not returned when getting AnalyzerReferences + Assert.Empty(environment.Workspace.CurrentSolution.Projects.Single().AnalyzerReferences) + + ' Add a non-codestyle analyzer to the project + project.AddAnalyzerReference(Path.Combine(TempRoot.Root, "Dir", "File.dll")) + + ' Ensure it is returned as expected + AssertEx.Equal( + { + Path.Combine(TempRoot.Root, "Dir", "File.dll") + }, environment.Workspace.CurrentSolution.Projects.Single().AnalyzerReferences.Select(Function(r) r.FullPath)) + End Using + End Function End Class End Namespace diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/ProjectSystemProjectFactoryTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/ProjectSystemProjectFactoryTests.vb new file mode 100644 index 0000000000000..3b744dfa4fd93 --- /dev/null +++ b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/ProjectSystemProjectFactoryTests.vb @@ -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. + +Imports System.Collections.Immutable +Imports System.Threading +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.Workspaces.ProjectSystem +Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem +Imports Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Framework +Imports Roslyn.Test.Utilities + +Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim + <[UseExportProvider]> + Public Class ProjectSystemProjectFactoryTests + + Public Async Function ProjectInstantiatedWithCompilationOutputAssemblyFilePathCanBeChanged() As Task + Using environment = New TestEnvironment() + Dim creationInfo = New VisualStudioProjectCreationInfo() + creationInfo.CompilationOutputAssemblyFilePath = "C:\output\project.dll" + Dim project1 = Await environment.ProjectFactory.CreateAndAddToWorkspaceAsync( + "project1", LanguageNames.CSharp, creationInfo, CancellationToken.None) + + Dim projectInSolution = environment.Workspace.CurrentSolution.GetProject(project1.Id) + + Assert.Equal(creationInfo.CompilationOutputAssemblyFilePath, projectInSolution.CompilationOutputInfo.AssemblyPath) + + ' Change the path and ensure it's updated + Dim newOutputPath = "C:\output\new\project.dll" + project1.CompilationOutputAssemblyFilePath = newOutputPath + + Dim newProjectInSolution As Project = environment.Workspace.CurrentSolution.GetProject(project1.Id) + Assert.Equal(newOutputPath, newProjectInSolution.CompilationOutputInfo.AssemblyPath) + End Using + End Function + End Class +End Namespace diff --git a/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerItemTests.vb b/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerItemTests.vb index 488f6983675c6..937376086056b 100644 --- a/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerItemTests.vb +++ b/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerItemTests.vb @@ -2,13 +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. +Imports Microsoft.CodeAnalysis.Editor.[Shared].Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.VisualStudio.LanguageServices.Implementation Imports Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer - <[UseExportProvider]> + Public Class AnalyzerItemTests @@ -23,7 +24,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Using workspace = EditorTestWorkspace.Create(workspaceXml) Dim project = workspace.Projects.Single() - Dim analyzerFolder = New AnalyzersFolderItem(workspace, project.Id, Nothing, Nothing) + Dim analyzerFolder = New AnalyzersFolderItem(workspace.GetService(Of IThreadingContext), workspace, project.Id, Nothing, Nothing) Dim analyzer = New AnalyzerItem(analyzerFolder, project.AnalyzerReferences.Single(), Nothing) Assert.Equal(expected:="Goo", actual:=analyzer.Text) @@ -42,7 +43,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Using workspace = EditorTestWorkspace.Create(workspaceXml) Dim project = workspace.Projects.Single() - Dim analyzerFolder = New AnalyzersFolderItem(workspace, project.Id, Nothing, Nothing) + Dim analyzerFolder = New AnalyzersFolderItem(workspace.GetService(Of IThreadingContext), workspace, project.Id, Nothing, Nothing) Dim analyzer = New AnalyzerItem(analyzerFolder, project.AnalyzerReferences.Single(), Nothing) Dim browseObject = DirectCast(analyzer.GetBrowseObject(), AnalyzerItem.BrowseObject) diff --git a/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerItemsSourceTests.vb b/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerItemsSourceTests.vb index bcf2f3deda1c7..a36cdeb68f6e4 100644 --- a/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerItemsSourceTests.vb +++ b/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerItemsSourceTests.vb @@ -2,15 +2,17 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities +Imports Microsoft.CodeAnalysis.Shared.TestHooks Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer +Imports Roslyn.Test.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer - <[UseExportProvider]> - Public Class AnalyzerItemsSourceTests - - Public Sub Ordering() + + Public NotInheritable Class AnalyzerItemsSourceTests + + Public Async Function Ordering() As Task Dim workspaceXml = @@ -23,8 +25,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Using workspace = EditorTestWorkspace.Create(workspaceXml) Dim project = workspace.Projects.Single() - Dim analyzerFolder = New AnalyzersFolderItem(workspace, project.Id, Nothing, Nothing) - Dim analyzerItemsSource = New AnalyzerItemSource(analyzerFolder, New FakeAnalyzersCommandHandler) + Dim analyzerFolder = New AnalyzersFolderItem(workspace.GetService(Of IThreadingContext), workspace, project.Id, Nothing, Nothing) + Dim listenerProvider = workspace.GetService(Of IAsynchronousOperationListenerProvider) + Dim analyzerItemsSource = New AnalyzerItemSource( + analyzerFolder, New FakeAnalyzersCommandHandler(), listenerProvider) + + Dim waiter = listenerProvider.GetWaiter(FeatureAttribute.SourceGenerators) + Await waiter.ExpeditedWaitAsync() Dim analyzers = analyzerItemsSource.Items.Cast(Of AnalyzerItem)().ToArray() @@ -33,7 +40,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Assert.Equal(expected:="Beta", actual:=analyzers(1).Text) Assert.Equal(expected:="Gamma", actual:=analyzers(2).Text) End Using - End Sub + End Function End Class End Namespace diff --git a/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzersFolderItemTests.vb b/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzersFolderItemTests.vb index 24764b596cfc3..596bed22efabb 100644 --- a/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzersFolderItemTests.vb +++ b/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzersFolderItemTests.vb @@ -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. -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.VisualStudio.LanguageServices.Implementation Imports Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer @@ -23,7 +23,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Using workspace = EditorTestWorkspace.Create(workspaceXml) Dim project = workspace.Projects.Single() - Dim analyzerFolder = New AnalyzersFolderItem(workspace, project.Id, Nothing, Nothing) + Dim analyzerFolder = New AnalyzersFolderItem(workspace.GetService(Of IThreadingContext), workspace, project.Id, Nothing, Nothing) Assert.Equal(expected:=SolutionExplorerShim.Analyzers, actual:=analyzerFolder.Text) End Using @@ -41,7 +41,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Using workspace = EditorTestWorkspace.Create(workspaceXml) Dim project = workspace.Projects.Single() - Dim analyzerFolder = New AnalyzersFolderItem(workspace, project.Id, Nothing, Nothing) + Dim analyzerFolder = New AnalyzersFolderItem(workspace.GetService(Of IThreadingContext), workspace, project.Id, Nothing, Nothing) Dim browseObject = DirectCast(analyzerFolder.GetBrowseObject(), AnalyzersFolderItem.BrowseObject) Assert.Equal(expected:=SolutionExplorerShim.Analyzers, actual:=browseObject.GetComponentName()) diff --git a/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzersFolderProviderTests.vb b/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzersFolderProviderTests.vb index 2f4af6c64eb54..201a9b3837eff 100644 --- a/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzersFolderProviderTests.vb +++ b/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzersFolderProviderTests.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.ObjectModel +Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.Internal.VisualStudio.PlatformUI Imports Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer @@ -15,12 +16,11 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer <[UseExportProvider]> Public Class AnalyzersFolderProviderTests - Public Sub CreateCollectionSource_NullItem() Using environment = New TestEnvironment() Dim provider As IAttachedCollectionSourceProvider = - New AnalyzersFolderItemSourceProvider(environment.Workspace, Nothing) + New AnalyzersFolderItemSourceProvider(environment.ExportProvider.GetExportedValue(Of IThreadingContext), environment.Workspace, Nothing) Dim collectionSource = provider.CreateCollectionSource(Nothing, KnownRelationships.Contains) @@ -32,7 +32,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Public Sub CreateCollectionSource_NullHierarchyIdentity() Using environment = New TestEnvironment() Dim provider As IAttachedCollectionSourceProvider = - New AnalyzersFolderItemSourceProvider(environment.Workspace, Nothing) + New AnalyzersFolderItemSourceProvider(environment.ExportProvider.GetExportedValue(Of IThreadingContext), environment.Workspace, Nothing) Dim hierarchyItem = New MockHierarchyItem With {.HierarchyIdentity = Nothing} @@ -63,7 +63,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer } } - Dim provider As IAttachedCollectionSourceProvider = New AnalyzersFolderItemSourceProvider(environment.Workspace, New FakeAnalyzersCommandHandler) + Dim provider As IAttachedCollectionSourceProvider = New AnalyzersFolderItemSourceProvider( + environment.ExportProvider.GetExportedValue(Of IThreadingContext), environment.Workspace, New FakeAnalyzersCommandHandler) Dim collectionSource = provider.CreateCollectionSource(hierarchyItem, KnownRelationships.Contains) diff --git a/src/VisualStudio/Core/Test/SolutionExplorer/CpsDiagnosticItemSourceTests.vb b/src/VisualStudio/Core/Test/SolutionExplorer/CpsDiagnosticItemSourceTests.vb index 4f75fb6c2e803..1896615e99942 100644 --- a/src/VisualStudio/Core/Test/SolutionExplorer/CpsDiagnosticItemSourceTests.vb +++ b/src/VisualStudio/Core/Test/SolutionExplorer/CpsDiagnosticItemSourceTests.vb @@ -5,18 +5,21 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Editor.[Shared].Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.[Shared].TestHooks Imports Microsoft.CodeAnalysis.Test.Utilities Imports Microsoft.Internal.VisualStudio.PlatformUI Imports Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer Imports Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Framework Imports Microsoft.VisualStudio.Shell +Imports Roslyn.Test.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Public Class CpsDiagnosticItemSourceTests - - Public Sub AnalyzerHasDiagnostics() + + Public Async Function AnalyzerHasDiagnostics() As Task Dim workspaceXml = @@ -35,17 +38,24 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Const analyzerPath = "C:\Analyzer.dll" workspace.OnAnalyzerReferenceAdded(project.Id, New TestAnalyzerReferenceByLanguage(analyzers, analyzerPath)) + Dim listenerProvider = workspace.GetService(Of IAsynchronousOperationListenerProvider) Dim source As IAttachedCollectionSource = New CpsDiagnosticItemSource( + workspace.GetService(Of IThreadingContext), workspace, project.FilePath, project.Id, New MockHierarchyItem() With {.CanonicalName = "\net472\analyzerdependency\" + analyzerPath}, - New FakeAnalyzersCommandHandler, workspace.GetService(Of IDiagnosticAnalyzerService)) + New FakeAnalyzersCommandHandler, workspace.GetService(Of IDiagnosticAnalyzerService), + listenerProvider) Assert.True(source.HasItems) + + Dim waiter = DirectCast(listenerProvider.GetListener(FeatureAttribute.SourceGenerators), IAsynchronousOperationWaiter) + Await waiter.ExpeditedWaitAsync() + Dim diagnostic = Assert.IsAssignableFrom(Of ITreeDisplayItem)(Assert.Single(source.Items)) Assert.Contains(IDEDiagnosticIds.UseAutoPropertyDiagnosticId, diagnostic.Text) End Using - End Sub + End Function End Class End Namespace diff --git a/src/VisualStudio/Core/Test/SolutionExplorer/SourceGeneratorItemTests.vb b/src/VisualStudio/Core/Test/SolutionExplorer/SourceGeneratorItemTests.vb index 74145221a2051..7074c37fd513b 100644 --- a/src/VisualStudio/Core/Test/SolutionExplorer/SourceGeneratorItemTests.vb +++ b/src/VisualStudio/Core/Test/SolutionExplorer/SourceGeneratorItemTests.vb @@ -19,7 +19,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Public Class SourceGeneratorItemTests - Public Sub SourceGeneratorsListed() + Public Async Function SourceGeneratorsListed() As Task Dim workspaceXml = @@ -30,13 +30,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Dim projectId = workspace.Projects.Single().Id Dim source = CreateItemSourceForAnalyzerReference(workspace, projectId) + Await WaitForGeneratorsAndItemSourcesAsync(workspace) Assert.True(source.HasItems) Dim generatorItem = Assert.IsAssignableFrom(Of SourceGeneratorItem)(Assert.Single(source.Items)) Assert.Equal(GetType(GenerateFileForEachAdditionalFileWithContentsCommented).FullName, generatorItem.Text) End Using - End Sub + End Function Public Async Function PlaceholderItemCreateIfGeneratorProducesNoFiles() As Task @@ -49,6 +50,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Using workspace = EditorTestWorkspace.Create(workspaceXml) Dim projectId = workspace.Projects.Single().Id Dim source = CreateItemSourceForAnalyzerReference(workspace, projectId) + Await WaitForGeneratorsAndItemSourcesAsync(workspace) Dim generatorItem = Assert.IsAssignableFrom(Of SourceGeneratorItem)(Assert.Single(source.Items)) Dim generatorFilesItemSource = CreateSourceGeneratedFilesItemSource(workspace, generatorItem) @@ -74,6 +76,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Using workspace = EditorTestWorkspace.Create(workspaceXml) Dim projectId = workspace.Projects.Single().Id Dim source = CreateItemSourceForAnalyzerReference(workspace, projectId) + Await WaitForGeneratorsAndItemSourcesAsync(workspace) Dim generatorItem = Assert.IsAssignableFrom(Of SourceGeneratorItem)(Assert.Single(source.Items)) Dim generatorFilesItemSource = CreateSourceGeneratedFilesItemSource(workspace, generatorItem) @@ -108,6 +111,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Using workspace = EditorTestWorkspace.Create(workspaceXml) Dim projectId = workspace.Projects.Single().Id Dim source = CreateItemSourceForAnalyzerReference(workspace, projectId) + Await WaitForGeneratorsAndItemSourcesAsync(workspace) Dim generatorItem = Assert.IsAssignableFrom(Of SourceGeneratorItem)(Assert.Single(source.Items)) Dim generatorFilesItemSource = CreateSourceGeneratedFilesItemSource(workspace, generatorItem) @@ -142,6 +146,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Dim projectId = workspace.Projects.Single().Id Dim source = CreateItemSourceForAnalyzerReference(workspace, projectId) + Await WaitForGeneratorsAndItemSourcesAsync(workspace) Dim generatorItem = Assert.IsAssignableFrom(Of SourceGeneratorItem)(Assert.Single(source.Items)) Dim generatorFilesItemSource = CreateSourceGeneratedFilesItemSource(workspace, generatorItem) @@ -182,6 +187,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Dim projectId = workspace.Projects.Single().Id Dim source = CreateItemSourceForAnalyzerReference(workspace, projectId) + Await WaitForGeneratorsAndItemSourcesAsync(workspace) Dim generatorItem = Assert.IsAssignableFrom(Of SourceGeneratorItem)(Assert.Single(source.Items)) Dim generatorFilesItemSource = CreateSourceGeneratedFilesItemSource(workspace, generatorItem) @@ -234,6 +240,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Using workspace = EditorTestWorkspace.Create(workspaceXml) Dim projectId = workspace.Projects.Single().Id Dim source = CreateItemSourceForAnalyzerReference(workspace, projectId) + Await WaitForGeneratorsAndItemSourcesAsync(workspace) + Dim generatorItem = Assert.IsAssignableFrom(Of SourceGeneratorItem)(Assert.Single(source.Items)) Dim generatorFilesItemSource = CreateSourceGeneratedFilesItemSource(workspace, generatorItem) @@ -261,15 +269,17 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer workspace.OnAnalyzerReferenceAdded(projectId, analyzerReference) Return New LegacyDiagnosticItemSource( - New AnalyzerItem(New AnalyzersFolderItem(workspace, projectId, Nothing, Nothing), analyzerReference, Nothing), + workspace.GetService(Of IThreadingContext), + New AnalyzerItem(New AnalyzersFolderItem(workspace.GetService(Of IThreadingContext), workspace, projectId, Nothing, Nothing), analyzerReference, Nothing), New FakeAnalyzersCommandHandler, - workspace.GetService(Of IDiagnosticAnalyzerService)) + workspace.GetService(Of IDiagnosticAnalyzerService), + workspace.GetService(Of IAsynchronousOperationListenerProvider)) End Function Private Shared Function CreateSourceGeneratedFilesItemSource(workspace As EditorTestWorkspace, generatorItem As SourceGeneratorItem) As Shell.IAttachedCollectionSource Dim asyncListener = workspace.GetService(Of IAsynchronousOperationListenerProvider).GetListener(FeatureAttribute.SourceGenerators) - Return New SourceGeneratedFileItemSource(generatorItem, workspace, asyncListener, workspace.GetService(Of IThreadingContext)()) + Return New SourceGeneratedFileItemSource(generatorItem, workspace.GetService(Of IThreadingContext), workspace, asyncListener) End Function Private Shared Function WaitForGeneratorsAndItemSourcesAsync(workspace As EditorTestWorkspace) As Task diff --git a/src/VisualStudio/Core/Test/Venus/DocumentServiceTests.vb b/src/VisualStudio/Core/Test/Venus/DocumentServiceTests.vb index ac3cc44b02664..55c62bcef8fff 100644 --- a/src/VisualStudio/Core/Test/Venus/DocumentServiceTests.vb +++ b/src/VisualStudio/Core/Test/Venus/DocumentServiceTests.vb @@ -114,7 +114,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Venus Dim openDocument = subjectDocument.GetOpenTextContainer() Dim sourceGeneratedDocumentId = workspace.GetDocumentIdInCurrentContext(openDocument) Dim document = Assert.IsType(Of SourceGeneratedDocument)(Await workspace.CurrentSolution.GetDocumentAsync(sourceGeneratedDocumentId, includeSourceGenerated:=True)) - Dim documentServices = document.State.Services + Dim documentServices = document.State.DocumentServiceProvider Dim documentOperations = documentServices.GetService(Of IDocumentOperationService)() Assert.False(documentOperations.CanApplyChange) diff --git a/src/VisualStudio/DevKit/Impl/Microsoft.VisualStudio.LanguageServices.DevKit.csproj b/src/VisualStudio/DevKit/Impl/Microsoft.VisualStudio.LanguageServices.DevKit.csproj index 3a6160a5a2293..4c7df6f74a51e 100644 --- a/src/VisualStudio/DevKit/Impl/Microsoft.VisualStudio.LanguageServices.DevKit.csproj +++ b/src/VisualStudio/DevKit/Impl/Microsoft.VisualStudio.LanguageServices.DevKit.csproj @@ -17,6 +17,7 @@ + @@ -54,8 +55,11 @@ - - + + <_Content Include="@(Content)" Condition="'%(Content.Pack)'=='true'"/> diff --git a/src/VisualStudio/DevKit/Impl/SourceLink/VSCodePdbSourceDocumentLogger.cs b/src/VisualStudio/DevKit/Impl/SourceLink/VSCodePdbSourceDocumentLogger.cs new file mode 100644 index 0000000000000..cf19ce314d0af --- /dev/null +++ b/src/VisualStudio/DevKit/Impl/SourceLink/VSCodePdbSourceDocumentLogger.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PdbSourceDocument; +using Microsoft.Extensions.Logging; + +namespace Microsoft.CodeAnalysis.LanguageServer.Services.SourceLink; + +[Export(typeof(IPdbSourceDocumentLogger)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal class VSCodePdbSourceDocumentLogger(ILoggerFactory loggerFactory) : IPdbSourceDocumentLogger +{ + private readonly ILogger _logger = loggerFactory.CreateLogger("SourceLink"); + + public void Clear() + { + // Do nothing, we just leave all the logs up. + return; + } + + public void Log(string message) + { + _logger.LogTrace(message); + } +} diff --git a/src/VisualStudio/DevKit/Impl/SourceLink/VSCodeSourceLinkService.cs b/src/VisualStudio/DevKit/Impl/SourceLink/VSCodeSourceLinkService.cs new file mode 100644 index 0000000000000..c89ac97d8e047 --- /dev/null +++ b/src/VisualStudio/DevKit/Impl/SourceLink/VSCodeSourceLinkService.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.BrokeredServices; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PdbSourceDocument; +using Microsoft.ServiceHub.Framework; +using Microsoft.VisualStudio.Debugger.Contracts.SourceLink; +using Microsoft.VisualStudio.Debugger.Contracts.SymbolLocator; +using Microsoft.VisualStudio.LanguageServices.PdbSourceDocument; + +namespace Microsoft.CodeAnalysis.LanguageServer.Services.SourceLink; + +[Export(typeof(ISourceLinkService)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal class VSCodeSourceLinkService(IServiceBrokerProvider serviceBrokerProvider, IPdbSourceDocumentLogger logger) : AbstractSourceLinkService +{ + private readonly IServiceBroker _serviceBroker = serviceBrokerProvider.ServiceBroker; + + protected override async Task LocateSymbolFileAsync(SymbolLocatorPdbInfo pdbInfo, SymbolLocatorSearchFlags flags, CancellationToken cancellationToken) + { + var proxy = await _serviceBroker.GetProxyAsync(BrokeredServiceDescriptors.DebuggerSymbolLocatorService, cancellationToken).ConfigureAwait(false); + using ((IDisposable?)proxy) + { + if (proxy is null) + { + return null; + } + + try + { + var result = await proxy.LocateSymbolFileAsync(pdbInfo, flags, progress: null, cancellationToken).ConfigureAwait(false); + return result; + } + catch (StreamJsonRpc.RemoteMethodNotFoundException) + { + // Older versions of DevKit use an invalid service descriptor - calling it will throw a RemoteMethodNotFoundException. + // Just return null as there isn't a valid service available. + return null; + } + } + } + + protected override async Task GetSourceLinkAsync(string url, string relativePath, CancellationToken cancellationToken) + { + var proxy = await _serviceBroker.GetProxyAsync(BrokeredServiceDescriptors.DebuggerSourceLinkService, cancellationToken).ConfigureAwait(false); + using ((IDisposable?)proxy) + { + if (proxy is null) + { + return null; + } + + try + { + var result = await proxy.GetSourceLinkAsync(url, relativePath, allowInteractiveLogin: false, cancellationToken).ConfigureAwait(false); + return result; + } + catch (StreamJsonRpc.RemoteMethodNotFoundException) + { + // Older versions of DevKit use an invalid service descriptor - calling it will throw a RemoteMethodNotFoundException. + // Just return null as there isn't a valid service available. + return null; + } + } + } + + protected override IPdbSourceDocumentLogger? Logger => logger; +} diff --git a/src/VisualStudio/Directory.Build.props b/src/VisualStudio/Directory.Build.props index 6eef643958f56..9dd0ddea9df26 100644 --- a/src/VisualStudio/Directory.Build.props +++ b/src/VisualStudio/Directory.Build.props @@ -1,6 +1,6 @@ - true + true diff --git a/src/VisualStudio/ExternalAccess/FSharp/FindUsages/FSharpDefinitionItem.cs b/src/VisualStudio/ExternalAccess/FSharp/FindUsages/FSharpDefinitionItem.cs index e46ad6e18659b..6d49d383ccf6d 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/FindUsages/FSharpDefinitionItem.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/FindUsages/FSharpDefinitionItem.cs @@ -12,15 +12,12 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.FindUsages { internal class FSharpDefinitionItem { - private readonly DefinitionItem _roslynDefinitionItem; - private FSharpDefinitionItem(DefinitionItem roslynDefinitionItem) { - _roslynDefinitionItem = roslynDefinitionItem; + RoslynDefinitionItem = roslynDefinitionItem; } - internal DefinitionItem RoslynDefinitionItem - => _roslynDefinitionItem; + internal DefinitionItem RoslynDefinitionItem { get; } public static FSharpDefinitionItem Create(ImmutableArray tags, ImmutableArray displayParts, FSharpDocumentSpan sourceSpan) => new( diff --git a/src/VisualStudio/ExternalAccess/FSharp/FindUsages/FSharpSourceReferenceItem.cs b/src/VisualStudio/ExternalAccess/FSharp/FindUsages/FSharpSourceReferenceItem.cs index a541081587da1..89c015bc481d7 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/FindUsages/FSharpSourceReferenceItem.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/FindUsages/FSharpSourceReferenceItem.cs @@ -8,26 +8,19 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.FindUsages { internal class FSharpSourceReferenceItem { - private readonly Microsoft.CodeAnalysis.FindUsages.SourceReferenceItem _roslynSourceReferenceItem; #pragma warning disable IDE0051 // Remove unused private members private FSharpSourceReferenceItem(Microsoft.CodeAnalysis.FindUsages.SourceReferenceItem roslynDefinitionItem) #pragma warning restore IDE0051 // Remove unused private members { - _roslynSourceReferenceItem = roslynDefinitionItem; + RoslynSourceReferenceItem = roslynDefinitionItem; } public FSharpSourceReferenceItem(FSharpDefinitionItem definition, FSharpDocumentSpan sourceSpan) { - _roslynSourceReferenceItem = new Microsoft.CodeAnalysis.FindUsages.SourceReferenceItem(definition.RoslynDefinitionItem, sourceSpan.ToRoslynDocumentSpan(), classifiedSpans: null); + RoslynSourceReferenceItem = new Microsoft.CodeAnalysis.FindUsages.SourceReferenceItem(definition.RoslynDefinitionItem, sourceSpan.ToRoslynDocumentSpan(), classifiedSpans: null); } - internal Microsoft.CodeAnalysis.FindUsages.SourceReferenceItem RoslynSourceReferenceItem - { - get - { - return _roslynSourceReferenceItem; - } - } + internal Microsoft.CodeAnalysis.FindUsages.SourceReferenceItem RoslynSourceReferenceItem { get; } } } diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs index d2ed503b29202..0fc2d99295a31 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FSharpEditorInlineRenameService.cs @@ -5,10 +5,10 @@ #nullable disable using System; -using System.Linq; using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor; @@ -87,15 +87,14 @@ public IEnumerable GetReplacements(DocumentId documentI internal class FSharpInlineRenameLocationSetLegacyWrapper : IInlineRenameLocationSet { private readonly IFSharpInlineRenameLocationSet _set; - private readonly IList _locations; public FSharpInlineRenameLocationSetLegacyWrapper(IFSharpInlineRenameLocationSet set) { _set = set; - _locations = set.Locations?.Select(x => new InlineRenameLocation(x.Document, x.TextSpan)).ToList(); + Locations = set.Locations?.Select(x => new InlineRenameLocation(x.Document, x.TextSpan)).ToList(); } - public IList Locations => _locations; + public IList Locations { get; } public async Task GetReplacementsAsync(string replacementText, SymbolRenameOptions options, CancellationToken cancellationToken) { @@ -202,6 +201,13 @@ public FSharpEditorInlineRenameService( _service = service; } + public bool IsEnabled => true; + + public Task>> GetRenameContextAsync(IInlineRenameInfo inlineRenameInfo, IInlineRenameLocationSet inlineRenameLocationSet, CancellationToken cancellationToken) + { + return Task.FromResult(ImmutableDictionary>.Empty); + } + public async Task GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken) { #pragma warning disable CS0612 // Type or member is obsolete diff --git a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesContext.cs b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesContext.cs index a8a69d9e7d5cf..4d03943a5f21d 100644 --- a/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesContext.cs +++ b/src/VisualStudio/ExternalAccess/FSharp/Internal/Editor/FindUsages/FSharpFindUsagesContext.cs @@ -13,29 +13,28 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Editor.FindUsage internal class FSharpFindUsagesContext : IFSharpFindUsagesContext { private readonly IFindUsagesContext _context; - private readonly CancellationToken _cancellationToken; public FSharpFindUsagesContext(IFindUsagesContext context, CancellationToken cancellationToken) { _context = context; - _cancellationToken = cancellationToken; + CancellationToken = cancellationToken; } - public CancellationToken CancellationToken => _cancellationToken; + public CancellationToken CancellationToken { get; } public Task OnDefinitionFoundAsync(FSharp.FindUsages.FSharpDefinitionItem definition) { - return _context.OnDefinitionFoundAsync(definition.RoslynDefinitionItem, _cancellationToken).AsTask(); + return _context.OnDefinitionFoundAsync(definition.RoslynDefinitionItem, CancellationToken).AsTask(); } public Task OnReferenceFoundAsync(FSharp.FindUsages.FSharpSourceReferenceItem reference) { - return _context.OnReferencesFoundAsync(IAsyncEnumerableExtensions.SingletonAsync(reference.RoslynSourceReferenceItem), _cancellationToken).AsTask(); + return _context.OnReferencesFoundAsync(IAsyncEnumerableExtensions.SingletonAsync(reference.RoslynSourceReferenceItem), CancellationToken).AsTask(); } public Task ReportMessageAsync(string message) { - return _context.ReportNoResultsAsync(message, _cancellationToken).AsTask(); + return _context.ReportNoResultsAsync(message, CancellationToken).AsTask(); } public Task ReportProgressAsync(int current, int maximum) @@ -45,7 +44,7 @@ public Task ReportProgressAsync(int current, int maximum) public Task SetSearchTitleAsync(string title) { - return _context.SetSearchTitleAsync(title, _cancellationToken).AsTask(); + return _context.SetSearchTitleAsync(title, CancellationToken).AsTask(); } } } diff --git a/src/VisualStudio/IntegrationTest/IntegrationTestBuildProject.csproj b/src/VisualStudio/IntegrationTest/IntegrationTestBuildProject.csproj index ed2f2c6590b3d..5471650a59f0c 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTestBuildProject.csproj +++ b/src/VisualStudio/IntegrationTest/IntegrationTestBuildProject.csproj @@ -1,7 +1,7 @@ net472 - true + true diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpBuild.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpBuild.cs index 05bc656900118..a73acd36acae3 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpBuild.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpBuild.cs @@ -42,8 +42,8 @@ static void Main(string[] args) await TestServices.Editor.SetTextAsync(editorText, HangMitigatingCancellationToken); - var buildSummary = await TestServices.SolutionExplorer.BuildSolutionAndWaitAsync(HangMitigatingCancellationToken); - Assert.Equal("========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========", buildSummary); + var succeed = await TestServices.SolutionExplorer.BuildSolutionAndWaitAsync(HangMitigatingCancellationToken); + Assert.True(succeed); await TestServices.ErrorList.ShowBuildErrorsAsync(HangMitigatingCancellationToken); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpExtractInterfaceDialog.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpExtractInterfaceDialog.cs index 75ae2902d1190..730ddf4261a7e 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpExtractInterfaceDialog.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpExtractInterfaceDialog.cs @@ -90,7 +90,7 @@ await TestServices.EditorVerifier.CodeActionAsync("Extract interface...", var selectedItems = await TestServices.ExtractInterfaceDialog.GetSelectedItemsAsync(HangMitigatingCancellationToken); Assert.Equal( - expected: new[] { "M1()", "M2()" }, + expected: ["M1()", "M2()"], actual: selectedItems.Select(item => item.SymbolName)); await TestServices.ExtractInterfaceDialog.ClickDeselectAllAsync(HangMitigatingCancellationToken); @@ -102,7 +102,7 @@ await TestServices.EditorVerifier.CodeActionAsync("Extract interface...", selectedItems = await TestServices.ExtractInterfaceDialog.GetSelectedItemsAsync(HangMitigatingCancellationToken); Assert.Equal( - expected: new[] { "M1()", "M2()" }, + expected: ["M1()", "M2()"], actual: selectedItems.Select(item => item.SymbolName)); await TestServices.ExtractInterfaceDialog.ClickCancelAsync(HangMitigatingCancellationToken); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpFindReferences.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpFindReferences.cs index 87ec1c5cf860c..b8263d60c0a38 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpFindReferences.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpFindReferences.cs @@ -56,8 +56,7 @@ void M() Assert.Collection( results, - new Action[] - { + [ reference => { Assert.Equal(expected: "class Program", actual: reference.TryGetValue(StandardTableKeyNames.Text, out string code) ? code : null); @@ -70,7 +69,7 @@ void M() Assert.Equal(expected: 5, actual: reference.TryGetValue(StandardTableKeyNames.Line, out int line) ? line : -1); Assert.Equal(expected: 24, actual: reference.TryGetValue(StandardTableKeyNames.Column, out int column) ? column : -1); } - }); + ]); results[0].NavigateTo(isPreview: false, shouldActivate: true); await WaitForNavigateAsync(HangMitigatingCancellationToken); @@ -101,8 +100,7 @@ static void Main() Assert.Collection( results, - new Action[] - { + [ reference => { Assert.Equal(expected: "int local = 1;", actual: reference.TryGetValue(StandardTableKeyNames.Text, out string code) ? code : null); @@ -115,7 +113,7 @@ static void Main() Assert.Equal(expected: 6, actual: reference.TryGetValue(StandardTableKeyNames.Line, out int line) ? line : -1); Assert.Equal(expected: 26, actual: reference.TryGetValue(StandardTableKeyNames.Column, out int column) ? column : -1); } - }); + ]); await telemetry.VerifyFiredAsync(["vs/platform/findallreferences/search", "vs/ide/vbcs/commandhandler/findallreference"], HangMitigatingCancellationToken); } @@ -139,15 +137,14 @@ static void Main() Assert.Collection( results, - new Action[] - { + [ reference => { Assert.Equal(expected: "string local = \"1\";", actual: reference.TryGetValue(StandardTableKeyNames.Text, out string code) ? code : null); Assert.Equal(expected: 5, actual: reference.TryGetValue(StandardTableKeyNames.Line, out int line) ? line : -1); Assert.Equal(expected: 24, actual: reference.TryGetValue(StandardTableKeyNames.Column, out int column) ? column : -1); } - }); + ]); } [IdeFact] diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpGoToDefinition.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpGoToDefinition.cs index 0588b8bcbb0b3..234ef73c140d9 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpGoToDefinition.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpGoToDefinition.cs @@ -92,8 +92,7 @@ partial class PartialClass { int i = 0; }", HangMitigatingCancellationToken); Assert.Collection( results, - new Action[] - { + [ reference => { Assert.Equal(expected: "partial class /*Marker*/ PartialClass { }", actual: reference.GetText()); @@ -106,7 +105,7 @@ partial class PartialClass { int i = 0; }", HangMitigatingCancellationToken); Assert.Equal(expected: 2, actual: reference.GetLine()); Assert.Equal(expected: 14, actual: reference.GetColumn()); } - }); + ]); } [IdeFact] diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNewDocumentFormatting.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNewDocumentFormatting.cs index 76c7c794d14ab..8a74ed8f13c70 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNewDocumentFormatting.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpNewDocumentFormatting.cs @@ -47,7 +47,7 @@ public async Task CreateSDKProjectWithFileScopedNamespaces() await TestServices.SolutionExplorer.AddProjectAsync("TestProj", WellKnownProjectTemplates.CSharpNetCoreConsoleApplication, LanguageNames.CSharp, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken); - await TestServices.Workspace.WaitForAllAsyncOperationsAsync(new[] { FeatureAttribute.Workspace }, HangMitigatingCancellationToken); + await TestServices.Workspace.WaitForAllAsyncOperationsAsync([FeatureAttribute.Workspace], HangMitigatingCancellationToken); await VerifyNoErrorsAsync(HangMitigatingCancellationToken); } @@ -70,7 +70,7 @@ public async Task CreateSDKProjectWithBlockScopedNamespacesFromEditorConfig() await TestServices.SolutionExplorer.AddProjectAsync("TestProj", WellKnownProjectTemplates.CSharpNetCoreClassLibrary, LanguageNames.CSharp, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken); - await TestServices.Workspace.WaitForAllAsyncOperationsAsync(new[] { FeatureAttribute.Workspace }, HangMitigatingCancellationToken); + await TestServices.Workspace.WaitForAllAsyncOperationsAsync([FeatureAttribute.Workspace], HangMitigatingCancellationToken); await VerifyNoErrorsAsync(HangMitigatingCancellationToken); @@ -100,7 +100,7 @@ public async Task CreateSDKProjectWithBlockScopedNamespacesFromIrrelevantEditorC await TestServices.SolutionExplorer.AddProjectAsync("TestProj", WellKnownProjectTemplates.CSharpNetCoreClassLibrary, LanguageNames.CSharp, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken); - await TestServices.Workspace.WaitForAllAsyncOperationsAsync(new[] { FeatureAttribute.Workspace }, HangMitigatingCancellationToken); + await TestServices.Workspace.WaitForAllAsyncOperationsAsync([FeatureAttribute.Workspace], HangMitigatingCancellationToken); await VerifyNoErrorsAsync(HangMitigatingCancellationToken); @@ -125,7 +125,7 @@ public async Task CreateSDKProjectWithFileScopedNamespacesFromEditorConfig() await TestServices.SolutionExplorer.AddProjectAsync("TestProj", WellKnownProjectTemplates.CSharpNetCoreClassLibrary, LanguageNames.CSharp, HangMitigatingCancellationToken); await TestServices.SolutionExplorer.RestoreNuGetPackagesAsync(HangMitigatingCancellationToken); - await TestServices.Workspace.WaitForAllAsyncOperationsAsync(new[] { FeatureAttribute.Workspace }, HangMitigatingCancellationToken); + await TestServices.Workspace.WaitForAllAsyncOperationsAsync([FeatureAttribute.Workspace], HangMitigatingCancellationToken); await VerifyNoErrorsAsync(HangMitigatingCancellationToken); @@ -135,7 +135,7 @@ public async Task CreateSDKProjectWithFileScopedNamespacesFromEditorConfig() private async Task VerifyNoErrorsAsync(CancellationToken cancellationToken) { await TestServices.ErrorList.ShowErrorListAsync(cancellationToken); - await TestServices.Workspace.WaitForAllAsyncOperationsAsync(new[] { FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawlerLegacy, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles, FeatureAttribute.ErrorList }, cancellationToken); + await TestServices.Workspace.WaitForAllAsyncOperationsAsync([FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawlerLegacy, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles, FeatureAttribute.ErrorList], cancellationToken); var actualContents = await TestServices.ErrorList.GetErrorsAsync(cancellationToken); AssertEx.EqualOrDiff( string.Join(Environment.NewLine, Array.Empty()), diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpSourceGenerators.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpSourceGenerators.cs index 531912d893bc0..a5039b8c1105c 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpSourceGenerators.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpSourceGenerators.cs @@ -111,8 +111,7 @@ public static void Main() Assert.Collection( results, - new Action[] - { + [ reference => { Assert.Equal(expected: "/// is a simple class to fetch the classic message.", actual: reference.GetText()); @@ -131,7 +130,7 @@ public static void Main() Assert.Equal(expected: 5, actual: reference.GetLine()); Assert.Equal(expected: 26, actual: reference.GetColumn()); }, - }); + ]); } [IdeTheory, CombinatorialData] diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ButtonBaseExtensions.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ButtonBaseExtensions.cs index 8812a9ca02d7b..d9bc27eea2be1 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ButtonBaseExtensions.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ButtonBaseExtensions.cs @@ -20,7 +20,7 @@ public static class ButtonBaseExtensions static ButtonBaseExtensions() { - var methodInfo = typeof(RoutedCommand).GetMethod("ExecuteCore", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(object), typeof(IInputElement), typeof(bool) }, null); + var methodInfo = typeof(RoutedCommand).GetMethod("ExecuteCore", BindingFlags.Instance | BindingFlags.NonPublic, null, [typeof(object), typeof(IInputElement), typeof(bool)], null); s_executeCoreMethod = methodInfo; //s_executeCore = (Action)Delegate.CreateDelegate(typeof(Action), firstArgument: null, methodInfo); } @@ -72,7 +72,7 @@ private static void ExecuteCommandSource(ICommandSource commandSource, bool user if (routedCommand.CanExecute(commandParameter, commandTarget)) { - s_executeCoreMethod.Invoke(routedCommand, new[] { commandParameter, commandTarget, userInitiated }); + s_executeCoreMethod.Invoke(routedCommand, [commandParameter, commandTarget, userInitiated]); //s_executeCore(routedCommand, commandParameter, commandTarget, userInitiated); } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/DialogHelpers.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/DialogHelpers.cs index bb5c2dd0bfc12..8a0053580fdd2 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/DialogHelpers.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/DialogHelpers.cs @@ -109,11 +109,10 @@ private static IUIAutomationElement FindDialogByPropertyWorker( var vsAutomationElement = Helper.Automation.ElementFromHandle(visualStudioHWnd); var elementCondition = Helper.Automation.CreateAndConditionFromArray( - new[] - { + [ Helper.Automation.CreatePropertyCondition(nameProperty.Id, propertyValue), Helper.Automation.CreatePropertyCondition(AutomationElementIdentifiers.ControlTypeProperty.Id, ControlType.Window.Id), - }); + ]); return vsAutomationElement.FindFirst(TreeScope.TreeScope_Children, elementCondition); } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InputInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InputInProcess.cs index 97b9b34c41bba..61d002c295b67 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InputInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InputInProcess.cs @@ -84,7 +84,7 @@ internal async Task SendToNavigateToAsync(InputKey[] keys, CancellationToken can var searchBox = Assert.IsAssignableFrom(Keyboard.FocusedElement); // Validate the focused control against the "old" search experience as well as the // all-in-one search experience. - Assert.Contains(searchBox.Name, new[] { "PART_SearchBox", "SearchBoxControl" }); + Assert.Contains(searchBox.Name, (string[])["PART_SearchBox", "SearchBoxControl"]); // AbstractSendKeys runs synchronously, so switch to a background thread before the call await TaskScheduler.Default; diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InteractiveWindowInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InteractiveWindowInProcess.cs index 828ba3a9fed35..f5f8d7464cdf4 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InteractiveWindowInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/InteractiveWindowInProcess.cs @@ -211,7 +211,7 @@ public async Task SubmitTextAsync(string text, CancellationToken cancellationTok await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var interactiveWindow = await GetInteractiveWindowAsync(cancellationToken); - await interactiveWindow.SubmitAsync(new[] { text }).WithCancellation(cancellationToken); + await interactiveWindow.SubmitAsync([text]).WithCancellation(cancellationToken); } public async Task CloseWindowAsync(CancellationToken cancellationToken) diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionExplorerInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionExplorerInProcess.cs index cf25d632cefe4..7d0545f754296 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionExplorerInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionExplorerInProcess.cs @@ -630,67 +630,27 @@ public async Task GetFileContentsAsync(string projectName, string relati } /// - /// The summary line for the build, which generally looks something like this: - /// - /// - /// ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ========== - /// + /// true if build succeeds, otherwise false. /// - public async Task BuildSolutionAndWaitAsync(CancellationToken cancellationToken) + public async Task BuildSolutionAndWaitAsync(CancellationToken cancellationToken) { await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - var buildOutputWindowPane = await GetBuildOutputWindowPaneAsync(cancellationToken); - buildOutputWindowPane.Clear(); - var buildManager = await GetRequiredGlobalServiceAsync(cancellationToken); using var solutionEvents = new UpdateSolutionEvents(buildManager); var buildCompleteTaskCompletionSource = new TaskCompletionSource(); - void HandleUpdateSolutionDone() => buildCompleteTaskCompletionSource.SetResult(true); + void HandleUpdateSolutionDone(bool buildSucceed) => buildCompleteTaskCompletionSource.SetResult(buildSucceed); solutionEvents.OnUpdateSolutionDone += HandleUpdateSolutionDone; try { - await TestServices.Shell.ExecuteCommandAsync(VSConstants.VSStd97CmdID.BuildSln, cancellationToken); - - await buildCompleteTaskCompletionSource.Task; + ErrorHandler.ThrowOnFailure(buildManager.StartSimpleUpdateSolutionConfiguration((uint)VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_BUILD, 0, 0)); + return await buildCompleteTaskCompletionSource.Task; } finally { solutionEvents.OnUpdateSolutionDone -= HandleUpdateSolutionDone; } - - // Force the error list to update - ErrorHandler.ThrowOnFailure(buildOutputWindowPane.FlushToTaskList()); - - var textView = (IVsTextView)buildOutputWindowPane; - var wpfTextViewHost = await textView.GetTextViewHostAsync(JoinableTaskFactory, cancellationToken); - var lines = wpfTextViewHost.TextView.TextViewLines; - if (lines.Count < 1) - { - return string.Empty; - } - - // Find the build summary line - for (var index = lines.Count - 1; index >= 0; index--) - { - var lineText = lines[index].Extent.GetText(); - if (lineText.StartsWith("========== Build:")) - { - return lineText; - } - } - - return string.Empty; - } - - public async Task GetBuildOutputWindowPaneAsync(CancellationToken cancellationToken) - { - await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - - var outputWindow = await GetRequiredGlobalServiceAsync(cancellationToken); - ErrorHandler.ThrowOnFailure(outputWindow.GetPane(VSConstants.OutputWindowPaneGuid.BuildOutputPane_guid, out var pane)); - return pane; } private static string ConvertLanguageName(string languageName) @@ -802,7 +762,7 @@ internal sealed class UpdateSolutionEvents : IVsUpdateSolutionEvents, IDisposabl private uint _cookie; private readonly IVsSolutionBuildManager2 _solutionBuildManager; - public event Action? OnUpdateSolutionDone; + public event Action? OnUpdateSolutionDone; internal UpdateSolutionEvents(IVsSolutionBuildManager2 solutionBuildManager) { @@ -819,8 +779,9 @@ internal UpdateSolutionEvents(IVsSolutionBuildManager2 solutionBuildManager) int IVsUpdateSolutionEvents.UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) { - OnUpdateSolutionDone?.Invoke(); - return 0; + var buildSucceeded = fSucceeded == 1; + OnUpdateSolutionDone?.Invoke(buildSucceeded); + return VSConstants.S_OK; } void IDisposable.Dispose() diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicBuild.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicBuild.cs index 3b6cc619938b8..2ed076ae4d016 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicBuild.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicBuild.cs @@ -40,8 +40,8 @@ End Sub await TestServices.Editor.SetTextAsync(editorText, HangMitigatingCancellationToken); - var buildSummary = await TestServices.SolutionExplorer.BuildSolutionAndWaitAsync(HangMitigatingCancellationToken); - Assert.Equal("========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========", buildSummary); + var succeed = await TestServices.SolutionExplorer.BuildSolutionAndWaitAsync(HangMitigatingCancellationToken); + Assert.True(succeed); await TestServices.ErrorList.ShowBuildErrorsAsync(HangMitigatingCancellationToken); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicErrorListCommon.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicErrorListCommon.cs index 7e30458823ff4..248b65f874c89 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicErrorListCommon.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicErrorListCommon.cs @@ -121,8 +121,8 @@ await TestServices.Editor.SetTextAsync(@"Class Class1 await TestServices.SolutionExplorer.CloseActiveWindow(HangMitigatingCancellationToken); // Build and verify build failure in the output window. - var buildSummary = await TestServices.SolutionExplorer.BuildSolutionAndWaitAsync(HangMitigatingCancellationToken); - Assert.Equal("========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========", buildSummary); + var succeed = await TestServices.SolutionExplorer.BuildSolutionAndWaitAsync(HangMitigatingCancellationToken); + Assert.False(succeed); await TestServices.Workspace.WaitForAllAsyncOperationsAsync([FeatureAttribute.Workspace, FeatureAttribute.SolutionCrawlerLegacy, FeatureAttribute.DiagnosticService, FeatureAttribute.ErrorSquiggles, FeatureAttribute.ErrorList], HangMitigatingCancellationToken); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicFindReferences.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicFindReferences.cs index cfe58fd38c3a7..2dbb4cc23fd41 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicFindReferences.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicFindReferences.cs @@ -42,8 +42,7 @@ End Class Assert.Collection( results, - new Action[] - { + [ reference => { Assert.Equal(expected: "Dim local = 1", actual: reference.GetText()); @@ -56,7 +55,7 @@ End Class Assert.Equal(expected: 4, actual: reference.GetLine()); Assert.Equal(expected: 24, actual: reference.GetColumn()); } - }); + ]); } [IdeFact] @@ -85,8 +84,7 @@ End Class Assert.Collection( results, - new Action[] - { + [ reference => { Assert.Equal(expected: "Public Shared Alpha As Int32", actual: reference.GetText()); @@ -99,7 +97,7 @@ End Class Assert.Equal(expected: 3, actual: reference.GetLine()); Assert.Equal(expected: 34, actual: reference.GetColumn()); } - }); + ]); await TestServices.FindReferencesWindow.NavigateToAsync(results[0], isPreview: false, shouldActivate: true, HangMitigatingCancellationToken); diff --git a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs index d4f8998ceafbb..39ade75d22b3b 100644 --- a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs +++ b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs @@ -98,8 +98,6 @@ public RemoteLanguageServiceWorkspace( void IOpenTextBufferEventListener.OnOpenDocument(string moniker, ITextBuffer textBuffer, IVsHierarchy? hierarchy) => NotifyOnDocumentOpened(moniker, textBuffer); - void IOpenTextBufferEventListener.OnDocumentOpenedIntoWindowFrame(string moniker, IVsWindowFrame windowFrame) { } - void IOpenTextBufferEventListener.OnCloseDocument(string moniker) => NotifyOnDocumentClosing(moniker); void IOpenTextBufferEventListener.OnRefreshDocumentContext(string moniker, IVsHierarchy hierarchy) @@ -112,6 +110,10 @@ void IOpenTextBufferEventListener.OnRenameDocument(string newMoniker, string old // Handled by Add/Remove. } + void IOpenTextBufferEventListener.OnDocumentOpenedIntoWindowFrame(string moniker, IVsWindowFrame windowFrame) { } + + void IOpenTextBufferEventListener.OnSaveDocument(string moniker) { } + public async Task SetSessionAsync(CollaborationSession session) { _session = session; diff --git a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspaceHost.cs b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspaceHost.cs index e7cb35f87985c..59648678294c0 100644 --- a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspaceHost.cs +++ b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspaceHost.cs @@ -37,13 +37,12 @@ internal sealed class RemoteLanguageServiceWorkspaceHost : ICollaborationService private ImmutableDictionary _loadedProjects = ImmutableDictionary.Create(StringComparer.OrdinalIgnoreCase); private ImmutableDictionary _loadedProjectInfo = ImmutableDictionary.Create(StringComparer.OrdinalIgnoreCase); private TaskCompletionSource _projectsLoadedTaskCompletionSource = new TaskCompletionSource(); - private readonly RemoteLanguageServiceWorkspace _remoteLanguageServiceWorkspace; private readonly RemoteProjectInfoProvider _remoteProjectInfoProvider; private readonly SVsServiceProvider _serviceProvider; private readonly IThreadingContext _threadingContext; - public RemoteLanguageServiceWorkspace Workspace => _remoteLanguageServiceWorkspace; + public RemoteLanguageServiceWorkspace Workspace { get; } /// /// Initializes a new instance of the class. @@ -56,7 +55,7 @@ public RemoteLanguageServiceWorkspaceHost(RemoteLanguageServiceWorkspace remoteL SVsServiceProvider serviceProvider, IThreadingContext threadingContext) { - _remoteLanguageServiceWorkspace = Requires.NotNull(remoteLanguageServiceWorkspace, nameof(remoteLanguageServiceWorkspace)); + Workspace = Requires.NotNull(remoteLanguageServiceWorkspace, nameof(remoteLanguageServiceWorkspace)); _remoteProjectInfoProvider = Requires.NotNull(remoteProjectInfoProvider, nameof(remoteProjectInfoProvider)); _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); _threadingContext = Requires.NotNull(threadingContext, nameof(threadingContext)); @@ -66,7 +65,7 @@ public async Task CreateServiceAsync(CollaborationSession { await LoadRoslynPackageAsync(cancellationToken).ConfigureAwait(false); - await _remoteLanguageServiceWorkspace.SetSessionAsync(collaborationSession).ConfigureAwait(false); + await Workspace.SetSessionAsync(collaborationSession).ConfigureAwait(false); // Kick off loading the projects in the background. // Clients can call EnsureProjectsLoadedAsync to await completion. @@ -75,9 +74,9 @@ public async Task CreateServiceAsync(CollaborationSession var lifeTimeService = new RemoteLanguageServiceSession(); lifeTimeService.Disposed += (s, e) => { - _remoteLanguageServiceWorkspace.EndSession(); + Workspace.EndSession(); CloseAllProjects(); - _remoteLanguageServiceWorkspace.Dispose(); + Workspace.Dispose(); _projectsLoadedTaskCompletionSource = new TaskCompletionSource(); }; @@ -124,7 +123,7 @@ private async Task LoadProjectsAsync(CancellationToken cancellationToken) // Adds the Roslyn project into the current solution; // and raise WorkspaceChanged event (WorkspaceChangeKind.ProjectAdded) - _remoteLanguageServiceWorkspace.OnProjectAdded(projectInfo); + Workspace.OnProjectAdded(projectInfo); _loadedProjects = _loadedProjects.Add(projectName, projectId); _loadedProjectInfo = _loadedProjectInfo.Add(projectName, projectInfo); @@ -135,7 +134,7 @@ private async Task LoadProjectsAsync(CancellationToken cancellationToken) { if (_loadedProjectInfo.TryGetValue(projectName, out var projInfo)) { - _remoteLanguageServiceWorkspace.OnProjectReloaded(projectInfo); + Workspace.OnProjectReloaded(projectInfo); } } } @@ -152,7 +151,7 @@ private void CloseAllProjects() { foreach (var projectId in _loadedProjects.Values) { - _remoteLanguageServiceWorkspace.OnProjectRemoved(projectId); + Workspace.OnProjectRemoved(projectId); } _loadedProjects = _loadedProjects.Clear(); diff --git a/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs b/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs index 5e1e1961cd06f..39413cf743dfc 100644 --- a/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs +++ b/src/VisualStudio/LiveShare/Impl/ProjectsHandler.cs @@ -21,11 +21,11 @@ internal class ProjectsHandler : ILspRequestHandler { public async Task HandleAsync(object param, RequestContext requestContext, CancellationToken cancellationToken) { - var projects = new ArrayBuilder(); + using var _1 = ArrayBuilder.GetInstance(out var projects); + using var _2 = ArrayBuilder.GetInstance(out var externalUris); var solution = requestContext.Context; foreach (var project in solution.Projects) { - var externalUris = new ArrayBuilder(); foreach (var sourceFile in project.Documents) { var uri = new Uri(sourceFile.FilePath); @@ -37,7 +37,7 @@ public async Task HandleAsync(object param, RequestContext r } } #pragma warning disable 0612 - await requestContext.ProtocolConverter.RegisterExternalFilesAsync(externalUris.ToArrayAndFree()).ConfigureAwait(false); + await requestContext.ProtocolConverter.RegisterExternalFilesAsync(externalUris.ToArray()).ConfigureAwait(false); #pragma warning restore 0612 var lspProject = new CustomProtocol.Project @@ -48,9 +48,10 @@ public async Task HandleAsync(object param, RequestContext r }; projects.Add(lspProject); + externalUris.Clear(); } - return projects.ToArrayAndFree(); + return projects.ToArray(); } } } diff --git a/src/VisualStudio/Setup.ServiceHub/arm64/Roslyn.VisualStudio.ServiceHub.Setup.arm64.csproj b/src/VisualStudio/Setup.ServiceHub/arm64/Roslyn.VisualStudio.ServiceHub.Setup.arm64.csproj index a175f8c54a2b0..cf34113c6e103 100644 --- a/src/VisualStudio/Setup.ServiceHub/arm64/Roslyn.VisualStudio.ServiceHub.Setup.arm64.csproj +++ b/src/VisualStudio/Setup.ServiceHub/arm64/Roslyn.VisualStudio.ServiceHub.Setup.arm64.csproj @@ -20,7 +20,7 @@ true false - PublishProjectOutputGroup + PublishedProjectOutputGroup false diff --git a/src/VisualStudio/Setup.ServiceHub/x64/Roslyn.VisualStudio.ServiceHub.Setup.x64.csproj b/src/VisualStudio/Setup.ServiceHub/x64/Roslyn.VisualStudio.ServiceHub.Setup.x64.csproj index 91e99dca1c9f0..214f738f1e1de 100644 --- a/src/VisualStudio/Setup.ServiceHub/x64/Roslyn.VisualStudio.ServiceHub.Setup.x64.csproj +++ b/src/VisualStudio/Setup.ServiceHub/x64/Roslyn.VisualStudio.ServiceHub.Setup.x64.csproj @@ -12,7 +12,7 @@ true false - PublishProjectOutputGroup + PublishedProjectOutputGroup false diff --git a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj index cb2b72d1b78c7..da3eccdcc04b8 100644 --- a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj +++ b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj @@ -206,7 +206,7 @@ CSharpVisualStudio - BuiltProjectOutputGroup;PkgDefProjectOutputGroup;ContentFilesProjectOutputGroup;SatelliteDllsProjectOutputGroup;ExtensionJsonOutputGroup + BuiltProjectOutputGroup;PkgDefProjectOutputGroup;ContentFilesProjectOutputGroup;SatelliteDllsProjectOutputGroup;ExtensionJsonOutputGroupFixed true BindingRedirect @@ -278,7 +278,7 @@ false InteractiveHost\Core - PublishProjectOutputGroup + PublishedProjectOutputGroup @@ -293,7 +293,7 @@ false InteractiveHost\Desktop - PublishProjectOutputGroup + PublishedProjectOutputGroup @@ -308,7 +308,7 @@ false InteractiveHost\Desktop - PublishProjectOutputGroup + PublishedProjectOutputGroup @@ -317,7 +317,7 @@ false false SemanticSearchRefs - PublishProjectOutputGroup + PublishedProjectOutputGroup false diff --git a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicCodeCleanupFixer.vb b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicCodeCleanupFixer.vb index 8fbe39d3e6eb2..68349b1b937ba 100644 --- a/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicCodeCleanupFixer.vb +++ b/src/VisualStudio/VisualBasic/Impl/LanguageService/VisualBasicCodeCleanupFixer.vb @@ -21,8 +21,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.LanguageService - Public Sub New(threadingContext As IThreadingContext, workspace As VisualStudioWorkspaceImpl, vsHierarchyItemManager As IVsHierarchyItemManager, globalOptions As IGlobalOptionService) - MyBase.New(threadingContext, workspace, vsHierarchyItemManager, globalOptions) + Public Sub New(threadingContext As IThreadingContext, workspace As VisualStudioWorkspaceImpl, vsHierarchyItemManager As IVsHierarchyItemManager) + MyBase.New(threadingContext, workspace, vsHierarchyItemManager) End Sub End Class End Namespace diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb index b83171035715c..f3383eddb4831 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb @@ -208,7 +208,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options Dim isSupportedTheme = values.isSupportedTheme Dim isCustomized = values.isCustomized - Editor_color_scheme.Visibility = If(isSupportedTheme, Visibility.Visible, Visibility.Collapsed) + Editor_color_scheme.IsEnabled = isSupportedTheme Customized_Theme_Warning.Visibility = If(isSupportedTheme AndAlso isCustomized, Visibility.Visible, Visibility.Collapsed) Custom_VS_Theme_Warning.Visibility = If(isSupportedTheme, Visibility.Collapsed, Visibility.Visible) diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/PerfMargin/DataModel.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/PerfMargin/DataModel.cs index 1659f16293a5c..d99edc1fdd2a8 100644 --- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/PerfMargin/DataModel.cs +++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/PerfMargin/DataModel.cs @@ -22,7 +22,7 @@ public DataModel() where !field.IsSpecialName select field; - var builder = new ArrayBuilder(); + using var _ = ArrayBuilder.GetInstance(out var builder); var features = new Dictionary(); var root = new ActivityLevel("All"); diff --git a/src/VisualStudio/Xaml/Impl/CodeFixes/RemoveUnnecessaryUsings/XamlRemoveUnnecessaryUsingsCodeFixProvider.cs b/src/VisualStudio/Xaml/Impl/CodeFixes/RemoveUnnecessaryUsings/XamlRemoveUnnecessaryUsingsCodeFixProvider.cs index 667ff5583be79..55d251f56d3d8 100644 --- a/src/VisualStudio/Xaml/Impl/CodeFixes/RemoveUnnecessaryUsings/XamlRemoveUnnecessaryUsingsCodeFixProvider.cs +++ b/src/VisualStudio/Xaml/Impl/CodeFixes/RemoveUnnecessaryUsings/XamlRemoveUnnecessaryUsingsCodeFixProvider.cs @@ -55,7 +55,7 @@ private static async Task RemoveUnnecessaryImportsAsync( Document document, CancellationToken cancellationToken) { var service = document.GetLanguageService(); - return await service.RemoveUnnecessaryImportsAsync(document, formattingOptions: null, cancellationToken).ConfigureAwait(false); + return await service.RemoveUnnecessaryImportsAsync(document, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/VisualStudio/Xaml/Impl/Features/InlineRename/XamlEditorInlineRenameService.cs b/src/VisualStudio/Xaml/Impl/Features/InlineRename/XamlEditorInlineRenameService.cs index 618fd9df2be78..080c38a091408 100644 --- a/src/VisualStudio/Xaml/Impl/Features/InlineRename/XamlEditorInlineRenameService.cs +++ b/src/VisualStudio/Xaml/Impl/Features/InlineRename/XamlEditorInlineRenameService.cs @@ -30,6 +30,13 @@ public XamlEditorInlineRenameService(IXamlRenameInfoService renameService) _renameService = renameService; } + public bool IsEnabled => true; + + public Task>> GetRenameContextAsync(IInlineRenameInfo inlineRenameInfo, IInlineRenameLocationSet inlineRenameLocationSet, CancellationToken cancellationToken) + { + return Task.FromResult(ImmutableDictionary>.Empty); + } + public async Task GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken) { var renameInfo = await _renameService.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false); diff --git a/src/VisualStudio/Xaml/Impl/Features/OrganizeImports/XamlRemoveUnnecessaryImportsService.cs b/src/VisualStudio/Xaml/Impl/Features/OrganizeImports/XamlRemoveUnnecessaryImportsService.cs index a100ffd03fea8..97d01f20e52c6 100644 --- a/src/VisualStudio/Xaml/Impl/Features/OrganizeImports/XamlRemoveUnnecessaryImportsService.cs +++ b/src/VisualStudio/Xaml/Impl/Features/OrganizeImports/XamlRemoveUnnecessaryImportsService.cs @@ -25,11 +25,11 @@ public XamlRemoveUnnecessaryImportsService(IXamlRemoveUnnecessaryNamespacesServi _removeService = removeService; } - public Task RemoveUnnecessaryImportsAsync(Document document, SyntaxFormattingOptions? formattingOptions, CancellationToken cancellationToken) - => RemoveUnnecessaryImportsAsync(document, predicate: null, formattingOptions, cancellationToken: cancellationToken); + public Task RemoveUnnecessaryImportsAsync(Document document, CancellationToken cancellationToken) + => RemoveUnnecessaryImportsAsync(document, predicate: null, cancellationToken: cancellationToken); public Task RemoveUnnecessaryImportsAsync( - Document document, Func? predicate, SyntaxFormattingOptions? formattingOptions, CancellationToken cancellationToken) + Document document, Func? predicate, CancellationToken cancellationToken) { return _removeService.RemoveUnnecessaryNamespacesAsync(document, cancellationToken) ?? Task.FromResult(document); } diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs index 32fd9373cc37c..6511946b2de07 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs @@ -58,6 +58,8 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe return [.. locations]; } + var solution = document.Project.Solution; + var xamlGoToDefinitionService = document.Project.Services.GetService(); if (xamlGoToDefinitionService == null) { @@ -73,7 +75,7 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe { var task = Task.Run(async () => { - foreach (var location in await this.GetLocationsAsync(definition, context, cancellationToken).ConfigureAwait(false)) + foreach (var location in await this.GetLocationsAsync(definition, document, solution, cancellationToken).ConfigureAwait(false)) { locations.Add(location); } @@ -86,17 +88,17 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe return [.. locations]; } - private async Task GetLocationsAsync(XamlDefinition definition, RequestContext context, CancellationToken cancellationToken) + private async Task GetLocationsAsync(XamlDefinition definition, Document document, Solution solution, CancellationToken cancellationToken) { using var _ = ArrayBuilder.GetInstance(out var locations); if (definition is XamlSourceDefinition sourceDefinition) { - locations.AddIfNotNull(await GetSourceDefinitionLocationAsync(sourceDefinition, context, cancellationToken).ConfigureAwait(false)); + locations.AddIfNotNull(await GetSourceDefinitionLocationAsync(sourceDefinition, solution, cancellationToken).ConfigureAwait(false)); } else if (definition is XamlSymbolDefinition symbolDefinition) { - locations.AddRange(await GetSymbolDefinitionLocationsAsync(symbolDefinition, context, _metadataAsSourceFileService, _globalOptions, cancellationToken).ConfigureAwait(false)); + locations.AddRange(await GetSymbolDefinitionLocationsAsync(symbolDefinition, document, solution, _metadataAsSourceFileService, _globalOptions, cancellationToken).ConfigureAwait(false)); } else { @@ -106,14 +108,14 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe return locations.ToArray(); } - private static async Task GetSourceDefinitionLocationAsync(XamlSourceDefinition sourceDefinition, RequestContext context, CancellationToken cancellationToken) + private static async Task GetSourceDefinitionLocationAsync(XamlSourceDefinition sourceDefinition, Solution solution, CancellationToken cancellationToken) { Contract.ThrowIfNull(sourceDefinition.FilePath); if (sourceDefinition.Span != null) { // If the Span is not null, use the span. - var document = context.Solution?.GetDocuments(ProtocolConversions.CreateAbsoluteUri(sourceDefinition.FilePath)).FirstOrDefault(); + var document = await solution.GetTextDocumentAsync(new TextDocumentIdentifier { Uri = ProtocolConversions.CreateAbsoluteUri(sourceDefinition.FilePath) }, cancellationToken).ConfigureAwait(false); if (document != null) { return await ProtocolConversions.TextSpanToLocationAsync( @@ -148,7 +150,7 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe } } - private static async Task GetSymbolDefinitionLocationsAsync(XamlSymbolDefinition symbolDefinition, RequestContext context, IMetadataAsSourceFileService metadataAsSourceFileService, IGlobalOptionService globalOptions, CancellationToken cancellationToken) + private static async Task GetSymbolDefinitionLocationsAsync(XamlSymbolDefinition symbolDefinition, Document document, Solution solution, IMetadataAsSourceFileService metadataAsSourceFileService, IGlobalOptionService globalOptions, CancellationToken cancellationToken) { Contract.ThrowIfNull(symbolDefinition.Symbol); @@ -156,15 +158,14 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe var symbol = symbolDefinition.Symbol; - var items = NavigableItemFactory.GetItemsFromPreferredSourceLocations(context.Solution, symbol, displayTaggedParts: null, cancellationToken); + var items = NavigableItemFactory.GetItemsFromPreferredSourceLocations(solution, symbol, displayTaggedParts: null, cancellationToken); if (items.Any()) { - RoslynDebug.AssertNotNull(context.Solution); foreach (var item in items) { - var document = await item.Document.GetRequiredDocumentAsync(context.Solution, cancellationToken).ConfigureAwait(false); + var navigableDocument = await item.Document.GetRequiredDocumentAsync(solution, cancellationToken).ConfigureAwait(false); var location = await ProtocolConversions.TextSpanToLocationAsync( - document, item.SourceSpan, item.IsStale, cancellationToken).ConfigureAwait(false); + navigableDocument, item.SourceSpan, item.IsStale, cancellationToken).ConfigureAwait(false); locations.AddIfNotNull(location); } } @@ -172,8 +173,8 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe { if (metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol)) { - var workspace = context.Workspace; - var project = context.Document?.GetCodeProject(); + var workspace = solution.Workspace; + var project = document.GetCodeProject(); if (workspace != null && project != null) { var options = globalOptions.GetMetadataAsSourceOptions(); diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs index 41c1810ca2b94..29d2279d9c4a6 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs @@ -76,7 +76,7 @@ protected AbstractPullDiagnosticHandler(IXamlPullDiagnosticService xamlDiagnosti { if (previousResult.TextDocument != null) { - var document = context.Solution.GetDocument(previousResult.TextDocument); + var document = await context.Solution.GetDocumentAsync(previousResult.TextDocument, cancellationToken).ConfigureAwait(false); if (document == null) { // We can no longer get this document, return null for both diagnostics and resultId @@ -161,7 +161,7 @@ private static LSP.DiagnosticSeverity ConvertDiagnosticSeverity(XamlDiagnosticSe /// /// If you make change in this method, please also update the corresponding file in - /// src\Features\LanguageServer\Protocol\Handler\Diagnostics\AbstractPullDiagnosticHandler.cs + /// src\\LanguageServer\Protocol\Extensions\ProtocolConversions.Diagnostics.cs /// private static DiagnosticTag[] ConvertTags(XamlDiagnostic diagnostic) { diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs index 3008dc4545771..03a1d678ccda8 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Formatting/AbstractFormatDocumentHandlerBase.cs @@ -39,7 +39,12 @@ internal abstract class AbstractFormatDocumentHandlerBase ProtocolConversions.TextChangeToTextEdit(change, text))); } diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Formatting/FormatDocumentOnTypeHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Formatting/FormatDocumentOnTypeHandler.cs index b5952b67e4583..4d1ada74896bf 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Formatting/FormatDocumentOnTypeHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Formatting/FormatDocumentOnTypeHandler.cs @@ -33,18 +33,18 @@ public FormatDocumentOnTypeHandler() public async Task HandleRequestAsync(DocumentOnTypeFormattingParams request, RequestContext context, CancellationToken cancellationToken) { - var edits = new ArrayBuilder(); if (string.IsNullOrEmpty(request.Character)) { - return edits.ToArrayAndFree(); + return []; } + using var _ = ArrayBuilder.GetInstance(out var edits); var document = context.Document; var formattingService = document?.Project.Services.GetService(); if (document != null && formattingService != null) { var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); - var options = new XamlFormattingOptions { InsertSpaces = request.Options.InsertSpaces, TabSize = request.Options.TabSize, OtherOptions = request.Options.OtherOptions }; + var options = new XamlFormattingOptions { InsertSpaces = request.Options.InsertSpaces, TabSize = request.Options.TabSize, OtherOptions = request.Options.OtherOptions?.AsUntyped() }; var textChanges = await formattingService.GetFormattingChangesAsync(document, options, request.Character[0], position, cancellationToken).ConfigureAwait(false); if (textChanges != null) { @@ -53,7 +53,7 @@ public async Task HandleRequestAsync(DocumentOnTypeFormattingParams } } - return edits.ToArrayAndFree(); + return edits.ToArray(); } } } diff --git a/src/Workspaces/CSharp/Portable/CaseCorrection/CSharpCaseCorrectionService.cs b/src/Workspaces/CSharp/Portable/CaseCorrection/CSharpCaseCorrectionService.cs index b2678f8e66d3b..c311dd12cf620 100644 --- a/src/Workspaces/CSharp/Portable/CaseCorrection/CSharpCaseCorrectionService.cs +++ b/src/Workspaces/CSharp/Portable/CaseCorrection/CSharpCaseCorrectionService.cs @@ -16,6 +16,7 @@ namespace Microsoft.CodeAnalysis.CSharp.CaseCorrection; [ExportLanguageService(typeof(ICaseCorrectionService), LanguageNames.CSharp), Shared] internal class CSharpCaseCorrectionService : AbstractCaseCorrectionService { + public static int I { get; } [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpCaseCorrectionService() diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index 7512194ba3485..95dc4d1a23c5d 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -39,20 +39,14 @@ public CSharpSyntaxGenerator() { } - internal override SyntaxTrivia ElasticCarriageReturnLineFeed => SyntaxFactory.ElasticCarriageReturnLineFeed; - internal override SyntaxTrivia CarriageReturnLineFeed => SyntaxFactory.CarriageReturnLineFeed; internal override SyntaxTrivia ElasticMarker => SyntaxFactory.ElasticMarker; - internal override bool RequiresExplicitImplementationForInterfaceMembers => false; - - internal override SyntaxGeneratorInternal SyntaxGeneratorInternal => CSharpSyntaxGeneratorInternal.Instance; + internal override SyntaxGeneratorInternal SyntaxGeneratorInternal + => CSharpSyntaxGeneratorInternal.Instance; internal override SyntaxTrivia Whitespace(string text) => SyntaxFactory.Whitespace(text); - internal override SyntaxTrivia SingleLineComment(string text) - => SyntaxFactory.Comment("//" + text); - internal override SeparatedSyntaxList SeparatedList(SyntaxNodeOrTokenList list) => SyntaxFactory.SeparatedList(list); @@ -3119,8 +3113,6 @@ public override SyntaxNode ThrowStatement(SyntaxNode? expression = null) public override SyntaxNode ThrowExpression(SyntaxNode expression) => SyntaxFactory.ThrowExpression((ExpressionSyntax)expression); - internal override bool SupportsThrowExpression() => true; - public override SyntaxNode IfStatement(SyntaxNode condition, IEnumerable trueStatements, IEnumerable? falseStatements = null) { if (falseStatements == null) diff --git a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/ExpressionSimplifier.cs b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/ExpressionSimplifier.cs index a901b00d4bfb1..e3824292c2717 100644 --- a/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/ExpressionSimplifier.cs +++ b/src/Workspaces/CSharp/Portable/Simplification/Simplifiers/ExpressionSimplifier.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. -#nullable disable - using System; -using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; @@ -21,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Simplification.Simplifiers; -internal partial class ExpressionSimplifier : AbstractCSharpSimplifier +internal sealed partial class ExpressionSimplifier : AbstractCSharpSimplifier { public static readonly ExpressionSimplifier Instance = new(); @@ -33,14 +31,14 @@ public override bool TrySimplify( ExpressionSyntax expression, SemanticModel semanticModel, CSharpSimplifierOptions options, - out ExpressionSyntax replacementNode, + [NotNullWhen(true)] out ExpressionSyntax? replacementNode, out TextSpan issueSpan, CancellationToken cancellationToken) { replacementNode = null; issueSpan = default; - if (expression is MemberAccessExpressionSyntax { Expression.RawKind: (int)SyntaxKind.ThisExpression } memberAccessExpression) + if (expression is MemberAccessExpressionSyntax { Expression: ThisExpressionSyntax } memberAccessExpression) { if (!MemberAccessExpressionSimplifier.Instance.ShouldSimplifyThisMemberAccessExpression( memberAccessExpression, semanticModel, options, out _, out _, cancellationToken)) @@ -65,7 +63,7 @@ public override bool TrySimplify( private static bool TryReduceExplicitName( ExpressionSyntax expression, SemanticModel semanticModel, - out TypeSyntax replacementNode, + [NotNullWhen(true)] out TypeSyntax? replacementNode, out TextSpan issueSpan, CSharpSimplifierOptions options, CancellationToken cancellationToken) @@ -88,7 +86,7 @@ private static bool TryReduceExplicitName( private static bool TryReduceMemberAccessExpression( MemberAccessExpressionSyntax memberAccess, SemanticModel semanticModel, - out TypeSyntax replacementNode, + [NotNullWhen(true)] out TypeSyntax? replacementNode, out TextSpan issueSpan, CSharpSimplifierOptions options, CancellationToken cancellationToken) @@ -147,17 +145,17 @@ private static bool TryReduceMemberAccessExpression( if (syntaxRef != null) { - var declIdentifier = ((UsingDirectiveSyntax)syntaxRef.GetSyntax(cancellationToken)).Alias.Name.Identifier; + var declIdentifier = ((UsingDirectiveSyntax)syntaxRef.GetSyntax(cancellationToken)).Alias!.Name.Identifier; text = declIdentifier.IsVerbatimIdentifier() ? declIdentifier.ToString()[1..] : declIdentifier.ToString(); } replacementNode = SyntaxFactory.IdentifierName( - memberAccess.Name.Identifier.CopyAnnotationsTo(SyntaxFactory.Identifier( - memberAccess.GetLeadingTrivia(), - SyntaxKind.IdentifierToken, - text, - aliasReplacement.Name, - memberAccess.GetTrailingTrivia()))); + memberAccess.Name.Identifier.CopyAnnotationsTo(SyntaxFactory.Identifier( + memberAccess.GetLeadingTrivia(), + SyntaxKind.IdentifierToken, + text, + aliasReplacement.Name, + memberAccess.GetTrailingTrivia()))); replacementNode = memberAccess.CopyAnnotationsTo(replacementNode); replacementNode = memberAccess.Name.CopyAnnotationsTo(replacementNode); @@ -245,9 +243,7 @@ private static void GetReplacementCandidates( private static bool IsReplacementCandidate(ISymbol actualSymbol, ImmutableArray speculativeSymbols, ImmutableArray speculativeNamespacesAndTypes) { if (speculativeSymbols.IsEmpty && speculativeNamespacesAndTypes.IsEmpty) - { return false; - } if (actualSymbol is object) { @@ -261,54 +257,58 @@ private static bool IsReplacementCandidate(ISymbol actualSymbol, ImmutableArray< private static bool TrySimplify( ExpressionSyntax expression, SemanticModel semanticModel, - out ExpressionSyntax replacementNode, + [NotNullWhen(true)] out ExpressionSyntax? replacementNode, out TextSpan issueSpan, CancellationToken cancellationToken) { - replacementNode = null; - issueSpan = default; + if (!TrySimplifyWorker(expression, semanticModel, out replacementNode, out issueSpan, cancellationToken)) + return false; + + // Ensure that replacement doesn't change semantics. + var speculationAnalyzer = new SpeculationAnalyzer(expression, replacementNode, semanticModel, cancellationToken); + return !speculationAnalyzer.ReplacementChangesSemantics(); - switch (expression.Kind()) + static bool TrySimplifyWorker( + ExpressionSyntax expression, + SemanticModel semanticModel, + [NotNullWhen(true)] out ExpressionSyntax? replacementNode, + out TextSpan issueSpan, + CancellationToken cancellationToken) { - case SyntaxKind.SimpleMemberAccessExpression: - { - var memberAccess = (MemberAccessExpressionSyntax)expression; - if (IsNonRemovablePartOfDynamicMethodInvocation(semanticModel, memberAccess, cancellationToken)) - { - return false; - } + replacementNode = null; + issueSpan = default; - if (TrySimplifyMemberAccessOrQualifiedName(memberAccess.Expression, memberAccess.Name, semanticModel, out var newLeft, out issueSpan)) + switch (expression) + { + case MemberAccessExpressionSyntax(SyntaxKind.SimpleMemberAccessExpression) memberAccess: { + if (IsNonRemovablePartOfDynamicMethodInvocation(semanticModel, memberAccess, cancellationToken)) + return false; + + if (!TrySimplifyMemberAccessOrQualifiedName(memberAccess.Expression, memberAccess.Name, semanticModel, out var newLeft, out issueSpan)) + return false; + // replacement node might not be in it's simplest form, so add simplify annotation to it. replacementNode = memberAccess.Update(newLeft, memberAccess.OperatorToken, memberAccess.Name) .WithAdditionalAnnotations(Simplifier.Annotation); - - // Ensure that replacement doesn't change semantics. - return !ReplacementChangesSemantics(memberAccess, replacementNode, semanticModel); + return true; } - return false; - } - - case SyntaxKind.QualifiedName: - { - var qualifiedName = (QualifiedNameSyntax)expression; - if (TrySimplifyMemberAccessOrQualifiedName(qualifiedName.Left, qualifiedName.Right, semanticModel, out var newLeft, out issueSpan)) + case QualifiedNameSyntax qualifiedName: { + if (!TrySimplifyMemberAccessOrQualifiedName(qualifiedName.Left, qualifiedName.Right, semanticModel, out var newLeft, out issueSpan)) + return false; + // replacement node might not be in it's simplest form, so add simplify annotation to it. replacementNode = qualifiedName.Update((NameSyntax)newLeft, qualifiedName.DotToken, qualifiedName.Right) .WithAdditionalAnnotations(Simplifier.Annotation); - // Ensure that replacement doesn't change semantics. - return !ReplacementChangesSemantics(qualifiedName, replacementNode, semanticModel); + return true; } + } - return false; - } + return false; } - - return false; } private static bool CanReplaceWithMemberAccessName( @@ -372,7 +372,7 @@ private static bool IsNonRemovablePartOfDynamicMethodInvocation( var leftSymbol = semanticModel.GetSymbolInfo(memberAccess.Expression, cancellationToken).GetAnySymbol(); if (leftSymbol is INamedTypeSymbol) { - var type = semanticModel.GetTypeInfo(memberAccess.Parent, cancellationToken).Type; + var type = semanticModel.GetTypeInfo(memberAccess.GetRequiredParent(), cancellationToken).Type; if (type?.Kind == SymbolKind.DynamicType) { return true; @@ -392,7 +392,7 @@ private static bool AccessMethodWithDynamicArgumentInsideStructConstructor(Membe { var constructor = memberAccess.Ancestors().OfType().SingleOrDefault(); - if (constructor == null || constructor.Parent.Kind() is not (SyntaxKind.StructDeclaration or SyntaxKind.RecordStructDeclaration)) + if (constructor == null || constructor.GetRequiredParent().Kind() is not (SyntaxKind.StructDeclaration or SyntaxKind.RecordStructDeclaration)) { return false; } @@ -405,7 +405,7 @@ private static bool TrySimplifyMemberAccessOrQualifiedName( ExpressionSyntax left, ExpressionSyntax right, SemanticModel semanticModel, - out ExpressionSyntax replacementNode, + [NotNullWhen(true)] out ExpressionSyntax? replacementNode, out TextSpan issueSpan) { replacementNode = null; @@ -414,51 +414,25 @@ private static bool TrySimplifyMemberAccessOrQualifiedName( if (left != null && right != null) { var leftSymbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, left); - if (leftSymbol != null && leftSymbol.Kind == SymbolKind.NamedType) + if (leftSymbol is INamedTypeSymbol) { var rightSymbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, right); if (rightSymbol != null && (rightSymbol.IsStatic || rightSymbol.Kind == SymbolKind.NamedType)) { // Static member access or nested type member access. - var containingType = rightSymbol.ContainingType; - - var enclosingSymbol = semanticModel.GetEnclosingSymbol(left.SpanStart); - var enclosingTypeParametersInsideOut = new List(); - - while (enclosingSymbol != null) + if (rightSymbol.ContainingType is { TypeArguments.Length: 0 } containingType && + !containingType.Equals(leftSymbol)) { - if (enclosingSymbol is IMethodSymbol methodSymbol) - { - if (methodSymbol.TypeArguments.Length != 0) - { - enclosingTypeParametersInsideOut.AddRange(methodSymbol.TypeArguments); - } - } - - if (enclosingSymbol is INamedTypeSymbol namedTypeSymbol) - { - if (namedTypeSymbol.TypeArguments.Length != 0) - { - enclosingTypeParametersInsideOut.AddRange(namedTypeSymbol.TypeArguments); - } - } - - enclosingSymbol = enclosingSymbol.ContainingSymbol; - } - - if (containingType != null && !containingType.Equals(leftSymbol)) - { - if (leftSymbol is INamedTypeSymbol && - containingType.TypeArguments.Length != 0) - { + // Don't simplify to a base type if it has the EditorBrowsable attribute on it. This is + // occasionally done in some APIs to have a 'pseudo internal' base type that has functionality, + // which a user is supposed to only access through some 'pseudo public' derived type instead. + if (!containingType.IsEditorBrowsable(hideAdvancedMembers: true, semanticModel.Compilation, includingSourceSymbols: true)) return false; - } // We have a static member access or a nested type member access using a more derived type. - // Simplify syntax so as to use accessed member's most immediate containing type instead of the derived type. - replacementNode = containingType.GenerateTypeSyntax() - .WithLeadingTrivia(left.GetLeadingTrivia()) - .WithTrailingTrivia(left.GetTrailingTrivia()); + // Simplify syntax so as to use accessed member's most immediate containing type instead of the + // derived type. + replacementNode = containingType.GenerateTypeSyntax().WithTriviaFrom(left); issueSpan = left.Span; return true; } @@ -468,10 +442,4 @@ private static bool TrySimplifyMemberAccessOrQualifiedName( return false; } - - protected static bool ReplacementChangesSemantics(ExpressionSyntax originalExpression, ExpressionSyntax replacedExpression, SemanticModel semanticModel) - { - var speculationAnalyzer = new SpeculationAnalyzer(originalExpression, replacedExpression, semanticModel, CancellationToken.None); - return speculationAnalyzer.ReplacementChangesSemantics(); - } } diff --git a/src/Workspaces/CSharp/Portable/Workspace/LanguageServices/CSharpSyntaxTreeFactoryService.cs b/src/Workspaces/CSharp/Portable/Workspace/LanguageServices/CSharpSyntaxTreeFactoryService.cs index 314028437561d..e8bc065d68a2d 100644 --- a/src/Workspaces/CSharp/Portable/Workspace/LanguageServices/CSharpSyntaxTreeFactoryService.cs +++ b/src/Workspaces/CSharp/Portable/Workspace/LanguageServices/CSharpSyntaxTreeFactoryService.cs @@ -55,10 +55,10 @@ public override bool OptionsDifferOnlyByPreprocessorDirectives(ParseOptions opti return csharpOptions1.WithPreprocessorSymbols(csharpOptions2.PreprocessorSymbolNames) == csharpOptions2; } - public override SyntaxTree CreateSyntaxTree(string filePath, ParseOptions options, Encoding encoding, SourceHashAlgorithm checksumAlgorithm, SyntaxNode root) + public override SyntaxTree CreateSyntaxTree(string filePath, ParseOptions options, SourceText text, Encoding encoding, SourceHashAlgorithm checksumAlgorithm, SyntaxNode root) { options ??= GetDefaultParseOptions(); - return new ParsedSyntaxTree(lazyText: null, (CSharpSyntaxNode)root, (CSharpParseOptions)options, filePath, encoding, checksumAlgorithm); + return new ParsedSyntaxTree(text, (CSharpSyntaxNode)root, (CSharpParseOptions)options, filePath, encoding, checksumAlgorithm); } public override SyntaxTree ParseSyntaxTree(string filePath, ParseOptions options, SourceText text, CancellationToken cancellationToken) diff --git a/src/Workspaces/CSharpTest/CodeGeneration/AddAttributesTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/AddAttributesTests.cs index 2f6adf67efba5..752885ae9108a 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/AddAttributesTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/AddAttributesTests.cs @@ -31,7 +31,7 @@ private static Document GetDocument(string code) "test", "test.dll", LanguageNames.CSharp, - metadataReferences: new[] { TestMetadata.Net451.mscorlib })); + metadataReferences: [NetFramework.mscorlib])); return emptyProject.AddDocument("test.cs", code); } diff --git a/src/Workspaces/CSharpTest/CodeGeneration/AddImportsTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/AddImportsTests.cs index 7024de4195a20..2760139540b26 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/AddImportsTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/AddImportsTests.cs @@ -35,7 +35,7 @@ private static async Task GetDocument(string code, bool withAnnotation "test", "test.dll", LanguageNames.CSharp, - metadataReferences: new[] { TestMetadata.Net451.mscorlib })); + metadataReferences: [NetFramework.mscorlib])); var doc = emptyProject.AddDocument("test.cs", code); @@ -781,7 +781,7 @@ public void M2([A] String p2) { } "test", "test.dll", LanguageNames.CSharp, - metadataReferences: new[] { TestMetadata.Net451.mscorlib })); + metadataReferences: [NetFramework.mscorlib])); var project = emptyProject .AddMetadataReferences([otherAssemblyReference]) @@ -835,7 +835,7 @@ private static MetadataReference GetInMemoryAssemblyReferenceForCode(string code var compilation = CSharpCompilation .Create("test.dll", [tree]) .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) - .AddReferences(TestMetadata.Net451.mscorlib); + .AddReferences(NetFramework.mscorlib); return compilation.ToMetadataReference(); } diff --git a/src/Workspaces/CSharpTest/CodeGeneration/SymbolEditorTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/SymbolEditorTests.cs index b962df4d6c7a5..099b9f309e0bd 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/SymbolEditorTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/SymbolEditorTests.cs @@ -40,7 +40,7 @@ private static Solution GetSolution(params string[] sources) loader: TextLoader.From(TextAndVersion.Create(SourceText.From(s, encoding: null, SourceHashAlgorithms.Default), VersionStamp.Default)))).ToList(); var proj = ProjectInfo.Create(pid, VersionStamp.Default, "test", "test.dll", LanguageNames.CSharp, documents: docs, - metadataReferences: new[] { TestMetadata.Net451.mscorlib }); + metadataReferences: [NetFramework.mscorlib]); return ws.AddProject(proj).Solution; } diff --git a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs index 15bdfdbda86cf..459ee718d0c3a 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs @@ -27,7 +27,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Editing public sealed class SyntaxGeneratorTests { private readonly CSharpCompilation _emptyCompilation = CSharpCompilation.Create("empty", - references: [TestMetadata.Net451.mscorlib, TestMetadata.Net451.System]); + references: [NetFramework.mscorlib, NetFramework.System]); private Workspace _workspace; private SyntaxGenerator _generator; @@ -41,7 +41,7 @@ private SyntaxGenerator Generator public static Compilation Compile(string code) { return CSharpCompilation.Create("test") - .AddReferences(TestMetadata.Net451.mscorlib, TestMetadata.Net451.System, TestMetadata.Net451.SystemCore, TestMetadata.Net451.SystemRuntime, TestReferences.NetFx.ValueTuple.tuplelib) + .AddReferences(NetFramework.mscorlib, NetFramework.System, NetFramework.SystemCore, NetFramework.SystemRuntime, NetFramework.SystemValueTuple) .AddSyntaxTrees(ParseSyntaxTree(code)); } @@ -971,13 +971,13 @@ public void TestOperatorDeclaration() [Fact, WorkItem(63410, "https://github.com/dotnet/roslyn/issues/63410")] public void TestCheckedOperator() { - var comp = CSharpCompilation.Create(null, new[] { SyntaxFactory.ParseSyntaxTree(""" + var comp = CSharpCompilation.Create(null, [SyntaxFactory.ParseSyntaxTree(""" public class C { public static C operator checked ++(C x) => x; public static C operator ++(C x) => x; } - """) }); + """)]); var operatorSymbol = (IMethodSymbol)comp.GetTypeByMetadataName("C").GetMembers(WellKnownMemberNames.CheckedIncrementOperatorName).Single(); VerifySyntax(Generator.OperatorDeclaration(operatorSymbol), "public static global::C operator checked ++(global::C x)\r\n{\r\n}"); } @@ -2611,7 +2611,7 @@ private void AssertNamesEqual(string[] expectedNames, IEnumerable ac } private void AssertNamesEqual(string name, IEnumerable actualNodes) - => AssertNamesEqual(new[] { name }, actualNodes); + => AssertNamesEqual([name], actualNodes); private void AssertMemberNamesEqual(string[] expectedNames, SyntaxNode declaration) => AssertNamesEqual(expectedNames, Generator.GetMembers(declaration)); @@ -2710,7 +2710,7 @@ public class C var cls = cu.Members[0]; var text = cls.DescendantNodes(descendIntoTrivia: true).OfType().First(); - var newCu = Generator.InsertNodesAfter(cu, text, new SyntaxNode[] { text }); + var newCu = Generator.InsertNodesAfter(cu, text, [text]); VerifySyntaxRaw( newCu, @" @@ -2733,7 +2733,7 @@ public class C var cls = cu.Members[0]; var text = cls.DescendantNodes(descendIntoTrivia: true).OfType().First(); - var newCu = Generator.InsertNodesBefore(cu, text, new SyntaxNode[] { text }); + var newCu = Generator.InsertNodesBefore(cu, text, [text]); VerifySyntaxRaw( newCu, @" @@ -3382,7 +3382,7 @@ public void TestAccessorDeclarations() VerifySyntax(newGetAccessor, @"get;"); - var newNewGetAccessor = Generator.WithStatements(newGetAccessor, new SyntaxNode[] { }); + var newNewGetAccessor = Generator.WithStatements(newGetAccessor, []); VerifySyntax(newNewGetAccessor, @"get { @@ -3544,10 +3544,10 @@ public void TestGetStatements() Assert.Equal(0, Generator.GetStatements(Generator.ConstructorDeclaration()).Count); Assert.Equal(2, Generator.GetStatements(Generator.ConstructorDeclaration(statements: stmts)).Count); - Assert.Equal(0, Generator.GetStatements(Generator.VoidReturningLambdaExpression(new SyntaxNode[] { })).Count); + Assert.Equal(0, Generator.GetStatements(Generator.VoidReturningLambdaExpression([])).Count); Assert.Equal(2, Generator.GetStatements(Generator.VoidReturningLambdaExpression(stmts)).Count); - Assert.Equal(0, Generator.GetStatements(Generator.ValueReturningLambdaExpression(new SyntaxNode[] { })).Count); + Assert.Equal(0, Generator.GetStatements(Generator.ValueReturningLambdaExpression([])).Count); Assert.Equal(2, Generator.GetStatements(Generator.ValueReturningLambdaExpression(stmts)).Count); Assert.Equal(0, Generator.GetStatements(Generator.IdentifierName("x")).Count); @@ -3567,8 +3567,8 @@ public void TestWithStatements() Assert.Equal(2, Generator.GetStatements(Generator.WithStatements(Generator.MethodDeclaration("m"), stmts)).Count); Assert.Equal(2, Generator.GetStatements(Generator.WithStatements(Generator.ConstructorDeclaration(), stmts)).Count); - Assert.Equal(2, Generator.GetStatements(Generator.WithStatements(Generator.VoidReturningLambdaExpression(new SyntaxNode[] { }), stmts)).Count); - Assert.Equal(2, Generator.GetStatements(Generator.WithStatements(Generator.ValueReturningLambdaExpression(new SyntaxNode[] { }), stmts)).Count); + Assert.Equal(2, Generator.GetStatements(Generator.WithStatements(Generator.VoidReturningLambdaExpression([]), stmts)).Count); + Assert.Equal(2, Generator.GetStatements(Generator.WithStatements(Generator.ValueReturningLambdaExpression([]), stmts)).Count); Assert.Equal(0, Generator.GetStatements(Generator.WithStatements(Generator.IdentifierName("x"), stmts)).Count); } @@ -3996,7 +3996,7 @@ public void TestInsertMembersOnRecordStruct_SemiColon() @"public record struct C; "; var comp = CSharpCompilation.Create("test") - .AddReferences(TestMetadata.Net451.mscorlib) + .AddReferences(NetFramework.mscorlib) .AddSyntaxTrees(ParseSyntaxTree(src, options: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview))); var symbolC = (INamedTypeSymbol)comp.GlobalNamespace.GetMembers("C").First(); diff --git a/src/Workspaces/Core/Desktop/Microsoft.CodeAnalysis.Workspaces.Desktop.csproj b/src/Workspaces/Core/Desktop/Microsoft.CodeAnalysis.Workspaces.Desktop.csproj index 2086ffedd9f66..0f3912a209e6f 100644 --- a/src/Workspaces/Core/Desktop/Microsoft.CodeAnalysis.Workspaces.Desktop.csproj +++ b/src/Workspaces/Core/Desktop/Microsoft.CodeAnalysis.Workspaces.Desktop.csproj @@ -5,7 +5,7 @@ Library Microsoft.CodeAnalysis net472;$(NetVS) - true + true true diff --git a/src/Workspaces/Core/MSBuild.BuildHost/Build/ProjectBuildManager.cs b/src/Workspaces/Core/MSBuild.BuildHost/Build/ProjectBuildManager.cs index 05ad5789c365a..bde7063efa92c 100644 --- a/src/Workspaces/Core/MSBuild.BuildHost/Build/ProjectBuildManager.cs +++ b/src/Workspaces/Core/MSBuild.BuildHost/Build/ProjectBuildManager.cs @@ -30,7 +30,7 @@ internal class ProjectBuildManager { PropertyNames.DesignTimeBuild, bool.TrueString }, // this will force CoreCompile task to execute even if all inputs and outputs are up to date -#if NETCOREAPP +#if NET { PropertyNames.NonExistentFile, "__NonExistentSubDir__\\__NonExistentFile__" }, #else // Setting `BuildingInsideVisualStudio` indirectly sets NonExistentFile: diff --git a/src/Workspaces/Core/MSBuild.BuildHost/BuildHost.cs b/src/Workspaces/Core/MSBuild.BuildHost/BuildHost.cs index 08e8008ad8046..c74d8ff18494f 100644 --- a/src/Workspaces/Core/MSBuild.BuildHost/BuildHost.cs +++ b/src/Workspaces/Core/MSBuild.BuildHost/BuildHost.cs @@ -161,9 +161,18 @@ private void EnsureMSBuildLoaded(string projectFilePath) /// /// Returns the target ID of the object created for this. /// - public async Task LoadProjectFileAsync(string projectFilePath, string languageName, CancellationToken cancellationToken) + public Task LoadProjectFileAsync(string projectFilePath, string languageName, CancellationToken cancellationToken) { EnsureMSBuildLoaded(projectFilePath); + return LoadProjectFileCoreAsync(projectFilePath, languageName, cancellationToken); + } + + // When using the Mono runtime, the MSBuild types used in this method must be available + // to the JIT during compilation of the method, so they have to be loaded by the caller; + // therefore this method must not be inlined. + [MethodImpl(MethodImplOptions.NoInlining)] + private async Task LoadProjectFileCoreAsync(string projectFilePath, string languageName, CancellationToken cancellationToken) + { CreateBuildManager(); ProjectFileLoader projectLoader = languageName switch diff --git a/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/Extensions.cs b/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/Extensions.cs index 62f7fac4a2e72..c38df008fd65e 100644 --- a/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/Extensions.cs +++ b/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/Extensions.cs @@ -60,7 +60,7 @@ public static ImmutableArray GetAliases(this MSB.Framework.ITaskItem ite var aliasesText = item.GetMetadata(MetadataNames.Aliases); return !string.IsNullOrWhiteSpace(aliasesText) - ? ImmutableArray.CreateRange(aliasesText.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(a => a.Trim())) + ? ImmutableArray.CreateRange(aliasesText.Split([','], StringSplitOptions.RemoveEmptyEntries).Select(a => a.Trim())) : []; } diff --git a/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/ProjectFile.cs b/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/ProjectFile.cs index 3d58407ffafb9..7aad5f1121ef8 100644 --- a/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/ProjectFile.cs +++ b/src/Workspaces/Core/MSBuild.BuildHost/MSBuild/ProjectFile/ProjectFile.cs @@ -9,6 +9,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.Build.Evaluation; +using Microsoft.Build.Globbing; +using Microsoft.Build.Globbing.Extensions; using Roslyn.Utilities; using MSB = Microsoft.Build; @@ -171,6 +174,8 @@ private ProjectFileInfo CreateProjectFileInfo(MSB.Execution.ProjectInstance proj var projectCapabilities = project.GetItems(ItemNames.ProjectCapability).SelectAsArray(item => item.ToString()); var contentFileInfo = GetContentFiles(project); + var fileGlobs = _loadedProject?.GetAllGlobs().Select(GetFileGlobs).ToImmutableArray() ?? []; + return ProjectFileInfo.Create( Language, project.FullPath, @@ -189,7 +194,13 @@ private ProjectFileInfo CreateProjectFileInfo(MSB.Execution.ProjectInstance proj project.GetProjectReferences().ToImmutableArray(), packageReferences, projectCapabilities, - contentFileInfo); + contentFileInfo, + fileGlobs); + + static FileGlobs GetFileGlobs(GlobResult g) + { + return new FileGlobs(g.IncludeGlobs.ToImmutableArray(), g.Excludes.ToImmutableArray(), g.Removes.ToImmutableArray()); + } } private static ImmutableArray GetContentFiles(MSB.Execution.ProjectInstance project) diff --git a/src/Workspaces/Core/MSBuild.BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj b/src/Workspaces/Core/MSBuild.BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj index 2044a92f4e678..5f057a9af8da1 100644 --- a/src/Workspaces/Core/MSBuild.BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj +++ b/src/Workspaces/Core/MSBuild.BuildHost/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj @@ -30,9 +30,11 @@ + + diff --git a/src/Workspaces/Core/MSBuild.BuildHost/Rpc/Contracts/FileGlobs.cs b/src/Workspaces/Core/MSBuild.BuildHost/Rpc/Contracts/FileGlobs.cs new file mode 100644 index 0000000000000..01a075550b3b8 --- /dev/null +++ b/src/Workspaces/Core/MSBuild.BuildHost/Rpc/Contracts/FileGlobs.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Runtime.Serialization; + +namespace Microsoft.CodeAnalysis.MSBuild; + +[DataContract] +internal record FileGlobs( + [property: DataMember(Order = 0)] ImmutableArray Includes, + [property: DataMember(Order = 1)] ImmutableArray Excludes, + [property: DataMember(Order = 2)] ImmutableArray Removes +); diff --git a/src/Workspaces/Core/MSBuild.BuildHost/Rpc/Contracts/ProjectFileInfo.cs b/src/Workspaces/Core/MSBuild.BuildHost/Rpc/Contracts/ProjectFileInfo.cs index 17bd6acb2a3c5..ea1f3fc969f5a 100644 --- a/src/Workspaces/Core/MSBuild.BuildHost/Rpc/Contracts/ProjectFileInfo.cs +++ b/src/Workspaces/Core/MSBuild.BuildHost/Rpc/Contracts/ProjectFileInfo.cs @@ -137,6 +137,9 @@ internal sealed class ProjectFileInfo [DataMember(Order = 18)] public string? TargetFrameworkVersion { get; } + [DataMember(Order = 19)] + public ImmutableArray FileGlobs { get; } + public override string ToString() => RoslynString.IsNullOrWhiteSpace(TargetFramework) ? FilePath ?? string.Empty @@ -161,7 +164,8 @@ public ProjectFileInfo( ImmutableArray projectReferences, ImmutableArray packageReferences, ImmutableArray projectCapabilities, - ImmutableArray contentFilePaths) + ImmutableArray contentFilePaths, + ImmutableArray fileGlobs) { RoslynDebug.Assert(filePath != null); @@ -184,6 +188,7 @@ public ProjectFileInfo( this.PackageReferences = packageReferences; this.ProjectCapabilities = projectCapabilities; this.ContentFilePaths = contentFilePaths; + this.FileGlobs = fileGlobs; } public static ProjectFileInfo Create( @@ -204,7 +209,8 @@ public static ProjectFileInfo Create( ImmutableArray projectReferences, ImmutableArray packageReferences, ImmutableArray projectCapabilities, - ImmutableArray contentFilePaths) + ImmutableArray contentFilePaths, + ImmutableArray fileGlobs) => new( isEmpty: false, language, @@ -224,7 +230,8 @@ public static ProjectFileInfo Create( projectReferences, packageReferences, projectCapabilities, - contentFilePaths); + contentFilePaths, + fileGlobs); public static ProjectFileInfo CreateEmpty(string language, string? filePath) => new( @@ -246,6 +253,7 @@ public static ProjectFileInfo CreateEmpty(string language, string? filePath) projectReferences: [], packageReferences: [], projectCapabilities: [], - contentFilePaths: []); + contentFilePaths: [], + fileGlobs: []); } } diff --git a/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj b/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj index 6d806fdba2eb8..ce6eb532a8a5a 100644 --- a/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj +++ b/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj @@ -87,7 +87,7 @@ --> - + <_NetFrameworkBuildHostProjectReference Include="..\..\..\Workspaces\Core\MSBuild.BuildHost\Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.csproj"> net472 BuildHost-net472 diff --git a/src/Workspaces/Core/Portable/CaseCorrection/AbstractCaseCorrectionService.cs b/src/Workspaces/Core/Portable/CaseCorrection/AbstractCaseCorrectionService.cs index 13189cecb59e1..76b0f134d4ef8 100644 --- a/src/Workspaces/Core/Portable/CaseCorrection/AbstractCaseCorrectionService.cs +++ b/src/Workspaces/Core/Portable/CaseCorrection/AbstractCaseCorrectionService.cs @@ -29,7 +29,7 @@ public async Task CaseCorrectAsync(Document document, ImmutableArray CaseCorrectAsync(Document document, Cancellat var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (root is null) { - throw new NotSupportedException(WorkspacesResources.Document_does_not_support_syntax_trees); + throw new NotSupportedException(WorkspaceExtensionsResources.Document_does_not_support_syntax_trees); } return await CaseCorrectAsync(document, root.FullSpan, cancellationToken).ConfigureAwait(false); @@ -43,7 +43,7 @@ public static async Task CaseCorrectAsync(Document document, SyntaxAnn var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); if (root is null) { - throw new NotSupportedException(WorkspacesResources.Document_does_not_support_syntax_trees); + throw new NotSupportedException(WorkspaceExtensionsResources.Document_does_not_support_syntax_trees); } return await CaseCorrectAsync(document, root.GetAnnotatedNodesAndTokens(annotation).Select(n => n.Span).ToImmutableArray(), cancellationToken).ConfigureAwait(false); diff --git a/src/Workspaces/Core/Portable/CodeActions/Annotations/SuppressDiagnosticsAnnotation.cs b/src/Workspaces/Core/Portable/CodeActions/Annotations/SuppressDiagnosticsAnnotation.cs index 21afa3dc41704..d0dfe492d7f97 100644 --- a/src/Workspaces/Core/Portable/CodeActions/Annotations/SuppressDiagnosticsAnnotation.cs +++ b/src/Workspaces/Core/Portable/CodeActions/Annotations/SuppressDiagnosticsAnnotation.cs @@ -4,7 +4,7 @@ namespace Microsoft.CodeAnalysis.CodeActions; -internal class SuppressDiagnosticsAnnotation +internal sealed class SuppressDiagnosticsAnnotation { public const string Kind = "CodeAction_SuppressDiagnostics"; diff --git a/src/Workspaces/Core/Portable/CodeActions/Operations/OpenDocumentOperation.cs b/src/Workspaces/Core/Portable/CodeActions/Operations/OpenDocumentOperation.cs index 974108bf99a03..4783dd013fb40 100644 --- a/src/Workspaces/Core/Portable/CodeActions/Operations/OpenDocumentOperation.cs +++ b/src/Workspaces/Core/Portable/CodeActions/Operations/OpenDocumentOperation.cs @@ -12,15 +12,13 @@ namespace Microsoft.CodeAnalysis.CodeActions; /// public sealed class OpenDocumentOperation(DocumentId documentId, bool activateIfAlreadyOpen = false) : CodeActionOperation { - private readonly DocumentId _documentId = documentId ?? throw new ArgumentNullException(nameof(documentId)); - - public DocumentId DocumentId => _documentId; + public DocumentId DocumentId { get; } = documentId ?? throw new ArgumentNullException(nameof(documentId)); public override void Apply(Workspace workspace, CancellationToken cancellationToken) { if (workspace.CanOpenDocuments) { - workspace.OpenDocument(_documentId, activateIfAlreadyOpen); + workspace.OpenDocument(DocumentId, activateIfAlreadyOpen); } } } diff --git a/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs b/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs index ef396f37af53b..d66fec3237654 100644 --- a/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs +++ b/src/Workspaces/Core/Portable/CodeCleanup/AbstractCodeCleanerService.cs @@ -633,7 +633,7 @@ private enum SpanMarkerType /// /// Internal annotation type to mark span location in the tree. /// - private class SpanMarker + private sealed class SpanMarker { /// /// Indicates the current marker type diff --git a/src/Workspaces/Core/Portable/CodeCleanup/Providers/ExportCodeCleanupProvider.cs b/src/Workspaces/Core/Portable/CodeCleanup/Providers/ExportCodeCleanupProvider.cs index 47af287f6a4c6..c38be22243b3f 100644 --- a/src/Workspaces/Core/Portable/CodeCleanup/Providers/ExportCodeCleanupProvider.cs +++ b/src/Workspaces/Core/Portable/CodeCleanup/Providers/ExportCodeCleanupProvider.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeCleanup.Providers; /// [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] -internal class ExportCodeCleanupProvider : ExportAttribute +internal sealed class ExportCodeCleanupProvider : ExportAttribute { public string Name { get; } public IEnumerable Languages { get; } diff --git a/src/Workspaces/Core/Portable/CodeCleanup/Providers/SimplificationCodeCleanupProvider.cs b/src/Workspaces/Core/Portable/CodeCleanup/Providers/SimplificationCodeCleanupProvider.cs index e9968427db4ad..fc30204eb8faf 100644 --- a/src/Workspaces/Core/Portable/CodeCleanup/Providers/SimplificationCodeCleanupProvider.cs +++ b/src/Workspaces/Core/Portable/CodeCleanup/Providers/SimplificationCodeCleanupProvider.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CodeCleanup.Providers; -internal class SimplificationCodeCleanupProvider : ICodeCleanupProvider +internal sealed class SimplificationCodeCleanupProvider : ICodeCleanupProvider { public string Name => PredefinedCodeCleanupProviderNames.Simplification; diff --git a/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs b/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs index 1a5be65d58641..e09c4199551a7 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/CodeFixContext.cs @@ -18,10 +18,6 @@ namespace Microsoft.CodeAnalysis.CodeFixes; /// public readonly struct CodeFixContext { - private readonly TextDocument _document; - private readonly TextSpan _span; - private readonly ImmutableArray _diagnostics; - private readonly CancellationToken _cancellationToken; private readonly Action> _registerCodeFix; /// @@ -50,34 +46,23 @@ public Document Document /// code fixes that support non-source documents by providing a non-default value for /// /// - public TextDocument TextDocument => _document; + public TextDocument TextDocument { get; } /// /// Text span within the or to fix. /// - public TextSpan Span => _span; + public TextSpan Span { get; } /// /// Diagnostics to fix. /// NOTE: All the diagnostics in this collection have the same . /// - public ImmutableArray Diagnostics => _diagnostics; + public ImmutableArray Diagnostics { get; } /// /// CancellationToken. /// - public CancellationToken CancellationToken => _cancellationToken; - - /// - /// IDE supplied options to use for settings not specified in the corresponding editorconfig file. - /// These are not available in Code Style layer. Use extension method - /// to access these options in code shared with Code Style layer. - /// - /// - /// This is a (rather than directly) - /// to allow code fix to update documents across multiple projects that differ in language (and hence language specific options). - /// - internal readonly CodeActionOptionsProvider Options; + public CancellationToken CancellationToken { get; } /// /// Creates a code fix context to be passed into method. @@ -103,11 +88,10 @@ public CodeFixContext( ImmutableArray diagnostics, Action> registerCodeFix, CancellationToken cancellationToken) - : this(document, + : this((TextDocument)document, span, diagnostics, registerCodeFix, - CodeActionOptions.DefaultProvider, cancellationToken) { } @@ -135,13 +119,14 @@ public CodeFixContext( ImmutableArray diagnostics, Action> registerCodeFix, CancellationToken cancellationToken) - : this(document, - span, - diagnostics, - registerCodeFix, - CodeActionOptions.DefaultProvider, - cancellationToken) { + VerifyDiagnosticsArgument(diagnostics, span); + + TextDocument = document ?? throw new ArgumentNullException(nameof(document)); + Span = span; + Diagnostics = diagnostics; + _registerCodeFix = registerCodeFix ?? throw new ArgumentNullException(nameof(registerCodeFix)); + CancellationToken = cancellationToken; } /// @@ -165,7 +150,6 @@ public CodeFixContext( (diagnostic ?? throw new ArgumentNullException(nameof(diagnostic))).Location.SourceSpan, [diagnostic], registerCodeFix, - CodeActionOptions.DefaultProvider, cancellationToken) { } @@ -190,29 +174,10 @@ public CodeFixContext( (diagnostic ?? throw new ArgumentNullException(nameof(diagnostic))).Location.SourceSpan, [diagnostic], registerCodeFix, - CodeActionOptions.DefaultProvider, cancellationToken) { } - internal CodeFixContext( - TextDocument document, - TextSpan span, - ImmutableArray diagnostics, - Action> registerCodeFix, - CodeActionOptionsProvider options, - CancellationToken cancellationToken) - { - VerifyDiagnosticsArgument(diagnostics, span); - - _document = document ?? throw new ArgumentNullException(nameof(document)); - _span = span; - _diagnostics = diagnostics; - _registerCodeFix = registerCodeFix ?? throw new ArgumentNullException(nameof(registerCodeFix)); - Options = options; - _cancellationToken = cancellationToken; - } - /// /// Add supplied to the list of fixes that will be offered to the user. /// @@ -260,7 +225,7 @@ public void RegisterCodeFix(CodeAction action, ImmutableArray diagno throw new ArgumentNullException(nameof(action)); } - VerifyDiagnosticsArgument(diagnostics, _span); + VerifyDiagnosticsArgument(diagnostics, Span); // TODO: // - Check that all diagnostics are unique (no duplicates). diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/BatchFixAllProvider.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/BatchFixAllProvider.cs index 2ab4e712c68eb..757b2fac65e17 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/BatchFixAllProvider.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/BatchFixAllProvider.cs @@ -153,7 +153,7 @@ private static async Task> GetAllChangedDocumentsInDiag // Create a context that will add the reported code actions into this using var _2 = ArrayBuilder.GetInstance(out var codeActions); var action = GetRegisterCodeFixAction(fixAllContext.CodeActionEquivalenceKey, codeActions); - var context = new CodeFixContext(document, diagnostic.Location.SourceSpan, [diagnostic], action, fixAllContext.State.CodeActionOptionsProvider, cancellationToken); + var context = new CodeFixContext(document, diagnostic.Location.SourceSpan, [diagnostic], action, cancellationToken); // Wait for the all the code actions to be reported for this diagnostic. var registerTask = fixAllContext.CodeFixProvider.RegisterCodeFixesAsync(context) ?? Task.CompletedTask; diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs index af773f09721a4..fe17d090ba470 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllContext.cs @@ -164,8 +164,7 @@ public FixAllContext( scope, codeActionEquivalenceKey, PublicContract.RequireNonNullItems(diagnosticIds, nameof(diagnosticIds)), - fixAllDiagnosticProvider ?? throw new ArgumentNullException(nameof(fixAllDiagnosticProvider)), - CodeActionOptions.DefaultProvider), + fixAllDiagnosticProvider ?? throw new ArgumentNullException(nameof(fixAllDiagnosticProvider))), CodeAnalysisProgress.None, cancellationToken) { } @@ -200,8 +199,7 @@ public FixAllContext( scope, codeActionEquivalenceKey, PublicContract.RequireNonNullItems(diagnosticIds, nameof(diagnosticIds)), - fixAllDiagnosticProvider ?? throw new ArgumentNullException(nameof(fixAllDiagnosticProvider)), - CodeActionOptions.DefaultProvider), + fixAllDiagnosticProvider ?? throw new ArgumentNullException(nameof(fixAllDiagnosticProvider))), CodeAnalysisProgress.None, cancellationToken) { if (scope is FixAllScope.ContainingMember or FixAllScope.ContainingType) diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllProvider.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllProvider.cs index 024a25dd2a463..113fffc4fe716 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllProvider.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllProvider.cs @@ -95,7 +95,7 @@ public static FixAllProvider Create( => this.GetFixAsync((FixAllContext)fixAllContext); #endregion - private class CallbackDocumentBasedFixAllProvider( + private sealed class CallbackDocumentBasedFixAllProvider( Func, Task> fixAllAsync, ImmutableArray supportedFixAllScopes) : DocumentBasedFixAllProvider(supportedFixAllScopes) { diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.FixMultipleDiagnosticProvider.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.FixMultipleDiagnosticProvider.cs index 8658e7b8bbe40..d300d1999f1eb 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.FixMultipleDiagnosticProvider.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.FixMultipleDiagnosticProvider.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes; -internal partial class FixAllState +internal sealed partial class FixAllState { /// /// Diagnostic provider to fetch document/project diagnostics to fix in a . diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.cs index 5b5b0ab65977d..3239e0cee06e1 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/FixAllState.cs @@ -33,9 +33,8 @@ internal FixAllState( FixAllScope scope, string? codeActionEquivalenceKey, IEnumerable diagnosticIds, - FixAllContext.DiagnosticProvider fixAllDiagnosticProvider, - CodeActionOptionsProvider codeActionOptionsProvider) - : base(fixAllProvider, document, project, codeFixProvider, codeActionOptionsProvider, scope, codeActionEquivalenceKey) + FixAllContext.DiagnosticProvider fixAllDiagnosticProvider) + : base(fixAllProvider, document, project, codeFixProvider, scope, codeActionEquivalenceKey) { // We need the trigger diagnostic span for span based fix all scopes, i.e. FixAllScope.ContainingMember and FixAllScope.ContainingType Debug.Assert(diagnosticSpan.HasValue || scope is not FixAllScope.ContainingMember or FixAllScope.ContainingType); @@ -57,8 +56,7 @@ protected override FixAllState With(Document? document, Project project, FixAllS scope, codeActionEquivalenceKey, DiagnosticIds, - DiagnosticProvider, - CodeActionOptionsProvider); + DiagnosticProvider); #region FixMultiple @@ -66,8 +64,7 @@ internal static FixAllState Create( FixAllProvider fixAllProvider, ImmutableDictionary> diagnosticsToFix, CodeFixProvider codeFixProvider, - string? codeActionEquivalenceKey, - CodeActionOptionsProvider codeActionOptionsProvider) + string? codeActionEquivalenceKey) { var triggerDocument = diagnosticsToFix.First().Key; var diagnosticSpan = diagnosticsToFix.First().Value.FirstOrDefault()?.Location.SourceSpan; @@ -82,16 +79,14 @@ internal static FixAllState Create( FixAllScope.Custom, codeActionEquivalenceKey, diagnosticIds, - diagnosticProvider, - codeActionOptionsProvider); + diagnosticProvider); } internal static FixAllState Create( FixAllProvider fixAllProvider, ImmutableDictionary> diagnosticsToFix, CodeFixProvider codeFixProvider, - string? codeActionEquivalenceKey, - CodeActionOptionsProvider codeActionOptionsProvider) + string? codeActionEquivalenceKey) { var triggerProject = diagnosticsToFix.First().Key; var diagnosticIds = GetDiagnosticsIds(diagnosticsToFix.Values); @@ -105,8 +100,7 @@ internal static FixAllState Create( FixAllScope.Custom, codeActionEquivalenceKey, diagnosticIds, - diagnosticProvider, - codeActionOptionsProvider); + diagnosticProvider); } private static ImmutableHashSet GetDiagnosticsIds(IEnumerable> diagnosticsCollection) diff --git a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/TextChangeMerger.cs b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/TextChangeMerger.cs index 1bc103f5bd389..54f3121429c3b 100644 --- a/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/TextChangeMerger.cs +++ b/src/Workspaces/Core/Portable/CodeFixes/FixAllOccurrences/TextChangeMerger.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.CodeFixes; /// /// Helper to merge many disparate text changes to a single document together into a total set of changes. /// -internal class TextChangeMerger +internal sealed class TextChangeMerger { private readonly struct IntervalIntrospector : IIntervalIntrospector { diff --git a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/CommonFixAllState.cs b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/CommonFixAllState.cs index eacf8559e2b03..7681dc9c307e9 100644 --- a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/CommonFixAllState.cs +++ b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/CommonFixAllState.cs @@ -22,14 +22,12 @@ internal abstract partial class CommonFixAllState Project.Solution; public FixAllScope Scope { get; } public abstract FixAllKind FixAllKind { get; } - public CodeActionOptionsProvider CodeActionOptionsProvider { get; } protected CommonFixAllState( TFixAllProvider fixAllProvider, Document? document, Project project, TProvider provider, - CodeActionOptionsProvider optionsProvider, FixAllScope scope, string? codeActionEquivalenceKey) { @@ -39,7 +37,6 @@ protected CommonFixAllState( Document = document; Project = project; Provider = provider; - CodeActionOptionsProvider = optionsProvider; Scope = scope; CodeActionEquivalenceKey = codeActionEquivalenceKey; } diff --git a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/FixAllProviderInfo.cs b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/FixAllProviderInfo.cs index 45d5809993b68..138d93cf713a4 100644 --- a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/FixAllProviderInfo.cs +++ b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/FixAllProviderInfo.cs @@ -112,7 +112,7 @@ private FixAllProviderInfo( public abstract bool CanBeFixed(Diagnostic diagnostic); - private class CodeFixerFixAllProviderInfo( + private sealed class CodeFixerFixAllProviderInfo( IFixAllProvider fixAllProvider, IEnumerable supportedDiagnosticIds, ImmutableArray supportedScopes) : FixAllProviderInfo(fixAllProvider, supportedScopes) @@ -121,7 +121,7 @@ public override bool CanBeFixed(Diagnostic diagnostic) => supportedDiagnosticIds.Contains(diagnostic.Id); } - private class SuppressionFixerFixAllProviderInfo( + private sealed class SuppressionFixerFixAllProviderInfo( IFixAllProvider fixAllProvider, IConfigurationFixProvider suppressionFixer, ImmutableArray supportedScopes) : FixAllProviderInfo(fixAllProvider, supportedScopes) @@ -132,7 +132,7 @@ public override bool CanBeFixed(Diagnostic diagnostic) => _canBeSuppressedOrUnsuppressed(diagnostic); } - private class CodeRefactoringFixAllProviderInfo( + private sealed class CodeRefactoringFixAllProviderInfo( IFixAllProvider fixAllProvider, ImmutableArray supportedScopes) : FixAllProviderInfo(fixAllProvider, supportedScopes) { diff --git a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/IFixAllState.cs b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/IFixAllState.cs index 9d9591ddf69e5..66083f1d4ac32 100644 --- a/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/IFixAllState.cs +++ b/src/Workspaces/Core/Portable/CodeFixesAndRefactorings/IFixAllState.cs @@ -26,8 +26,6 @@ internal interface IFixAllState /// object Provider { get; } - CodeActionOptionsProvider CodeActionOptionsProvider { get; } - IFixAllState With( Optional<(Document? document, Project project)> documentAndProject = default, Optional scope = default, diff --git a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs index 8b4f1ce55f3da..87f7d13d753d4 100644 --- a/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs +++ b/src/Workspaces/Core/Portable/CodeRefactorings/CodeRefactoringContext.cs @@ -53,8 +53,6 @@ public Document Document /// public CancellationToken CancellationToken { get; } - internal readonly CodeActionOptionsProvider Options; - private readonly Action _registerRefactoring; /// @@ -66,7 +64,7 @@ public CodeRefactoringContext( TextSpan span, Action registerRefactoring, CancellationToken cancellationToken) - : this(document, span, (action, textSpan) => registerRefactoring(action), CodeActionOptions.DefaultProvider, cancellationToken) + : this(document, span, (action, textSpan) => registerRefactoring(action), cancellationToken) { } /// @@ -77,7 +75,7 @@ public CodeRefactoringContext( TextSpan span, Action registerRefactoring, CancellationToken cancellationToken) - : this(document, span, (action, textSpan) => registerRefactoring(action), CodeActionOptions.DefaultProvider, cancellationToken) + : this(document, span, (action, textSpan) => registerRefactoring(action), cancellationToken) { } /// @@ -87,7 +85,6 @@ internal CodeRefactoringContext( TextDocument document, TextSpan span, Action registerRefactoring, - CodeActionOptionsProvider options, CancellationToken cancellationToken) { // NOTE/TODO: Don't make this overload public & obsolete the `Action registerRefactoring` @@ -95,7 +92,6 @@ internal CodeRefactoringContext( TextDocument = document ?? throw new ArgumentNullException(nameof(document)); Span = span; _registerRefactoring = registerRefactoring ?? throw new ArgumentNullException(nameof(registerRefactoring)); - Options = options; CancellationToken = cancellationToken; } diff --git a/src/Workspaces/Core/Portable/CodeRefactorings/FixAllOccurences/FixAllState.cs b/src/Workspaces/Core/Portable/CodeRefactorings/FixAllOccurences/FixAllState.cs index b4f7f3c5fe8bc..c100f75be9641 100644 --- a/src/Workspaces/Core/Portable/CodeRefactorings/FixAllOccurences/FixAllState.cs +++ b/src/Workspaces/Core/Portable/CodeRefactorings/FixAllOccurences/FixAllState.cs @@ -36,11 +36,10 @@ public FixAllState( Document document, TextSpan selectionSpan, CodeRefactoringProvider codeRefactoringProvider, - CodeActionOptionsProvider optionsProvider, FixAllScope fixAllScope, CodeAction codeAction) : this(fixAllProvider, document ?? throw new ArgumentNullException(nameof(document)), document.Project, selectionSpan, codeRefactoringProvider, - optionsProvider, fixAllScope, codeAction.Title, codeAction.EquivalenceKey) + fixAllScope, codeAction.Title, codeAction.EquivalenceKey) { } @@ -49,11 +48,10 @@ public FixAllState( Project project, TextSpan selectionSpan, CodeRefactoringProvider codeRefactoringProvider, - CodeActionOptionsProvider optionsProvider, FixAllScope fixAllScope, CodeAction codeAction) : this(fixAllProvider, document: null, project ?? throw new ArgumentNullException(nameof(project)), selectionSpan, codeRefactoringProvider, - optionsProvider, fixAllScope, codeAction.Title, codeAction.EquivalenceKey) + fixAllScope, codeAction.Title, codeAction.EquivalenceKey) { } @@ -63,11 +61,10 @@ private FixAllState( Project project, TextSpan selectionSpan, CodeRefactoringProvider codeRefactoringProvider, - CodeActionOptionsProvider optionsProvider, FixAllScope fixAllScope, string codeActionTitle, string? codeActionEquivalenceKey) - : base(fixAllProvider, document, project, codeRefactoringProvider, optionsProvider, fixAllScope, codeActionEquivalenceKey) + : base(fixAllProvider, document, project, codeRefactoringProvider, fixAllScope, codeActionEquivalenceKey) { _selectionSpan = selectionSpan; this.CodeActionTitle = codeActionTitle; @@ -81,7 +78,6 @@ protected override FixAllState With(Document? document, Project project, FixAllS project, _selectionSpan, this.Provider, - this.CodeActionOptionsProvider, scope, this.CodeActionTitle, codeActionEquivalenceKey); diff --git a/src/Workspaces/Core/Portable/CodeRefactorings/SyntaxEditorBasedCodeRefactoringProvider.cs b/src/Workspaces/Core/Portable/CodeRefactorings/SyntaxEditorBasedCodeRefactoringProvider.cs index 07905dc7e269f..3064aa9009685 100644 --- a/src/Workspaces/Core/Portable/CodeRefactorings/SyntaxEditorBasedCodeRefactoringProvider.cs +++ b/src/Workspaces/Core/Portable/CodeRefactorings/SyntaxEditorBasedCodeRefactoringProvider.cs @@ -29,7 +29,7 @@ internal abstract partial class SyntaxEditorBasedCodeRefactoringProvider : CodeR return FixAllProvider.Create( async (fixAllContext, document, fixAllSpans) => { - return await this.FixAllAsync(document, fixAllSpans, fixAllContext.GetOptionsProvider(), fixAllContext.CodeActionEquivalenceKey, fixAllContext.CancellationToken).ConfigureAwait(false); + return await this.FixAllAsync(document, fixAllSpans, fixAllContext.CodeActionEquivalenceKey, fixAllContext.CancellationToken).ConfigureAwait(false); }, SupportedFixAllScopes); } @@ -37,19 +37,17 @@ internal abstract partial class SyntaxEditorBasedCodeRefactoringProvider : CodeR protected Task FixAsync( Document document, TextSpan fixAllSpan, - CodeActionOptionsProvider optionsProvider, string? equivalenceKey, CancellationToken cancellationToken) { return FixAllWithEditorAsync(document, - editor => FixAllAsync(document, [fixAllSpan], editor, optionsProvider, equivalenceKey, cancellationToken), + editor => FixAllAsync(document, [fixAllSpan], editor, equivalenceKey, cancellationToken), cancellationToken); } protected Task FixAllAsync( Document document, Optional> fixAllSpans, - CodeActionOptionsProvider optionsProvider, string? equivalenceKey, CancellationToken cancellationToken) { @@ -60,7 +58,7 @@ Task FixAllAsync(SyntaxEditor editor) { // Fix the entire document if there are no sub-spans to fix. var spans = fixAllSpans.HasValue ? fixAllSpans.Value : [editor.OriginalRoot.FullSpan]; - return this.FixAllAsync(document, spans, editor, optionsProvider, equivalenceKey, cancellationToken); + return this.FixAllAsync(document, spans, editor, equivalenceKey, cancellationToken); } } @@ -82,7 +80,6 @@ protected abstract Task FixAllAsync( Document document, ImmutableArray fixAllSpans, SyntaxEditor editor, - CodeActionOptionsProvider optionsProvider, string? equivalenceKey, CancellationToken cancellationToken); } diff --git a/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs b/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs index 91f752c040ed9..e82c4bf830e09 100644 --- a/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs +++ b/src/Workspaces/Core/Portable/CodeStyle/CodeStyleOption.cs @@ -25,11 +25,10 @@ internal interface ICodeStyleOption /// public sealed class CodeStyleOption : ICodeStyleOption, IEquatable> { - private readonly CodeStyleOption2 _codeStyleOptionImpl; public static CodeStyleOption Default => new(default!, NotificationOption.Silent); internal CodeStyleOption(CodeStyleOption2 codeStyleOptionImpl) - => _codeStyleOptionImpl = codeStyleOptionImpl; + => UnderlyingOption = codeStyleOptionImpl; public CodeStyleOption(T value, NotificationOption notification) : this(new CodeStyleOption2(value, new NotificationOption2(notification.Severity, IsExplicitlySpecified: false))) @@ -38,39 +37,39 @@ public CodeStyleOption(T value, NotificationOption notification) public T Value { - get => _codeStyleOptionImpl.Value; + get => UnderlyingOption.Value; [Obsolete("Modifying a CodeStyleOption is not supported.", error: true)] set => throw new InvalidOperationException(); } object? ICodeStyleOption.Value => this.Value; - NotificationOption2 ICodeStyleOption.Notification => _codeStyleOptionImpl.Notification; + NotificationOption2 ICodeStyleOption.Notification => UnderlyingOption.Notification; ICodeStyleOption ICodeStyleOption.WithValue(object value) => new CodeStyleOption((T)value, Notification); ICodeStyleOption ICodeStyleOption.WithNotification(NotificationOption2 notification) => new CodeStyleOption(Value, (NotificationOption)notification); public NotificationOption Notification { - get => (NotificationOption)_codeStyleOptionImpl.Notification; + get => (NotificationOption)UnderlyingOption.Notification; [Obsolete("Modifying a CodeStyleOption is not supported.", error: true)] set => throw new InvalidOperationException(); } - internal CodeStyleOption2 UnderlyingOption => _codeStyleOptionImpl; + internal CodeStyleOption2 UnderlyingOption { get; } - public XElement ToXElement() => _codeStyleOptionImpl.ToXElement(); + public XElement ToXElement() => UnderlyingOption.ToXElement(); public static CodeStyleOption FromXElement(XElement element) => new(CodeStyleOption2.FromXElement(element)); public bool Equals(CodeStyleOption? other) - => _codeStyleOptionImpl.Equals(other?._codeStyleOptionImpl); + => UnderlyingOption.Equals(other?.UnderlyingOption); public override bool Equals(object? obj) => obj is CodeStyleOption option && Equals(option); public override int GetHashCode() - => _codeStyleOptionImpl.GetHashCode(); + => UnderlyingOption.GetHashCode(); } diff --git a/src/Workspaces/Core/Portable/Diagnostics/DefaultAnalyzerAssemblyLoaderService.cs b/src/Workspaces/Core/Portable/Diagnostics/DefaultAnalyzerAssemblyLoaderService.cs deleted file mode 100644 index a697216286a76..0000000000000 --- a/src/Workspaces/Core/Portable/Diagnostics/DefaultAnalyzerAssemblyLoaderService.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. - -using System; -using System.Composition; -using System.IO; -using Microsoft.CodeAnalysis.Host.Mef; -using System.Collections.Immutable; -using System.Collections.Generic; - -namespace Microsoft.CodeAnalysis.Host; - -[ExportWorkspaceServiceFactory(typeof(IAnalyzerAssemblyLoaderProvider)), Shared] -[method: ImportingConstructor] -[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal sealed class DefaultAnalyzerAssemblyLoaderServiceFactory([ImportMany] IEnumerable externalResolvers) : IWorkspaceServiceFactory -{ - public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) - => new DefaultAnalyzerAssemblyLoaderProvider(workspaceServices.Workspace.Kind ?? "default", [.. externalResolvers]); - - private sealed class DefaultAnalyzerAssemblyLoaderProvider(string workspaceKind, ImmutableArray externalResolvers) : IAnalyzerAssemblyLoaderProvider - { - private readonly DefaultAnalyzerAssemblyLoader _loader = new(externalResolvers); - - /// - /// We include the of the workspace in the path we produce. That way we don't - /// collide in the common case of a normal host workspace and OOP workspace running together. This avoids an - /// annoying exception as each will try to clean up this directory, throwing exceptions because the other is - /// locking it. The exception is fine, since the cleanup is just hygienic and isn't intended to be needed for - /// correctness. But it is annoying and does cause noise in our perf test harness. - /// - private readonly IAnalyzerAssemblyLoader _shadowCopyLoader = DefaultAnalyzerAssemblyLoader.CreateNonLockingLoader( - Path.Combine(Path.GetTempPath(), "CodeAnalysis", "WorkspacesAnalyzerShadowCopies", workspaceKind), - externalResolvers: externalResolvers); - - public IAnalyzerAssemblyLoader GetLoader(bool shadowCopy) - => shadowCopy ? _shadowCopyLoader : _loader; - } -} diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs index 7a9d6e324871e..39cf69d1943d9 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs @@ -199,7 +199,7 @@ public static DiagnosticData Create(Diagnostic diagnostic, TextDocument document var additionalLocations = GetAdditionalLocations(document, diagnostic); var additionalProperties = GetAdditionalProperties(document, diagnostic); - var documentPropertiesService = document.Services.GetService(); + var documentPropertiesService = document.DocumentServiceProvider.GetService(); var diagnosticsLspClientName = documentPropertiesService?.DiagnosticsLspClientName; if (diagnosticsLspClientName != null) diff --git a/src/Workspaces/Core/Portable/Differencing/Edit.cs b/src/Workspaces/Core/Portable/Differencing/Edit.cs index abb0c7253ba96..3cf8f1bf23290 100644 --- a/src/Workspaces/Core/Portable/Differencing/Edit.cs +++ b/src/Workspaces/Core/Portable/Differencing/Edit.cs @@ -18,9 +18,6 @@ namespace Microsoft.CodeAnalysis.Differencing; public readonly struct Edit : IEquatable> { private readonly TreeComparer _comparer; - private readonly EditKind _kind; - private readonly TNode _oldNode; - private readonly TNode _newNode; internal Edit(EditKind kind, TreeComparer comparer, TNode oldNode, TNode newNode) { @@ -33,12 +30,12 @@ internal Edit(EditKind kind, TreeComparer comparer, TNode oldNode, TNode !comparer.TreesEqual(oldNode, newNode)); _comparer = comparer; - _kind = kind; - _oldNode = oldNode; - _newNode = newNode; + Kind = kind; + OldNode = oldNode; + NewNode = newNode; } - public EditKind Kind => _kind; + public EditKind Kind { get; } /// /// Insert: @@ -50,7 +47,7 @@ internal Edit(EditKind kind, TreeComparer comparer, TNode oldNode, TNode /// Move, Update: /// Node in the old tree/sequence. /// - public TNode OldNode => _oldNode; + public TNode OldNode { get; } /// /// Insert: @@ -62,29 +59,29 @@ internal Edit(EditKind kind, TreeComparer comparer, TNode oldNode, TNode /// Move, Update: /// Node in the new tree/sequence. /// - public TNode NewNode => _newNode; + public TNode NewNode { get; } public override bool Equals(object obj) => obj is Edit && Equals((Edit)obj); public bool Equals(Edit other) { - return _kind == other._kind - && (_oldNode == null) ? other._oldNode == null : _oldNode.Equals(other._oldNode) - && (_newNode == null) ? other._newNode == null : _newNode.Equals(other._newNode); + return Kind == other.Kind + && (OldNode == null) ? other.OldNode == null : OldNode.Equals(other.OldNode) + && (NewNode == null) ? other.NewNode == null : NewNode.Equals(other.NewNode); } public override int GetHashCode() { - var hash = (int)_kind; - if (_oldNode != null) + var hash = (int)Kind; + if (OldNode != null) { - hash = Hash.Combine(_oldNode.GetHashCode(), hash); + hash = Hash.Combine(OldNode.GetHashCode(), hash); } - if (_newNode != null) + if (NewNode != null) { - hash = Hash.Combine(_newNode.GetHashCode(), hash); + hash = Hash.Combine(NewNode.GetHashCode(), hash); } return hash; @@ -97,17 +94,17 @@ internal string GetDebuggerDisplay() switch (Kind) { case EditKind.Delete: - return result + " [" + _oldNode.ToString() + "]" + DisplayPosition(_oldNode); + return result + " [" + OldNode.ToString() + "]" + DisplayPosition(OldNode); case EditKind.Insert: - return result + " [" + _newNode.ToString() + "]" + DisplayPosition(_newNode); + return result + " [" + NewNode.ToString() + "]" + DisplayPosition(NewNode); case EditKind.Update: - return result + " [" + _oldNode.ToString() + "]" + DisplayPosition(_oldNode) + " -> [" + _newNode.ToString() + "]" + DisplayPosition(_newNode); + return result + " [" + OldNode.ToString() + "]" + DisplayPosition(OldNode) + " -> [" + NewNode.ToString() + "]" + DisplayPosition(NewNode); case EditKind.Move: case EditKind.Reorder: - return result + " [" + _oldNode.ToString() + "]" + DisplayPosition(_oldNode) + " -> " + DisplayPosition(_newNode); + return result + " [" + OldNode.ToString() + "]" + DisplayPosition(OldNode) + " -> " + DisplayPosition(NewNode); } return result; diff --git a/src/Workspaces/Core/Portable/Differencing/EditScript.cs b/src/Workspaces/Core/Portable/Differencing/EditScript.cs index a308e4f050de4..d02c64c2eb084 100644 --- a/src/Workspaces/Core/Portable/Differencing/EditScript.cs +++ b/src/Workspaces/Core/Portable/Differencing/EditScript.cs @@ -15,29 +15,26 @@ namespace Microsoft.CodeAnalysis.Differencing; /// public sealed partial class EditScript { - private readonly Match _match; - private readonly ImmutableArray> _edits; - internal EditScript(Match match) { - _match = match; + Match = match; var edits = new List>(); AddUpdatesInsertsMoves(edits); AddDeletes(edits); - _edits = edits.AsImmutable(); + Edits = edits.AsImmutable(); } - public ImmutableArray> Edits => _edits; + public ImmutableArray> Edits { get; } - public Match Match => _match; + public Match Match { get; } - private TreeComparer Comparer => _match.Comparer; + private TreeComparer Comparer => Match.Comparer; - private TNode Root1 => _match.OldRoot; + private TNode Root1 => Match.OldRoot; - private TNode Root2 => _match.NewRoot; + private TNode Root2 => Match.NewRoot; private void AddUpdatesInsertsMoves(List> edits) { @@ -86,7 +83,7 @@ private void ProcessNode(List> edits, TNode x) // // NOTE: // If we needed z then we would need to be updating M' as we encounter insertions. - var hasPartner = _match.TryGetPartnerInTree1(x, out var w); + var hasPartner = Match.TryGetPartnerInTree1(x, out var w); var hasParent = Comparer.TryGetParent(x, out var y); if (!hasPartner) @@ -120,7 +117,7 @@ private void ProcessNode(List> edits, TNode x) // If parents of w and x don't match, it's a move. // iii. if not (v, y) in M' // NOTE: The paper says (y, v) but that seems wrong since M': T1 -> T2 and w,v in T1 and x,y in T2. - if (!_match.Contains(v, y)) + if (!Match.Contains(v, y)) { // A. Let z be the partner of y in M'. (NOTE: z not needed) // B. k := FindPos(x) @@ -154,7 +151,7 @@ private void AddDeletes(List> edits) foreach (var w in Comparer.GetDescendants(Root1)) { - if (!_match.HasPartnerInTree2(w)) + if (!Match.HasPartnerInTree2(w)) { edits.Add(new Edit(EditKind.Delete, Comparer, oldNode: w, newNode: default)); } @@ -183,7 +180,7 @@ private void AlignChildren(List> edits, TNode w, TNode x) List s1 = null; foreach (var e in wChildren) { - if (_match.TryGetPartnerInTree2(e, out var pw) && Comparer.GetParent(pw).Equals(x)) + if (Match.TryGetPartnerInTree2(e, out var pw) && Comparer.GetParent(pw).Equals(x)) { s1 ??= []; @@ -194,7 +191,7 @@ private void AlignChildren(List> edits, TNode w, TNode x) List s2 = null; foreach (var e in xChildren) { - if (_match.TryGetPartnerInTree1(e, out var px) && Comparer.GetParent(px).Equals(w)) + if (Match.TryGetPartnerInTree1(e, out var px) && Comparer.GetParent(px).Equals(w)) { s2 ??= []; @@ -210,7 +207,7 @@ private void AlignChildren(List> edits, TNode w, TNode x) // Step 3, 4 // Define the function Equal(a,b) to be true if and only if (a,c) in M' // Let S <- LCS(S1, S2, Equal) - var lcs = new Match.LongestCommonSubsequence(_match); + var lcs = new Match.LongestCommonSubsequence(Match); var s = lcs.GetMatchingNodes(s1, s2); // Step 5 @@ -229,7 +226,7 @@ private void AlignChildren(List> edits, TNode w, TNode x) // (a,b) in M // => b in S2 since S2 == { b | parent(b) == x && parent(partner(b)) == w } // (a,b) not in S - if (_match.TryGetPartnerInTree2(a, out var b) && + if (Match.TryGetPartnerInTree2(a, out var b) && Comparer.GetParent(b).Equals(x) && !ContainsPair(s, a, b)) { diff --git a/src/Workspaces/Core/Portable/Differencing/Match.cs b/src/Workspaces/Core/Portable/Differencing/Match.cs index 0feeb00b14d6e..8b3ab265c38d5 100644 --- a/src/Workspaces/Core/Portable/Differencing/Match.cs +++ b/src/Workspaces/Core/Portable/Differencing/Match.cs @@ -20,19 +20,14 @@ public sealed partial class Match private const double MatchingDistance2 = 0.5; private const double MatchingDistance3 = 0.75; private const double MaxDistance = 1.0; - - private readonly TreeComparer _comparer; - private readonly TNode _root1; - private readonly TNode _root2; - private readonly Dictionary _oneToTwo = []; private readonly Dictionary _twoToOne = []; internal Match(TNode root1, TNode root2, TreeComparer comparer, IEnumerable> knownMatches) { - _root1 = root1; - _root2 = root2; - _comparer = comparer; + OldRoot = root1; + NewRoot = root2; + Comparer = comparer; var labelCount = comparer.LabelCount; CategorizeNodesByLabels(comparer, root1, labelCount, out var nodes1, out _); @@ -150,7 +145,7 @@ private void ComputeMatch(List[] nodes1, List[] nodes2) private void ComputeMatchForLabel(int label, List s1, List s2) { - var tiedToAncestor = _comparer.TiedToAncestor(label); + var tiedToAncestor = Comparer.TiedToAncestor(label); ComputeMatchForLabel(s1, s2, tiedToAncestor, EpsilonDistance); // almost exact match ComputeMatchForLabel(s1, s2, tiedToAncestor, MatchingDistance1); // ok match @@ -213,8 +208,8 @@ private void ComputeMatchForLabel(List s1, List s2, int tiedToAnce // If one node's ancestor is present in the subtree and the other isn't then we are not in the scenario // of comparing subtrees with matching roots and thus we consider the nodes not matching. - var hasAncestor1 = _comparer.TryGetAncestor(node1, tiedToAncestor, out var ancestor1); - var hasAncestor2 = _comparer.TryGetAncestor(node2, tiedToAncestor, out var ancestor2); + var hasAncestor1 = Comparer.TryGetAncestor(node1, tiedToAncestor, out var ancestor1); + var hasAncestor2 = Comparer.TryGetAncestor(node2, tiedToAncestor, out var ancestor2); if (hasAncestor1 != hasAncestor2) { continue; @@ -225,7 +220,7 @@ private void ComputeMatchForLabel(List s1, List s2, int tiedToAnce // Since CategorizeNodesByLabels added nodes to the s1/s2 lists in depth-first prefix order, // we can also accept equality in the following condition. That's because we find the partner // of the parent node before we get to finding it for the child node of the same kind. - Debug.Assert(_comparer.GetLabel(ancestor1) <= _comparer.GetLabel(node1)); + Debug.Assert(Comparer.GetLabel(ancestor1) <= Comparer.GetLabel(node1)); if (!Contains(ancestor1, ancestor2)) { @@ -241,7 +236,7 @@ private void ComputeMatchForLabel(List s1, List s2, int tiedToAnce // Now, we have no other choice than comparing the node "values" // and looking for the one with the smaller distance. - var distance = _comparer.GetDistance(node1, node2); + var distance = Comparer.GetDistance(node1, node2); if (distance < bestDistance) { matched = true; @@ -284,8 +279,8 @@ private void ComputeMatchForLabel(List s1, List s2, int tiedToAnce internal bool TryAdd(TNode node1, TNode node2) { - Debug.Assert(_comparer.TreesEqual(node1, _root1)); - Debug.Assert(_comparer.TreesEqual(node2, _root2)); + Debug.Assert(Comparer.TreesEqual(node1, OldRoot)); + Debug.Assert(Comparer.TreesEqual(node2, NewRoot)); if (_oneToTwo.ContainsKey(node1) || _twoToOne.ContainsKey(node2)) { @@ -300,42 +295,42 @@ internal bool TryAdd(TNode node1, TNode node2) internal bool TryGetPartnerInTree1(TNode node2, out TNode partner1) { var result = _twoToOne.TryGetValue(node2, out partner1); - Debug.Assert(_comparer.TreesEqual(node2, _root2)); - Debug.Assert(!result || _comparer.TreesEqual(partner1, _root1)); + Debug.Assert(Comparer.TreesEqual(node2, NewRoot)); + Debug.Assert(!result || Comparer.TreesEqual(partner1, OldRoot)); return result; } internal bool HasPartnerInTree1(TNode node2) { - Debug.Assert(_comparer.TreesEqual(node2, _root2)); + Debug.Assert(Comparer.TreesEqual(node2, NewRoot)); return _twoToOne.ContainsKey(node2); } internal bool TryGetPartnerInTree2(TNode node1, out TNode partner2) { var result = _oneToTwo.TryGetValue(node1, out partner2); - Debug.Assert(_comparer.TreesEqual(node1, _root1)); - Debug.Assert(!result || _comparer.TreesEqual(partner2, _root2)); + Debug.Assert(Comparer.TreesEqual(node1, OldRoot)); + Debug.Assert(!result || Comparer.TreesEqual(partner2, NewRoot)); return result; } internal bool HasPartnerInTree2(TNode node1) { - Debug.Assert(_comparer.TreesEqual(node1, _root1)); + Debug.Assert(Comparer.TreesEqual(node1, OldRoot)); return _oneToTwo.ContainsKey(node1); } internal bool Contains(TNode node1, TNode node2) { - Debug.Assert(_comparer.TreesEqual(node2, _root2)); + Debug.Assert(Comparer.TreesEqual(node2, NewRoot)); return TryGetPartnerInTree2(node1, out var partner2) && node2.Equals(partner2); } - public TreeComparer Comparer => _comparer; + public TreeComparer Comparer { get; } - public TNode OldRoot => _root1; + public TNode OldRoot { get; } - public TNode NewRoot => _root2; + public TNode NewRoot { get; } public IReadOnlyDictionary Matches { diff --git a/src/Workspaces/Core/Portable/Differencing/SequenceEdit.cs b/src/Workspaces/Core/Portable/Differencing/SequenceEdit.cs index ade9a93f1ffec..bbf51d974c919 100644 --- a/src/Workspaces/Core/Portable/Differencing/SequenceEdit.cs +++ b/src/Workspaces/Core/Portable/Differencing/SequenceEdit.cs @@ -16,17 +16,14 @@ namespace Microsoft.CodeAnalysis.Differencing; [DebuggerDisplay("{GetDebuggerDisplay(), nq}")] internal readonly struct SequenceEdit : IEquatable { - private readonly int _oldIndex; - private readonly int _newIndex; - internal SequenceEdit(int oldIndex, int newIndex) { Debug.Assert(oldIndex >= -1); Debug.Assert(newIndex >= -1); Debug.Assert(newIndex != -1 || oldIndex != -1); - _oldIndex = oldIndex; - _newIndex = newIndex; + OldIndex = oldIndex; + NewIndex = newIndex; } /// @@ -36,12 +33,12 @@ public EditKind Kind { get { - if (_oldIndex == -1) + if (OldIndex == -1) { return EditKind.Insert; } - if (_newIndex == -1) + if (NewIndex == -1) { return EditKind.Delete; } @@ -53,24 +50,24 @@ public EditKind Kind /// /// Index in the old sequence, or -1 if the edit is insert. /// - public int OldIndex => _oldIndex; + public int OldIndex { get; } /// /// Index in the new sequence, or -1 if the edit is delete. /// - public int NewIndex => _newIndex; + public int NewIndex { get; } public bool Equals(SequenceEdit other) { - return _oldIndex == other._oldIndex - && _newIndex == other._newIndex; + return OldIndex == other.OldIndex + && NewIndex == other.NewIndex; } public override bool Equals(object obj) => obj is SequenceEdit && Equals((SequenceEdit)obj); public override int GetHashCode() - => Hash.Combine(_oldIndex, _newIndex); + => Hash.Combine(OldIndex, NewIndex); private string GetDebuggerDisplay() { @@ -78,13 +75,13 @@ private string GetDebuggerDisplay() switch (Kind) { case EditKind.Delete: - return result + " (" + _oldIndex + ")"; + return result + " (" + OldIndex + ")"; case EditKind.Insert: - return result + " (" + _newIndex + ")"; + return result + " (" + NewIndex + ")"; case EditKind.Update: - return result + " (" + _oldIndex + " -> " + _newIndex + ")"; + return result + " (" + OldIndex + " -> " + NewIndex + ")"; } return result; diff --git a/src/Workspaces/Core/Portable/Editing/DocumentEditor.cs b/src/Workspaces/Core/Portable/Editing/DocumentEditor.cs index a0aaa49e4922a..0db674289e9ea 100644 --- a/src/Workspaces/Core/Portable/Editing/DocumentEditor.cs +++ b/src/Workspaces/Core/Portable/Editing/DocumentEditor.cs @@ -15,14 +15,11 @@ namespace Microsoft.CodeAnalysis.Editing; /// public class DocumentEditor : SyntaxEditor { - private readonly Document _document; - private readonly SemanticModel _model; - private DocumentEditor(Document document, SemanticModel model, SyntaxNode root) : base(root, document.Project.Solution.Services) { - _document = document; - _model = model; + OriginalDocument = document; + SemanticModel = model; } /// @@ -43,16 +40,16 @@ public static async Task CreateAsync(Document document, Cancella /// /// The specified when the editor was first created. /// - public Document OriginalDocument => _document; + public Document OriginalDocument { get; } /// /// The of the original document. /// - public SemanticModel SemanticModel => _model; + public SemanticModel SemanticModel { get; } /// /// Returns the changed . /// public Document GetChangedDocument() - => _document.WithSyntaxRoot(this.GetChangedRoot()); + => OriginalDocument.WithSyntaxRoot(this.GetChangedRoot()); } diff --git a/src/Workspaces/Core/Portable/Editing/SymbolEditor.cs b/src/Workspaces/Core/Portable/Editing/SymbolEditor.cs index 06360045d7d9f..8a54d42c8e009 100644 --- a/src/Workspaces/Core/Portable/Editing/SymbolEditor.cs +++ b/src/Workspaces/Core/Portable/Editing/SymbolEditor.cs @@ -19,13 +19,10 @@ namespace Microsoft.CodeAnalysis.Editing; /// public sealed class SymbolEditor { - private readonly Solution _originalSolution; - private Solution _currentSolution; - private SymbolEditor(Solution solution) { - _originalSolution = solution; - _currentSolution = solution; + OriginalSolution = solution; + ChangedSolution = solution; } /// @@ -57,30 +54,30 @@ public static SymbolEditor Create(Document document) /// /// The original solution. /// - public Solution OriginalSolution => _originalSolution; + public Solution OriginalSolution { get; } /// /// The solution with the edits applied. /// - public Solution ChangedSolution => _currentSolution; + public Solution ChangedSolution { get; private set; } /// /// The documents changed since the was constructed. /// public IEnumerable GetChangedDocuments() { - var solutionChanges = _currentSolution.GetChanges(_originalSolution); + var solutionChanges = ChangedSolution.GetChanges(OriginalSolution); foreach (var projectChanges in solutionChanges.GetProjectChanges()) { foreach (var id in projectChanges.GetAddedDocuments()) { - yield return _currentSolution.GetDocument(id); + yield return ChangedSolution.GetDocument(id); } foreach (var id in projectChanges.GetChangedDocuments()) { - yield return _currentSolution.GetDocument(id); + yield return ChangedSolution.GetDocument(id); } } @@ -103,23 +100,23 @@ public async Task GetCurrentSymbolAsync(ISymbol symbol, CancellationTok return null; // check to see if symbol is from current solution - var project = _currentSolution.GetProject(symbol.ContainingAssembly, cancellationToken); + var project = ChangedSolution.GetProject(symbol.ContainingAssembly, cancellationToken); if (project != null) { - return await GetSymbolAsync(_currentSolution, project.Id, symbolId, cancellationToken).ConfigureAwait(false); + return await GetSymbolAsync(ChangedSolution, project.Id, symbolId, cancellationToken).ConfigureAwait(false); } // check to see if it is from original solution - project = _originalSolution.GetProject(symbol.ContainingAssembly, cancellationToken); + project = OriginalSolution.GetProject(symbol.ContainingAssembly, cancellationToken); if (project != null) { - return await GetSymbolAsync(_currentSolution, project.Id, symbolId, cancellationToken).ConfigureAwait(false); + return await GetSymbolAsync(ChangedSolution, project.Id, symbolId, cancellationToken).ConfigureAwait(false); } // try to find symbol from any project (from current solution) with matching assembly name foreach (var projectId in this.GetProjectsForAssembly(symbol.ContainingAssembly)) { - var currentSymbol = await GetSymbolAsync(_currentSolution, projectId, symbolId, cancellationToken).ConfigureAwait(false); + var currentSymbol = await GetSymbolAsync(ChangedSolution, projectId, symbolId, cancellationToken).ConfigureAwait(false); if (currentSymbol != null) { return currentSymbol; @@ -133,7 +130,7 @@ public async Task GetCurrentSymbolAsync(ISymbol symbol, CancellationTok private ImmutableArray GetProjectsForAssembly(IAssemblySymbol assembly) { - _assemblyNameToProjectIdMap ??= _originalSolution.Projects + _assemblyNameToProjectIdMap ??= OriginalSolution.Projects .ToLookup(p => p.AssemblyName, p => p.Id) .ToImmutableDictionary(g => g.Key, g => ImmutableArray.CreateRange(g)); @@ -196,7 +193,7 @@ private IEnumerable GetDeclarations(ISymbol symbol) { return symbol.DeclaringSyntaxReferences .Select(sr => sr.GetSyntax()) - .Select(n => SyntaxGenerator.GetGenerator(_originalSolution.Workspace, n.Language).GetDeclaration(n)) + .Select(n => SyntaxGenerator.GetGenerator(OriginalSolution.Workspace, n.Language).GetDeclaration(n)) .Where(d => d != null); } @@ -287,14 +284,14 @@ private async Task EditDeclarationAsync( AsyncDeclarationEditAction editAction, CancellationToken cancellationToken) { - var doc = _currentSolution.GetDocument(declaration.SyntaxTree); + var doc = ChangedSolution.GetDocument(declaration.SyntaxTree); var editor = await DocumentEditor.CreateAsync(doc, cancellationToken).ConfigureAwait(false); editor.TrackNode(declaration); await editAction(editor, declaration, cancellationToken).ConfigureAwait(false); var newDoc = editor.GetChangedDocument(); - _currentSolution = newDoc.Project.Solution; + ChangedSolution = newDoc.Project.Solution; // try to find new symbol by looking up via original declaration var model = await newDoc.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); @@ -329,7 +326,7 @@ public Task EditOneDeclarationAsync( { var sourceTree = location.SourceTree; - var doc = _currentSolution.GetDocument(sourceTree) ?? _originalSolution.GetDocument(sourceTree); + var doc = ChangedSolution.GetDocument(sourceTree) ?? OriginalSolution.GetDocument(sourceTree); if (doc != null) { return EditOneDeclarationAsync(symbol, doc.Id, location.SourceSpan.Start, editAction, cancellationToken); @@ -376,7 +373,7 @@ private async Task EditOneDeclarationAsync( var decl = this.GetDeclarations(currentSymbol).FirstOrDefault(d => { - var doc = _currentSolution.GetDocument(d.SyntaxTree); + var doc = ChangedSolution.GetDocument(d.SyntaxTree); return doc != null && doc.Id == documentId && d.FullSpan.IntersectsWith(position); }); @@ -463,9 +460,9 @@ public async Task EditAllDeclarationsAsync( var currentSymbol = await this.GetCurrentSymbolAsync(symbol, cancellationToken).ConfigureAwait(false); CheckSymbolArgument(currentSymbol, symbol); - var declsByDocId = this.GetDeclarations(currentSymbol).ToLookup(d => _currentSolution.GetDocument(d.SyntaxTree).Id); + var declsByDocId = this.GetDeclarations(currentSymbol).ToLookup(d => ChangedSolution.GetDocument(d.SyntaxTree).Id); - var solutionEditor = new SolutionEditor(_currentSolution); + var solutionEditor = new SolutionEditor(ChangedSolution); foreach (var declGroup in declsByDocId) { @@ -479,12 +476,12 @@ public async Task EditAllDeclarationsAsync( } } - _currentSolution = solutionEditor.GetChangedSolution(); + ChangedSolution = solutionEditor.GetChangedSolution(); // try to find new symbol by looking up via original declarations foreach (var declGroup in declsByDocId) { - var doc = _currentSolution.GetDocument(declGroup.Key); + var doc = ChangedSolution.GetDocument(declGroup.Key); var model = await doc.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); foreach (var decl in declGroup) diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs b/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs index 62140b91ca451..3b0c8e09a5837 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs @@ -55,7 +55,6 @@ namespace Microsoft.CodeAnalysis.Editing; /// public class SyntaxEditor { - private readonly SyntaxGenerator _generator; private readonly List _changes = []; /// @@ -87,7 +86,7 @@ public SyntaxEditor(SyntaxNode root, SolutionServices services) internal SyntaxEditor(SyntaxNode root, SyntaxGenerator generator) { OriginalRoot = root; - _generator = generator; + Generator = generator; } /// @@ -98,7 +97,7 @@ internal SyntaxEditor(SyntaxNode root, SyntaxGenerator generator) /// /// A to use to create and change 's. /// - public SyntaxGenerator Generator => _generator; + public SyntaxGenerator Generator { get; } /// /// Returns the changed root node. @@ -110,7 +109,7 @@ public SyntaxNode GetChangedRoot() var newRoot = OriginalRoot.TrackNodes(nodes); foreach (var change in _changes) - newRoot = change.Apply(newRoot, _generator); + newRoot = change.Apply(newRoot, Generator); return newRoot; } diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs index da35c94ba2347..70da68cf4cf59 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs @@ -33,16 +33,22 @@ public abstract class SyntaxGenerator : ILanguageService { public static readonly SyntaxRemoveOptions DefaultRemoveOptions = SyntaxRemoveOptions.KeepUnbalancedDirectives | SyntaxRemoveOptions.AddElasticMarker; - internal abstract SyntaxTrivia CarriageReturnLineFeed { get; } - internal abstract SyntaxTrivia ElasticCarriageReturnLineFeed { get; } + internal abstract SyntaxGeneratorInternal SyntaxGeneratorInternal { get; } + + internal SyntaxTrivia CarriageReturnLineFeed => this.SyntaxGeneratorInternal.CarriageReturnLineFeed; + internal SyntaxTrivia ElasticCarriageReturnLineFeed => this.SyntaxGeneratorInternal.ElasticCarriageReturnLineFeed; internal abstract SyntaxTrivia ElasticMarker { get; } - internal abstract bool RequiresExplicitImplementationForInterfaceMembers { get; } - internal ISyntaxFacts SyntaxFacts => SyntaxGeneratorInternal.SyntaxFacts; - internal abstract SyntaxGeneratorInternal SyntaxGeneratorInternal { get; } + internal bool RequiresExplicitImplementationForInterfaceMembers + => this.SyntaxGeneratorInternal.RequiresExplicitImplementationForInterfaceMembers; + + internal ISyntaxFacts SyntaxFacts + => SyntaxGeneratorInternal.SyntaxFacts; internal abstract SyntaxTrivia Whitespace(string text); - internal abstract SyntaxTrivia SingleLineComment(string text); + + internal SyntaxTrivia SingleLineComment(string text) + => this.SyntaxGeneratorInternal.SingleLineComment(text); internal abstract SyntaxToken CreateInterpolatedStringStartToken(bool isVerbatim); internal abstract SyntaxToken CreateInterpolatedStringEndToken(); @@ -1590,7 +1596,8 @@ internal SyntaxNode YieldReturnStatement(SyntaxNode expression) /// /// True if can be used /// - internal abstract bool SupportsThrowExpression(); + internal bool SupportsThrowExpression() + => this.SyntaxGeneratorInternal.SupportsThrowExpression(); /// /// if the language requires a diff --git a/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs b/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs index 1eab0a3867d8f..00ed83a7d1461 100644 --- a/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs +++ b/src/Workspaces/Core/Portable/ExtractMethod/ExtractMethodOptions.cs @@ -26,8 +26,8 @@ internal readonly record struct ExtractMethodGenerationOptions public static ExtractMethodGenerationOptions GetDefault(LanguageServices languageServices) => new() { - CodeGenerationOptions = CodeGenerationOptions.GetDefault(languageServices), - CodeCleanupOptions = CodeCleanupOptions.GetDefault(languageServices), + CodeGenerationOptions = CodeGenerationOptionsProviders.GetDefault(languageServices), + CodeCleanupOptions = CodeCleanupOptionsProviders.GetDefault(languageServices), }; public ExtractMethodGenerationOptions() diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindLiterals/FindLiteralsSearchEngine.cs b/src/Workspaces/Core/Portable/FindSymbols/FindLiterals/FindLiteralsSearchEngine.cs index c993c80dd9373..f9ef84d99ba00 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindLiterals/FindLiteralsSearchEngine.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindLiterals/FindLiteralsSearchEngine.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal class FindLiteralsSearchEngine +internal sealed class FindLiteralsSearchEngine { private enum SearchKind { diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesProgress.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesProgress.cs index 747dc1dde863f..b533154f7cd2c 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesProgress.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesProgress.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; /// A does-nothing version of the . Useful for /// clients that have no need to report progress as they work. /// -internal class NoOpFindReferencesProgress : IFindReferencesProgress +internal sealed class NoOpFindReferencesProgress : IFindReferencesProgress { public static readonly IFindReferencesProgress Instance = new NoOpFindReferencesProgress(); diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.BidirectionalSymbolSet.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.BidirectionalSymbolSet.cs index cf11c3110e238..84d1eb09e6a8d 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.BidirectionalSymbolSet.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.BidirectionalSymbolSet.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal partial class FindReferencesSearchEngine +internal sealed partial class FindReferencesSearchEngine { /// /// Symbol set used when is /// A symbol set used when the find refs caller does not want cascading. This is a trivial impl that basically diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs index 388ae43021ac5..31e41ecb5ea83 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.SymbolSet.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal partial class FindReferencesSearchEngine +internal sealed partial class FindReferencesSearchEngine { /// /// Represents the set of symbols that the engine is searching for. While the find-refs engine is passed an diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.UnidirectionalSymbolSet.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.UnidirectionalSymbolSet.cs index 37d07184a193d..9cbb5846a849e 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.UnidirectionalSymbolSet.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine.UnidirectionalSymbolSet.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal partial class FindReferencesSearchEngine +internal sealed partial class FindReferencesSearchEngine { /// /// Symbol set used when is ? documents, ImmutableArray finders, diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine_FindReferencesInDocuments.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine_FindReferencesInDocuments.cs index 18345b5713bef..87b7f4ca622f0 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine_FindReferencesInDocuments.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/FindReferencesSearchEngine_FindReferencesInDocuments.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal partial class FindReferencesSearchEngine +internal sealed partial class FindReferencesSearchEngine { public async Task FindReferencesInDocumentsAsync( ISymbol originalSymbol, IImmutableSet documents, CancellationToken cancellationToken) diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.UnderlyingNamedTypeVisitor.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.UnderlyingNamedTypeVisitor.cs index f19e4534e5689..ba51ea651a930 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.UnderlyingNamedTypeVisitor.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.UnderlyingNamedTypeVisitor.cs @@ -6,9 +6,9 @@ namespace Microsoft.CodeAnalysis.FindSymbols.Finders; -internal partial class ExplicitConversionSymbolReferenceFinder +internal sealed partial class ExplicitConversionSymbolReferenceFinder { - private class UnderlyingNamedTypeVisitor : SymbolVisitor + private sealed class UnderlyingNamedTypeVisitor : SymbolVisitor { public static readonly UnderlyingNamedTypeVisitor Instance = new(); diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.cs index 11d7594d8abfc..4095dec2e2f8e 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/NoOpStreamingFindReferencesProgress.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; /// A does-nothing version of the . Useful for /// clients that have no need to report progress as they work. /// -internal class NoOpStreamingFindReferencesProgress : IStreamingFindReferencesProgress +internal sealed class NoOpStreamingFindReferencesProgress : IStreamingFindReferencesProgress { public static readonly IStreamingFindReferencesProgress Instance = new NoOpStreamingFindReferencesProgress(); @@ -30,7 +30,7 @@ private NoOpStreamingFindReferencesProgress() public ValueTask OnDefinitionFoundAsync(SymbolGroup group, CancellationToken cancellationToken) => default; public ValueTask OnReferencesFoundAsync(ImmutableArray<(SymbolGroup group, ISymbol symbol, ReferenceLocation location)> references, CancellationToken cancellationToken) => default; - private class NoOpProgressTracker : IStreamingProgressTracker + private sealed class NoOpProgressTracker : IStreamingProgressTracker { public ValueTask AddItemsAsync(int count, CancellationToken cancellationToken) => default; public ValueTask ItemsCompletedAsync(int count, CancellationToken cancellationToken) => default; diff --git a/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs b/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs index c03d06080bd05..b9ba9ac99f35f 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/IStreamingFindReferencesProgress.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; /// that we search for. Placing these in a group allows the final consumer to know that these /// symbols can be merged together. /// -internal class SymbolGroup : IEquatable +internal sealed class SymbolGroup : IEquatable { /// /// All the symbols in the group. diff --git a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs index 76ecf5ed4e36a..30dd5c46447e0 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/Shared/AbstractSyntaxIndex_Persistence.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal partial class AbstractSyntaxIndex +internal abstract partial class AbstractSyntaxIndex { private static readonly string s_persistenceName = typeof(TIndex).Name; diff --git a/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs b/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs index 3d58d7e4a8bd9..5e5bd005202b1 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/StreamingProgressCollector.cs @@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; /// APIs to return all the results at the end of the operation, as opposed to broadcasting /// the results as they are found. /// -internal class StreamingProgressCollector( +internal sealed class StreamingProgressCollector( IStreamingFindReferencesProgress underlyingProgress) : IStreamingFindReferencesProgress { private readonly object _gate = new(); diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.FirstEntityHandleProvider.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.FirstEntityHandleProvider.cs index b27b1b4ca3b6c..6618d973a1245 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.FirstEntityHandleProvider.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.FirstEntityHandleProvider.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal partial class SymbolTreeInfo +internal sealed partial class SymbolTreeInfo { /// /// Used to produce the simple-full-name components of a type from metadata. @@ -18,7 +18,7 @@ internal partial class SymbolTreeInfo /// are added. For example, for the type "X.Y.O`1.I`2, we will produce [X, Y, O, I] /// /// - private class FirstEntityHandleProvider : ISignatureTypeProvider + private sealed class FirstEntityHandleProvider : ISignatureTypeProvider { public static readonly FirstEntityHandleProvider Instance = new(); diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.Node.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.Node.cs index 67113a1c276e4..b7e571fa0b14a 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.Node.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.Node.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal partial class SymbolTreeInfo +internal sealed partial class SymbolTreeInfo { private const int RootNodeParentIndex = -1; diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs index fe3a5ac849b02..e0b2b86906e9a 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs @@ -25,7 +25,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; /// will still incur a heavy cost (for example, getting the root symbol for a /// particular project). /// -internal partial class SymbolTreeInfo +internal sealed partial class SymbolTreeInfo { private static readonly StringComparer s_caseInsensitiveComparer = CaseInsensitiveComparison.Comparer; diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs index f314281d828e6..810bc31ae5b2b 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs @@ -25,7 +25,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal partial class SymbolTreeInfo +internal sealed partial class SymbolTreeInfo { /// /// Cache the symbol tree infos for assembly symbols produced from a particular > s_symbolMapPool = new(() => []); diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs index 0e605748beea1..cb45509fe84e2 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.ContextInfo.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal partial class SyntaxTreeIndex +internal sealed partial class SyntaxTreeIndex { private readonly struct ContextInfo { diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.IdentifierInfo.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.IdentifierInfo.cs index b976cf94dc374..cc663756511f3 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.IdentifierInfo.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.IdentifierInfo.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal partial class SyntaxTreeIndex +internal sealed partial class SyntaxTreeIndex { private readonly struct IdentifierInfo( BloomFilter identifierFilter, diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.LiteralInfo.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.LiteralInfo.cs index b6ae46a8b5321..4b1b52694057b 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.LiteralInfo.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.LiteralInfo.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols; -internal partial class SyntaxTreeIndex +internal sealed partial class SyntaxTreeIndex { private readonly struct LiteralInfo(BloomFilter literalsFilter) { diff --git a/src/Workspaces/Core/Portable/ImplementType/ImplementTypeOptions.cs b/src/Workspaces/Core/Portable/ImplementType/ImplementTypeOptions.cs deleted file mode 100644 index 06864055b258c..0000000000000 --- a/src/Workspaces/Core/Portable/ImplementType/ImplementTypeOptions.cs +++ /dev/null @@ -1,20 +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.Serialization; - -namespace Microsoft.CodeAnalysis.ImplementType; - -[DataContract] -internal readonly record struct ImplementTypeOptions -{ - [DataMember] public ImplementTypeInsertionBehavior InsertionBehavior { get; init; } = ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind; - [DataMember] public ImplementTypePropertyGenerationBehavior PropertyGenerationBehavior { get; init; } = ImplementTypePropertyGenerationBehavior.PreferThrowingProperties; - - public ImplementTypeOptions() - { - } - - public static readonly ImplementTypeOptions Default = new(); -} diff --git a/src/Workspaces/Core/Portable/LinkedFileDiffMerging/DefaultDocumentTextDifferencingService.cs b/src/Workspaces/Core/Portable/LinkedFileDiffMerging/DefaultDocumentTextDifferencingService.cs index 13ebef1eb5278..c58d86eaff7b7 100644 --- a/src/Workspaces/Core/Portable/LinkedFileDiffMerging/DefaultDocumentTextDifferencingService.cs +++ b/src/Workspaces/Core/Portable/LinkedFileDiffMerging/DefaultDocumentTextDifferencingService.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis; [ExportWorkspaceService(typeof(IDocumentTextDifferencingService), ServiceLayer.Default), Shared] -internal class DefaultDocumentTextDifferencingService : IDocumentTextDifferencingService +internal sealed class DefaultDocumentTextDifferencingService : IDocumentTextDifferencingService { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Workspaces/Core/Portable/Log/CountLogAggregator.cs b/src/Workspaces/Core/Portable/Log/CountLogAggregator.cs index 59d1d7986d073..75b2cb05d3121 100644 --- a/src/Workspaces/Core/Portable/Log/CountLogAggregator.cs +++ b/src/Workspaces/Core/Portable/Log/CountLogAggregator.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Internal.Log; -internal class CountLogAggregator : AbstractLogAggregator.Counter> where TKey : notnull +internal sealed class CountLogAggregator : AbstractLogAggregator.Counter> where TKey : notnull { protected override Counter CreateCounter() => new(); diff --git a/src/Workspaces/Core/Portable/Log/InteractionClass.cs b/src/Workspaces/Core/Portable/Log/InteractionClass.cs index 460d959d15d4c..fc0abeb2fe404 100644 --- a/src/Workspaces/Core/Portable/Log/InteractionClass.cs +++ b/src/Workspaces/Core/Portable/Log/InteractionClass.cs @@ -29,7 +29,7 @@ internal enum InteractionClass } [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] -internal class PerfGoalAttribute(InteractionClass interactionClass) : Attribute +internal sealed class PerfGoalAttribute(InteractionClass interactionClass) : Attribute { public InteractionClass InteractionClass => interactionClass; } diff --git a/src/Workspaces/Core/Portable/Log/KeyValueLogMessage.cs b/src/Workspaces/Core/Portable/Log/KeyValueLogMessage.cs index 69d8d05b664be..a4d802e1ed118 100644 --- a/src/Workspaces/Core/Portable/Log/KeyValueLogMessage.cs +++ b/src/Workspaces/Core/Portable/Log/KeyValueLogMessage.cs @@ -44,24 +44,23 @@ public static KeyValueLogMessage Create(LogType kind, Action? _lazyMap; private Action>? _propertySetter; private KeyValueLogMessage() { // prevent it from being created directly - _kind = LogType.Trace; + Kind = LogType.Trace; } private void Initialize(LogType kind, Action>? propertySetter, LogLevel logLevel) { - _kind = kind; + Kind = kind; _propertySetter = propertySetter; LogLevel = logLevel; } - public LogType Kind => _kind; + public LogType Kind { get; private set; } public bool ContainsProperty { diff --git a/src/Workspaces/Core/Portable/Log/RoslynEventSource.LogBlock.cs b/src/Workspaces/Core/Portable/Log/RoslynEventSource.LogBlock.cs index d56db13758dfe..70f76b95e6458 100644 --- a/src/Workspaces/Core/Portable/Log/RoslynEventSource.LogBlock.cs +++ b/src/Workspaces/Core/Portable/Log/RoslynEventSource.LogBlock.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Internal.Log; -internal partial class RoslynEventSource +internal sealed partial class RoslynEventSource { /// /// Logs an informational block with given 's representation as the message diff --git a/src/Workspaces/Core/Portable/Log/WorkspaceErrorLogger.cs b/src/Workspaces/Core/Portable/Log/WorkspaceErrorLogger.cs index cf42ec26a4317..597435b4dba98 100644 --- a/src/Workspaces/Core/Portable/Log/WorkspaceErrorLogger.cs +++ b/src/Workspaces/Core/Portable/Log/WorkspaceErrorLogger.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.ErrorLogger; [ExportWorkspaceService(typeof(IErrorLoggerService)), Export(typeof(IErrorLoggerService)), Shared] -internal class WorkspaceErrorLogger : IErrorLoggerService +internal sealed class WorkspaceErrorLogger : IErrorLoggerService { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj index 4fcbf691d4469..31f3ea1946bc8 100644 --- a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj +++ b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj @@ -23,7 +23,7 @@ - + - - + + + <_PublishPaths Include="@(PublishItemsOutputGroupOutputs->'%(OutputPath)')" /> + <_PublishDllPaths Include="@(_PublishPaths)" Condition="'%(Extension)' == '.dll'" /> + <_R2RAssemblies Include="@(ReferencePath->'%(FileName)%(Extension)')" Condition="'%(ReferenceSourceTarget)' == 'ProjectReference'" /> @@ -58,7 +61,7 @@ <_R2RAssemblies Include="Microsoft.NET.StringTools.dll" /> - <_AllPublishedAssemblyPaths Include="$(PublishDir)**\*.dll" Exclude="$(PublishDir)**\*.resources.dll" /> + <_AllPublishedAssemblyPaths Include="@(_PublishDllPaths)" Exclude="%(FileName).EndsWith('.resources')" /> <_AllPublishedAssemblies Include="@(_AllPublishedAssemblyPaths->'%(FileName)%(Extension)')" > <_FullFilePath>%(FullPath) @@ -71,6 +74,15 @@ <_R2RAssemblyPaths Include="@(_AllPublishedAssemblyPaths)" Exclude="@(_NoR2RAssemblyPaths)" /> + + + <_RuntimeLibraries Include="$(_RuntimeLibrariesPath)**\*.dll" /> + <_WinRuntimeLibraries Include="$(_WinRuntimeLibrariesPath)**\*.dll" /> + + <_RuntimeLibrariesInPublishDir Include="@(_RuntimeLibraries->'$(PublishDir)%(FileName)%(Extension)')" /> + <_RuntimeLibrariesInPublishDir Include="@(_WinRuntimeLibraries->'$(PublishDir)%(FileName)%(Extension)')" /> + + <_NonRuntimeAssembliesInPublishDir Include="@(_PublishDllPaths)" Exclude="@(_RuntimeLibrariesInPublishDir)" /> @@ -79,13 +91,13 @@ - + <_CrossgenTargetsAsDependencies Include="$(OriginalAssemblyDir)*.dll" /> - <_NonCrossgenTargetsAsDependencies Include="@(_NonRuntimeAssembliesInPublishDir)" Exclude="@(_R2RAssemblyPaths)" /> + <_NonCrossgenTargetsAsDependencies Include="@(_NonRuntimeAssembliesInPublishDir)" Exclude="@(_R2RAssemblyPaths)" /> <_CrossgenTargetPaths Include="@(_CrossgenTargetsAsDependencies)"> $(PublishDir)%(_CrossgenTargetsAsDependencies.Filename)%(_CrossgenTargetsAsDependencies.Extension) @@ -93,14 +105,14 @@ + Outputs="%(_CrossgenTargetPaths.OutputPath)"> <_Crossgen2ExePath>$(PkgMicrosoft_NETCore_App_crossgen2_win-x64)\tools\crossgen2.exe <_R2ROptimizeAssemblyPath>%(_CrossgenTargetPaths.FullPath) - <_R2ROptimizeAssemblyOutputPath>$(PublishDir)%(_CrossgenTargetPaths.Filename)%(_CrossgenTargetPaths.Extension) + <_R2ROptimizeAssemblyOutputPath>$(PublishDir)%(_CrossgenTargetPaths.Filename)%(_CrossgenTargetPaths.Extension) <_RspFilePath>$(CrossgenWorkDir)%(_CrossgenTargetPaths.Filename).CrossgenArgs.rsp @@ -121,25 +133,11 @@ - + - - - <_RuntimeLibraries Include="$(_RuntimeLibrariesPath)**\*.dll" /> - <_WinRuntimeLibraries Include="$(_WinRuntimeLibrariesPath)**\*.dll" /> - - <_RuntimeLibrariesInPublishDir Include="@(_RuntimeLibraries->'$(PublishDir)%(FileName)%(Extension)')" /> - <_RuntimeLibrariesInPublishDir Include="@(_WinRuntimeLibraries->'$(PublishDir)%(FileName)%(Extension)')" /> - - <_NonRuntimeAssembliesInPublishDir Include="$(PublishDir)*.dll" Exclude="@(_RuntimeLibrariesInPublishDir)" /> - - - - - - + <_ExcludeRuntimeLibraries Condition="'$(OfficialBuild)' == 'true'">true + - <_ExcludedFiles Include="$(PublishDir)**\Microsoft.CodeAnalysis.Remote.ServiceHub.CoreComponents.*" /> - <_ExcludedFiles Include="$(PublishDir)**\*.pdb" /> - <_ExcludedFiles Include="$(CrossgenWorkDir)**\*" /> + + <_VsixItem Include="@(_PublishPaths)" /> + <_VsixItem Remove="@(_VsixItem)" Condition="'%(Extension)' == '.pdb'" /> + + + <_VsixItem Remove="@(_VsixItem)" Condition="$([MSBuild]::ValueOrDefault('%(FileName)', '').StartsWith('$(TargetName)'))" /> - <_ExcludedFiles Include="$(PublishDir)runtimes\**\*.*" /> - <_ExcludedFiles Condition="'$(_ExcludeRuntimeLibraries)' == 'true'" Include="@(_RuntimeLibrariesInPublishDir)" /> + <_VsixItem Remove="@(_VsixItem)" Condition="$([MSBuild]::ValueOrDefault('%(FullPath)', '').StartsWith('$(PublishDir)runtimes'))" /> + + <_VsixItem Remove="@(_RuntimeLibrariesInPublishDir)" Condition="'$(_ExcludeRuntimeLibraries)' == 'true'" /> - - - <_PublishedFiles Include="$(PublishDir)**\*.*" Exclude="@(_ExcludedFiles)"/> - - <_PublishedFiles Update="@(_PublishedFiles)" TargetPath="%(RecursiveDir)%(Filename)%(Extension)" /> - + + diff --git a/src/Workspaces/Remote/ServiceHub/ExternalAccess/Pythia/Api/PythiaBrokeredServiceImplementation.cs b/src/Workspaces/Remote/ServiceHub/ExternalAccess/Pythia/Api/PythiaBrokeredServiceImplementation.cs index 07b255a7db4ed..da0e4ea0ed774 100644 --- a/src/Workspaces/Remote/ServiceHub/ExternalAccess/Pythia/Api/PythiaBrokeredServiceImplementation.cs +++ b/src/Workspaces/Remote/ServiceHub/ExternalAccess/Pythia/Api/PythiaBrokeredServiceImplementation.cs @@ -8,21 +8,20 @@ using Microsoft.CodeAnalysis.Remote; using Microsoft.ServiceHub.Framework; -namespace Microsoft.CodeAnalysis.ExternalAccess.Pythia.Api +namespace Microsoft.CodeAnalysis.ExternalAccess.Pythia.Api; + +internal static class PythiaBrokeredServiceImplementation { - internal static class PythiaBrokeredServiceImplementation - { - public static ValueTask RunServiceAsync(Func> implementation, CancellationToken cancellationToken) - => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); + public static ValueTask RunServiceAsync(Func> implementation, CancellationToken cancellationToken) + => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); - public static ValueTask RunServiceAsync(Func implementation, CancellationToken cancellationToken) - => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); + public static ValueTask RunServiceAsync(Func implementation, CancellationToken cancellationToken) + => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); - [Obsolete("Use RunServiceAsync (that is passsed a Solution) instead", error: false)] - public static ValueTask GetSolutionAsync(this PythiaPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, CancellationToken cancellationToken) - => RemoteWorkspaceManager.Default.GetSolutionAsync(client, solutionInfo.UnderlyingObject, cancellationToken); + [Obsolete("Use RunServiceAsync (that is passsed a Solution) instead", error: false)] + public static ValueTask GetSolutionAsync(this PythiaPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, CancellationToken cancellationToken) + => RemoteWorkspaceManager.Default.GetSolutionAsync(client, solutionInfo.UnderlyingObject, cancellationToken); - public static ValueTask RunServiceAsync(this PythiaPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, Func> implementation, CancellationToken cancellationToken) - => RemoteWorkspaceManager.Default.RunServiceAsync(client, solutionInfo.UnderlyingObject, implementation, cancellationToken); - } + public static ValueTask RunServiceAsync(this PythiaPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, Func> implementation, CancellationToken cancellationToken) + => RemoteWorkspaceManager.Default.RunServiceAsync(client, solutionInfo.UnderlyingObject, implementation, cancellationToken); } diff --git a/src/Workspaces/Remote/ServiceHub/ExternalAccess/Razor/Api/RazorBrokeredServiceImplementation.cs b/src/Workspaces/Remote/ServiceHub/ExternalAccess/Razor/Api/RazorBrokeredServiceImplementation.cs index 96801ddd6613d..f5d01ef480775 100644 --- a/src/Workspaces/Remote/ServiceHub/ExternalAccess/Razor/Api/RazorBrokeredServiceImplementation.cs +++ b/src/Workspaces/Remote/ServiceHub/ExternalAccess/Razor/Api/RazorBrokeredServiceImplementation.cs @@ -8,20 +8,19 @@ using Microsoft.CodeAnalysis.Remote; using Microsoft.ServiceHub.Framework; -namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Api +namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Api; + +internal static class RazorBrokeredServiceImplementation { - internal static class RazorBrokeredServiceImplementation - { - public static ValueTask RunServiceAsync(Func> implementation, CancellationToken cancellationToken) - => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); + public static ValueTask RunServiceAsync(Func> implementation, CancellationToken cancellationToken) + => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); - public static ValueTask RunServiceAsync(Func implementation, CancellationToken cancellationToken) - => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); + public static ValueTask RunServiceAsync(Func implementation, CancellationToken cancellationToken) + => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); - public static ValueTask RunServiceAsync(this RazorPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, Func> implementation, CancellationToken cancellationToken) - => RemoteWorkspaceManager.Default.RunServiceAsync(client, solutionInfo.UnderlyingObject, implementation, cancellationToken); + public static ValueTask RunServiceAsync(this RazorPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, Func> implementation, CancellationToken cancellationToken) + => RemoteWorkspaceManager.Default.RunServiceAsync(client, solutionInfo.UnderlyingObject, implementation, cancellationToken); - public static Workspace GetWorkspace() - => RemoteWorkspaceManager.Default.GetWorkspace(); - } + public static Workspace GetWorkspace() + => RemoteWorkspaceManager.Default.GetWorkspace(); } diff --git a/src/Workspaces/Remote/ServiceHub/ExternalAccess/UnitTesting/Api/UnitTestingBrokeredServiceImplementation.cs b/src/Workspaces/Remote/ServiceHub/ExternalAccess/UnitTesting/Api/UnitTestingBrokeredServiceImplementation.cs index b9d302c83dc3e..a646c943687bd 100644 --- a/src/Workspaces/Remote/ServiceHub/ExternalAccess/UnitTesting/Api/UnitTestingBrokeredServiceImplementation.cs +++ b/src/Workspaces/Remote/ServiceHub/ExternalAccess/UnitTesting/Api/UnitTestingBrokeredServiceImplementation.cs @@ -8,23 +8,22 @@ using Microsoft.CodeAnalysis.Remote; using Microsoft.ServiceHub.Framework; -namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api -{ - internal static class UnitTestingBrokeredServiceImplementation - { - public static ValueTask RunServiceAsync(Func> implementation, CancellationToken cancellationToken) - => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); +namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api; - public static ValueTask RunServiceAsync(Func implementation, CancellationToken cancellationToken) - => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); +internal static class UnitTestingBrokeredServiceImplementation +{ + public static ValueTask RunServiceAsync(Func> implementation, CancellationToken cancellationToken) + => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); - public static NewUnitTestingIncrementalAnalyzerProvider? TryRegisterNewAnalyzerProvider(string analyzerName, INewUnitTestingIncrementalAnalyzerProviderImplementation provider) - { - var workspace = RemoteWorkspaceManager.Default.GetWorkspace(); - return NewUnitTestingIncrementalAnalyzerProvider.TryRegister(workspace.Kind, workspace.Services.SolutionServices, analyzerName, provider); - } + public static ValueTask RunServiceAsync(Func implementation, CancellationToken cancellationToken) + => BrokeredServiceBase.RunServiceImplAsync(implementation, cancellationToken); - public static ValueTask RunServiceAsync(this UnitTestingPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, Func> implementation, CancellationToken cancellationToken) - => RemoteWorkspaceManager.Default.RunServiceAsync(client, solutionInfo.UnderlyingObject, implementation, cancellationToken); + public static NewUnitTestingIncrementalAnalyzerProvider? TryRegisterNewAnalyzerProvider(string analyzerName, INewUnitTestingIncrementalAnalyzerProviderImplementation provider) + { + var workspace = RemoteWorkspaceManager.Default.GetWorkspace(); + return NewUnitTestingIncrementalAnalyzerProvider.TryRegister(workspace.Kind, workspace.Services.SolutionServices, analyzerName, provider); } + + public static ValueTask RunServiceAsync(this UnitTestingPinnedSolutionInfoWrapper solutionInfo, ServiceBrokerClient client, Func> implementation, CancellationToken cancellationToken) + => RemoteWorkspaceManager.Default.RunServiceAsync(client, solutionInfo.UnderlyingObject, implementation, cancellationToken); } diff --git a/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs b/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs index 4addfe242f3d9..a448f0e6feb7e 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/AssetProvider.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Serialization; @@ -18,16 +19,20 @@ namespace Microsoft.CodeAnalysis.Remote; /// /// This service provide a way to get roslyn objects from checksum /// -internal sealed partial class AssetProvider(Checksum solutionChecksum, SolutionAssetCache assetCache, IAssetSource assetSource, ISerializerService serializerService) +internal sealed partial class AssetProvider( + Checksum solutionChecksum, + SolutionAssetCache assetCache, + IAssetSource assetSource, + SolutionServices solutionServices) : AbstractAssetProvider { private const int PooledChecksumArraySize = 1024; private static readonly ObjectPool s_checksumPool = new(() => new Checksum[PooledChecksumArraySize], 16); private readonly Checksum _solutionChecksum = solutionChecksum; - private readonly ISerializerService _serializerService = serializerService; private readonly SolutionAssetCache _assetCache = assetCache; private readonly IAssetSource _assetSource = assetSource; + private readonly SolutionServices _solutionServices = solutionServices; public override async ValueTask GetAssetAsync( AssetPath assetPath, Checksum checksum, CancellationToken cancellationToken) @@ -289,14 +294,15 @@ private async ValueTask SynchronizeAssetsAsync( var missingChecksumsMemory = new ReadOnlyMemory(missingChecksums, 0, missingChecksumsCount); Contract.ThrowIfTrue(missingChecksumsMemory.Length == 0); -#if NETCOREAPP +#if NET Contract.ThrowIfTrue(missingChecksumsMemory.Span.Contains(Checksum.Null)); #else Contract.ThrowIfTrue(missingChecksumsMemory.Span.IndexOf(Checksum.Null) >= 0); #endif + var serializerService = _solutionServices.GetRequiredService(); await _assetSource.GetAssetsAsync( - _solutionChecksum, assetPath, missingChecksumsMemory, _serializerService, + _solutionChecksum, assetPath, missingChecksumsMemory, serializerService, static ( Checksum missingChecksum, T missingAsset, diff --git a/src/Workspaces/Remote/ServiceHub/Host/IGlobalServiceBroker.cs b/src/Workspaces/Remote/ServiceHub/Host/IGlobalServiceBroker.cs index d75fc44e7567b..5015459c30384 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/IGlobalServiceBroker.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/IGlobalServiceBroker.cs @@ -9,42 +9,41 @@ using Microsoft.ServiceHub.Framework; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote.Host +namespace Microsoft.CodeAnalysis.Remote.Host; + +internal interface IGlobalServiceBroker +{ + IServiceBroker Instance { get; } +} + +/// +/// Hacky way to expose a to workspace services that expect there to be a global +/// singleton (like in visual studio). Effectively the first service that gets called into will record its +/// broker here for these services to use. +/// +// Note: this Export is only so MEF picks up the exported member internally. +[Export(typeof(IGlobalServiceBroker)), Shared] +internal class GlobalServiceBroker : IGlobalServiceBroker { - internal interface IGlobalServiceBroker + private static IServiceBroker? s_instance; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public GlobalServiceBroker() { - IServiceBroker Instance { get; } } - /// - /// Hacky way to expose a to workspace services that expect there to be a global - /// singleton (like in visual studio). Effectively the first service that gets called into will record its - /// broker here for these services to use. - /// - // Note: this Export is only so MEF picks up the exported member internally. - [Export(typeof(IGlobalServiceBroker)), Shared] - internal class GlobalServiceBroker : IGlobalServiceBroker + public static void RegisterServiceBroker(IServiceBroker serviceBroker) { - private static IServiceBroker? s_instance; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public GlobalServiceBroker() - { - } - - public static void RegisterServiceBroker(IServiceBroker serviceBroker) - { - Interlocked.CompareExchange(ref s_instance, serviceBroker, null); - } + Interlocked.CompareExchange(ref s_instance, serviceBroker, null); + } - public IServiceBroker Instance + public IServiceBroker Instance + { + get { - get - { - Contract.ThrowIfNull(s_instance, "Global service broker not registered"); - return s_instance; - } + Contract.ThrowIfNull(s_instance, "Global service broker not registered"); + return s_instance; } } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/ProcessExtensions.cs b/src/Workspaces/Remote/ServiceHub/Host/ProcessExtensions.cs index 668b817fdae13..2cd3337a3f12c 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/ProcessExtensions.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/ProcessExtensions.cs @@ -6,31 +6,30 @@ using System.ComponentModel; using System.Diagnostics; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal static class ProcessExtensions { - internal static class ProcessExtensions - { - private static bool s_settingPrioritySupported = true; + private static bool s_settingPrioritySupported = true; - public static bool TrySetPriorityClass(this Process process, ProcessPriorityClass priorityClass) + public static bool TrySetPriorityClass(this Process process, ProcessPriorityClass priorityClass) + { + if (!s_settingPrioritySupported) { - if (!s_settingPrioritySupported) - { - return false; - } + return false; + } - try - { - process.PriorityClass = priorityClass; - return true; - } - catch (Exception e) when (e is PlatformNotSupportedException or Win32Exception) - { - // the runtime does not support changing process priority - s_settingPrioritySupported = false; + try + { + process.PriorityClass = priorityClass; + return true; + } + catch (Exception e) when (e is PlatformNotSupportedException or Win32Exception) + { + // the runtime does not support changing process priority + s_settingPrioritySupported = false; - return false; - } + return false; } } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoader.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoader.cs index 78d093bdb1e57..fd36b3e185862 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoader.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoader.cs @@ -5,33 +5,32 @@ using System.IO; using System.Collections.Immutable; -namespace Microsoft.CodeAnalysis.Remote.Diagnostics +namespace Microsoft.CodeAnalysis.Remote.Diagnostics; + +/// +/// For analyzers shipped in Roslyn, different set of assemblies might be used when running +/// in-proc and OOP e.g. in-proc (VS) running on desktop clr and OOP running on ServiceHub .Net6 +/// host. We need to make sure to use the ones from the same location as the remote. +/// +internal sealed class RemoteAnalyzerAssemblyLoader : AnalyzerAssemblyLoader { - /// - /// For analyzers shipped in Roslyn, different set of assemblies might be used when running - /// in-proc and OOP e.g. in-proc (VS) running on desktop clr and OOP running on ServiceHub .Net6 - /// host. We need to make sure to use the ones from the same location as the remote. - /// - internal sealed class RemoteAnalyzerAssemblyLoader : AnalyzerAssemblyLoader - { - private readonly string _baseDirectory; + private readonly string _baseDirectory; - public RemoteAnalyzerAssemblyLoader(string baseDirectory, ImmutableArray? externalResolvers = null) - : base(externalResolvers ?? []) - { - _baseDirectory = baseDirectory; - } + public RemoteAnalyzerAssemblyLoader(string baseDirectory, ImmutableArray? externalResolvers = null) + : base(externalResolvers ?? []) + { + _baseDirectory = baseDirectory; + } - protected override string PreparePathToLoad(string fullPath) - { - var fixedPath = Path.GetFullPath(Path.Combine(_baseDirectory, Path.GetFileName(fullPath))); - return File.Exists(fixedPath) ? fixedPath : fullPath; - } + protected override string PreparePathToLoad(string fullPath) + { + var fixedPath = Path.GetFullPath(Path.Combine(_baseDirectory, Path.GetFileName(fullPath))); + return File.Exists(fixedPath) ? fixedPath : fullPath; + } - protected override string PrepareSatelliteAssemblyToLoad(string fullPath, string cultureName) - { - var fixedPath = Path.GetFullPath(Path.Combine(_baseDirectory, cultureName, Path.GetFileName(fullPath))); - return File.Exists(fixedPath) ? fixedPath : fullPath; - } + protected override string PrepareSatelliteAssemblyToLoad(string fullPath, string cultureName) + { + var fixedPath = Path.GetFullPath(Path.Combine(_baseDirectory, cultureName, Path.GetFileName(fullPath))); + return File.Exists(fixedPath) ? fixedPath : fullPath; } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoaderService.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoaderService.cs deleted file mode 100644 index 07f2b46c51e1d..0000000000000 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteAnalyzerAssemblyLoaderService.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; -using System.Composition; -using System.Collections.Immutable; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using System.Collections.Generic; - -namespace Microsoft.CodeAnalysis.Remote.Diagnostics -{ - /// - /// Customizes the path where to store shadow-copies of analyzer assemblies. - /// - [ExportWorkspaceService(typeof(IAnalyzerAssemblyLoaderProvider), [WorkspaceKind.RemoteWorkspace]), Shared] - internal sealed class RemoteAnalyzerAssemblyLoaderService : IAnalyzerAssemblyLoaderProvider - { - private readonly RemoteAnalyzerAssemblyLoader _loader; - private readonly ShadowCopyAnalyzerAssemblyLoader _shadowCopyLoader; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RemoteAnalyzerAssemblyLoaderService([ImportMany] IEnumerable externalResolvers) - { - var baseDirectory = Path.GetDirectoryName(Path.GetFullPath(typeof(RemoteAnalyzerAssemblyLoader).GetTypeInfo().Assembly.Location)); - Debug.Assert(baseDirectory != null); - - var resolvers = externalResolvers.ToImmutableArray(); - _loader = new(baseDirectory, resolvers); - _shadowCopyLoader = new(Path.Combine(Path.GetTempPath(), "VS", "AnalyzerAssemblyLoader"), resolvers); - } - - public IAnalyzerAssemblyLoader GetLoader(bool shadowCopy) - => shadowCopy ? _shadowCopyLoader : _loader; - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteDocumentDifferenceService.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteDocumentDifferenceService.cs index 98767800238b5..428cb91515795 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteDocumentDifferenceService.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteDocumentDifferenceService.cs @@ -10,42 +10,41 @@ using Microsoft.CodeAnalysis.SolutionCrawler; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +/// +/// Provide document difference service specific to remote workspace's behavior. +/// +/// Default is optimized for typing case in editor where we have events +/// for each typing. But in remote workspace, we aggregate changes and update solution in bulk and we don't have concept +/// of active file making default implementation unsuitable. Functionally, default one is still correct, but it often +/// time makes us to do more than we need. Basically, it always says this project has semantic change which can cause +/// a lot of re-analysis. +/// +internal class RemoteDocumentDifferenceService : IDocumentDifferenceService { - /// - /// Provide document difference service specific to remote workspace's behavior. - /// - /// Default is optimized for typing case in editor where we have events - /// for each typing. But in remote workspace, we aggregate changes and update solution in bulk and we don't have concept - /// of active file making default implementation unsuitable. Functionally, default one is still correct, but it often - /// time makes us to do more than we need. Basically, it always says this project has semantic change which can cause - /// a lot of re-analysis. - /// - internal class RemoteDocumentDifferenceService : IDocumentDifferenceService + [ExportLanguageService(typeof(IDocumentDifferenceService), LanguageNames.CSharp, layer: ServiceLayer.Host), Shared] + internal sealed class CSharpDocumentDifferenceService : RemoteDocumentDifferenceService { - [ExportLanguageService(typeof(IDocumentDifferenceService), LanguageNames.CSharp, layer: ServiceLayer.Host), Shared] - internal sealed class CSharpDocumentDifferenceService : RemoteDocumentDifferenceService + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpDocumentDifferenceService() { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpDocumentDifferenceService() - { - } } + } - [ExportLanguageService(typeof(IDocumentDifferenceService), LanguageNames.VisualBasic, layer: ServiceLayer.Host), Shared] - internal sealed class VisualBasicDocumentDifferenceService : AbstractDocumentDifferenceService + [ExportLanguageService(typeof(IDocumentDifferenceService), LanguageNames.VisualBasic, layer: ServiceLayer.Host), Shared] + internal sealed class VisualBasicDocumentDifferenceService : AbstractDocumentDifferenceService + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public VisualBasicDocumentDifferenceService() { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualBasicDocumentDifferenceService() - { - } } + } - public Task GetChangedMemberAsync(Document oldDocument, Document newDocument, CancellationToken cancellationToken) - { - return SpecializedTasks.Null(); - } + public Task GetChangedMemberAsync(Document oldDocument, Document newDocument, CancellationToken cancellationToken) + { + return SpecializedTasks.Null(); } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteHostTestData.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteHostTestData.cs index 2ba9210f572fd..e9867b69da7c4 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteHostTestData.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteHostTestData.cs @@ -5,20 +5,19 @@ using System; using Microsoft.CodeAnalysis.Host; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +/// +/// Test hook used to pass test data to remote services. +/// +internal sealed class RemoteHostTestData { - /// - /// Test hook used to pass test data to remote services. - /// - internal sealed class RemoteHostTestData - { - public readonly RemoteWorkspaceManager WorkspaceManager; - public readonly bool IsInProc; + public readonly RemoteWorkspaceManager WorkspaceManager; + public readonly bool IsInProc; - public RemoteHostTestData(RemoteWorkspaceManager workspaceManager, bool isInProc) - { - WorkspaceManager = workspaceManager; - IsInProc = isInProc; - } + public RemoteHostTestData(RemoteWorkspaceManager workspaceManager, bool isInProc) + { + WorkspaceManager = workspaceManager; + IsInProc = isInProc; } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.InFlightSolution.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.InFlightSolution.cs index baafc6a9372e2..eb70bc2e000a7 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.InFlightSolution.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.InFlightSolution.cs @@ -11,181 +11,180 @@ using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed partial class RemoteWorkspace { - internal sealed partial class RemoteWorkspace + /// + /// Wrapper around asynchronously produced solution for a particular . The + /// computation for producing the solution will be canceled when the number of in-flight operations using it + /// goes down to 0. + /// + public sealed class InFlightSolution { + private readonly RemoteWorkspace _workspace; + + public readonly Checksum SolutionChecksum; + + /// + /// CancellationTokenSource controlling the execution of and . + /// + private readonly CancellationTokenSource _cancellationTokenSource_doNotAccessDirectly = new(); + + /// + /// Background work to just compute the disconnected solution associated with this + /// + private readonly Task _disconnectedSolutionTask; + + /// + /// Optional work to try to elevate the solution computed by to be + /// the primary solution of this . Must only be read/written while holding + /// . + /// + private Task? _primaryBranchTask; + + /// + /// Initially set to 1 to represent the operation that requested and is using this solution. This also + /// allows us to use 0 to represent a point that this solution computation is canceled and can not be + /// used again. + /// + public int InFlightCount { get; private set; } = 1; + + public InFlightSolution( + RemoteWorkspace workspace, + Checksum solutionChecksum, + Func> computeDisconnectedSolutionAsync) + { + Contract.ThrowIfFalse(workspace._gate.CurrentCount == 0); + + _workspace = workspace; + SolutionChecksum = solutionChecksum; + + // Grab the cancellation token up front while we know we are holding the lock and mutating state. We + // don't want to potentially grab it at some undefined point at the future when this type has already + // had its in-flight-count reduced to 0 and thus had our CTS be disposed. + // + // Also kick this off in a dedicated task. The state mutation updating of this InFlightSolution and the + // cache state in RemoteWorkspace must always run fully to completion without issue. We don't want + // anything we call in the constructor to possibly prevent the constructor from running to completion. + var cancellationToken = this.CancellationToken; + _disconnectedSolutionTask = Task.Run(() => computeDisconnectedSolutionAsync(cancellationToken), cancellationToken); + } + + private CancellationToken CancellationToken + { + get + { + // Only safe to get this when the lock is being held. That way nothing is racing against the work + // in DecrementInFlightCount_NoLock which cancels this CTS. + Contract.ThrowIfFalse(_workspace._gate.CurrentCount == 0); + return _cancellationTokenSource_doNotAccessDirectly.Token; + } + } + + public Task PreferredSolutionTask_NoLock + { + get + { + Contract.ThrowIfFalse(_workspace._gate.CurrentCount == 0); + + // Defer to the primary branch task if we have it, otherwise, fallback to the any-branch-task. This + // keeps everything on the primary branch if possible, allowing more sharing of services/caches. + return _primaryBranchTask ?? _disconnectedSolutionTask; + } + } + /// - /// Wrapper around asynchronously produced solution for a particular . The - /// computation for producing the solution will be canceled when the number of in-flight operations using it - /// goes down to 0. + /// Allow the RemoteWorkspace to try to elevate this solution to be the primary solution for itself. This + /// commonly happens because when a change happens to the host, features may kick off immediately, creating + /// the disconnected solution, followed shortly afterwards by a request from the host to make that same + /// checksum be the primary solution of this workspace. /// - public sealed class InFlightSolution + /// + public void TryKickOffPrimaryBranchWork_NoLock(Func> updatePrimaryBranchAsync) { - private readonly RemoteWorkspace _workspace; - - public readonly Checksum SolutionChecksum; - - /// - /// CancellationTokenSource controlling the execution of and . - /// - private readonly CancellationTokenSource _cancellationTokenSource_doNotAccessDirectly = new(); - - /// - /// Background work to just compute the disconnected solution associated with this - /// - private readonly Task _disconnectedSolutionTask; - - /// - /// Optional work to try to elevate the solution computed by to be - /// the primary solution of this . Must only be read/written while holding - /// . - /// - private Task? _primaryBranchTask; - - /// - /// Initially set to 1 to represent the operation that requested and is using this solution. This also - /// allows us to use 0 to represent a point that this solution computation is canceled and can not be - /// used again. - /// - public int InFlightCount { get; private set; } = 1; - - public InFlightSolution( - RemoteWorkspace workspace, - Checksum solutionChecksum, - Func> computeDisconnectedSolutionAsync) + try { - Contract.ThrowIfFalse(workspace._gate.CurrentCount == 0); + Contract.ThrowIfFalse(_workspace._gate.CurrentCount == 0); + Contract.ThrowIfNull(updatePrimaryBranchAsync); + Contract.ThrowIfTrue(this._cancellationTokenSource_doNotAccessDirectly.IsCancellationRequested); - _workspace = workspace; - SolutionChecksum = solutionChecksum; + // Already set up the work to update the primary branch + if (_primaryBranchTask != null) + return; // Grab the cancellation token up front while we know we are holding the lock and mutating state. We // don't want to potentially grab it at some undefined point at the future when this type has already // had its in-flight-count reduced to 0 and thus had our CTS be disposed. // // Also kick this off in a dedicated task. The state mutation updating of this InFlightSolution and the - // cache state in RemoteWorkspace must always run fully to completion without issue. We don't want - // anything we call in the constructor to possibly prevent the constructor from running to completion. + // cache state in RemoteWorkspace must always run fully to completion without issue. We don't want + // anything we call in this method to possibly prevent the method from running to completion. var cancellationToken = this.CancellationToken; - _disconnectedSolutionTask = Task.Run(() => computeDisconnectedSolutionAsync(cancellationToken), cancellationToken); + _primaryBranchTask = Task.Run(() => ComputePrimaryBranchAsync(cancellationToken), cancellationToken); } - - private CancellationToken CancellationToken + catch (Exception ex) when (FatalError.ReportAndPropagate(ex, ErrorSeverity.General)) { - get - { - // Only safe to get this when the lock is being held. That way nothing is racing against the work - // in DecrementInFlightCount_NoLock which cancels this CTS. - Contract.ThrowIfFalse(_workspace._gate.CurrentCount == 0); - return _cancellationTokenSource_doNotAccessDirectly.Token; - } + // The above must never throw. If it does our caller will not properly update the cache state + // properly and can leave things invalid. } - public Task PreferredSolutionTask_NoLock - { - get - { - Contract.ThrowIfFalse(_workspace._gate.CurrentCount == 0); - - // Defer to the primary branch task if we have it, otherwise, fallback to the any-branch-task. This - // keeps everything on the primary branch if possible, allowing more sharing of services/caches. - return _primaryBranchTask ?? _disconnectedSolutionTask; - } - } + return; - /// - /// Allow the RemoteWorkspace to try to elevate this solution to be the primary solution for itself. This - /// commonly happens because when a change happens to the host, features may kick off immediately, creating - /// the disconnected solution, followed shortly afterwards by a request from the host to make that same - /// checksum be the primary solution of this workspace. - /// - /// - public void TryKickOffPrimaryBranchWork_NoLock(Func> updatePrimaryBranchAsync) + async Task ComputePrimaryBranchAsync(CancellationToken cancellationToken) { - try - { - Contract.ThrowIfFalse(_workspace._gate.CurrentCount == 0); - Contract.ThrowIfNull(updatePrimaryBranchAsync); - Contract.ThrowIfTrue(this._cancellationTokenSource_doNotAccessDirectly.IsCancellationRequested); - - // Already set up the work to update the primary branch - if (_primaryBranchTask != null) - return; - - // Grab the cancellation token up front while we know we are holding the lock and mutating state. We - // don't want to potentially grab it at some undefined point at the future when this type has already - // had its in-flight-count reduced to 0 and thus had our CTS be disposed. - // - // Also kick this off in a dedicated task. The state mutation updating of this InFlightSolution and the - // cache state in RemoteWorkspace must always run fully to completion without issue. We don't want - // anything we call in this method to possibly prevent the method from running to completion. - var cancellationToken = this.CancellationToken; - _primaryBranchTask = Task.Run(() => ComputePrimaryBranchAsync(cancellationToken), cancellationToken); - } - catch (Exception ex) when (FatalError.ReportAndPropagate(ex, ErrorSeverity.General)) - { - // The above must never throw. If it does our caller will not properly update the cache state - // properly and can leave things invalid. - } - - return; - - async Task ComputePrimaryBranchAsync(CancellationToken cancellationToken) - { - var solution = await _disconnectedSolutionTask.ConfigureAwait(false); - cancellationToken.ThrowIfCancellationRequested(); - - return await updatePrimaryBranchAsync(solution, cancellationToken).ConfigureAwait(false); - } - } + var solution = await _disconnectedSolutionTask.ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); - public void IncrementInFlightCount_NoLock() - { - Contract.ThrowIfFalse(_workspace._gate.CurrentCount == 0); - Contract.ThrowIfTrue(InFlightCount < 1); - InFlightCount++; + return await updatePrimaryBranchAsync(solution, cancellationToken).ConfigureAwait(false); } + } - /// - /// Returns the in-flight solution computations when the in-flight-count is decremented to 0. This - /// allows the caller to wait for those computations to complete (which will hopefully be quickly as they - /// will have just been canceled). This ensures the caller doesn't return back to the host (potentially - /// unpinning the solution on the host) while the solution-computation tasks are still running and may still - /// attempt to call into the host. - /// - public ImmutableArray DecrementInFlightCount_NoLock() - { - Contract.ThrowIfFalse(_workspace._gate.CurrentCount == 0); - Contract.ThrowIfTrue(InFlightCount < 1); - InFlightCount--; - if (InFlightCount != 0) - return []; + public void IncrementInFlightCount_NoLock() + { + Contract.ThrowIfFalse(_workspace._gate.CurrentCount == 0); + Contract.ThrowIfTrue(InFlightCount < 1); + InFlightCount++; + } + + /// + /// Returns the in-flight solution computations when the in-flight-count is decremented to 0. This + /// allows the caller to wait for those computations to complete (which will hopefully be quickly as they + /// will have just been canceled). This ensures the caller doesn't return back to the host (potentially + /// unpinning the solution on the host) while the solution-computation tasks are still running and may still + /// attempt to call into the host. + /// + public ImmutableArray DecrementInFlightCount_NoLock() + { + Contract.ThrowIfFalse(_workspace._gate.CurrentCount == 0); + Contract.ThrowIfTrue(InFlightCount < 1); + InFlightCount--; + if (InFlightCount != 0) + return []; - _cancellationTokenSource_doNotAccessDirectly.Cancel(); - _cancellationTokenSource_doNotAccessDirectly.Dispose(); + _cancellationTokenSource_doNotAccessDirectly.Cancel(); + _cancellationTokenSource_doNotAccessDirectly.Dispose(); - // If we're going away, we better find ourself in the mapping for this checksum. - Contract.ThrowIfFalse(_workspace._solutionChecksumToSolution.TryGetValue(SolutionChecksum, out var existingSolution)); - Contract.ThrowIfFalse(existingSolution == this); + // If we're going away, we better find ourself in the mapping for this checksum. + Contract.ThrowIfFalse(_workspace._solutionChecksumToSolution.TryGetValue(SolutionChecksum, out var existingSolution)); + Contract.ThrowIfFalse(existingSolution == this); - // And we better succeed at actually removing. - Contract.ThrowIfFalse(_workspace._solutionChecksumToSolution.Remove(SolutionChecksum)); + // And we better succeed at actually removing. + Contract.ThrowIfFalse(_workspace._solutionChecksumToSolution.Remove(SolutionChecksum)); - _workspace.CheckCacheInvariants_NoLock(); + _workspace.CheckCacheInvariants_NoLock(); - // Return the solutions we were in the process of computing. Note, returning the _primaryBranchTask is - // likely not necessary as all that task does is take the _disconnectedSolutionTask and make it the - // primary branch of hte workspace (which doesn't involve a call back from OOP to the host). However, - // this is just safer to return both, esp. if that might ever change in the future. - using var solutions = TemporaryArray.Empty; + // Return the solutions we were in the process of computing. Note, returning the _primaryBranchTask is + // likely not necessary as all that task does is take the _disconnectedSolutionTask and make it the + // primary branch of hte workspace (which doesn't involve a call back from OOP to the host). However, + // this is just safer to return both, esp. if that might ever change in the future. + using var solutions = TemporaryArray.Empty; - solutions.Add(_disconnectedSolutionTask); - solutions.AsRef().AddIfNotNull(_primaryBranchTask); + solutions.Add(_disconnectedSolutionTask); + solutions.AsRef().AddIfNotNull(_primaryBranchTask); - return solutions.ToImmutableAndClear(); - } + return solutions.ToImmutableAndClear(); } } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs index b6d046d3d60f7..694cd7b67f5b5 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs @@ -19,663 +19,599 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal partial class RemoteWorkspace { - internal partial class RemoteWorkspace + /// + /// Create solution for given checksum from base solution + /// + private readonly struct SolutionCreator(RemoteWorkspace workspace, AssetProvider assetService, Solution baseSolution) { - /// - /// Create solution for given checksum from base solution - /// - private readonly struct SolutionCreator(HostServices hostServices, AssetProvider assetService, Solution baseSolution) - { #pragma warning disable IDE0052 // used only in DEBUG builds - private readonly HostServices _hostServices = hostServices; + private readonly RemoteWorkspace _workspace = workspace; #pragma warning restore - private readonly AssetProvider _assetProvider = assetService; - private readonly Solution _baseSolution = baseSolution; + private readonly AssetProvider _assetProvider = assetService; + private readonly Solution _baseSolution = baseSolution; - public async Task CreateSolutionAsync(Checksum newSolutionChecksum, CancellationToken cancellationToken) + public async Task CreateSolutionAsync(Checksum newSolutionChecksum, CancellationToken cancellationToken) + { + try { - try - { - var solution = _baseSolution; + var solution = _baseSolution; - // If we previously froze a source generated document and then held onto that, unfreeze it now. We'll re-freeze the new document - // if needed again later. - solution = solution.WithoutFrozenSourceGeneratedDocuments(); + // If we previously froze a source generated document and then held onto that, unfreeze it now. We'll re-freeze the new document + // if needed again later. + solution = solution.WithoutFrozenSourceGeneratedDocuments(); - var newSolutionCompilationChecksums = await _assetProvider.GetAssetAsync( - AssetPathKind.SolutionCompilationStateChecksums, newSolutionChecksum, cancellationToken).ConfigureAwait(false); - var newSolutionChecksums = await _assetProvider.GetAssetAsync( - AssetPathKind.SolutionStateChecksums, newSolutionCompilationChecksums.SolutionState, cancellationToken).ConfigureAwait(false); + var newSolutionCompilationChecksums = await _assetProvider.GetAssetAsync( + AssetPathKind.SolutionCompilationStateChecksums, newSolutionChecksum, cancellationToken).ConfigureAwait(false); + var newSolutionChecksums = await _assetProvider.GetAssetAsync( + AssetPathKind.SolutionStateChecksums, newSolutionCompilationChecksums.SolutionState, cancellationToken).ConfigureAwait(false); - var oldSolutionCompilationChecksums = await solution.CompilationState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - var oldSolutionChecksums = await solution.CompilationState.SolutionState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); + var oldSolutionCompilationChecksums = await solution.CompilationState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); + var oldSolutionChecksums = await solution.CompilationState.SolutionState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - if (oldSolutionChecksums.Attributes != newSolutionChecksums.Attributes) - { - var newSolutionInfo = await _assetProvider.GetAssetAsync( - AssetPathKind.SolutionAttributes, newSolutionChecksums.Attributes, cancellationToken).ConfigureAwait(false); - - // if either id or file path has changed, then this is not update - Contract.ThrowIfFalse(solution.Id == newSolutionInfo.Id && solution.FilePath == newSolutionInfo.FilePath); - } + if (oldSolutionChecksums.Attributes != newSolutionChecksums.Attributes) + { + var newSolutionInfo = await _assetProvider.GetAssetAsync( + AssetPathKind.SolutionAttributes, newSolutionChecksums.Attributes, cancellationToken).ConfigureAwait(false); - if (oldSolutionChecksums.Projects.Checksum != newSolutionChecksums.Projects.Checksum) - { - solution = await UpdateProjectsAsync( - solution, oldSolutionChecksums, newSolutionChecksums, cancellationToken).ConfigureAwait(false); - } + // if either id or file path has changed, then this is not update + Contract.ThrowIfFalse(solution.Id == newSolutionInfo.Id && solution.FilePath == newSolutionInfo.FilePath); + } - if (oldSolutionChecksums.AnalyzerReferences.Checksum != newSolutionChecksums.AnalyzerReferences.Checksum) - { - solution = solution.WithAnalyzerReferences(await _assetProvider.GetAssetsArrayAsync( - AssetPathKind.SolutionAnalyzerReferences, newSolutionChecksums.AnalyzerReferences, cancellationToken).ConfigureAwait(false)); - } + if (oldSolutionChecksums.Projects.Checksum != newSolutionChecksums.Projects.Checksum) + { + solution = await UpdateProjectsAsync( + solution, oldSolutionChecksums, newSolutionChecksums, cancellationToken).ConfigureAwait(false); + } - if (oldSolutionChecksums.FallbackAnalyzerOptions != newSolutionChecksums.FallbackAnalyzerOptions) - { - solution = solution.WithFallbackAnalyzerOptions(await _assetProvider.GetAssetAsync>( - AssetPathKind.SolutionFallbackAnalyzerOptions, newSolutionChecksums.FallbackAnalyzerOptions, cancellationToken).ConfigureAwait(false)); - } + if (oldSolutionChecksums.AnalyzerReferences.Checksum != newSolutionChecksums.AnalyzerReferences.Checksum) + { + solution = solution.WithAnalyzerReferences(await _assetProvider.GetAssetsArrayAsync( + AssetPathKind.SolutionAnalyzerReferences, newSolutionChecksums.AnalyzerReferences, cancellationToken).ConfigureAwait(false)); + } - if (newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentIdentities.HasValue && - newSolutionCompilationChecksums.FrozenSourceGeneratedDocuments.HasValue && - !newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentGenerationDateTimes.IsDefault) - { - var newSolutionFrozenSourceGeneratedDocumentIdentities = newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentIdentities.Value; - var newSolutionFrozenSourceGeneratedDocuments = newSolutionCompilationChecksums.FrozenSourceGeneratedDocuments.Value; - var count = newSolutionFrozenSourceGeneratedDocuments.Ids.Length; + if (oldSolutionChecksums.FallbackAnalyzerOptions != newSolutionChecksums.FallbackAnalyzerOptions) + { + solution = solution.WithFallbackAnalyzerOptions(await _assetProvider.GetAssetAsync>( + AssetPathKind.SolutionFallbackAnalyzerOptions, newSolutionChecksums.FallbackAnalyzerOptions, cancellationToken).ConfigureAwait(false)); + } - var frozenDocuments = new FixedSizeArrayBuilder<(SourceGeneratedDocumentIdentity identity, DateTime generationDateTime, SourceText text)>(count); - for (var i = 0; i < count; i++) - { - var frozenDocumentId = newSolutionFrozenSourceGeneratedDocuments.Ids[i]; - var frozenDocumentTextChecksum = newSolutionFrozenSourceGeneratedDocuments.TextChecksums[i]; - var frozenDocumentIdentity = newSolutionFrozenSourceGeneratedDocumentIdentities[i]; + if (newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentIdentities.HasValue && + newSolutionCompilationChecksums.FrozenSourceGeneratedDocuments.HasValue && + !newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentGenerationDateTimes.IsDefault) + { + var newSolutionFrozenSourceGeneratedDocumentIdentities = newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentIdentities.Value; + var newSolutionFrozenSourceGeneratedDocuments = newSolutionCompilationChecksums.FrozenSourceGeneratedDocuments.Value; + var count = newSolutionFrozenSourceGeneratedDocuments.Ids.Length; - var identity = await _assetProvider.GetAssetAsync( - new(AssetPathKind.SolutionFrozenSourceGeneratedDocumentIdentities, frozenDocumentId), frozenDocumentIdentity, cancellationToken).ConfigureAwait(false); + var frozenDocuments = new FixedSizeArrayBuilder<(SourceGeneratedDocumentIdentity identity, DateTime generationDateTime, SourceText text)>(count); + for (var i = 0; i < count; i++) + { + var frozenDocumentId = newSolutionFrozenSourceGeneratedDocuments.Ids[i]; + var frozenDocumentTextChecksum = newSolutionFrozenSourceGeneratedDocuments.TextChecksums[i]; + var frozenDocumentIdentity = newSolutionFrozenSourceGeneratedDocumentIdentities[i]; - var serializableSourceText = await _assetProvider.GetAssetAsync( - new(AssetPathKind.SolutionFrozenSourceGeneratedDocumentText, frozenDocumentId), frozenDocumentTextChecksum, cancellationToken).ConfigureAwait(false); + var identity = await _assetProvider.GetAssetAsync( + new(AssetPathKind.SolutionFrozenSourceGeneratedDocumentIdentities, frozenDocumentId), frozenDocumentIdentity, cancellationToken).ConfigureAwait(false); - var generationDateTime = newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentGenerationDateTimes[i]; - var text = await serializableSourceText.GetTextAsync(cancellationToken).ConfigureAwait(false); - frozenDocuments.Add((identity, generationDateTime, text)); - } + var serializableSourceText = await _assetProvider.GetAssetAsync( + new(AssetPathKind.SolutionFrozenSourceGeneratedDocumentText, frozenDocumentId), frozenDocumentTextChecksum, cancellationToken).ConfigureAwait(false); - solution = solution.WithFrozenSourceGeneratedDocuments(frozenDocuments.MoveToImmutable()); + var generationDateTime = newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentGenerationDateTimes[i]; + var text = await serializableSourceText.GetTextAsync(cancellationToken).ConfigureAwait(false); + frozenDocuments.Add((identity, generationDateTime, text)); } - if (oldSolutionCompilationChecksums.SourceGeneratorExecutionVersionMap != - newSolutionCompilationChecksums.SourceGeneratorExecutionVersionMap) - { - var newVersions = await _assetProvider.GetAssetAsync( - AssetPathKind.SolutionSourceGeneratorExecutionVersionMap, newSolutionCompilationChecksums.SourceGeneratorExecutionVersionMap, cancellationToken).ConfigureAwait(false); + solution = solution.WithFrozenSourceGeneratedDocuments(frozenDocuments.MoveToImmutable()); + } + + if (oldSolutionCompilationChecksums.SourceGeneratorExecutionVersionMap != + newSolutionCompilationChecksums.SourceGeneratorExecutionVersionMap) + { + var newVersions = await _assetProvider.GetAssetAsync( + AssetPathKind.SolutionSourceGeneratorExecutionVersionMap, newSolutionCompilationChecksums.SourceGeneratorExecutionVersionMap, cancellationToken).ConfigureAwait(false); #if DEBUG - var projectCone = newSolutionChecksums.ProjectCone; - if (projectCone != null) - { - Debug.Assert(projectCone.ProjectIds.Count == newVersions.Map.Count); - Debug.Assert(projectCone.ProjectIds.All(id => newVersions.Map.ContainsKey(id))); - } - else - { - Debug.Assert(solution.ProjectIds.Count == newVersions.Map.Count); - Debug.Assert(solution.ProjectIds.All(id => newVersions.Map.ContainsKey(id))); - } + var projectCone = newSolutionChecksums.ProjectCone; + if (projectCone != null) + { + Debug.Assert(projectCone.ProjectIds.Count == newVersions.Map.Count); + Debug.Assert(projectCone.ProjectIds.All(id => newVersions.Map.ContainsKey(id))); + } + else + { + Debug.Assert(solution.ProjectIds.Count == newVersions.Map.Count); + Debug.Assert(solution.ProjectIds.All(id => newVersions.Map.ContainsKey(id))); + } #endif - solution = solution.UpdateSpecificSourceGeneratorExecutionVersions(newVersions); - } + solution = solution.UpdateSpecificSourceGeneratorExecutionVersions(newVersions); + } #if DEBUG - // make sure created solution has same checksum as given one - await ValidateChecksumAsync(newSolutionChecksum, solution, newSolutionChecksums.ProjectConeId, cancellationToken).ConfigureAwait(false); + // make sure created solution has same checksum as given one + await ValidateChecksumAsync(newSolutionChecksum, solution, newSolutionChecksums.ProjectConeId, cancellationToken).ConfigureAwait(false); #endif - return solution; - } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) - { - throw ExceptionUtilities.Unreachable(); - } + return solution; } - - private async Task UpdateProjectsAsync( - Solution solution, SolutionStateChecksums oldSolutionChecksums, SolutionStateChecksums newSolutionChecksums, CancellationToken cancellationToken) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) { - var solutionState = solution.SolutionState; - - using var _1 = PooledDictionary.GetInstance(out var oldProjectIdToChecksum); - using var _2 = PooledDictionary.GetInstance(out var newProjectIdToChecksum); - - foreach (var (oldChecksum, projectId) in oldSolutionChecksums.Projects) - oldProjectIdToChecksum.Add(projectId, oldChecksum); - - foreach (var (newChecksum, projectId) in newSolutionChecksums.Projects) - newProjectIdToChecksum.Add(projectId, newChecksum); + throw ExceptionUtilities.Unreachable(); + } + } - // remove projects that are the same on both sides. We can just iterate over one of the maps as, - // definitionally, for the project to be on both sides, it will be contained in both. - foreach (var (oldChecksum, projectId) in oldSolutionChecksums.Projects) - { - if (newProjectIdToChecksum.TryGetValue(projectId, out var newChecksum) && - oldChecksum == newChecksum) - { - oldProjectIdToChecksum.Remove(projectId); - newProjectIdToChecksum.Remove(projectId); - } - } + private async Task UpdateProjectsAsync( + Solution solution, SolutionStateChecksums oldSolutionChecksums, SolutionStateChecksums newSolutionChecksums, CancellationToken cancellationToken) + { + var solutionState = solution.SolutionState; - // If there are old projects that are now missing on the new side, and this is a projectConeSync, then - // exclude them from the old side as well. This way we only consider projects actually added or - // changed. - // - // Importantly, this means in the event of a cone-sync, we never drop projects locally. That's very - // desirable as it will likely be useful in future calls to still know about that project info without - // it being dropped and having to be resynced. - var isConeSync = newSolutionChecksums.ProjectConeId != null; - if (isConeSync) - { - foreach (var (oldChecksum, oldProjectId) in oldSolutionChecksums.Projects) - { - if (!newProjectIdToChecksum.ContainsKey(oldProjectId)) - oldProjectIdToChecksum.Remove(oldProjectId); - } + using var _1 = PooledDictionary.GetInstance(out var oldProjectIdToChecksum); + using var _2 = PooledDictionary.GetInstance(out var newProjectIdToChecksum); - // All the old projects must be in the new project set. Though the reverse doesn't have to hold. - // The new project set may contain additional projects to add. - Contract.ThrowIfFalse(oldProjectIdToChecksum.Keys.All(newProjectIdToChecksum.Keys.Contains)); - } + foreach (var (oldChecksum, projectId) in oldSolutionChecksums.Projects) + oldProjectIdToChecksum.Add(projectId, oldChecksum); - using var _3 = PooledDictionary.GetInstance(out var oldProjectIdToStateChecksums); - using var _4 = PooledDictionary.GetInstance(out var newProjectIdToStateChecksums); + foreach (var (newChecksum, projectId) in newSolutionChecksums.Projects) + newProjectIdToChecksum.Add(projectId, newChecksum); - // Now, find the full state checksums for all the old projects - foreach (var (projectId, oldChecksum) in oldProjectIdToChecksum) + // remove projects that are the same on both sides. We can just iterate over one of the maps as, + // definitionally, for the project to be on both sides, it will be contained in both. + foreach (var (oldChecksum, projectId) in oldSolutionChecksums.Projects) + { + if (newProjectIdToChecksum.TryGetValue(projectId, out var newChecksum) && + oldChecksum == newChecksum) { - // this should be cheap since we already computed oldSolutionChecksums (which calls into this). - var oldProjectStateChecksums = await solutionState - .GetRequiredProjectState(projectId) - .GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - Contract.ThrowIfTrue(oldProjectStateChecksums.ProjectId != projectId); - Contract.ThrowIfTrue(oldChecksum != oldProjectStateChecksums.Checksum); - - oldProjectIdToStateChecksums.Add(projectId, oldProjectStateChecksums); + oldProjectIdToChecksum.Remove(projectId); + newProjectIdToChecksum.Remove(projectId); } - - using var _5 = PooledHashSet.GetInstance(out var newChecksumsToSync); - newChecksumsToSync.AddRange(newProjectIdToChecksum.Values); - - await _assetProvider.GetAssetHelper().GetAssetsAsync( - assetPath: AssetPathKind.ProjectStateChecksums, newChecksumsToSync, - static (checksum, newProjectStateChecksum, newProjectIdToStateChecksums) => - { - Contract.ThrowIfTrue(checksum != newProjectStateChecksum.Checksum); - newProjectIdToStateChecksums.Add(newProjectStateChecksum.ProjectId, newProjectStateChecksum); - }, - arg: newProjectIdToStateChecksums, - cancellationToken).ConfigureAwait(false); - - // Now that we've collected the old and new project state checksums, we can actually process them to - // determine what to remove, what to add, and what to change. - solution = await UpdateProjectsAsync( - solution, isConeSync, oldProjectIdToStateChecksums, newProjectIdToStateChecksums, cancellationToken).ConfigureAwait(false); - - return solution; } - private async Task UpdateProjectsAsync( - Solution solution, - bool isConeSync, - Dictionary oldProjectIdToStateChecksums, - Dictionary newProjectIdToStateChecksums, - CancellationToken cancellationToken) + // If there are old projects that are now missing on the new side, and this is a projectConeSync, then + // exclude them from the old side as well. This way we only consider projects actually added or + // changed. + // + // Importantly, this means in the event of a cone-sync, we never drop projects locally. That's very + // desirable as it will likely be useful in future calls to still know about that project info without + // it being dropped and having to be resynced. + var isConeSync = newSolutionChecksums.ProjectConeId != null; + if (isConeSync) { - // Note: it's common to need to collect a large set of project-attributes and compilation options. So - // attempt to collect all of those in a single call for each kind instead of a call for each instance - // needed. + foreach (var (oldChecksum, oldProjectId) in oldSolutionChecksums.Projects) { - using var _ = PooledHashSet.GetInstance(out var projectItemChecksums); - foreach (var (_, newProjectChecksums) in newProjectIdToStateChecksums) - projectItemChecksums.Add(newProjectChecksums.Info); + if (!newProjectIdToChecksum.ContainsKey(oldProjectId)) + oldProjectIdToChecksum.Remove(oldProjectId); + } - await _assetProvider.GetAssetsAsync( - assetPath: AssetPathKind.ProjectAttributes, projectItemChecksums, cancellationToken).ConfigureAwait(false); + // All the old projects must be in the new project set. Though the reverse doesn't have to hold. + // The new project set may contain additional projects to add. + Contract.ThrowIfFalse(oldProjectIdToChecksum.Keys.All(newProjectIdToChecksum.Keys.Contains)); + } - projectItemChecksums.Clear(); - foreach (var (_, newProjectChecksums) in newProjectIdToStateChecksums) - projectItemChecksums.Add(newProjectChecksums.CompilationOptions); + using var _3 = PooledDictionary.GetInstance(out var oldProjectIdToStateChecksums); + using var _4 = PooledDictionary.GetInstance(out var newProjectIdToStateChecksums); - await _assetProvider.GetAssetsAsync( - assetPath: AssetPathKind.ProjectCompilationOptions, projectItemChecksums, cancellationToken).ConfigureAwait(false); - } + // Now, find the full state checksums for all the old projects + foreach (var (projectId, oldChecksum) in oldProjectIdToChecksum) + { + // this should be cheap since we already computed oldSolutionChecksums (which calls into this). + var oldProjectStateChecksums = await solutionState + .GetRequiredProjectState(projectId) + .GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); + Contract.ThrowIfTrue(oldProjectStateChecksums.ProjectId != projectId); + Contract.ThrowIfTrue(oldChecksum != oldProjectStateChecksums.Checksum); + + oldProjectIdToStateChecksums.Add(projectId, oldProjectStateChecksums); + } - using var _2 = ArrayBuilder.GetInstance(out var projectStateChecksumsToAdd); + using var _5 = PooledHashSet.GetInstance(out var newChecksumsToSync); + newChecksumsToSync.AddRange(newProjectIdToChecksum.Values); - // added project - foreach (var (projectId, newProjectChecksums) in newProjectIdToStateChecksums) + await _assetProvider.GetAssetHelper().GetAssetsAsync( + assetPath: AssetPathKind.ProjectStateChecksums, newChecksumsToSync, + static (checksum, newProjectStateChecksum, newProjectIdToStateChecksums) => { - if (!oldProjectIdToStateChecksums.ContainsKey(projectId)) - projectStateChecksumsToAdd.Add(newProjectChecksums); - } + Contract.ThrowIfTrue(checksum != newProjectStateChecksum.Checksum); + newProjectIdToStateChecksums.Add(newProjectStateChecksum.ProjectId, newProjectStateChecksum); + }, + arg: newProjectIdToStateChecksums, + cancellationToken).ConfigureAwait(false); - // bulk sync added project assets fully since we'll definitely need that data, and we can fetch more - // efficiently in bulk and in parallel. - await _assetProvider.SynchronizeProjectAssetsAsync(projectStateChecksumsToAdd, cancellationToken).ConfigureAwait(false); + // Now that we've collected the old and new project state checksums, we can actually process them to + // determine what to remove, what to add, and what to change. + solution = await UpdateProjectsAsync( + solution, isConeSync, oldProjectIdToStateChecksums, newProjectIdToStateChecksums, cancellationToken).ConfigureAwait(false); - using var _3 = ArrayBuilder.GetInstance(projectStateChecksumsToAdd.Count, out var projectInfos); - foreach (var (projectId, newProjectChecksums) in newProjectIdToStateChecksums) - { - if (!oldProjectIdToStateChecksums.ContainsKey(projectId)) - { - // Now make a ProjectInfo corresponding to the new project checksums. This should be fast due - // to the bulk sync we just performed above. - var projectInfo = await _assetProvider.CreateProjectInfoAsync(newProjectChecksums, cancellationToken).ConfigureAwait(false); - projectInfos.Add(projectInfo); - } - } + return solution; + } - // Add solutions in bulk. Avoiding intermediary forking of it. - solution = solution.AddProjects(projectInfos); + private async Task UpdateProjectsAsync( + Solution solution, + bool isConeSync, + Dictionary oldProjectIdToStateChecksums, + Dictionary newProjectIdToStateChecksums, + CancellationToken cancellationToken) + { + // Note: it's common to need to collect a large set of project-attributes and compilation options. So + // attempt to collect all of those in a single call for each kind instead of a call for each instance + // needed. + { + using var _ = PooledHashSet.GetInstance(out var projectItemChecksums); + foreach (var (_, newProjectChecksums) in newProjectIdToStateChecksums) + projectItemChecksums.Add(newProjectChecksums.Info); - // remove all project references from projects that changed. this ensures exceptions will not occur for - // cyclic references during an incremental update. - foreach (var (projectId, newProjectChecksums) in newProjectIdToStateChecksums) - { - // Only have to do something if this was a changed project, and specifically the project references - // changed. - if (oldProjectIdToStateChecksums.TryGetValue(projectId, out var oldProjectChecksums) && - oldProjectChecksums.ProjectReferences.Checksum != newProjectChecksums.ProjectReferences.Checksum) - { - solution = solution.WithProjectReferences(projectId, projectReferences: []); - } - } + await _assetProvider.GetAssetsAsync( + assetPath: AssetPathKind.ProjectAttributes, projectItemChecksums, cancellationToken).ConfigureAwait(false); - using var _4 = ArrayBuilder.GetInstance(out var projectsToRemove); + projectItemChecksums.Clear(); + foreach (var (_, newProjectChecksums) in newProjectIdToStateChecksums) + projectItemChecksums.Add(newProjectChecksums.CompilationOptions); - // removed project - foreach (var (projectId, _) in oldProjectIdToStateChecksums) - { - if (!newProjectIdToStateChecksums.ContainsKey(projectId)) - { - // Should never be removing projects during cone syncing. - Contract.ThrowIfTrue(isConeSync); - projectsToRemove.Add(projectId); - } - } + await _assetProvider.GetAssetsAsync( + assetPath: AssetPathKind.ProjectCompilationOptions, projectItemChecksums, cancellationToken).ConfigureAwait(false); + } - // Remove solutions in bulk. Avoiding intermediary forking of it. - solution = solution.RemoveProjects(projectsToRemove); + using var _2 = ArrayBuilder.GetInstance(out var projectStateChecksumsToAdd); - // changed project - foreach (var (projectId, newProjectChecksums) in newProjectIdToStateChecksums) - { - if (oldProjectIdToStateChecksums.TryGetValue(projectId, out var oldProjectChecksums)) - { - // If this project was in the old map, then the project must have changed. Otherwise, we would - // have removed it earlier on. - Contract.ThrowIfTrue(oldProjectChecksums.Checksum == newProjectChecksums.Checksum); - solution = await UpdateProjectAsync( - solution.GetRequiredProject(projectId), oldProjectChecksums, newProjectChecksums, cancellationToken).ConfigureAwait(false); - } - } - - return solution; + // added project + foreach (var (projectId, newProjectChecksums) in newProjectIdToStateChecksums) + { + if (!oldProjectIdToStateChecksums.ContainsKey(projectId)) + projectStateChecksumsToAdd.Add(newProjectChecksums); } - private async Task UpdateProjectAsync(Project project, ProjectStateChecksums oldProjectChecksums, ProjectStateChecksums newProjectChecksums, CancellationToken cancellationToken) + // bulk sync added project assets fully since we'll definitely need that data, and we can fetch more + // efficiently in bulk and in parallel. + await _assetProvider.SynchronizeProjectAssetsAsync(projectStateChecksumsToAdd, cancellationToken).ConfigureAwait(false); + + using var _3 = ArrayBuilder.GetInstance(projectStateChecksumsToAdd.Count, out var projectInfos); + foreach (var (projectId, newProjectChecksums) in newProjectIdToStateChecksums) { - // changed info - if (oldProjectChecksums.Info != newProjectChecksums.Info) + if (!oldProjectIdToStateChecksums.ContainsKey(projectId)) { - project = await UpdateProjectInfoAsync(project, newProjectChecksums.Info, cancellationToken).ConfigureAwait(false); + // Now make a ProjectInfo corresponding to the new project checksums. This should be fast due + // to the bulk sync we just performed above. + var projectInfo = await _assetProvider.CreateProjectInfoAsync(newProjectChecksums, cancellationToken).ConfigureAwait(false); + projectInfos.Add(projectInfo); } + } - // changed compilation options - if (oldProjectChecksums.CompilationOptions != newProjectChecksums.CompilationOptions) - { - project = project.WithCompilationOptions( - project.State.ProjectInfo.Attributes.FixUpCompilationOptions( - await _assetProvider.GetAssetAsync( - assetPath: project.Id, newProjectChecksums.CompilationOptions, cancellationToken).ConfigureAwait(false))); - } + // Add solutions in bulk. Avoiding intermediary forking of it. + solution = solution.AddProjects(projectInfos); - // changed parse options - if (oldProjectChecksums.ParseOptions != newProjectChecksums.ParseOptions) + // remove all project references from projects that changed. this ensures exceptions will not occur for + // cyclic references during an incremental update. + foreach (var (projectId, newProjectChecksums) in newProjectIdToStateChecksums) + { + // Only have to do something if this was a changed project, and specifically the project references + // changed. + if (oldProjectIdToStateChecksums.TryGetValue(projectId, out var oldProjectChecksums) && + oldProjectChecksums.ProjectReferences.Checksum != newProjectChecksums.ProjectReferences.Checksum) { - project = project.WithParseOptions(await _assetProvider.GetAssetAsync( - assetPath: project.Id, newProjectChecksums.ParseOptions, cancellationToken).ConfigureAwait(false)); + solution = solution.WithProjectReferences(projectId, projectReferences: []); } + } - // changed project references - if (oldProjectChecksums.ProjectReferences.Checksum != newProjectChecksums.ProjectReferences.Checksum) - { - project = project.WithProjectReferences(await _assetProvider.GetAssetsArrayAsync( - assetPath: project.Id, newProjectChecksums.ProjectReferences, cancellationToken).ConfigureAwait(false)); - } + using var _4 = ArrayBuilder.GetInstance(out var projectsToRemove); - // changed metadata references - if (oldProjectChecksums.MetadataReferences.Checksum != newProjectChecksums.MetadataReferences.Checksum) + // removed project + foreach (var (projectId, _) in oldProjectIdToStateChecksums) + { + if (!newProjectIdToStateChecksums.ContainsKey(projectId)) { - project = project.WithMetadataReferences(await _assetProvider.GetAssetsArrayAsync( - assetPath: project.Id, newProjectChecksums.MetadataReferences, cancellationToken).ConfigureAwait(false)); + // Should never be removing projects during cone syncing. + Contract.ThrowIfTrue(isConeSync); + projectsToRemove.Add(projectId); } + } - // changed analyzer references - if (oldProjectChecksums.AnalyzerReferences.Checksum != newProjectChecksums.AnalyzerReferences.Checksum) - { - project = project.WithAnalyzerReferences(await _assetProvider.GetAssetsArrayAsync( - assetPath: project.Id, newProjectChecksums.AnalyzerReferences, cancellationToken).ConfigureAwait(false)); - } + // Remove solutions in bulk. Avoiding intermediary forking of it. + solution = solution.RemoveProjects(projectsToRemove); - // changed analyzer references - if (oldProjectChecksums.Documents.Checksum != newProjectChecksums.Documents.Checksum) + // changed project + foreach (var (projectId, newProjectChecksums) in newProjectIdToStateChecksums) + { + if (oldProjectIdToStateChecksums.TryGetValue(projectId, out var oldProjectChecksums)) { - project = await UpdateDocumentsAsync( - project, - oldProjectChecksums.Documents, - newProjectChecksums.Documents, - static (solution, documents) => solution.AddDocuments(documents), - static (solution, documentIds) => solution.RemoveDocuments(documentIds), - cancellationToken).ConfigureAwait(false); - } + // If this project was in the old map, then the project must have changed. Otherwise, we would + // have removed it earlier on. + Contract.ThrowIfTrue(oldProjectChecksums.Checksum == newProjectChecksums.Checksum); - // changed additional documents - if (oldProjectChecksums.AdditionalDocuments.Checksum != newProjectChecksums.AdditionalDocuments.Checksum) - { - project = await UpdateDocumentsAsync( - project, - oldProjectChecksums.AdditionalDocuments, - newProjectChecksums.AdditionalDocuments, - static (solution, documents) => solution.AddAdditionalDocuments(documents), - static (solution, documentIds) => solution.RemoveAdditionalDocuments(documentIds), - cancellationToken).ConfigureAwait(false); - } + // changed info + if (oldProjectChecksums.Info != newProjectChecksums.Info) + { + solution = solution.WithProjectAttributes(await _assetProvider.GetAssetAsync( + assetPath: projectId, newProjectChecksums.Info, cancellationToken).ConfigureAwait(false)); + } - // changed analyzer config documents - if (oldProjectChecksums.AnalyzerConfigDocuments.Checksum != newProjectChecksums.AnalyzerConfigDocuments.Checksum) - { - project = await UpdateDocumentsAsync( - project, - oldProjectChecksums.AnalyzerConfigDocuments, - newProjectChecksums.AnalyzerConfigDocuments, - static (solution, documents) => solution.AddAnalyzerConfigDocuments(documents), - static (solution, documentIds) => solution.RemoveAnalyzerConfigDocuments(documentIds), - cancellationToken).ConfigureAwait(false); + solution = await UpdateProjectAsync( + solution.GetRequiredProject(projectId), oldProjectChecksums, newProjectChecksums, cancellationToken).ConfigureAwait(false); } - - return project.Solution; } - private async Task UpdateProjectInfoAsync(Project project, Checksum infoChecksum, CancellationToken cancellationToken) - { - var newProjectAttributes = await _assetProvider.GetAssetAsync( - assetPath: project.Id, infoChecksum, cancellationToken).ConfigureAwait(false); - - // there is no API to change these once project is created - Contract.ThrowIfFalse(project.State.ProjectInfo.Attributes.Id == newProjectAttributes.Id); - Contract.ThrowIfFalse(project.State.ProjectInfo.Attributes.Language == newProjectAttributes.Language); - Contract.ThrowIfFalse(project.State.ProjectInfo.Attributes.IsSubmission == newProjectAttributes.IsSubmission); + return solution; + } - var projectId = project.Id; + private async Task UpdateProjectAsync(Project project, ProjectStateChecksums oldProjectChecksums, ProjectStateChecksums newProjectChecksums, CancellationToken cancellationToken) + { + // changed compilation options + if (oldProjectChecksums.CompilationOptions != newProjectChecksums.CompilationOptions) + { + project = project.WithCompilationOptions( + project.State.ProjectInfo.Attributes.FixUpCompilationOptions( + await _assetProvider.GetAssetAsync( + assetPath: project.Id, newProjectChecksums.CompilationOptions, cancellationToken).ConfigureAwait(false))); + } - if (project.State.ProjectInfo.Attributes.Name != newProjectAttributes.Name) - { - project = project.Solution.WithProjectName(projectId, newProjectAttributes.Name).GetRequiredProject(projectId); - } + // changed parse options + if (oldProjectChecksums.ParseOptions != newProjectChecksums.ParseOptions) + { + project = project.WithParseOptions(await _assetProvider.GetAssetAsync( + assetPath: project.Id, newProjectChecksums.ParseOptions, cancellationToken).ConfigureAwait(false)); + } - if (project.State.ProjectInfo.Attributes.AssemblyName != newProjectAttributes.AssemblyName) - { - project = project.Solution.WithProjectAssemblyName(projectId, newProjectAttributes.AssemblyName).GetRequiredProject(projectId); - } + // changed project references + if (oldProjectChecksums.ProjectReferences.Checksum != newProjectChecksums.ProjectReferences.Checksum) + { + project = project.WithProjectReferences(await _assetProvider.GetAssetsArrayAsync( + assetPath: project.Id, newProjectChecksums.ProjectReferences, cancellationToken).ConfigureAwait(false)); + } - if (project.State.ProjectInfo.Attributes.FilePath != newProjectAttributes.FilePath) - { - project = project.Solution.WithProjectFilePath(projectId, newProjectAttributes.FilePath).GetRequiredProject(projectId); - } + // changed metadata references + if (oldProjectChecksums.MetadataReferences.Checksum != newProjectChecksums.MetadataReferences.Checksum) + { + project = project.WithMetadataReferences(await _assetProvider.GetAssetsArrayAsync( + assetPath: project.Id, newProjectChecksums.MetadataReferences, cancellationToken).ConfigureAwait(false)); + } - if (project.State.ProjectInfo.Attributes.OutputFilePath != newProjectAttributes.OutputFilePath) - { - project = project.Solution.WithProjectOutputFilePath(projectId, newProjectAttributes.OutputFilePath).GetRequiredProject(projectId); - } + // changed analyzer references + if (oldProjectChecksums.AnalyzerReferences.Checksum != newProjectChecksums.AnalyzerReferences.Checksum) + { + project = project.WithAnalyzerReferences(await _assetProvider.GetAssetsArrayAsync( + assetPath: project.Id, newProjectChecksums.AnalyzerReferences, cancellationToken).ConfigureAwait(false)); + } - if (project.State.ProjectInfo.Attributes.OutputRefFilePath != newProjectAttributes.OutputRefFilePath) - { - project = project.Solution.WithProjectOutputRefFilePath(projectId, newProjectAttributes.OutputRefFilePath).GetRequiredProject(projectId); - } + // changed analyzer references + if (oldProjectChecksums.Documents.Checksum != newProjectChecksums.Documents.Checksum) + { + project = await UpdateDocumentsAsync( + project, + oldProjectChecksums.Documents, + newProjectChecksums.Documents, + static (solution, documents) => solution.AddDocuments(documents), + static (solution, documentIds) => solution.RemoveDocuments(documentIds), + cancellationToken).ConfigureAwait(false); + } - if (project.State.ProjectInfo.Attributes.CompilationOutputInfo != newProjectAttributes.CompilationOutputInfo) - { - project = project.Solution.WithProjectCompilationOutputInfo(project.Id, newProjectAttributes.CompilationOutputInfo).GetRequiredProject(project.Id); - } + // changed additional documents + if (oldProjectChecksums.AdditionalDocuments.Checksum != newProjectChecksums.AdditionalDocuments.Checksum) + { + project = await UpdateDocumentsAsync( + project, + oldProjectChecksums.AdditionalDocuments, + newProjectChecksums.AdditionalDocuments, + static (solution, documents) => solution.AddAdditionalDocuments(documents), + static (solution, documentIds) => solution.RemoveAdditionalDocuments(documentIds), + cancellationToken).ConfigureAwait(false); + } - if (project.State.ProjectInfo.Attributes.DefaultNamespace != newProjectAttributes.DefaultNamespace) - { - project = project.Solution.WithProjectDefaultNamespace(projectId, newProjectAttributes.DefaultNamespace).GetRequiredProject(projectId); - } + // changed analyzer config documents + if (oldProjectChecksums.AnalyzerConfigDocuments.Checksum != newProjectChecksums.AnalyzerConfigDocuments.Checksum) + { + project = await UpdateDocumentsAsync( + project, + oldProjectChecksums.AnalyzerConfigDocuments, + newProjectChecksums.AnalyzerConfigDocuments, + static (solution, documents) => solution.AddAnalyzerConfigDocuments(documents), + static (solution, documentIds) => solution.RemoveAnalyzerConfigDocuments(documentIds), + cancellationToken).ConfigureAwait(false); + } - if (project.State.ProjectInfo.Attributes.HasAllInformation != newProjectAttributes.HasAllInformation) - { - project = project.Solution.WithHasAllInformation(projectId, newProjectAttributes.HasAllInformation).GetRequiredProject(projectId); - } + return project.Solution; + } - if (project.State.ProjectInfo.Attributes.RunAnalyzers != newProjectAttributes.RunAnalyzers) - { - project = project.Solution.WithRunAnalyzers(projectId, newProjectAttributes.RunAnalyzers).GetRequiredProject(projectId); - } + private async Task UpdateDocumentsAsync( + Project project, + DocumentChecksumsAndIds oldChecksums, + DocumentChecksumsAndIds newChecksums, + Func, Solution> addDocuments, + Func, Solution> removeDocuments, + CancellationToken cancellationToken) where TDocumentState : TextDocumentState + { + using var _1 = PooledDictionary.GetInstance(out var oldDocumentIdToChecksums); + using var _2 = PooledDictionary.GetInstance(out var newDocumentIdToChecksums); - if (project.State.ProjectInfo.Attributes.ChecksumAlgorithm != newProjectAttributes.ChecksumAlgorithm) - { - project = project.Solution.WithProjectChecksumAlgorithm(projectId, newProjectAttributes.ChecksumAlgorithm).GetRequiredProject(projectId); - } + foreach (var (oldAttributeChecksum, oldTextChecksum, documentId) in oldChecksums) + oldDocumentIdToChecksums.Add(documentId, (oldAttributeChecksum, oldTextChecksum)); - return project; - } + foreach (var (newAttributeChecksum, newTextChecksum, documentId) in newChecksums) + newDocumentIdToChecksums.Add(documentId, (newAttributeChecksum, newTextChecksum)); - private async Task UpdateDocumentsAsync( - Project project, - DocumentChecksumsAndIds oldChecksums, - DocumentChecksumsAndIds newChecksums, - Func, Solution> addDocuments, - Func, Solution> removeDocuments, - CancellationToken cancellationToken) where TDocumentState : TextDocumentState + // remove documents that are the same on both sides. We can just iterate over one of the maps as, + // definitionally, for the project to be on both sides, it will be contained in both. + foreach (var (oldAttributeChecksum, oldTextChecksum, documentId) in oldChecksums) { - using var _1 = PooledDictionary.GetInstance(out var oldDocumentIdToChecksums); - using var _2 = PooledDictionary.GetInstance(out var newDocumentIdToChecksums); - - foreach (var (oldAttributeChecksum, oldTextChecksum, documentId) in oldChecksums) - oldDocumentIdToChecksums.Add(documentId, (oldAttributeChecksum, oldTextChecksum)); - - foreach (var (newAttributeChecksum, newTextChecksum, documentId) in newChecksums) - newDocumentIdToChecksums.Add(documentId, (newAttributeChecksum, newTextChecksum)); - - // remove documents that are the same on both sides. We can just iterate over one of the maps as, - // definitionally, for the project to be on both sides, it will be contained in both. - foreach (var (oldAttributeChecksum, oldTextChecksum, documentId) in oldChecksums) + if (newDocumentIdToChecksums.TryGetValue(documentId, out var newChecksum) && + oldAttributeChecksum == newChecksum.attributeChecksum && + oldTextChecksum == newChecksum.textChecksum) { - if (newDocumentIdToChecksums.TryGetValue(documentId, out var newChecksum) && - oldAttributeChecksum == newChecksum.attributeChecksum && - oldTextChecksum == newChecksum.textChecksum) - { - oldDocumentIdToChecksums.Remove(documentId); - newDocumentIdToChecksums.Remove(documentId); - } + oldDocumentIdToChecksums.Remove(documentId); + newDocumentIdToChecksums.Remove(documentId); } + } - // sync over the *info* about all the added/changed documents. We'll want the info so we can determine - // what actually changed. - using var _5 = PooledHashSet.GetInstance(out var newChecksumsToSync); - newChecksumsToSync.AddRange(newDocumentIdToChecksums.Values.Select(v => v.attributeChecksum)); + // sync over the *info* about all the added/changed documents. We'll want the info so we can determine + // what actually changed. + using var _5 = PooledHashSet.GetInstance(out var newChecksumsToSync); + newChecksumsToSync.AddRange(newDocumentIdToChecksums.Values.Select(v => v.attributeChecksum)); - await _assetProvider.GetAssetsAsync( - assetPath: new(AssetPathKind.DocumentAttributes, project.Id), newChecksumsToSync, cancellationToken).ConfigureAwait(false); + await _assetProvider.GetAssetsAsync( + assetPath: new(AssetPathKind.DocumentAttributes, project.Id), newChecksumsToSync, cancellationToken).ConfigureAwait(false); - newChecksumsToSync.Clear(); - newChecksumsToSync.AddRange(newDocumentIdToChecksums.Values.Select(v => v.textChecksum)); + newChecksumsToSync.Clear(); + newChecksumsToSync.AddRange(newDocumentIdToChecksums.Values.Select(v => v.textChecksum)); - await _assetProvider.GetAssetsAsync( - assetPath: new(AssetPathKind.DocumentText, project.Id), newChecksumsToSync, cancellationToken).ConfigureAwait(false); + await _assetProvider.GetAssetsAsync( + assetPath: new(AssetPathKind.DocumentText, project.Id), newChecksumsToSync, cancellationToken).ConfigureAwait(false); - return await UpdateDocumentsAsync(project, addDocuments, removeDocuments, oldDocumentIdToChecksums, newDocumentIdToChecksums, cancellationToken).ConfigureAwait(false); - } + return await UpdateDocumentsAsync(project, addDocuments, removeDocuments, oldDocumentIdToChecksums, newDocumentIdToChecksums, cancellationToken).ConfigureAwait(false); + } - private async Task UpdateDocumentsAsync( - Project project, - Func, Solution> addDocuments, - Func, Solution> removeDocuments, - Dictionary oldDocumentIdToStateChecksums, - Dictionary newDocumentIdToStateChecksums, - CancellationToken cancellationToken) + private async Task UpdateDocumentsAsync( + Project project, + Func, Solution> addDocuments, + Func, Solution> removeDocuments, + Dictionary oldDocumentIdToStateChecksums, + Dictionary newDocumentIdToStateChecksums, + CancellationToken cancellationToken) + { + // added document + ImmutableArray.Builder? lazyDocumentsToAdd = null; + foreach (var (documentId, newDocumentChecksums) in newDocumentIdToStateChecksums) { - // added document - ImmutableArray.Builder? lazyDocumentsToAdd = null; - foreach (var (documentId, newDocumentChecksums) in newDocumentIdToStateChecksums) + if (!oldDocumentIdToStateChecksums.ContainsKey(documentId)) { - if (!oldDocumentIdToStateChecksums.ContainsKey(documentId)) - { - lazyDocumentsToAdd ??= ImmutableArray.CreateBuilder(); + lazyDocumentsToAdd ??= ImmutableArray.CreateBuilder(); - // we have new document added - var documentInfo = await _assetProvider.CreateDocumentInfoAsync( - documentId, newDocumentChecksums.attributeChecksum, newDocumentChecksums.textChecksum, cancellationToken).ConfigureAwait(false); - lazyDocumentsToAdd.Add(documentInfo); - } - } - - if (lazyDocumentsToAdd != null) - { - project = addDocuments(project.Solution, lazyDocumentsToAdd.ToImmutable()).GetProject(project.Id)!; + // we have new document added + var documentInfo = await _assetProvider.CreateDocumentInfoAsync( + documentId, newDocumentChecksums.attributeChecksum, newDocumentChecksums.textChecksum, cancellationToken).ConfigureAwait(false); + lazyDocumentsToAdd.Add(documentInfo); } + } - // removed document - ImmutableArray.Builder? lazyDocumentsToRemove = null; - foreach (var (documentId, _) in oldDocumentIdToStateChecksums) - { - if (!newDocumentIdToStateChecksums.ContainsKey(documentId)) - { - // we have a document removed - lazyDocumentsToRemove ??= ImmutableArray.CreateBuilder(); - lazyDocumentsToRemove.Add(documentId); - } - } + if (lazyDocumentsToAdd != null) + { + project = addDocuments(project.Solution, lazyDocumentsToAdd.ToImmutable()).GetProject(project.Id)!; + } - if (lazyDocumentsToRemove is not null) + // removed document + ImmutableArray.Builder? lazyDocumentsToRemove = null; + foreach (var (documentId, _) in oldDocumentIdToStateChecksums) + { + if (!newDocumentIdToStateChecksums.ContainsKey(documentId)) { - project = removeDocuments(project.Solution, lazyDocumentsToRemove.ToImmutable()).GetProject(project.Id)!; + // we have a document removed + lazyDocumentsToRemove ??= ImmutableArray.CreateBuilder(); + lazyDocumentsToRemove.Add(documentId); } + } - // changed document - foreach (var (documentId, newDocumentChecksums) in newDocumentIdToStateChecksums) - { - if (!oldDocumentIdToStateChecksums.TryGetValue(documentId, out var oldDocumentChecksums)) - continue; + if (lazyDocumentsToRemove is not null) + { + project = removeDocuments(project.Solution, lazyDocumentsToRemove.ToImmutable()).GetProject(project.Id)!; + } - Contract.ThrowIfTrue( - oldDocumentChecksums.attributeChecksum == newDocumentChecksums.attributeChecksum && - oldDocumentChecksums.textChecksum == newDocumentChecksums.textChecksum); + // changed document + foreach (var (documentId, newDocumentChecksums) in newDocumentIdToStateChecksums) + { + if (!oldDocumentIdToStateChecksums.TryGetValue(documentId, out var oldDocumentChecksums)) + continue; - var document = project.GetDocument(documentId) ?? project.GetAdditionalDocument(documentId) ?? project.GetAnalyzerConfigDocument(documentId); - Contract.ThrowIfNull(document); + Contract.ThrowIfTrue( + oldDocumentChecksums.attributeChecksum == newDocumentChecksums.attributeChecksum && + oldDocumentChecksums.textChecksum == newDocumentChecksums.textChecksum); - project = await UpdateDocumentAsync(document, oldDocumentChecksums, newDocumentChecksums, cancellationToken).ConfigureAwait(false); - } + var document = project.GetDocument(documentId) ?? project.GetAdditionalDocument(documentId) ?? project.GetAnalyzerConfigDocument(documentId); + Contract.ThrowIfNull(document); - return project; + project = await UpdateDocumentAsync(document, oldDocumentChecksums, newDocumentChecksums, cancellationToken).ConfigureAwait(false); } - private async Task UpdateDocumentAsync( - TextDocument document, - (Checksum attributeChecksum, Checksum textChecksum) oldDocumentChecksums, - (Checksum attributeChecksum, Checksum textChecksum) newDocumentChecksums, - CancellationToken cancellationToken) - { - // changed info - if (oldDocumentChecksums.attributeChecksum != newDocumentChecksums.attributeChecksum) - { - document = await UpdateDocumentInfoAsync(document, newDocumentChecksums.attributeChecksum, cancellationToken).ConfigureAwait(false); - } - - // changed text - if (oldDocumentChecksums.textChecksum != newDocumentChecksums.textChecksum) - { - var serializableSourceText = await _assetProvider.GetAssetAsync( - assetPath: document.Id, newDocumentChecksums.textChecksum, cancellationToken).ConfigureAwait(false); - var loader = serializableSourceText.ToTextLoader(document.FilePath); - var mode = PreservationMode.PreserveValue; - - document = document.Kind switch - { - TextDocumentKind.Document => document.Project.Solution.WithDocumentTextLoader(document.Id, loader, mode).GetRequiredDocument(document.Id), - TextDocumentKind.AnalyzerConfigDocument => document.Project.Solution.WithAnalyzerConfigDocumentTextLoader(document.Id, loader, mode).GetRequiredAnalyzerConfigDocument(document.Id), - TextDocumentKind.AdditionalDocument => document.Project.Solution.WithAdditionalDocumentTextLoader(document.Id, loader, mode).GetRequiredAdditionalDocument(document.Id), - _ => throw ExceptionUtilities.UnexpectedValue(document.Kind), - }; - } + return project; + } - return document.Project; + private async Task UpdateDocumentAsync( + TextDocument document, + (Checksum attributeChecksum, Checksum textChecksum) oldDocumentChecksums, + (Checksum attributeChecksum, Checksum textChecksum) newDocumentChecksums, + CancellationToken cancellationToken) + { + // changed info + if (oldDocumentChecksums.attributeChecksum != newDocumentChecksums.attributeChecksum) + { + document = await UpdateDocumentInfoAsync(document, newDocumentChecksums.attributeChecksum, cancellationToken).ConfigureAwait(false); } - private async Task UpdateDocumentInfoAsync(TextDocument document, Checksum infoChecksum, CancellationToken cancellationToken) + // changed text + if (oldDocumentChecksums.textChecksum != newDocumentChecksums.textChecksum) { - var newDocumentInfo = await _assetProvider.GetAssetAsync( - assetPath: document.Id, infoChecksum, cancellationToken).ConfigureAwait(false); + var serializableSourceText = await _assetProvider.GetAssetAsync( + assetPath: document.Id, newDocumentChecksums.textChecksum, cancellationToken).ConfigureAwait(false); + var loader = serializableSourceText.ToTextLoader(document.FilePath); + var mode = PreservationMode.PreserveValue; + + document = document.Kind switch + { + TextDocumentKind.Document => document.Project.Solution.WithDocumentTextLoader(document.Id, loader, mode).GetRequiredDocument(document.Id), + TextDocumentKind.AnalyzerConfigDocument => document.Project.Solution.WithAnalyzerConfigDocumentTextLoader(document.Id, loader, mode).GetRequiredAnalyzerConfigDocument(document.Id), + TextDocumentKind.AdditionalDocument => document.Project.Solution.WithAdditionalDocumentTextLoader(document.Id, loader, mode).GetRequiredAdditionalDocument(document.Id), + _ => throw ExceptionUtilities.UnexpectedValue(document.Kind), + }; + } - // there is no api to change these once document is created - Contract.ThrowIfFalse(document.State.Attributes.Id == newDocumentInfo.Id); - Contract.ThrowIfFalse(document.State.Attributes.Name == newDocumentInfo.Name); - Contract.ThrowIfFalse(document.State.Attributes.FilePath == newDocumentInfo.FilePath); - Contract.ThrowIfFalse(document.State.Attributes.IsGenerated == newDocumentInfo.IsGenerated); - Contract.ThrowIfFalse(document.State.Attributes.DesignTimeOnly == newDocumentInfo.DesignTimeOnly); + return document.Project; + } - if (document.State.Attributes.Folders != newDocumentInfo.Folders) - { - // additional document can't change folder once created - Contract.ThrowIfFalse(document is Document); - document = document.Project.Solution.WithDocumentFolders(document.Id, newDocumentInfo.Folders).GetDocument(document.Id)!; - } + private async Task UpdateDocumentInfoAsync(TextDocument document, Checksum infoChecksum, CancellationToken cancellationToken) + { + var newDocumentInfo = await _assetProvider.GetAssetAsync( + assetPath: document.Id, infoChecksum, cancellationToken).ConfigureAwait(false); - if (document.State.Attributes.SourceCodeKind != newDocumentInfo.SourceCodeKind) - { - // additional document can't change sourcecode kind once created - Contract.ThrowIfFalse(document is Document); - document = document.Project.Solution.WithDocumentSourceCodeKind(document.Id, newDocumentInfo.SourceCodeKind).GetDocument(document.Id)!; - } + // there is no api to change these once document is created + Contract.ThrowIfFalse(document.State.Attributes.Id == newDocumentInfo.Id); + Contract.ThrowIfFalse(document.State.Attributes.Name == newDocumentInfo.Name); + Contract.ThrowIfFalse(document.State.Attributes.FilePath == newDocumentInfo.FilePath); + Contract.ThrowIfFalse(document.State.Attributes.IsGenerated == newDocumentInfo.IsGenerated); + Contract.ThrowIfFalse(document.State.Attributes.DesignTimeOnly == newDocumentInfo.DesignTimeOnly); - return document; + if (document.State.Attributes.Folders != newDocumentInfo.Folders) + { + // additional document can't change folder once created + Contract.ThrowIfFalse(document is Document); + document = document.Project.Solution.WithDocumentFolders(document.Id, newDocumentInfo.Folders).GetDocument(document.Id)!; } -#if DEBUG - private async Task ValidateChecksumAsync( - Checksum checksumFromRequest, - Solution incrementalSolutionBuilt, - ProjectId? projectConeId, - CancellationToken cancellationToken) + if (document.State.Attributes.SourceCodeKind != newDocumentInfo.SourceCodeKind) { - // In the case of a cone sync, we only want to compare the checksum of the cone sync'ed over to the - // current checksum of that same cone. What is outside of those cones is totally allowed to be - // different. - // - // Note: this is acceptable because that's the contract of a cone sync. Features themselves are not - // allowed to cone-sync and then do anything that needs host/remote invariants outside of that cone. - var currentSolutionChecksum = projectConeId == null - ? await incrementalSolutionBuilt.CompilationState.GetChecksumAsync(cancellationToken).ConfigureAwait(false) - : await incrementalSolutionBuilt.CompilationState.GetChecksumAsync(projectConeId, cancellationToken).ConfigureAwait(false); - - if (checksumFromRequest == currentSolutionChecksum) - return; - - var solutionInfo = await _assetProvider.CreateSolutionInfoAsync(checksumFromRequest, cancellationToken).ConfigureAwait(false); - var workspace = new AdhocWorkspace(_hostServices); - workspace.AddSolution(solutionInfo); - - await TestUtils.AssertChecksumsAsync(_assetProvider, checksumFromRequest, workspace.CurrentSolution, incrementalSolutionBuilt, projectConeId).ConfigureAwait(false); + // additional document can't change sourcecode kind once created + Contract.ThrowIfFalse(document is Document); + document = document.Project.Solution.WithDocumentSourceCodeKind(document.Id, newDocumentInfo.SourceCodeKind).GetDocument(document.Id)!; } -#endif + + return document; + } + +#if DEBUG + private async Task ValidateChecksumAsync( + Checksum checksumFromRequest, + Solution incrementalSolutionBuilt, + ProjectId? projectConeId, + CancellationToken cancellationToken) + { + // In the case of a cone sync, we only want to compare the checksum of the cone sync'ed over to the + // current checksum of that same cone. What is outside of those cones is totally allowed to be + // different. + // + // Note: this is acceptable because that's the contract of a cone sync. Features themselves are not + // allowed to cone-sync and then do anything that needs host/remote invariants outside of that cone. + var currentSolutionChecksum = projectConeId == null + ? await incrementalSolutionBuilt.CompilationState.GetChecksumAsync(cancellationToken).ConfigureAwait(false) + : await incrementalSolutionBuilt.CompilationState.GetChecksumAsync(projectConeId, cancellationToken).ConfigureAwait(false); + + if (checksumFromRequest == currentSolutionChecksum) + return; + + var solutionInfo = await _assetProvider.CreateSolutionInfoAsync(checksumFromRequest, cancellationToken).ConfigureAwait(false); + var workspace = new AdhocWorkspace(_workspace.Services.HostServices); + workspace.AddSolution(solutionInfo); + + await TestUtils.AssertChecksumsAsync(_assetProvider, checksumFromRequest, workspace.CurrentSolution, incrementalSolutionBuilt, projectConeId).ConfigureAwait(false); } +#endif } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs index 37c38418ba746..bb8c4b03cad06 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs @@ -15,338 +15,334 @@ using Roslyn.Utilities; using static Microsoft.VisualStudio.Threading.ThreadingTools; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +/// +/// Workspace created by the remote host that mirrors the corresponding client workspace. +/// +internal sealed partial class RemoteWorkspace : Workspace { /// - /// Workspace created by the remote host that mirrors the corresponding client workspace. + /// Guards updates to all mutable state in this workspace. /// - internal sealed partial class RemoteWorkspace : Workspace + private readonly SemaphoreSlim _gate = new(initialCount: 1); + + // internal for testing purposes. + internal RemoteWorkspace(HostServices hostServices) + : base(hostServices, WorkspaceKind.RemoteWorkspace) { - /// - /// Guards updates to all mutable state in this workspace. - /// - private readonly SemaphoreSlim _gate = new(initialCount: 1); - - // internal for testing purposes. - internal RemoteWorkspace(HostServices hostServices) - : base(hostServices, WorkspaceKind.RemoteWorkspace) - { - } + } - public AssetProvider CreateAssetProvider(Checksum solutionChecksum, SolutionAssetCache assetCache, IAssetSource assetSource) - { - var serializerService = Services.GetRequiredService(); - return new AssetProvider(solutionChecksum, assetCache, assetSource, serializerService); - } + public AssetProvider CreateAssetProvider(Checksum solutionChecksum, SolutionAssetCache assetCache, IAssetSource assetSource) + => new(solutionChecksum, assetCache, assetSource, this.Services.SolutionServices); + + protected internal override bool PartialSemanticsEnabled => true; + + /// + /// Syncs over the solution corresponding to and sets it as the current + /// solution for workspace. This will also end up updating and , allowing + /// them to be pre-populated for feature requests that come in soon after this call completes. + /// + public async Task UpdatePrimaryBranchSolutionAsync( + AssetProvider assetProvider, Checksum solutionChecksum, CancellationToken cancellationToken) + { + // See if the current snapshot we're pointing at is the same one the host wants us to sync to. If so, we + // don't need to do anything. + var currentSolutionChecksum = await this.CurrentSolution.CompilationState.GetChecksumAsync(cancellationToken).ConfigureAwait(false); + if (currentSolutionChecksum == solutionChecksum) + return; + + // Do a normal Run with a no-op for `implementation`. This will still ensure that we compute and cache this + // checksum/solution pair for future callers. + await RunWithSolutionAsync( + assetProvider, + solutionChecksum, + updatePrimaryBranch: true, + implementation: static _ => ValueTaskFactory.FromResult(false), + cancellationToken).ConfigureAwait(false); + } + + /// + /// Given an appropriate , gets or computes the corresponding snapshot for it, and then invokes with that snapshot. That + /// snapshot and the result of are then returned from this method. Note: the + /// solution returned is only for legacy cases where we expose OOP to 2nd party clients who expect to be able to + /// call through and who expose that statically to + /// themselves. + /// + /// During the life of the call to the solution corresponding to will be kept alive and returned to any other concurrent calls to this method with + /// the same . + /// + /// + public ValueTask<(Solution solution, T result)> RunWithSolutionAsync( + AssetProvider assetProvider, + Checksum solutionChecksum, + Func> implementation, + CancellationToken cancellationToken) + { + return RunWithSolutionAsync(assetProvider, solutionChecksum, updatePrimaryBranch: false, implementation, cancellationToken); + } + + private async ValueTask<(Solution solution, T result)> RunWithSolutionAsync( + AssetProvider assetProvider, + Checksum solutionChecksum, + bool updatePrimaryBranch, + Func> implementation, + CancellationToken cancellationToken) + { + Contract.ThrowIfTrue(solutionChecksum == Checksum.Null); - protected internal override bool PartialSemanticsEnabled => true; + // Gets or creates a solution corresponding to the requested checksum. This will always succeed, and will + // increment the in-flight of that solution until we decrement it at the end of our try/finally block. + var (inFlightSolution, solutionTask) = await AcquireSolutionAndIncrementInFlightCountAsync().ConfigureAwait(false); - /// - /// Syncs over the solution corresponding to and sets it as the current - /// solution for workspace. This will also end up updating and , allowing - /// them to be pre-populated for feature requests that come in soon after this call completes. - /// - public async Task UpdatePrimaryBranchSolutionAsync( - AssetProvider assetProvider, Checksum solutionChecksum, CancellationToken cancellationToken) + try { - // See if the current snapshot we're pointing at is the same one the host wants us to sync to. If so, we - // don't need to do anything. - var currentSolutionChecksum = await this.CurrentSolution.CompilationState.GetChecksumAsync(cancellationToken).ConfigureAwait(false); - if (currentSolutionChecksum == solutionChecksum) - return; - - // Do a normal Run with a no-op for `implementation`. This will still ensure that we compute and cache this - // checksum/solution pair for future callers. - await RunWithSolutionAsync( - assetProvider, - solutionChecksum, - updatePrimaryBranch: true, - implementation: static _ => ValueTaskFactory.FromResult(false), - cancellationToken).ConfigureAwait(false); + return await ProcessSolutionAsync(inFlightSolution, solutionTask).ConfigureAwait(false); } - - /// - /// Given an appropriate , gets or computes the corresponding snapshot for it, and then invokes with that snapshot. That - /// snapshot and the result of are then returned from this method. Note: the - /// solution returned is only for legacy cases where we expose OOP to 2nd party clients who expect to be able to - /// call through and who expose that statically to - /// themselves. - /// - /// During the life of the call to the solution corresponding to will be kept alive and returned to any other concurrent calls to this method with - /// the same . - /// - /// - public ValueTask<(Solution solution, T result)> RunWithSolutionAsync( - AssetProvider assetProvider, - Checksum solutionChecksum, - Func> implementation, - CancellationToken cancellationToken) + catch (Exception ex) when (FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken, ErrorSeverity.Critical)) { - return RunWithSolutionAsync(assetProvider, solutionChecksum, updatePrimaryBranch: false, implementation, cancellationToken); + // Any non-cancellation exception is bad and needs to be reported. We will still ensure that we cleanup + // below though no matter what happens so that other calls to OOP can properly work. + throw ExceptionUtilities.Unreachable(); } - - private async ValueTask<(Solution solution, T result)> RunWithSolutionAsync( - AssetProvider assetProvider, - Checksum solutionChecksum, - bool updatePrimaryBranch, - Func> implementation, - CancellationToken cancellationToken) + finally { - Contract.ThrowIfTrue(solutionChecksum == Checksum.Null); - - // Gets or creates a solution corresponding to the requested checksum. This will always succeed, and will - // increment the in-flight of that solution until we decrement it at the end of our try/finally block. - var (inFlightSolution, solutionTask) = await AcquireSolutionAndIncrementInFlightCountAsync().ConfigureAwait(false); - - try - { - return await ProcessSolutionAsync(inFlightSolution, solutionTask).ConfigureAwait(false); - } - catch (Exception ex) when (FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken, ErrorSeverity.Critical)) - { - // Any non-cancellation exception is bad and needs to be reported. We will still ensure that we cleanup - // below though no matter what happens so that other calls to OOP can properly work. - throw ExceptionUtilities.Unreachable(); - } - finally - { - await DecrementInFlightCountAsync(inFlightSolution).ConfigureAwait(false); - } - - // Gets or creates a solution corresponding to the requested checksum. This will always succeed, and will - // increment the in-flight of that solution until we decrement it at the end of our try/finally block. - async ValueTask<(InFlightSolution inFlightSolution, Task solutionTask)> AcquireSolutionAndIncrementInFlightCountAsync() - { - using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) - { - try - { - inFlightSolution = GetOrCreateSolutionAndAddInFlightCount_NoLock( - assetProvider, solutionChecksum, updatePrimaryBranch); - solutionTask = inFlightSolution.PreferredSolutionTask_NoLock; - - // We must have at least 1 for the in-flight-count (representing this current in-flight call). - Contract.ThrowIfTrue(inFlightSolution.InFlightCount < 1); - - return (inFlightSolution, solutionTask); - } - catch (Exception ex) when (FatalError.ReportAndPropagate(ex, ErrorSeverity.Critical)) - { - // Any exception thrown in the above (including cancellation) is critical and unrecoverable. We - // will have potentially started work, while also leaving ourselves in some inconsistent state. - throw ExceptionUtilities.Unreachable(); - } - } - } - - async ValueTask<(Solution solution, T result)> ProcessSolutionAsync(InFlightSolution inFlightSolution, Task solutionTask) - { - // We must have at least 1 for the in-flight-count (representing this current in-flight call). - Contract.ThrowIfTrue(inFlightSolution.InFlightCount < 1); - - // Actually get the solution, computing it ourselves, or getting the result that another caller was - // computing. Note: we use our own cancellation token here as the task is currently operating using a - // private CTS token that inFlightSolution controls. - var solution = await solutionTask.WithCancellation(cancellationToken).ConfigureAwait(false); - - // now that we've computed the solution, cache it to help out future requests. - using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) - { - if (updatePrimaryBranch) - _lastRequestedPrimaryBranchSolution = (solutionChecksum, solution); - else - _lastRequestedAnyBranchSolutions.Add(solutionChecksum, solution); - } - - // Now, pass it to the callback to do the work. Any other callers into us will be able to benefit from - // using this same solution as well - var result = await implementation(solution).ConfigureAwait(false); - - return (solution, result); - } + await DecrementInFlightCountAsync(inFlightSolution).ConfigureAwait(false); + } - async ValueTask DecrementInFlightCountAsync(InFlightSolution inFlightSolution) + // Gets or creates a solution corresponding to the requested checksum. This will always succeed, and will + // increment the in-flight of that solution until we decrement it at the end of our try/finally block. + async ValueTask<(InFlightSolution inFlightSolution, Task solutionTask)> AcquireSolutionAndIncrementInFlightCountAsync() + { + using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { - // All this work is intentionally not cancellable. We must do the decrement to ensure our cache state - // is consistent. This will block the calling thread. However, this should only be for a short amount - // of time as nothing in RemoteWorkspace should ever hold this lock for long periods of time. - try { - ImmutableArray solutionComputationTasks; - using (await _gate.DisposableWaitAsync(CancellationToken.None).ConfigureAwait(false)) - { + inFlightSolution = GetOrCreateSolutionAndAddInFlightCount_NoLock( + assetProvider, solutionChecksum, updatePrimaryBranch); + solutionTask = inFlightSolution.PreferredSolutionTask_NoLock; - // finally, decrement our in-flight-count on the solution. If we were the last one keeping it alive, it - // will get removed from our caches. - solutionComputationTasks = inFlightSolution.DecrementInFlightCount_NoLock(); - } + // We must have at least 1 for the in-flight-count (representing this current in-flight call). + Contract.ThrowIfTrue(inFlightSolution.InFlightCount < 1); - // If we were the request that decremented the in-flight-count to 0, then ensure we wait for all the - // solution-computation tasks to finish. If we do not do this then it's possible for this call to - // return all the way back to the host side unpinning the solution we have pinned there. This may - // happen concurrently with the solution-computation calls calling back into the host which will - // then crash due to that solution no longer being pinned there. While this does force this caller - // to wait for those tasks to stop, this should ideally be fast as they will have been cancelled - // when the in-flight-count went to 0. - // - // Use a NoThrowAwaitable as we want to await all tasks here regardless of how individual ones may cancel. - foreach (var task in solutionComputationTasks) - await task.NoThrowAwaitable(false); + return (inFlightSolution, solutionTask); } catch (Exception ex) when (FatalError.ReportAndPropagate(ex, ErrorSeverity.Critical)) { - // Similar to AcquireSolutionAndIncrementInFlightCountAsync Any exception thrown in the above - // (including cancellation) is critical and unrecoverable. We must clean up our state, and anything - // that prevents that could leave us in an inconsistent position. + // Any exception thrown in the above (including cancellation) is critical and unrecoverable. We + // will have potentially started work, while also leaving ourselves in some inconsistent state. + throw ExceptionUtilities.Unreachable(); } } } - private async Task GetOrCreateSolutionToUpdateAsync( - AssetProvider assetProvider, - Checksum solutionChecksum, - CancellationToken cancellationToken) + async ValueTask<(Solution solution, T result)> ProcessSolutionAsync(InFlightSolution inFlightSolution, Task solutionTask) { - // See if we can just incrementally update the current solution. - var currentSolution = this.CurrentSolution; - if (await IsIncrementalUpdateAsync().ConfigureAwait(false)) - return currentSolution; + // We must have at least 1 for the in-flight-count (representing this current in-flight call). + Contract.ThrowIfTrue(inFlightSolution.InFlightCount < 1); - // If not, have to create a new, fresh, solution instance to update. - var solutionInfo = await assetProvider.CreateSolutionInfoAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); - return CreateSolutionFromInfo(solutionInfo); + // Actually get the solution, computing it ourselves, or getting the result that another caller was + // computing. Note: we use our own cancellation token here as the task is currently operating using a + // private CTS token that inFlightSolution controls. + var solution = await solutionTask.WithCancellation(cancellationToken).ConfigureAwait(false); - async Task IsIncrementalUpdateAsync() + // now that we've computed the solution, cache it to help out future requests. + using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { - var newSolutionCompilationChecksums = await assetProvider.GetAssetAsync( - AssetPathKind.SolutionCompilationStateChecksums, solutionChecksum, cancellationToken).ConfigureAwait(false); - var newSolutionChecksums = await assetProvider.GetAssetAsync( - AssetPathKind.SolutionStateChecksums, newSolutionCompilationChecksums.SolutionState, cancellationToken).ConfigureAwait(false); + if (updatePrimaryBranch) + _lastRequestedPrimaryBranchSolution = (solutionChecksum, solution); + else + _lastRequestedAnyBranchSolutions.Add(solutionChecksum, solution); + } - var newSolutionInfo = await assetProvider.GetAssetAsync( - AssetPathKind.SolutionAttributes, newSolutionChecksums.Attributes, cancellationToken).ConfigureAwait(false); + // Now, pass it to the callback to do the work. Any other callers into us will be able to benefit from + // using this same solution as well + var result = await implementation(solution).ConfigureAwait(false); - // if either solution id or file path changed, then we consider it as new solution - return currentSolution.Id == newSolutionInfo.Id && currentSolution.FilePath == newSolutionInfo.FilePath; - } + return (solution, result); } - /// - /// Create an appropriate instance corresponding to the passed in. Note: this method changes no Workspace state and exists purely to - /// compute the corresponding solution. Updating of our caches, or storing this solution as the of this is the responsibility of any - /// callers. - /// - /// The term 'disconnected' is used to mean that this solution is not assigned to be the current solution of - /// this . It is effectively a fork of that instead. - /// - /// - /// This method will either create the new solution from scratch if it has to. Or it will attempt to create a - /// fork off of if possible. The latter is almost always what will - /// happen (once the first sync completes) as most calls to the remote workspace are using a solution snapshot - /// very close to the primary one, and so can share almost all state with that. - /// - /// - private async Task ComputeDisconnectedSolutionAsync( - AssetProvider assetProvider, - Checksum newSolutionChecksum, - CancellationToken cancellationToken) + async ValueTask DecrementInFlightCountAsync(InFlightSolution inFlightSolution) { + // All this work is intentionally not cancellable. We must do the decrement to ensure our cache state + // is consistent. This will block the calling thread. However, this should only be for a short amount + // of time as nothing in RemoteWorkspace should ever hold this lock for long periods of time. + try { - var solutionToUpdate = await GetOrCreateSolutionToUpdateAsync( - assetProvider, newSolutionChecksum, cancellationToken).ConfigureAwait(false); + ImmutableArray solutionComputationTasks; + using (await _gate.DisposableWaitAsync(CancellationToken.None).ConfigureAwait(false)) + { + + // finally, decrement our in-flight-count on the solution. If we were the last one keeping it alive, it + // will get removed from our caches. + solutionComputationTasks = inFlightSolution.DecrementInFlightCount_NoLock(); + } - // Now, bring that solution in line with the snapshot defined by solutionChecksum. - var updater = new SolutionCreator(Services.HostServices, assetProvider, solutionToUpdate); - return await updater.CreateSolutionAsync(newSolutionChecksum, cancellationToken).ConfigureAwait(false); + // If we were the request that decremented the in-flight-count to 0, then ensure we wait for all the + // solution-computation tasks to finish. If we do not do this then it's possible for this call to + // return all the way back to the host side unpinning the solution we have pinned there. This may + // happen concurrently with the solution-computation calls calling back into the host which will + // then crash due to that solution no longer being pinned there. While this does force this caller + // to wait for those tasks to stop, this should ideally be fast as they will have been cancelled + // when the in-flight-count went to 0. + // + // Use a NoThrowAwaitable as we want to await all tasks here regardless of how individual ones may cancel. + foreach (var task in solutionComputationTasks) + await task.NoThrowAwaitable(false); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) + catch (Exception ex) when (FatalError.ReportAndPropagate(ex, ErrorSeverity.Critical)) { - throw ExceptionUtilities.Unreachable(); + // Similar to AcquireSolutionAndIncrementInFlightCountAsync Any exception thrown in the above + // (including cancellation) is critical and unrecoverable. We must clean up our state, and anything + // that prevents that could leave us in an inconsistent position. } } + } + + private async Task GetOrCreateSolutionToUpdateAsync( + AssetProvider assetProvider, + Checksum solutionChecksum, + CancellationToken cancellationToken) + { + // See if we can just incrementally update the current solution. + var currentSolution = this.CurrentSolution; + if (await IsIncrementalUpdateAsync().ConfigureAwait(false)) + return currentSolution; - private Solution CreateSolutionFromInfo(SolutionInfo solutionInfo) + // If not, have to create a new, fresh, solution instance to update. + var solutionInfo = await assetProvider.CreateSolutionInfoAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); + return CreateSolutionFromInfo(solutionInfo); + + async Task IsIncrementalUpdateAsync() { - var solution = this.CreateSolution(solutionInfo); - using var _ = ArrayBuilder.GetInstance(solutionInfo.Projects.Count, out var projectInfos); - projectInfos.AddRange(solutionInfo.Projects); + var newSolutionCompilationChecksums = await assetProvider.GetAssetAsync( + AssetPathKind.SolutionCompilationStateChecksums, solutionChecksum, cancellationToken).ConfigureAwait(false); + var newSolutionChecksums = await assetProvider.GetAssetAsync( + AssetPathKind.SolutionStateChecksums, newSolutionCompilationChecksums.SolutionState, cancellationToken).ConfigureAwait(false); + + var newSolutionInfo = await assetProvider.GetAssetAsync( + AssetPathKind.SolutionAttributes, newSolutionChecksums.Attributes, cancellationToken).ConfigureAwait(false); - // Add in one operation, avoiding intermediary forking of the solution. - return solution.AddProjects(projectInfos); + // if either solution id or file path changed, then we consider it as new solution + return currentSolution.Id == newSolutionInfo.Id && currentSolution.FilePath == newSolutionInfo.FilePath; } + } - /// - /// Updates this workspace with the given . The solution returned is the actual - /// one the workspace now points to. - /// - private async Task UpdateWorkspaceCurrentSolutionAsync( - Solution newSolution, - CancellationToken cancellationToken) + /// + /// Create an appropriate instance corresponding to the passed in. Note: this method changes no Workspace state and exists purely to + /// compute the corresponding solution. Updating of our caches, or storing this solution as the of this is the responsibility of any + /// callers. + /// + /// The term 'disconnected' is used to mean that this solution is not assigned to be the current solution of + /// this . It is effectively a fork of that instead. + /// + /// + /// This method will either create the new solution from scratch if it has to. Or it will attempt to create a + /// fork off of if possible. The latter is almost always what will + /// happen (once the first sync completes) as most calls to the remote workspace are using a solution snapshot + /// very close to the primary one, and so can share almost all state with that. + /// + /// + private async Task ComputeDisconnectedSolutionAsync( + AssetProvider assetProvider, + Checksum newSolutionChecksum, + CancellationToken cancellationToken) + { + try { - using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) - { - // if either solution id or file path changed, then we consider it as new solution. Otherwise, - // update the current solution in place. - - // Ensure we update newSolution with the result of SetCurrentSolution. It will be the one appropriately - // 'attached' to this workspace. - (_, newSolution) = this.SetCurrentSolution( - _ => newSolution, - changeKind: static (oldSolution, newSolution) => - (IsAddingSolution(oldSolution, newSolution) ? WorkspaceChangeKind.SolutionAdded : WorkspaceChangeKind.SolutionChanged, projectId: null, documentId: null), - onBeforeUpdate: (oldSolution, newSolution) => - { - if (IsAddingSolution(oldSolution, newSolution)) - { - // We're not doing an update, we're moving to a new solution entirely. Clear out the old one. This - // is necessary so that we clear out any open document information this workspace is tracking. Note: - // this seems suspect as the remote workspace should not be tracking any open document state. - this.ClearSolutionData(); - } - }); - - return newSolution; - } + var solutionToUpdate = await GetOrCreateSolutionToUpdateAsync( + assetProvider, newSolutionChecksum, cancellationToken).ConfigureAwait(false); - static bool IsAddingSolution(Solution oldSolution, Solution newSolution) - => oldSolution.Id != newSolution.Id || oldSolution.FilePath != newSolution.FilePath; + // Now, bring that solution in line with the snapshot defined by solutionChecksum. + var updater = new SolutionCreator(this, assetProvider, solutionToUpdate); + return await updater.CreateSolutionAsync(newSolutionChecksum, cancellationToken).ConfigureAwait(false); } + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) + { + throw ExceptionUtilities.Unreachable(); + } + } + + private Solution CreateSolutionFromInfo(SolutionInfo solutionInfo) + { + var solution = this.CreateSolution(solutionInfo); + using var _ = ArrayBuilder.GetInstance(solutionInfo.Projects.Count, out var projectInfos); + projectInfos.AddRange(solutionInfo.Projects); - public TestAccessor GetTestAccessor() - => new(this); + // Add in one operation, avoiding intermediary forking of the solution. + return solution.AddProjects(projectInfos); + } - public readonly struct TestAccessor + /// + /// Updates this workspace with the given . The solution returned is the actual + /// one the workspace now points to. + /// + private async Task UpdateWorkspaceCurrentSolutionAsync( + Solution newSolution, + CancellationToken cancellationToken) + { + using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { - private readonly RemoteWorkspace _remoteWorkspace; + // if either solution id or file path changed, then we consider it as new solution. Otherwise, + // update the current solution in place. + + // Ensure we update newSolution with the result of SetCurrentSolution. It will be the one appropriately + // 'attached' to this workspace. + (_, newSolution) = this.SetCurrentSolution( + _ => newSolution, + changeKind: static (oldSolution, newSolution) => + (IsAddingSolution(oldSolution, newSolution) ? WorkspaceChangeKind.SolutionAdded : WorkspaceChangeKind.SolutionChanged, projectId: null, documentId: null), + onBeforeUpdate: (oldSolution, newSolution) => + { + if (IsAddingSolution(oldSolution, newSolution)) + { + // We're not doing an update, we're moving to a new solution entirely. Clear out the old one. This + // is necessary so that we clear out any open document information this workspace is tracking. Note: + // this seems suspect as the remote workspace should not be tracking any open document state. + this.ClearSolutionData(); + } + }); - public TestAccessor(RemoteWorkspace remoteWorkspace) - { - _remoteWorkspace = remoteWorkspace; - } + return newSolution; + } - public Solution CreateSolutionFromInfo(SolutionInfo solutionInfo) - => _remoteWorkspace.CreateSolutionFromInfo(solutionInfo); + static bool IsAddingSolution(Solution oldSolution, Solution newSolution) + => oldSolution.Id != newSolution.Id || oldSolution.FilePath != newSolution.FilePath; + } - public Task UpdateWorkspaceCurrentSolutionAsync(Solution newSolution) - => _remoteWorkspace.UpdateWorkspaceCurrentSolutionAsync(newSolution, CancellationToken.None); + public TestAccessor GetTestAccessor() + => new(this); - public async ValueTask GetSolutionAsync( - AssetProvider assetProvider, - Checksum solutionChecksum, - bool updatePrimaryBranch, - CancellationToken cancellationToken) - { - var (solution, _) = await _remoteWorkspace.RunWithSolutionAsync( - assetProvider, solutionChecksum, updatePrimaryBranch, _ => ValueTaskFactory.FromResult(false), cancellationToken).ConfigureAwait(false); - return solution; - } + public readonly struct TestAccessor + { + private readonly RemoteWorkspace _remoteWorkspace; + + public TestAccessor(RemoteWorkspace remoteWorkspace) + { + _remoteWorkspace = remoteWorkspace; + } + + public Solution CreateSolutionFromInfo(SolutionInfo solutionInfo) + => _remoteWorkspace.CreateSolutionFromInfo(solutionInfo); + + public Task UpdateWorkspaceCurrentSolutionAsync(Solution newSolution) + => _remoteWorkspace.UpdateWorkspaceCurrentSolutionAsync(newSolution, CancellationToken.None); + + public async ValueTask GetSolutionAsync( + AssetProvider assetProvider, + Checksum solutionChecksum, + bool updatePrimaryBranch, + CancellationToken cancellationToken) + { + var (solution, _) = await _remoteWorkspace.RunWithSolutionAsync( + assetProvider, solutionChecksum, updatePrimaryBranch, _ => ValueTaskFactory.FromResult(false), cancellationToken).ConfigureAwait(false); + return solution; } } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspaceManager.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspaceManager.cs index d4306cf90b55f..99ae2276be734 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspaceManager.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspaceManager.cs @@ -8,157 +8,158 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.Internal.EmbeddedLanguages; +using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.ServiceHub.Framework; using Microsoft.VisualStudio.Composition; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +/// +/// Manages remote workspaces. Currently supports only a single, primary workspace of kind . In future it should support workspaces of all kinds. +/// +internal class RemoteWorkspaceManager { + internal static readonly ImmutableArray RemoteHostAssemblies = + MefHostServices.DefaultAssemblies + .Add(typeof(AspNetCoreEmbeddedLanguageClassifier).Assembly) + .Add(typeof(BrokeredServiceBase).Assembly) + .Add(typeof(RazorAnalyzerAssemblyResolver).Assembly) + .Add(typeof(RemoteWorkspacesResources).Assembly); + /// - /// Manages remote workspaces. Currently supports only a single, primary workspace of kind . In future it should support workspaces of all kinds. + /// Default workspace manager used by the product. Tests may specify a custom in order to override workspace services. /// - internal class RemoteWorkspaceManager + /// + /// The general thinking behind these timings is that we don't want to be too aggressive constantly waking up + /// and cleaning purging items from the cache. But we also don't want to wait an excessive amount of time, + /// allowing it to get too full. + /// + /// Also note that the asset cache will not remove items associated with the of the workspace it is created against (as well as any recent in-flight + /// solutions). This ensures that the assets associated with the solution that most closely corresponds to what + /// the user is working with will stay pinned on the remote side and not get purged just because the user + /// stopped interactive for a while. This ensures the next sync (which likely overlaps heavily with the current + /// solution) will not force the same assets to be resent. + /// + /// + /// CleanupInterval=30s gives what feels to be a reasonable non-aggressive amount of time to let the cache + /// do its job, while also making sure several times a minute it is scanned for things that can be + /// dropped. + /// PurgeAfter=1m effectively states that an item will be dumped from the cache if not used in the last + /// minute. This seems reasonable for keeping around all the parts of the current solutions in use, while + /// allowing values from the past, or values removed from the solution to not persist too long. + /// GcAfter=1m means that we'll force some GCs to happen after that amount of time of *non-activity*. In + /// other words, as long as OOP is being touched for operations, we will avoid doing the GCs. + /// + /// + /// + internal static readonly RemoteWorkspaceManager Default = new( + workspace => new SolutionAssetCache(workspace, cleanupInterval: TimeSpan.FromSeconds(30), purgeAfter: TimeSpan.FromMinutes(1))); + + private readonly RemoteWorkspace _workspace; + internal readonly SolutionAssetCache SolutionAssetCache; + + public RemoteWorkspaceManager(Func createAssetCache) + : this(createAssetCache, CreatePrimaryWorkspace()) { - internal static readonly ImmutableArray RemoteHostAssemblies = - MefHostServices.DefaultAssemblies - .Add(typeof(AspNetCoreEmbeddedLanguageClassifier).Assembly) - .Add(typeof(BrokeredServiceBase).Assembly) - .Add(typeof(RemoteWorkspacesResources).Assembly); - - /// - /// Default workspace manager used by the product. Tests may specify a custom in order to override workspace services. - /// - /// - /// The general thinking behind these timings is that we don't want to be too aggressive constantly waking up - /// and cleaning purging items from the cache. But we also don't want to wait an excessive amount of time, - /// allowing it to get too full. - /// - /// Also note that the asset cache will not remove items associated with the of the workspace it is created against (as well as any recent in-flight - /// solutions). This ensures that the assets associated with the solution that most closely corresponds to what - /// the user is working with will stay pinned on the remote side and not get purged just because the user - /// stopped interactive for a while. This ensures the next sync (which likely overlaps heavily with the current - /// solution) will not force the same assets to be resent. - /// - /// - /// CleanupInterval=30s gives what feels to be a reasonable non-aggressive amount of time to let the cache - /// do its job, while also making sure several times a minute it is scanned for things that can be - /// dropped. - /// PurgeAfter=1m effectively states that an item will be dumped from the cache if not used in the last - /// minute. This seems reasonable for keeping around all the parts of the current solutions in use, while - /// allowing values from the past, or values removed from the solution to not persist too long. - /// GcAfter=1m means that we'll force some GCs to happen after that amount of time of *non-activity*. In - /// other words, as long as OOP is being touched for operations, we will avoid doing the GCs. - /// - /// - /// - internal static readonly RemoteWorkspaceManager Default = new( - workspace => new SolutionAssetCache(workspace, cleanupInterval: TimeSpan.FromSeconds(30), purgeAfter: TimeSpan.FromMinutes(1))); - - private readonly RemoteWorkspace _workspace; - internal readonly SolutionAssetCache SolutionAssetCache; - - public RemoteWorkspaceManager(Func createAssetCache) - : this(createAssetCache, CreatePrimaryWorkspace()) - { - } + } - public RemoteWorkspaceManager( - Func createAssetCache, - RemoteWorkspace workspace) - { - _workspace = workspace; - SolutionAssetCache = createAssetCache(workspace); - } + public RemoteWorkspaceManager( + Func createAssetCache, + RemoteWorkspace workspace) + { + _workspace = workspace; + SolutionAssetCache = createAssetCache(workspace); + } - private static ComposableCatalog CreateCatalog(ImmutableArray assemblies) - { - var resolver = new Resolver(SimpleAssemblyLoader.Instance); - var discovery = new AttributedPartDiscovery(resolver, isNonPublicSupported: true); - var parts = Task.Run(async () => await discovery.CreatePartsAsync(assemblies).ConfigureAwait(false)).GetAwaiter().GetResult(); - return ComposableCatalog.Create(resolver).AddParts(parts); - } + private static ComposableCatalog CreateCatalog(ImmutableArray assemblies) + { + var resolver = new Resolver(SimpleAssemblyLoader.Instance); + var discovery = new AttributedPartDiscovery(resolver, isNonPublicSupported: true); + var parts = Task.Run(async () => await discovery.CreatePartsAsync(assemblies).ConfigureAwait(false)).GetAwaiter().GetResult(); + return ComposableCatalog.Create(resolver).AddParts(parts); + } - private static IExportProviderFactory CreateExportProviderFactory(ComposableCatalog catalog) - { - var configuration = CompositionConfiguration.Create(catalog); - var runtimeComposition = RuntimeComposition.CreateRuntimeComposition(configuration); - return runtimeComposition.CreateExportProviderFactory(); - } + private static IExportProviderFactory CreateExportProviderFactory(ComposableCatalog catalog) + { + var configuration = CompositionConfiguration.Create(catalog); + var runtimeComposition = RuntimeComposition.CreateRuntimeComposition(configuration); + return runtimeComposition.CreateExportProviderFactory(); + } - private static RemoteWorkspace CreatePrimaryWorkspace() - { - var catalog = CreateCatalog(RemoteHostAssemblies); - var exportProviderFactory = CreateExportProviderFactory(catalog); - var exportProvider = exportProviderFactory.CreateExportProvider(); + private static RemoteWorkspace CreatePrimaryWorkspace() + { + var catalog = CreateCatalog(RemoteHostAssemblies); + var exportProviderFactory = CreateExportProviderFactory(catalog); + var exportProvider = exportProviderFactory.CreateExportProvider(); - return new RemoteWorkspace(VisualStudioMefHostServices.Create(exportProvider)); - } + return new RemoteWorkspace(VisualStudioMefHostServices.Create(exportProvider)); + } - public RemoteWorkspace GetWorkspace() => _workspace; + public RemoteWorkspace GetWorkspace() => _workspace; - /// - /// Not ideal that we exposing the workspace solution, while not ensuring it stays alive for other calls using - /// the same ). However, this is used by Pythia/Razor/UnitTesting which all - /// assume they can get that solution instance and use as desired by them. - /// - [Obsolete("Use RunServiceAsync (that is passsed a Solution) instead", error: false)] - public async ValueTask GetSolutionAsync(ServiceBrokerClient client, Checksum solutionChecksum, CancellationToken cancellationToken) - { - var assetSource = new SolutionAssetSource(client); - var workspace = GetWorkspace(); - var assetProvider = workspace.CreateAssetProvider(solutionChecksum, SolutionAssetCache, assetSource); + /// + /// Not ideal that we exposing the workspace solution, while not ensuring it stays alive for other calls using + /// the same ). However, this is used by Pythia/Razor/UnitTesting which all + /// assume they can get that solution instance and use as desired by them. + /// + [Obsolete("Use RunServiceAsync (that is passed a Solution) instead", error: false)] + public async ValueTask GetSolutionAsync(ServiceBrokerClient client, Checksum solutionChecksum, CancellationToken cancellationToken) + { + var assetSource = new SolutionAssetSource(client); + var workspace = GetWorkspace(); + var assetProvider = workspace.CreateAssetProvider(solutionChecksum, SolutionAssetCache, assetSource); - var (solution, _) = await workspace.RunWithSolutionAsync( - assetProvider, - solutionChecksum, - static _ => ValueTaskFactory.FromResult(false), - cancellationToken).ConfigureAwait(false); + var (solution, _) = await workspace.RunWithSolutionAsync( + assetProvider, + solutionChecksum, + static _ => ValueTaskFactory.FromResult(false), + cancellationToken).ConfigureAwait(false); - return solution; - } + return solution; + } - public async ValueTask RunServiceAsync( - ServiceBrokerClient client, - Checksum solutionChecksum, - Func> implementation, - CancellationToken cancellationToken) - { - var assetSource = new SolutionAssetSource(client); - var workspace = GetWorkspace(); - var assetProvider = workspace.CreateAssetProvider(solutionChecksum, SolutionAssetCache, assetSource); + public async ValueTask RunServiceAsync( + ServiceBrokerClient client, + Checksum solutionChecksum, + Func> implementation, + CancellationToken cancellationToken) + { + var assetSource = new SolutionAssetSource(client); + var workspace = GetWorkspace(); + var assetProvider = workspace.CreateAssetProvider(solutionChecksum, SolutionAssetCache, assetSource); - var (_, result) = await workspace.RunWithSolutionAsync( - assetProvider, - solutionChecksum, - implementation, - cancellationToken).ConfigureAwait(false); + var (_, result) = await workspace.RunWithSolutionAsync( + assetProvider, + solutionChecksum, + implementation, + cancellationToken).ConfigureAwait(false); - return result; - } + return result; + } - private sealed class SimpleAssemblyLoader : IAssemblyLoader - { - public static readonly IAssemblyLoader Instance = new SimpleAssemblyLoader(); + private sealed class SimpleAssemblyLoader : IAssemblyLoader + { + public static readonly IAssemblyLoader Instance = new SimpleAssemblyLoader(); - public Assembly LoadAssembly(AssemblyName assemblyName) - => Assembly.Load(assemblyName); + public Assembly LoadAssembly(AssemblyName assemblyName) + => Assembly.Load(assemblyName); - public Assembly LoadAssembly(string assemblyFullName, string? codeBasePath) + public Assembly LoadAssembly(string assemblyFullName, string? codeBasePath) + { + var assemblyName = new AssemblyName(assemblyFullName); + if (!string.IsNullOrEmpty(codeBasePath)) { - var assemblyName = new AssemblyName(assemblyFullName); - if (!string.IsNullOrEmpty(codeBasePath)) - { #pragma warning disable SYSLIB0044 // https://github.com/dotnet/roslyn/issues/71510 - assemblyName.CodeBase = codeBasePath; + assemblyName.CodeBase = codeBasePath; #pragma warning restore SYSLIB0044 - } - - return LoadAssembly(assemblyName); } + + return LoadAssembly(assemblyName); } } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace_SolutionCaching.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace_SolutionCaching.cs index 119d58327f58f..29fd71de14295 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace_SolutionCaching.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace_SolutionCaching.cs @@ -9,133 +9,132 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed partial class RemoteWorkspace { - internal sealed partial class RemoteWorkspace + /// + /// The last solution for the primary branch fetched from the client. Cached as it's very common to have a + /// flurry of requests for the same checksum that don't run concurrently. Only read/write while holding . + /// + private (Checksum checksum, Solution solution) _lastRequestedPrimaryBranchSolution; + + /// + /// Cache of last N solutions requested by a service. Cached as it's very common to have a flurry of requests + /// for the same few checksum that don't run concurrently. Only read/write while holding . + /// + private readonly RemoteSolutionCache _lastRequestedAnyBranchSolutions = new(); + + /// + /// Mapping from solution-checksum to the solution computed for it. This is used so that we can hold a solution + /// around as long as the checksum for it is being used in service of some feature operation (e.g. + /// classification). As long as we're holding onto it, concurrent feature requests for the same solution + /// checksum can share the computation of that particular solution and avoid duplicated concurrent work. Only + /// read/write while holding . + /// + private readonly Dictionary _solutionChecksumToSolution = []; + + /// + /// Deliberately not cancellable. This code must always run fully to completion. + /// + private InFlightSolution GetOrCreateSolutionAndAddInFlightCount_NoLock( + AssetProvider assetProvider, + Checksum solutionChecksum, + bool updatePrimaryBranch) { - /// - /// The last solution for the primary branch fetched from the client. Cached as it's very common to have a - /// flurry of requests for the same checksum that don't run concurrently. Only read/write while holding . - /// - private (Checksum checksum, Solution solution) _lastRequestedPrimaryBranchSolution; - - /// - /// Cache of last N solutions requested by a service. Cached as it's very common to have a flurry of requests - /// for the same few checksum that don't run concurrently. Only read/write while holding . - /// - private readonly RemoteSolutionCache _lastRequestedAnyBranchSolutions = new(); - - /// - /// Mapping from solution-checksum to the solution computed for it. This is used so that we can hold a solution - /// around as long as the checksum for it is being used in service of some feature operation (e.g. - /// classification). As long as we're holding onto it, concurrent feature requests for the same solution - /// checksum can share the computation of that particular solution and avoid duplicated concurrent work. Only - /// read/write while holding . - /// - private readonly Dictionary _solutionChecksumToSolution = []; - - /// - /// Deliberately not cancellable. This code must always run fully to completion. - /// - private InFlightSolution GetOrCreateSolutionAndAddInFlightCount_NoLock( - AssetProvider assetProvider, - Checksum solutionChecksum, - bool updatePrimaryBranch) - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); + Contract.ThrowIfFalse(_gate.CurrentCount == 0); - CheckCacheInvariants_NoLock(); + CheckCacheInvariants_NoLock(); - var solution = GetOrCreateSolutionAndAddInFlightCount_NoLock(); + var solution = GetOrCreateSolutionAndAddInFlightCount_NoLock(); - // The solution must now have a valid in-flight-count. - Contract.ThrowIfTrue(solution.InFlightCount < 1); + // The solution must now have a valid in-flight-count. + Contract.ThrowIfTrue(solution.InFlightCount < 1); - // We may be getting back a solution that only was computing a non-primary branch. If we were asked - // to compute the primary branch as well, let it know so it can start that now. - if (updatePrimaryBranch) - { - solution.TryKickOffPrimaryBranchWork_NoLock((disconnectedSolution, cancellationToken) => - this.UpdateWorkspaceCurrentSolutionAsync(disconnectedSolution, cancellationToken)); - } + // We may be getting back a solution that only was computing a non-primary branch. If we were asked + // to compute the primary branch as well, let it know so it can start that now. + if (updatePrimaryBranch) + { + solution.TryKickOffPrimaryBranchWork_NoLock((disconnectedSolution, cancellationToken) => + this.UpdateWorkspaceCurrentSolutionAsync(disconnectedSolution, cancellationToken)); + } - CheckCacheInvariants_NoLock(); + CheckCacheInvariants_NoLock(); - return solution; + return solution; - InFlightSolution GetOrCreateSolutionAndAddInFlightCount_NoLock() - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); + InFlightSolution GetOrCreateSolutionAndAddInFlightCount_NoLock() + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); - if (_solutionChecksumToSolution.TryGetValue(solutionChecksum, out var solution)) - { - // The cached solution must have a valid in-flight-count - Contract.ThrowIfTrue(solution.InFlightCount < 1); + if (_solutionChecksumToSolution.TryGetValue(solutionChecksum, out var solution)) + { + // The cached solution must have a valid in-flight-count + Contract.ThrowIfTrue(solution.InFlightCount < 1); - // Increase the count as our caller now is keeping this solution in-flight - solution.IncrementInFlightCount_NoLock(); - Contract.ThrowIfTrue(solution.InFlightCount < 2); + // Increase the count as our caller now is keeping this solution in-flight + solution.IncrementInFlightCount_NoLock(); + Contract.ThrowIfTrue(solution.InFlightCount < 2); - return solution; - } + return solution; + } - // See if we're being asked for a checksum we already have cached a solution for. Safe to read directly - // as we're holding _gate. - var cachedSolution = _lastRequestedPrimaryBranchSolution.checksum == solutionChecksum - ? _lastRequestedPrimaryBranchSolution.solution - : _lastRequestedAnyBranchSolutions.Find(solutionChecksum); + // See if we're being asked for a checksum we already have cached a solution for. Safe to read directly + // as we're holding _gate. + var cachedSolution = _lastRequestedPrimaryBranchSolution.checksum == solutionChecksum + ? _lastRequestedPrimaryBranchSolution.solution + : _lastRequestedAnyBranchSolutions.Find(solutionChecksum); - // We're the first call that is asking about this checksum. Kick off async computation to compute it - // (or use an existing cached value we already have). Start with an in-flight-count of 1 to represent - // our caller. - solution = new InFlightSolution( - this, solutionChecksum, - async cancellationToken => cachedSolution ?? await ComputeDisconnectedSolutionAsync(assetProvider, solutionChecksum, cancellationToken).ConfigureAwait(false)); - Contract.ThrowIfFalse(solution.InFlightCount == 1); + // We're the first call that is asking about this checksum. Kick off async computation to compute it + // (or use an existing cached value we already have). Start with an in-flight-count of 1 to represent + // our caller. + solution = new InFlightSolution( + this, solutionChecksum, + async cancellationToken => cachedSolution ?? await ComputeDisconnectedSolutionAsync(assetProvider, solutionChecksum, cancellationToken).ConfigureAwait(false)); + Contract.ThrowIfFalse(solution.InFlightCount == 1); - _solutionChecksumToSolution.Add(solutionChecksum, solution); + _solutionChecksumToSolution.Add(solutionChecksum, solution); - return solution; - } + return solution; } + } - private void CheckCacheInvariants_NoLock() - { - Contract.ThrowIfFalse(_gate.CurrentCount == 0); + private void CheckCacheInvariants_NoLock() + { + Contract.ThrowIfFalse(_gate.CurrentCount == 0); - foreach (var (solutionChecksum, solution) in _solutionChecksumToSolution) - { - // Anything in this dictionary is currently in flight with an existing request. So it must have an - // in-flight-count of at least 1. Note: this in-flight-request may be an actual request that has come - // in from the client. Or it can be a virtual one we've created through _lastAnyBranchSolution or - // _lastPrimaryBranchSolution - Contract.ThrowIfTrue(solution.InFlightCount < 1); - Contract.ThrowIfTrue(solutionChecksum != solution.SolutionChecksum); - } + foreach (var (solutionChecksum, solution) in _solutionChecksumToSolution) + { + // Anything in this dictionary is currently in flight with an existing request. So it must have an + // in-flight-count of at least 1. Note: this in-flight-request may be an actual request that has come + // in from the client. Or it can be a virtual one we've created through _lastAnyBranchSolution or + // _lastPrimaryBranchSolution + Contract.ThrowIfTrue(solution.InFlightCount < 1); + Contract.ThrowIfTrue(solutionChecksum != solution.SolutionChecksum); } + } - /// - /// Gets all the solution instances this remote workspace knows about because of the primary solution or any - /// in-flight operations. - /// - public async ValueTask AddPinnedSolutionsAsync(HashSet solutions, CancellationToken cancellationToken) + /// + /// Gets all the solution instances this remote workspace knows about because of the primary solution or any + /// in-flight operations. + /// + public async ValueTask AddPinnedSolutionsAsync(HashSet solutions, CancellationToken cancellationToken) + { + using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { - using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) - { - // Ensure everything in the workspace's current solution is pinned. We def don't want any of its data - // dropped from the checksum->asset cache. - solutions.Add(this.CurrentSolution); - - // Also the data for the last 'current solution' this workspace had that we actually got an OOP request - // for. this is commonly the same as CurrentSolution, but technically could be slightly behind if the - // primary solution just got updated. - solutions.AddIfNotNull(_lastRequestedPrimaryBranchSolution.solution); - - // Also add the last few forked solutions we were asked about. As with the above solutions, there's a - // reasonable chance it will refer to data needed by future oop calls. - _lastRequestedAnyBranchSolutions.AddAllTo(solutions); - } + // Ensure everything in the workspace's current solution is pinned. We def don't want any of its data + // dropped from the checksum->asset cache. + solutions.Add(this.CurrentSolution); + + // Also the data for the last 'current solution' this workspace had that we actually got an OOP request + // for. this is commonly the same as CurrentSolution, but technically could be slightly behind if the + // primary solution just got updated. + solutions.AddIfNotNull(_lastRequestedPrimaryBranchSolution.solution); + + // Also add the last few forked solutions we were asked about. As with the above solutions, there's a + // reasonable chance it will refer to data needed by future oop calls. + _lastRequestedAnyBranchSolutions.AddAllTo(solutions); } } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/TestUtils.cs b/src/Workspaces/Remote/ServiceHub/Host/TestUtils.cs index ada4f5f1be1c1..8640af5f5c12c 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/TestUtils.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/TestUtils.cs @@ -16,267 +16,266 @@ using Microsoft.CodeAnalysis.Internal.Log; #endif -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal static class TestUtils { - internal static class TestUtils + public static void RemoveChecksums(this Dictionary map, ChecksumCollection checksums) { - public static void RemoveChecksums(this Dictionary map, ChecksumCollection checksums) - { - var set = new HashSet(); - set.AppendChecksums(checksums); + var set = new HashSet(); + set.AppendChecksums(checksums); - RemoveChecksums(map, set); - } + RemoveChecksums(map, set); + } - public static void RemoveChecksums(this Dictionary map, IEnumerable checksums) + public static void RemoveChecksums(this Dictionary map, IEnumerable checksums) + { + foreach (var checksum in checksums) { - foreach (var checksum in checksums) - { - map.Remove(checksum); - } + map.Remove(checksum); } + } - internal static async Task AssertChecksumsAsync( - AssetProvider assetService, - Checksum checksumFromRequest, - Solution solutionFromScratch, - Solution incrementalSolutionBuilt, - ProjectId? projectConeId) - { + internal static async Task AssertChecksumsAsync( + AssetProvider assetService, + Checksum checksumFromRequest, + Solution solutionFromScratch, + Solution incrementalSolutionBuilt, + ProjectId? projectConeId) + { #if DEBUG - var sb = new StringBuilder(); - var allChecksumsFromRequest = await GetAllChildrenChecksumsAsync(checksumFromRequest).ConfigureAwait(false); + var sb = new StringBuilder(); + var allChecksumsFromRequest = await GetAllChildrenChecksumsAsync(checksumFromRequest).ConfigureAwait(false); - var assetMapFromNewSolution = await solutionFromScratch.GetAssetMapAsync(projectConeId, CancellationToken.None).ConfigureAwait(false); - var assetMapFromIncrementalSolution = await incrementalSolutionBuilt.GetAssetMapAsync(projectConeId, CancellationToken.None).ConfigureAwait(false); + var assetMapFromNewSolution = await solutionFromScratch.GetAssetMapAsync(projectConeId, CancellationToken.None).ConfigureAwait(false); + var assetMapFromIncrementalSolution = await incrementalSolutionBuilt.GetAssetMapAsync(projectConeId, CancellationToken.None).ConfigureAwait(false); - // check 4 things - // 1. first see if we create new solution from scratch, it works as expected (indicating a bug in incremental update) - var mismatch1 = assetMapFromNewSolution.Where(p => !allChecksumsFromRequest.Contains(p.Key)).ToList(); - AppendMismatch(mismatch1, "Assets only in new solution but not in the request", sb); + // check 4 things + // 1. first see if we create new solution from scratch, it works as expected (indicating a bug in incremental update) + var mismatch1 = assetMapFromNewSolution.Where(p => !allChecksumsFromRequest.Contains(p.Key)).ToList(); + AppendMismatch(mismatch1, "Assets only in new solution but not in the request", sb); - // 2. second check what items is mismatching for incremental solution - var mismatch2 = assetMapFromIncrementalSolution.Where(p => !allChecksumsFromRequest.Contains(p.Key)).ToList(); - AppendMismatch(mismatch2, "Assets only in the incremental solution but not in the request", sb); + // 2. second check what items is mismatching for incremental solution + var mismatch2 = assetMapFromIncrementalSolution.Where(p => !allChecksumsFromRequest.Contains(p.Key)).ToList(); + AppendMismatch(mismatch2, "Assets only in the incremental solution but not in the request", sb); - // 3. check whether solution created from scratch and incremental one have any mismatch - var mismatch3 = assetMapFromNewSolution.Where(p => !assetMapFromIncrementalSolution.ContainsKey(p.Key)).ToList(); - AppendMismatch(mismatch3, "Assets only in new solution but not in incremental solution", sb); + // 3. check whether solution created from scratch and incremental one have any mismatch + var mismatch3 = assetMapFromNewSolution.Where(p => !assetMapFromIncrementalSolution.ContainsKey(p.Key)).ToList(); + AppendMismatch(mismatch3, "Assets only in new solution but not in incremental solution", sb); - var mismatch4 = assetMapFromIncrementalSolution.Where(p => !assetMapFromNewSolution.ContainsKey(p.Key)).ToList(); - AppendMismatch(mismatch4, "Assets only in incremental solution but not in new solution", sb); + var mismatch4 = assetMapFromIncrementalSolution.Where(p => !assetMapFromNewSolution.ContainsKey(p.Key)).ToList(); + AppendMismatch(mismatch4, "Assets only in incremental solution but not in new solution", sb); - // 4. see what item is missing from request - var mismatch5 = await GetAssetFromAssetServiceAsync(allChecksumsFromRequest.Except(assetMapFromNewSolution.Keys)).ConfigureAwait(false); - AppendMismatch(mismatch5, "Assets only in the request but not in new solution", sb); + // 4. see what item is missing from request + var mismatch5 = await GetAssetFromAssetServiceAsync(allChecksumsFromRequest.Except(assetMapFromNewSolution.Keys)).ConfigureAwait(false); + AppendMismatch(mismatch5, "Assets only in the request but not in new solution", sb); - var mismatch6 = await GetAssetFromAssetServiceAsync(allChecksumsFromRequest.Except(assetMapFromIncrementalSolution.Keys)).ConfigureAwait(false); - AppendMismatch(mismatch6, "Assets only in the request but not in incremental solution", sb); + var mismatch6 = await GetAssetFromAssetServiceAsync(allChecksumsFromRequest.Except(assetMapFromIncrementalSolution.Keys)).ConfigureAwait(false); + AppendMismatch(mismatch6, "Assets only in the request but not in incremental solution", sb); - var result = sb.ToString(); - if (result.Length > 0) - { - Logger.Log(FunctionId.SolutionCreator_AssetDifferences, result); - Debug.Fail($"Differences detected in solution checksum (ProjectId={projectConeId}):\r\n{result}"); - } + var result = sb.ToString(); + if (result.Length > 0) + { + Logger.Log(FunctionId.SolutionCreator_AssetDifferences, result); + Debug.Fail($"Differences detected in solution checksum (ProjectId={projectConeId}):\r\n{result}"); + } - return; + return; - static void AppendMismatch(List> items, string title, StringBuilder stringBuilder) + static void AppendMismatch(List> items, string title, StringBuilder stringBuilder) + { + if (items.Count == 0) { - if (items.Count == 0) - { - return; - } - - stringBuilder.AppendLine(title); - foreach (var kv in items) - { - stringBuilder.AppendLine($"{kv.Key.ToString()}, {kv.Value?.ToString()}"); - } - - stringBuilder.AppendLine(); + return; } - async Task>> GetAssetFromAssetServiceAsync(IEnumerable checksums) + stringBuilder.AppendLine(title); + foreach (var kv in items) { - var items = new List>(); + stringBuilder.AppendLine($"{kv.Key.ToString()}, {kv.Value?.ToString()}"); + } - foreach (var checksum in checksums) - { - items.Add(KeyValuePairUtil.Create(checksum, await assetService.GetAssetAsync( - AssetPath.FullLookupForTesting, checksum, CancellationToken.None).ConfigureAwait(false))); - } + stringBuilder.AppendLine(); + } - return items; - } + async Task>> GetAssetFromAssetServiceAsync(IEnumerable checksums) + { + var items = new List>(); - async Task> GetAllChildrenChecksumsAsync(Checksum solutionChecksum) + foreach (var checksum in checksums) { - var set = new HashSet(); + items.Add(KeyValuePairUtil.Create(checksum, await assetService.GetAssetAsync( + AssetPath.FullLookupForTesting, checksum, CancellationToken.None).ConfigureAwait(false))); + } + + return items; + } - var solutionCompilationChecksums = await assetService.GetAssetAsync( - AssetPathKind.SolutionCompilationStateChecksums, solutionChecksum, CancellationToken.None).ConfigureAwait(false); - var solutionChecksums = await assetService.GetAssetAsync( - AssetPathKind.SolutionStateChecksums, solutionCompilationChecksums.SolutionState, CancellationToken.None).ConfigureAwait(false); + async Task> GetAllChildrenChecksumsAsync(Checksum solutionChecksum) + { + var set = new HashSet(); - solutionCompilationChecksums.AddAllTo(set); - solutionChecksums.AddAllTo(set); + var solutionCompilationChecksums = await assetService.GetAssetAsync( + AssetPathKind.SolutionCompilationStateChecksums, solutionChecksum, CancellationToken.None).ConfigureAwait(false); + var solutionChecksums = await assetService.GetAssetAsync( + AssetPathKind.SolutionStateChecksums, solutionCompilationChecksums.SolutionState, CancellationToken.None).ConfigureAwait(false); - foreach (var (projectChecksum, projectId) in solutionChecksums.Projects) - { - var projectChecksums = await assetService.GetAssetAsync( - assetPath: projectId, projectChecksum, CancellationToken.None).ConfigureAwait(false); - projectChecksums.AddAllTo(set); + solutionCompilationChecksums.AddAllTo(set); + solutionChecksums.AddAllTo(set); - projectChecksums.Documents.AddAllTo(set); - projectChecksums.AdditionalDocuments.AddAllTo(set); - projectChecksums.AnalyzerConfigDocuments.AddAllTo(set); - } + foreach (var (projectChecksum, projectId) in solutionChecksums.Projects) + { + var projectChecksums = await assetService.GetAssetAsync( + assetPath: projectId, projectChecksum, CancellationToken.None).ConfigureAwait(false); + projectChecksums.AddAllTo(set); - return set; + projectChecksums.Documents.AddAllTo(set); + projectChecksums.AdditionalDocuments.AddAllTo(set); + projectChecksums.AnalyzerConfigDocuments.AddAllTo(set); } + return set; + } + #else - // have this to avoid error on async - await Task.CompletedTask.ConfigureAwait(false); + // have this to avoid error on async + await Task.CompletedTask.ConfigureAwait(false); #endif - } + } - private static void AddAllTo(DocumentStateChecksums documentStateChecksums, HashSet checksums) - { - checksums.AddIfNotNullChecksum(documentStateChecksums.Checksum); - checksums.AddIfNotNullChecksum(documentStateChecksums.Info); - checksums.AddIfNotNullChecksum(documentStateChecksums.Text); - } + private static void AddAllTo(DocumentStateChecksums documentStateChecksums, HashSet checksums) + { + checksums.AddIfNotNullChecksum(documentStateChecksums.Checksum); + checksums.AddIfNotNullChecksum(documentStateChecksums.Info); + checksums.AddIfNotNullChecksum(documentStateChecksums.Text); + } - /// - /// create checksum to corresponding object map from solution this map should contain every parts of solution - /// that can be used to re-create the solution back - /// - public static async Task> GetAssetMapAsync(this Solution solution, ProjectId? projectConeId, CancellationToken cancellationToken) - { - var map = new Dictionary(); - await solution.AppendAssetMapAsync(map, projectConeId, cancellationToken).ConfigureAwait(false); - return map; - } + /// + /// create checksum to corresponding object map from solution this map should contain every parts of solution + /// that can be used to re-create the solution back + /// + public static async Task> GetAssetMapAsync(this Solution solution, ProjectId? projectConeId, CancellationToken cancellationToken) + { + var map = new Dictionary(); + await solution.AppendAssetMapAsync(map, projectConeId, cancellationToken).ConfigureAwait(false); + return map; + } - /// - /// create checksum to corresponding object map from project this map should contain every parts of project that - /// can be used to re-create the project back - /// - public static async Task> GetAssetMapAsync(this Project project, CancellationToken cancellationToken) - { - var map = new Dictionary(); + /// + /// create checksum to corresponding object map from project this map should contain every parts of project that + /// can be used to re-create the project back + /// + public static async Task> GetAssetMapAsync(this Project project, CancellationToken cancellationToken) + { + var map = new Dictionary(); - await project.AppendAssetMapAsync(map, cancellationToken).ConfigureAwait(false); + await project.AppendAssetMapAsync(map, cancellationToken).ConfigureAwait(false); - // don't include the root checksum itself. it's not one of the assets of the actual project. - var projectStateChecksums = await project.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - map.Remove(projectStateChecksums.Checksum); + // don't include the root checksum itself. it's not one of the assets of the actual project. + var projectStateChecksums = await project.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); + map.Remove(projectStateChecksums.Checksum); - return map; - } + return map; + } - public static Task AppendAssetMapAsync(this Solution solution, Dictionary map, CancellationToken cancellationToken) - => AppendAssetMapAsync(solution, map, projectId: null, cancellationToken); + public static Task AppendAssetMapAsync(this Solution solution, Dictionary map, CancellationToken cancellationToken) + => AppendAssetMapAsync(solution, map, projectId: null, cancellationToken); - public static async Task AppendAssetMapAsync( - this Solution solution, Dictionary map, ProjectId? projectId, CancellationToken cancellationToken) + public static async Task AppendAssetMapAsync( + this Solution solution, Dictionary map, ProjectId? projectId, CancellationToken cancellationToken) + { + var callback = static (Checksum checksum, object asset, Dictionary map) => { map[checksum] = asset; }; + + if (projectId == null) { - var callback = static (Checksum checksum, object asset, Dictionary map) => { map[checksum] = asset; }; + var compilationChecksums = await solution.CompilationState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); + await compilationChecksums.FindAsync(solution.CompilationState, projectCone: null, AssetPath.FullLookupForTesting, Flatten(compilationChecksums), callback, map, cancellationToken).ConfigureAwait(false); - if (projectId == null) + foreach (var frozenSourceGeneratedDocumentState in solution.CompilationState.FrozenSourceGeneratedDocumentStates?.States.Values ?? []) { - var compilationChecksums = await solution.CompilationState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - await compilationChecksums.FindAsync(solution.CompilationState, projectCone: null, AssetPath.FullLookupForTesting, Flatten(compilationChecksums), callback, map, cancellationToken).ConfigureAwait(false); - - foreach (var frozenSourceGeneratedDocumentState in solution.CompilationState.FrozenSourceGeneratedDocumentStates?.States.Values ?? []) - { - var documentChecksums = await frozenSourceGeneratedDocumentState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - await compilationChecksums.FindAsync(solution.CompilationState, projectCone: null, AssetPath.FullLookupForTesting, Flatten(documentChecksums), callback, map, cancellationToken).ConfigureAwait(false); - } - - var solutionChecksums = await solution.CompilationState.SolutionState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - Contract.ThrowIfTrue(solutionChecksums.ProjectCone != null); - await solutionChecksums.FindAsync(solution.CompilationState.SolutionState, projectCone: null, AssetPath.FullLookupForTesting, Flatten(solutionChecksums), callback, map, cancellationToken).ConfigureAwait(false); - - foreach (var project in solution.Projects) - await project.AppendAssetMapAsync(map, cancellationToken).ConfigureAwait(false); + var documentChecksums = await frozenSourceGeneratedDocumentState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); + await compilationChecksums.FindAsync(solution.CompilationState, projectCone: null, AssetPath.FullLookupForTesting, Flatten(documentChecksums), callback, map, cancellationToken).ConfigureAwait(false); } - else - { - var (compilationChecksums, projectCone) = await solution.CompilationState.GetStateChecksumsAsync(projectId, cancellationToken).ConfigureAwait(false); - await compilationChecksums.FindAsync(solution.CompilationState, projectCone, AssetPath.SolutionAndProjectForTesting(projectId), Flatten(compilationChecksums), callback, map, cancellationToken).ConfigureAwait(false); - var solutionChecksums = await solution.CompilationState.SolutionState.GetStateChecksumsAsync(projectId, cancellationToken).ConfigureAwait(false); - Contract.ThrowIfFalse(projectCone.Equals(solutionChecksums.ProjectCone)); - await solutionChecksums.FindAsync(solution.CompilationState.SolutionState, projectCone, AssetPath.SolutionAndProjectForTesting(projectId), Flatten(solutionChecksums), callback, map, cancellationToken).ConfigureAwait(false); + var solutionChecksums = await solution.CompilationState.SolutionState.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); + Contract.ThrowIfTrue(solutionChecksums.ProjectCone != null); + await solutionChecksums.FindAsync(solution.CompilationState.SolutionState, projectCone: null, AssetPath.FullLookupForTesting, Flatten(solutionChecksums), callback, map, cancellationToken).ConfigureAwait(false); - var project = solution.GetRequiredProject(projectId); + foreach (var project in solution.Projects) await project.AppendAssetMapAsync(map, cancellationToken).ConfigureAwait(false); - foreach (var dep in solution.GetProjectDependencyGraph().GetProjectsThatThisProjectTransitivelyDependsOn(projectId)) - await solution.GetRequiredProject(dep).AppendAssetMapAsync(map, cancellationToken).ConfigureAwait(false); - } } - - private static async Task AppendAssetMapAsync(this Project project, Dictionary map, CancellationToken cancellationToken) + else { - if (!RemoteSupportedLanguages.IsSupported(project.Language)) - { - return; - } - - var callback = static (Checksum checksum, object asset, Dictionary map) => { map[checksum] = asset; }; + var (compilationChecksums, projectCone) = await solution.CompilationState.GetStateChecksumsAsync(projectId, cancellationToken).ConfigureAwait(false); + await compilationChecksums.FindAsync(solution.CompilationState, projectCone, AssetPath.SolutionAndProjectForTesting(projectId), Flatten(compilationChecksums), callback, map, cancellationToken).ConfigureAwait(false); - var projectChecksums = await project.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - await projectChecksums.FindAsync(project.State, AssetPath.FullLookupForTesting, Flatten(projectChecksums), callback, map, cancellationToken).ConfigureAwait(false); + var solutionChecksums = await solution.CompilationState.SolutionState.GetStateChecksumsAsync(projectId, cancellationToken).ConfigureAwait(false); + Contract.ThrowIfFalse(projectCone.Equals(solutionChecksums.ProjectCone)); + await solutionChecksums.FindAsync(solution.CompilationState.SolutionState, projectCone, AssetPath.SolutionAndProjectForTesting(projectId), Flatten(solutionChecksums), callback, map, cancellationToken).ConfigureAwait(false); - foreach (var document in project.Documents.Concat(project.AdditionalDocuments).Concat(project.AnalyzerConfigDocuments)) - { - var documentChecksums = await document.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); - await documentChecksums.FindAsync(AssetPathKind.Documents, document.State, Flatten(documentChecksums), callback, map, cancellationToken).ConfigureAwait(false); - } + var project = solution.GetRequiredProject(projectId); + await project.AppendAssetMapAsync(map, cancellationToken).ConfigureAwait(false); + foreach (var dep in solution.GetProjectDependencyGraph().GetProjectsThatThisProjectTransitivelyDependsOn(projectId)) + await solution.GetRequiredProject(dep).AppendAssetMapAsync(map, cancellationToken).ConfigureAwait(false); } + } - private static HashSet Flatten(SolutionCompilationStateChecksums checksums) + private static async Task AppendAssetMapAsync(this Project project, Dictionary map, CancellationToken cancellationToken) + { + if (!RemoteSupportedLanguages.IsSupported(project.Language)) { - var set = new HashSet(); - checksums.AddAllTo(set); - return set; + return; } - private static HashSet Flatten(SolutionStateChecksums checksums) - { - var set = new HashSet(); - checksums.AddAllTo(set); - return set; - } + var callback = static (Checksum checksum, object asset, Dictionary map) => { map[checksum] = asset; }; - private static HashSet Flatten(ProjectStateChecksums checksums) - { - var set = new HashSet(); - checksums.AddAllTo(set); - return set; - } + var projectChecksums = await project.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); + await projectChecksums.FindAsync(project.State, AssetPath.FullLookupForTesting, Flatten(projectChecksums), callback, map, cancellationToken).ConfigureAwait(false); - private static HashSet Flatten(DocumentStateChecksums checksums) + foreach (var document in project.Documents.Concat(project.AdditionalDocuments).Concat(project.AnalyzerConfigDocuments)) { - var set = new HashSet(); - AddAllTo(checksums, set); - return set; + var documentChecksums = await document.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); + await documentChecksums.FindAsync(AssetPathKind.Documents, document.State, Flatten(documentChecksums), callback, map, cancellationToken).ConfigureAwait(false); } + } - public static void AppendChecksums(this HashSet set, ChecksumCollection checksums) - { - set.Add(checksums.Checksum); + private static HashSet Flatten(SolutionCompilationStateChecksums checksums) + { + var set = new HashSet(); + checksums.AddAllTo(set); + return set; + } - foreach (var child in checksums.Children) - { - if (child != Checksum.Null) - set.Add(child); - } + private static HashSet Flatten(SolutionStateChecksums checksums) + { + var set = new HashSet(); + checksums.AddAllTo(set); + return set; + } + + private static HashSet Flatten(ProjectStateChecksums checksums) + { + var set = new HashSet(); + checksums.AddAllTo(set); + return set; + } + + private static HashSet Flatten(DocumentStateChecksums checksums) + { + var set = new HashSet(); + AddAllTo(checksums, set); + return set; + } + + public static void AppendChecksums(this HashSet set, ChecksumCollection checksums) + { + set.Add(checksums.Checksum); + + foreach (var child in checksums.Children) + { + if (child != Checksum.Null) + set.Add(child); } } } diff --git a/src/Workspaces/Remote/ServiceHub/Host/ThrowingTraceListener.cs b/src/Workspaces/Remote/ServiceHub/Host/ThrowingTraceListener.cs index 34b4ed6dc43a1..c5c25c2f94456 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/ThrowingTraceListener.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/ThrowingTraceListener.cs @@ -5,47 +5,46 @@ using System; using System.Diagnostics; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class ThrowingTraceListener : TraceListener { - internal sealed class ThrowingTraceListener : TraceListener - { - public override void Fail(string? message, string? detailMessage) - { - throw new InvalidOperationException( - (string.IsNullOrEmpty(message) ? "Assertion failed" : message) + - (string.IsNullOrEmpty(detailMessage) ? "" : Environment.NewLine + detailMessage)); - } - - public override void Write(object? o) - { - } - - public override void Write(object? o, string? category) - { - } - - public override void Write(string? message) - { - } - - public override void Write(string? message, string? category) - { - } - - public override void WriteLine(object? o) - { - } - - public override void WriteLine(object? o, string? category) - { - } - - public override void WriteLine(string? message) - { - } - - public override void WriteLine(string? message, string? category) - { - } + public override void Fail(string? message, string? detailMessage) + { + throw new InvalidOperationException( + (string.IsNullOrEmpty(message) ? "Assertion failed" : message) + + (string.IsNullOrEmpty(detailMessage) ? "" : Environment.NewLine + detailMessage)); + } + + public override void Write(object? o) + { + } + + public override void Write(object? o, string? category) + { + } + + public override void Write(string? message) + { + } + + public override void Write(string? message, string? category) + { + } + + public override void WriteLine(object? o) + { + } + + public override void WriteLine(object? o, string? category) + { + } + + public override void WriteLine(string? message) + { + } + + public override void WriteLine(string? message, string? category) + { } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/AsynchronousOperationListener/RemoteAsynchronousOperationListenerService.cs b/src/Workspaces/Remote/ServiceHub/Services/AsynchronousOperationListener/RemoteAsynchronousOperationListenerService.cs index 1b405b7c66a44..7c300e43e717e 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/AsynchronousOperationListener/RemoteAsynchronousOperationListenerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/AsynchronousOperationListener/RemoteAsynchronousOperationListenerService.cs @@ -9,52 +9,51 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.TestHooks; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteAsynchronousOperationListenerService : BrokeredServiceBase, IRemoteAsynchronousOperationListenerService { - internal sealed class RemoteAsynchronousOperationListenerService : BrokeredServiceBase, IRemoteAsynchronousOperationListenerService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteAsynchronousOperationListenerService CreateService(in ServiceConstructionArguments arguments) - => new RemoteAsynchronousOperationListenerService(in arguments); - } + protected override IRemoteAsynchronousOperationListenerService CreateService(in ServiceConstructionArguments arguments) + => new RemoteAsynchronousOperationListenerService(in arguments); + } - public RemoteAsynchronousOperationListenerService(in ServiceConstructionArguments arguments) - : base(in arguments) - { - } + public RemoteAsynchronousOperationListenerService(in ServiceConstructionArguments arguments) + : base(in arguments) + { + } - public ValueTask EnableAsync(bool enable, bool diagnostics, CancellationToken cancellationToken) + public ValueTask EnableAsync(bool enable, bool diagnostics, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => { - return RunServiceAsync(cancellationToken => - { - AsynchronousOperationListenerProvider.Enable(enable, diagnostics); - return default; - }, cancellationToken); - } - - public ValueTask IsCompletedAsync(ImmutableArray featureNames, CancellationToken cancellationToken) + AsynchronousOperationListenerProvider.Enable(enable, diagnostics); + return default; + }, cancellationToken); + } + + public ValueTask IsCompletedAsync(ImmutableArray featureNames, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => { - return RunServiceAsync(cancellationToken => - { - var workspace = GetWorkspace(); - var exportProvider = workspace.Services.SolutionServices.ExportProvider; - var listenerProvider = exportProvider.GetExports().Single().Value; + var workspace = GetWorkspace(); + var exportProvider = workspace.Services.SolutionServices.ExportProvider; + var listenerProvider = exportProvider.GetExports().Single().Value; - return new ValueTask(!listenerProvider.HasPendingWaiter([.. featureNames])); - }, cancellationToken); - } + return new ValueTask(!listenerProvider.HasPendingWaiter([.. featureNames])); + }, cancellationToken); + } - public ValueTask ExpeditedWaitAsync(ImmutableArray featureNames, CancellationToken cancellationToken) + public ValueTask ExpeditedWaitAsync(ImmutableArray featureNames, CancellationToken cancellationToken) + { + return RunServiceAsync(async cancellationToken => { - return RunServiceAsync(async cancellationToken => - { - var workspace = GetWorkspace(); - var exportProvider = workspace.Services.SolutionServices.ExportProvider; - var listenerProvider = exportProvider.GetExports().Single().Value; - - await listenerProvider.WaitAllAsync(workspace, [.. featureNames]).ConfigureAwait(false); - }, cancellationToken); - } + var workspace = GetWorkspace(); + var exportProvider = workspace.Services.SolutionServices.ExportProvider; + var listenerProvider = exportProvider.GetExports().Single().Value; + + await listenerProvider.WaitAllAsync(workspace, [.. featureNames]).ConfigureAwait(false); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.FactoryBase.cs b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.FactoryBase.cs index a06d5a2962ebb..905ef1fcd1120 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.FactoryBase.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.FactoryBase.cs @@ -17,123 +17,122 @@ using Nerdbank.Streams; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal abstract partial class BrokeredServiceBase { - internal abstract partial class BrokeredServiceBase + private static int s_cultureInitialized; + + internal interface IFactory { - private static int s_cultureInitialized; + object Create(IDuplexPipe pipe, IServiceProvider hostProvidedServices, ServiceActivationOptions serviceActivationOptions, IServiceBroker serviceBroker); + Type ServiceType { get; } + } - internal interface IFactory + internal abstract class FactoryBase : IServiceHubServiceFactory, IFactory + where TService : class + { + static FactoryBase() { - object Create(IDuplexPipe pipe, IServiceProvider hostProvidedServices, ServiceActivationOptions serviceActivationOptions, IServiceBroker serviceBroker); - Type ServiceType { get; } + Debug.Assert(typeof(TService).IsInterface); } - internal abstract class FactoryBase : IServiceHubServiceFactory, IFactory - where TService : class + protected abstract TService CreateService(in ServiceConstructionArguments arguments); + + protected virtual TService CreateService( + in ServiceConstructionArguments arguments, + ServiceRpcDescriptor descriptor, + ServiceRpcDescriptor.RpcConnection serverConnection, + object? clientRpcTarget) + => CreateService(arguments); + + public Task CreateAsync( + Stream stream, + IServiceProvider hostProvidedServices, + ServiceActivationOptions serviceActivationOptions, + IServiceBroker serviceBroker, + AuthorizationServiceClient? authorizationServiceClient) { - static FactoryBase() + // Exception from IServiceHubServiceFactory.CreateAsync are not propagated to the client. + // Intercept the exception here and report it to the log. + // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1410923 + try { - Debug.Assert(typeof(TService).IsInterface); - } + // Dispose the AuthorizationServiceClient since we won't be using it + authorizationServiceClient?.Dispose(); - protected abstract TService CreateService(in ServiceConstructionArguments arguments); - - protected virtual TService CreateService( - in ServiceConstructionArguments arguments, - ServiceRpcDescriptor descriptor, - ServiceRpcDescriptor.RpcConnection serverConnection, - object? clientRpcTarget) - => CreateService(arguments); - - public Task CreateAsync( - Stream stream, - IServiceProvider hostProvidedServices, - ServiceActivationOptions serviceActivationOptions, - IServiceBroker serviceBroker, - AuthorizationServiceClient? authorizationServiceClient) - { - // Exception from IServiceHubServiceFactory.CreateAsync are not propagated to the client. - // Intercept the exception here and report it to the log. - // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1410923 - try + // First request determines the default culture: + // TODO: Flow culture explicitly where needed https://github.com/dotnet/roslyn/issues/43670 + if (Interlocked.CompareExchange(ref s_cultureInitialized, 1, 0) == 0) { - // Dispose the AuthorizationServiceClient since we won't be using it - authorizationServiceClient?.Dispose(); - - // First request determines the default culture: - // TODO: Flow culture explicitly where needed https://github.com/dotnet/roslyn/issues/43670 - if (Interlocked.CompareExchange(ref s_cultureInitialized, 1, 0) == 0) - { - CultureInfo.DefaultThreadCurrentUICulture = serviceActivationOptions.ClientUICulture; - CultureInfo.DefaultThreadCurrentCulture = serviceActivationOptions.ClientCulture; - } - - return Task.FromResult((object)Create( - stream.UsePipe(), - hostProvidedServices, - serviceActivationOptions, - serviceBroker)); - } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) - { - throw ExceptionUtilities.Unreachable(); + CultureInfo.DefaultThreadCurrentUICulture = serviceActivationOptions.ClientUICulture; + CultureInfo.DefaultThreadCurrentCulture = serviceActivationOptions.ClientCulture; } + + return Task.FromResult((object)Create( + stream.UsePipe(), + hostProvidedServices, + serviceActivationOptions, + serviceBroker)); } + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + { + throw ExceptionUtilities.Unreachable(); + } + } - object IFactory.Create(IDuplexPipe pipe, IServiceProvider hostProvidedServices, ServiceActivationOptions serviceActivationOptions, IServiceBroker serviceBroker) - => Create(pipe, hostProvidedServices, serviceActivationOptions, serviceBroker); + object IFactory.Create(IDuplexPipe pipe, IServiceProvider hostProvidedServices, ServiceActivationOptions serviceActivationOptions, IServiceBroker serviceBroker) + => Create(pipe, hostProvidedServices, serviceActivationOptions, serviceBroker); - Type IFactory.ServiceType => typeof(TService); + Type IFactory.ServiceType => typeof(TService); - internal TService Create( - IDuplexPipe pipe, - IServiceProvider hostProvidedServices, - ServiceActivationOptions serviceActivationOptions, - IServiceBroker serviceBroker) - { - // Register this service broker globally (if it's the first we encounter) so it can be used by other - // global services that need it. - GlobalServiceBroker.RegisterServiceBroker(serviceBroker); + internal TService Create( + IDuplexPipe pipe, + IServiceProvider hostProvidedServices, + ServiceActivationOptions serviceActivationOptions, + IServiceBroker serviceBroker) + { + // Register this service broker globally (if it's the first we encounter) so it can be used by other + // global services that need it. + GlobalServiceBroker.RegisterServiceBroker(serviceBroker); - var descriptor = ServiceDescriptors.Instance.GetServiceDescriptorForServiceFactory(typeof(TService)); - var serviceHubTraceSource = (TraceSource?)hostProvidedServices.GetService(typeof(TraceSource)); - var serverConnection = descriptor.WithTraceSource(serviceHubTraceSource).ConstructRpcConnection(pipe); + var descriptor = ServiceDescriptors.Instance.GetServiceDescriptorForServiceFactory(typeof(TService)); + var serviceHubTraceSource = (TraceSource?)hostProvidedServices.GetService(typeof(TraceSource)); + var serverConnection = descriptor.WithTraceSource(serviceHubTraceSource).ConstructRpcConnection(pipe); - var args = new ServiceConstructionArguments(hostProvidedServices, serviceBroker); - var service = CreateService(args, descriptor, serverConnection, serviceActivationOptions.ClientRpcTarget); + var args = new ServiceConstructionArguments(hostProvidedServices, serviceBroker); + var service = CreateService(args, descriptor, serverConnection, serviceActivationOptions.ClientRpcTarget); - serverConnection.AddLocalRpcTarget(service); - serverConnection.StartListening(); + serverConnection.AddLocalRpcTarget(service); + serverConnection.StartListening(); - return service; - } + return service; } + } - internal abstract class FactoryBase : FactoryBase - where TService : class - where TCallback : class + internal abstract class FactoryBase : FactoryBase + where TService : class + where TCallback : class + { + static FactoryBase() { - static FactoryBase() - { - Debug.Assert(typeof(TCallback).IsInterface); - } + Debug.Assert(typeof(TCallback).IsInterface); + } - protected abstract TService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback); + protected abstract TService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback); - protected sealed override TService CreateService(in ServiceConstructionArguments arguments) - => throw ExceptionUtilities.Unreachable(); + protected sealed override TService CreateService(in ServiceConstructionArguments arguments) + => throw ExceptionUtilities.Unreachable(); - protected sealed override TService CreateService( - in ServiceConstructionArguments arguments, - ServiceRpcDescriptor descriptor, - ServiceRpcDescriptor.RpcConnection serverConnection, - object? clientRpcTarget) - { - Contract.ThrowIfNull(descriptor.ClientInterface); - var callback = (TCallback)(clientRpcTarget ?? serverConnection.ConstructRpcClient(descriptor.ClientInterface)); - return CreateService(arguments, new RemoteCallback(callback)); - } + protected sealed override TService CreateService( + in ServiceConstructionArguments arguments, + ServiceRpcDescriptor descriptor, + ServiceRpcDescriptor.RpcConnection serverConnection, + object? clientRpcTarget) + { + Contract.ThrowIfNull(descriptor.ClientInterface); + var callback = (TCallback)(clientRpcTarget ?? serverConnection.ConstructRpcClient(descriptor.ClientInterface)); + return CreateService(arguments, new RemoteCallback(callback)); } } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.ServiceConstructionArguments.cs b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.ServiceConstructionArguments.cs index 4c0b1f6d83761..ed30f32e26b4e 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.ServiceConstructionArguments.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.ServiceConstructionArguments.cs @@ -5,20 +5,19 @@ using System; using Microsoft.ServiceHub.Framework; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal abstract partial class BrokeredServiceBase { - internal abstract partial class BrokeredServiceBase + internal readonly struct ServiceConstructionArguments { - internal readonly struct ServiceConstructionArguments - { - public readonly IServiceProvider ServiceProvider; - public readonly IServiceBroker ServiceBroker; + public readonly IServiceProvider ServiceProvider; + public readonly IServiceBroker ServiceBroker; - public ServiceConstructionArguments(IServiceProvider serviceProvider, IServiceBroker serviceBroker) - { - ServiceProvider = serviceProvider; - ServiceBroker = serviceBroker; - } + public ServiceConstructionArguments(IServiceProvider serviceProvider, IServiceBroker serviceBroker) + { + ServiceProvider = serviceProvider; + ServiceBroker = serviceBroker; } } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.cs b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.cs index 5bc7109b8958b..3a5967c980aa4 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/BrokeredServiceBase.cs @@ -16,203 +16,202 @@ using Microsoft.ServiceHub.Framework; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +/// +/// Base type for Roslyn brokered services hosted in ServiceHub. +/// +internal abstract partial class BrokeredServiceBase : IDisposable { - /// - /// Base type for Roslyn brokered services hosted in ServiceHub. - /// - internal abstract partial class BrokeredServiceBase : IDisposable - { - protected readonly TraceSource TraceLogger; - protected readonly RemoteWorkspaceManager WorkspaceManager; + protected readonly TraceSource TraceLogger; + protected readonly RemoteWorkspaceManager WorkspaceManager; - protected readonly SolutionAssetSource SolutionAssetSource; - protected readonly ServiceBrokerClient ServiceBrokerClient; + protected readonly SolutionAssetSource SolutionAssetSource; + protected readonly ServiceBrokerClient ServiceBrokerClient; - // test data are only available when running tests: - internal readonly RemoteHostTestData? TestData; + // test data are only available when running tests: + internal readonly RemoteHostTestData? TestData; - static BrokeredServiceBase() + static BrokeredServiceBase() + { + if (GCSettings.IsServerGC) { - if (GCSettings.IsServerGC) - { - // Server GC runs processor-affinitized threads with high priority. To avoid interfering with other - // applications while still allowing efficient out-of-process execution, slightly reduce the process - // priority when using server GC. - Process.GetCurrentProcess().TrySetPriorityClass(ProcessPriorityClass.BelowNormal); - } + // Server GC runs processor-affinitized threads with high priority. To avoid interfering with other + // applications while still allowing efficient out-of-process execution, slightly reduce the process + // priority when using server GC. + Process.GetCurrentProcess().TrySetPriorityClass(ProcessPriorityClass.BelowNormal); + } - // Make encodings that is by default present in desktop framework but not in corefx available to runtime. - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + // Make encodings that is by default present in desktop framework but not in corefx available to runtime. + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); #if DEBUG - // Make sure debug assertions in ServiceHub result in exceptions instead of the assertion UI - Trace.Listeners.Clear(); - Trace.Listeners.Add(new ThrowingTraceListener()); + // Make sure debug assertions in ServiceHub result in exceptions instead of the assertion UI + Trace.Listeners.Clear(); + Trace.Listeners.Add(new ThrowingTraceListener()); #endif - SetNativeDllSearchDirectories(); - } + SetNativeDllSearchDirectories(); + } - protected BrokeredServiceBase(in ServiceConstructionArguments arguments) - { - var traceSource = (TraceSource?)arguments.ServiceProvider.GetService(typeof(TraceSource)); - Contract.ThrowIfNull(traceSource); - TraceLogger = traceSource; + protected BrokeredServiceBase(in ServiceConstructionArguments arguments) + { + var traceSource = (TraceSource?)arguments.ServiceProvider.GetService(typeof(TraceSource)); + Contract.ThrowIfNull(traceSource); + TraceLogger = traceSource; - TestData = (RemoteHostTestData?)arguments.ServiceProvider.GetService(typeof(RemoteHostTestData)); - WorkspaceManager = TestData?.WorkspaceManager ?? RemoteWorkspaceManager.Default; + TestData = (RemoteHostTestData?)arguments.ServiceProvider.GetService(typeof(RemoteHostTestData)); + WorkspaceManager = TestData?.WorkspaceManager ?? RemoteWorkspaceManager.Default; #pragma warning disable VSTHRD012 // Provide JoinableTaskFactory where allowed - ServiceBrokerClient = new ServiceBrokerClient(arguments.ServiceBroker); + ServiceBrokerClient = new ServiceBrokerClient(arguments.ServiceBroker); #pragma warning restore - SolutionAssetSource = new SolutionAssetSource(ServiceBrokerClient); - } + SolutionAssetSource = new SolutionAssetSource(ServiceBrokerClient); + } - public virtual void Dispose() - => ServiceBrokerClient.Dispose(); + public virtual void Dispose() + => ServiceBrokerClient.Dispose(); - public RemoteWorkspace GetWorkspace() - => WorkspaceManager.GetWorkspace(); + public RemoteWorkspace GetWorkspace() + => WorkspaceManager.GetWorkspace(); - public SolutionServices GetWorkspaceServices() - => GetWorkspace().Services.SolutionServices; + public SolutionServices GetWorkspaceServices() + => GetWorkspace().Services.SolutionServices; - protected void Log(TraceEventType errorType, string message) - => TraceLogger.TraceEvent(errorType, 0, $"{GetType()}: {message}"); + protected void Log(TraceEventType errorType, string message) + => TraceLogger.TraceEvent(errorType, 0, $"{GetType()}: {message}"); - protected async ValueTask RunWithSolutionAsync( - Checksum solutionChecksum, - Func> implementation, - CancellationToken cancellationToken) - { - var workspace = GetWorkspace(); - var assetProvider = workspace.CreateAssetProvider(solutionChecksum, WorkspaceManager.SolutionAssetCache, SolutionAssetSource); - var (_, result) = await workspace.RunWithSolutionAsync( - assetProvider, - solutionChecksum, - implementation, - cancellationToken).ConfigureAwait(false); - - return result; - } + protected async ValueTask RunWithSolutionAsync( + Checksum solutionChecksum, + Func> implementation, + CancellationToken cancellationToken) + { + var workspace = GetWorkspace(); + var assetProvider = workspace.CreateAssetProvider(solutionChecksum, WorkspaceManager.SolutionAssetCache, SolutionAssetSource); + var (_, result) = await workspace.RunWithSolutionAsync( + assetProvider, + solutionChecksum, + implementation, + cancellationToken).ConfigureAwait(false); + + return result; + } + + protected static ValueTask RunServiceAsync(Func> implementation, CancellationToken cancellationToken) + { + return RunServiceImplAsync(implementation, cancellationToken); + } - protected static ValueTask RunServiceAsync(Func> implementation, CancellationToken cancellationToken) + protected ValueTask RunServiceAsync( + Checksum solutionChecksum, Func> implementation, CancellationToken cancellationToken) + { + return RunServiceAsync( + c => RunWithSolutionAsync(solutionChecksum, implementation, c), cancellationToken); + } + + internal static async ValueTask RunServiceImplAsync(Func> implementation, CancellationToken cancellationToken) + { + try { - return RunServiceImplAsync(implementation, cancellationToken); + return await implementation(cancellationToken).ConfigureAwait(false); } - - protected ValueTask RunServiceAsync( - Checksum solutionChecksum, Func> implementation, CancellationToken cancellationToken) + catch (Exception ex) when (FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken)) { - return RunServiceAsync( - c => RunWithSolutionAsync(solutionChecksum, implementation, c), cancellationToken); + throw ExceptionUtilities.Unreachable(); } + } - internal static async ValueTask RunServiceImplAsync(Func> implementation, CancellationToken cancellationToken) - { - try - { - return await implementation(cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) when (FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken)) + protected static ValueTask RunServiceAsync(Func implementation, CancellationToken cancellationToken) + { + return RunServiceImplAsync(implementation, cancellationToken); + } + + protected ValueTask RunServiceAsync( + Checksum solutionChecksum, Func implementation, CancellationToken cancellationToken) + { + return RunServiceAsync( + async c => { - throw ExceptionUtilities.Unreachable(); - } - } + await RunWithSolutionAsync( + solutionChecksum, + async s => + { + await implementation(s).ConfigureAwait(false); + // bridge this void 'implementation' callback to the non-void type the underlying api needs. + return false; + }, c).ConfigureAwait(false); + }, cancellationToken); + } - protected static ValueTask RunServiceAsync(Func implementation, CancellationToken cancellationToken) - { - return RunServiceImplAsync(implementation, cancellationToken); - } + protected ValueTask RunServiceAsync( + Checksum solutionChecksum1, + Checksum solutionChecksum2, + Func implementation, + CancellationToken cancellationToken) + { + return RunServiceAsync( + solutionChecksum1, + s1 => RunServiceAsync( + solutionChecksum2, + s2 => implementation(s1, s2), + cancellationToken), + cancellationToken); + } - protected ValueTask RunServiceAsync( - Checksum solutionChecksum, Func implementation, CancellationToken cancellationToken) + internal static async ValueTask RunServiceImplAsync(Func implementation, CancellationToken cancellationToken) + { + try { - return RunServiceAsync( - async c => - { - await RunWithSolutionAsync( - solutionChecksum, - async s => - { - await implementation(s).ConfigureAwait(false); - // bridge this void 'implementation' callback to the non-void type the underlying api needs. - return false; - }, c).ConfigureAwait(false); - }, cancellationToken); + await implementation(cancellationToken).ConfigureAwait(false); } - - protected ValueTask RunServiceAsync( - Checksum solutionChecksum1, - Checksum solutionChecksum2, - Func implementation, - CancellationToken cancellationToken) + catch (Exception ex) when (FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken)) { - return RunServiceAsync( - solutionChecksum1, - s1 => RunServiceAsync( - solutionChecksum2, - s2 => implementation(s1, s2), - cancellationToken), - cancellationToken); + throw ExceptionUtilities.Unreachable(); } + } - internal static async ValueTask RunServiceImplAsync(Func implementation, CancellationToken cancellationToken) - { - try - { - await implementation(cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) when (FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken)) - { - throw ExceptionUtilities.Unreachable(); - } - } + /// + /// Use for on-demand retrieval of language-specific options from the client. + /// + /// If the service doesn't know up-front for which languages it will need to retrieve specific options, + /// its ICallback interface should implement and use this + /// method to create the options provider to be passed to the feature implementation. + /// + protected static OptionsProvider GetClientOptionsProvider(RemoteCallback callback, RemoteServiceCallbackId callbackId) + where TCallback : class, IRemoteOptionsCallback + => new ClientOptionsProvider(callback, callbackId); - /// - /// Use for on-demand retrieval of language-specific options from the client. - /// - /// If the service doesn't know up-front for which languages it will need to retrieve specific options, - /// its ICallback interface should implement and use this - /// method to create the options provider to be passed to the feature implementation. - /// - protected static OptionsProvider GetClientOptionsProvider(RemoteCallback callback, RemoteServiceCallbackId callbackId) - where TCallback : class, IRemoteOptionsCallback - => new ClientOptionsProvider(callback, callbackId); - - private static void SetNativeDllSearchDirectories() + private static void SetNativeDllSearchDirectories() + { + if (PlatformInformation.IsWindows) { - if (PlatformInformation.IsWindows) + // Set LoadLibrary search directory to %VSINSTALLDIR%\Common7\IDE so that the compiler + // can P/Invoke to Microsoft.DiaSymReader.Native when emitting Windows PDBs. + // + // The AppDomain base directory is specified in VisualStudio\Setup\codeAnalysisService.servicehub.service.json + // to be the directory where devenv.exe is -- which is exactly the directory we need to add to the search paths: + // + // "appBasePath": "%VSAPPIDDIR%" + // + + var loadDir = AppDomain.CurrentDomain.BaseDirectory!; + + try { - // Set LoadLibrary search directory to %VSINSTALLDIR%\Common7\IDE so that the compiler - // can P/Invoke to Microsoft.DiaSymReader.Native when emitting Windows PDBs. - // - // The AppDomain base directory is specified in VisualStudio\Setup\codeAnalysisService.servicehub.service.json - // to be the directory where devenv.exe is -- which is exactly the directory we need to add to the search paths: - // - // "appBasePath": "%VSAPPIDDIR%" - // - - var loadDir = AppDomain.CurrentDomain.BaseDirectory!; - - try - { - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - static extern IntPtr AddDllDirectory(string directory); + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + static extern IntPtr AddDllDirectory(string directory); - if (AddDllDirectory(loadDir) == IntPtr.Zero) - { - throw new Win32Exception(); - } - } - catch (EntryPointNotFoundException) + if (AddDllDirectory(loadDir) == IntPtr.Zero) { - // AddDllDirectory API might not be available on Windows 7. - Environment.SetEnvironmentVariable("MICROSOFT_DIASYMREADER_NATIVE_ALT_LOAD_PATH", loadDir); + throw new Win32Exception(); } } + catch (EntryPointNotFoundException) + { + // AddDllDirectory API might not be available on Windows 7. + Environment.SetEnvironmentVariable("MICROSOFT_DIASYMREADER_NATIVE_ALT_LOAD_PATH", loadDir); + } } } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeLensReferences/RemoteCodeLensReferencesService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeLensReferences/RemoteCodeLensReferencesService.cs index 5a9190087541a..7e616ec467c1f 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/CodeLensReferences/RemoteCodeLensReferencesService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeLensReferences/RemoteCodeLensReferencesService.cs @@ -10,80 +10,100 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteCodeLensReferencesService : BrokeredServiceBase, IRemoteCodeLensReferencesService { - internal sealed class RemoteCodeLensReferencesService : BrokeredServiceBase, IRemoteCodeLensReferencesService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteCodeLensReferencesService CreateService(in ServiceConstructionArguments arguments) - => new RemoteCodeLensReferencesService(arguments); - } + protected override IRemoteCodeLensReferencesService CreateService(in ServiceConstructionArguments arguments) + => new RemoteCodeLensReferencesService(arguments); + } + + public RemoteCodeLensReferencesService(in ServiceConstructionArguments arguments) + : base(arguments) + { + } - public RemoteCodeLensReferencesService(in ServiceConstructionArguments arguments) - : base(arguments) + private static async ValueTask TryFindNodeAsync(Solution solution, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) + { + var document = await solution.GetDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + if (document == null) { + return null; } - private static async ValueTask TryFindNodeAsync(Solution solution, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) - { - var document = await solution.GetDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); - if (document == null) - { - return null; - } + var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + // Pass getInnermostNodeForTie so top-level statements that are contained within a GlobalStatementSyntax picks the actual + // definition and not just the GlobalStatementSyntax. + return syntaxRoot.FindNode(textSpan, getInnermostNodeForTie: true); + } - var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + public async ValueTask GetReferenceCountAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, int maxResultCount, CancellationToken cancellationToken) + { + using (Logger.LogBlock(FunctionId.CodeAnalysisService_GetReferenceCountAsync, documentId.ProjectId.DebugName, cancellationToken)) + { + return await RunServiceAsync(solutionChecksum, async solution => + { + var syntaxNode = await TryFindNodeAsync(solution, documentId, textSpan, cancellationToken).ConfigureAwait(false); + if (syntaxNode == null) + { + return null; + } - // Pass getInnermostNodeForTie so top-level statements that are contained within a GlobalStatementSyntax picks the actual - // definition and not just the GlobalStatementSyntax. - return syntaxRoot.FindNode(textSpan, getInnermostNodeForTie: true); + return await CodeLensReferencesServiceFactory.Instance.GetReferenceCountAsync( + solution, + documentId, + syntaxNode, + maxResultCount, + cancellationToken).ConfigureAwait(false); + }, + cancellationToken).ConfigureAwait(false); } + } - public async ValueTask GetReferenceCountAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, int maxResultCount, CancellationToken cancellationToken) + public async ValueTask?> FindReferenceLocationsAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) + { + using (Logger.LogBlock(FunctionId.CodeAnalysisService_FindReferenceLocationsAsync, documentId.ProjectId.DebugName, cancellationToken)) { - using (Logger.LogBlock(FunctionId.CodeAnalysisService_GetReferenceCountAsync, documentId.ProjectId.DebugName, cancellationToken)) + return await RunServiceAsync(solutionChecksum, async solution => { - return await RunServiceAsync(solutionChecksum, async solution => - { - var syntaxNode = await TryFindNodeAsync(solution, documentId, textSpan, cancellationToken).ConfigureAwait(false); - if (syntaxNode == null) - { - return null; - } + var syntaxNode = await TryFindNodeAsync(solution, documentId, textSpan, cancellationToken).ConfigureAwait(false); + if (syntaxNode == null) + { + return null; + } - return await CodeLensReferencesServiceFactory.Instance.GetReferenceCountAsync( - solution, - documentId, - syntaxNode, - maxResultCount, - cancellationToken).ConfigureAwait(false); - }, - cancellationToken).ConfigureAwait(false); - } + return await CodeLensReferencesServiceFactory.Instance.FindReferenceLocationsAsync( + solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); } + } - public async ValueTask?> FindReferenceLocationsAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) + public async ValueTask?> FindReferenceMethodsAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) + { + using (Logger.LogBlock(FunctionId.CodeAnalysisService_FindReferenceMethodsAsync, documentId.ProjectId.DebugName, cancellationToken)) { - using (Logger.LogBlock(FunctionId.CodeAnalysisService_FindReferenceLocationsAsync, documentId.ProjectId.DebugName, cancellationToken)) + return await RunServiceAsync(solutionChecksum, async solution => { - return await RunServiceAsync(solutionChecksum, async solution => + var syntaxNode = await TryFindNodeAsync(solution, documentId, textSpan, cancellationToken).ConfigureAwait(false); + if (syntaxNode == null) { - var syntaxNode = await TryFindNodeAsync(solution, documentId, textSpan, cancellationToken).ConfigureAwait(false); - if (syntaxNode == null) - { - return null; - } + return null; + } - return await CodeLensReferencesServiceFactory.Instance.FindReferenceLocationsAsync( - solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false); - }, cancellationToken).ConfigureAwait(false); - } + return await CodeLensReferencesServiceFactory.Instance.FindReferenceMethodsAsync( + solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); } + } - public async ValueTask?> FindReferenceMethodsAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) + public ValueTask GetFullyQualifiedNameAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) + { + return RunServiceAsync(async cancellationToken => { - using (Logger.LogBlock(FunctionId.CodeAnalysisService_FindReferenceMethodsAsync, documentId.ProjectId.DebugName, cancellationToken)) + using (Logger.LogBlock(FunctionId.CodeAnalysisService_GetFullyQualifiedName, documentId.ProjectId.DebugName, cancellationToken)) { return await RunServiceAsync(solutionChecksum, async solution => { @@ -93,31 +113,10 @@ public RemoteCodeLensReferencesService(in ServiceConstructionArguments arguments return null; } - return await CodeLensReferencesServiceFactory.Instance.FindReferenceMethodsAsync( + return await CodeLensReferencesServiceFactory.Instance.GetFullyQualifiedNameAsync( solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false); }, cancellationToken).ConfigureAwait(false); } - } - - public ValueTask GetFullyQualifiedNameAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) - { - return RunServiceAsync(async cancellationToken => - { - using (Logger.LogBlock(FunctionId.CodeAnalysisService_GetFullyQualifiedName, documentId.ProjectId.DebugName, cancellationToken)) - { - return await RunServiceAsync(solutionChecksum, async solution => - { - var syntaxNode = await TryFindNodeAsync(solution, documentId, textSpan, cancellationToken).ConfigureAwait(false); - if (syntaxNode == null) - { - return null; - } - - return await CodeLensReferencesServiceFactory.Instance.GetFullyQualifiedNameAsync( - solution, documentId, syntaxNode, cancellationToken).ConfigureAwait(false); - }, cancellationToken).ConfigureAwait(false); - } - }, cancellationToken); - } + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs b/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs index 132962f789182..f13d42d978535 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ConvertTupleToStructCodeRefactoringProvider/RemoteConvertTupleToStructCodeRefactoringService.cs @@ -16,84 +16,83 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteConvertTupleToStructCodeRefactoringService(in BrokeredServiceBase.ServiceConstructionArguments arguments) + : BrokeredServiceBase(arguments), IRemoteConvertTupleToStructCodeRefactoringService { - internal sealed class RemoteConvertTupleToStructCodeRefactoringService(in BrokeredServiceBase.ServiceConstructionArguments arguments) - : BrokeredServiceBase(arguments), IRemoteConvertTupleToStructCodeRefactoringService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteConvertTupleToStructCodeRefactoringService CreateService(in ServiceConstructionArguments arguments) - => new RemoteConvertTupleToStructCodeRefactoringService(arguments); - } + protected override IRemoteConvertTupleToStructCodeRefactoringService CreateService(in ServiceConstructionArguments arguments) + => new RemoteConvertTupleToStructCodeRefactoringService(arguments); + } - public ValueTask ConvertToStructAsync( - Checksum solutionChecksum, - DocumentId documentId, - TextSpan span, - Scope scope, - bool isRecord, - CancellationToken cancellationToken) + public ValueTask ConvertToStructAsync( + Checksum solutionChecksum, + DocumentId documentId, + TextSpan span, + Scope scope, + bool isRecord, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var document = solution.GetRequiredDocument(documentId); + var document = solution.GetRequiredDocument(documentId); - var service = document.GetRequiredLanguageService(); + var service = document.GetRequiredLanguageService(); - var updatedSolution = await service.ConvertToStructAsync(document, span, scope, isRecord, cancellationToken).ConfigureAwait(false); + var updatedSolution = await service.ConvertToStructAsync(document, span, scope, isRecord, cancellationToken).ConfigureAwait(false); - var cleanedSolution = await CleanupAsync(solution, updatedSolution, cancellationToken).ConfigureAwait(false); + var cleanedSolution = await CleanupAsync(solution, updatedSolution, cancellationToken).ConfigureAwait(false); - var documentTextChanges = await RemoteUtilities.GetDocumentTextChangesAsync( - solution, cleanedSolution, cancellationToken).ConfigureAwait(false); - var renamedToken = await GetRenamedTokenAsync( - solution, cleanedSolution, cancellationToken).ConfigureAwait(false); + var documentTextChanges = await RemoteUtilities.GetDocumentTextChangesAsync( + solution, cleanedSolution, cancellationToken).ConfigureAwait(false); + var renamedToken = await GetRenamedTokenAsync( + solution, cleanedSolution, cancellationToken).ConfigureAwait(false); - return new SerializableConvertTupleToStructResult(documentTextChanges, renamedToken); - }, cancellationToken); - } - - private static async Task<(DocumentId, TextSpan)> GetRenamedTokenAsync( - Solution oldSolution, Solution newSolution, CancellationToken cancellationToken) - { - var changes = newSolution.GetChangedDocuments(oldSolution); + return new SerializableConvertTupleToStructResult(documentTextChanges, renamedToken); + }, cancellationToken); + } - foreach (var docId in changes) - { - var document = newSolution.GetRequiredDocument(docId); - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var renamedToken = root.GetAnnotatedTokens(RenameAnnotation.Kind).FirstOrNull(); - if (renamedToken == null) - continue; + private static async Task<(DocumentId, TextSpan)> GetRenamedTokenAsync( + Solution oldSolution, Solution newSolution, CancellationToken cancellationToken) + { + var changes = newSolution.GetChangedDocuments(oldSolution); - return (docId, renamedToken.Value.Span); - } + foreach (var docId in changes) + { + var document = newSolution.GetRequiredDocument(docId); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var renamedToken = root.GetAnnotatedTokens(RenameAnnotation.Kind).FirstOrNull(); + if (renamedToken == null) + continue; - throw ExceptionUtilities.Unreachable(); + return (docId, renamedToken.Value.Span); } - private static async Task CleanupAsync(Solution oldSolution, Solution newSolution, CancellationToken cancellationToken) - { - var changes = newSolution.GetChangedDocuments(oldSolution); - var final = newSolution; + throw ExceptionUtilities.Unreachable(); + } - var changedDocuments = await ProducerConsumer<(DocumentId documentId, SyntaxNode newRoot)>.RunParallelAsync( - source: changes, - produceItems: static async (docId, callback, newSolution, cancellationToken) => - { - var document = newSolution.GetRequiredDocument(docId); + private static async Task CleanupAsync(Solution oldSolution, Solution newSolution, CancellationToken cancellationToken) + { + var changes = newSolution.GetChangedDocuments(oldSolution); + var final = newSolution; - var options = await document.GetCodeCleanupOptionsAsync(cancellationToken).ConfigureAwait(false); - var cleaned = await CodeAction.CleanupDocumentAsync(document, options, cancellationToken).ConfigureAwait(false); + var changedDocuments = await ProducerConsumer<(DocumentId documentId, SyntaxNode newRoot)>.RunParallelAsync( + source: changes, + produceItems: static async (docId, callback, newSolution, cancellationToken) => + { + var document = newSolution.GetRequiredDocument(docId); - var cleanedRoot = await cleaned.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - callback((docId, cleanedRoot)); - }, - args: newSolution, - cancellationToken).ConfigureAwait(false); + var options = await document.GetCodeCleanupOptionsAsync(cancellationToken).ConfigureAwait(false); + var cleaned = await CodeAction.CleanupDocumentAsync(document, options, cancellationToken).ConfigureAwait(false); - return newSolution.WithDocumentSyntaxRoots(changedDocuments); - } + var cleanedRoot = await cleaned.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + callback((docId, cleanedRoot)); + }, + args: newSolution, + cancellationToken).ConfigureAwait(false); + + return newSolution.WithDocumentSyntaxRoots(changedDocuments); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs b/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs index 5a0955c038613..59b6f592c331b 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DependentTypeFinder/RemoteDependentTypeFinderService.cs @@ -11,43 +11,42 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteDependentTypeFinderService : BrokeredServiceBase, IRemoteDependentTypeFinderService { - internal sealed class RemoteDependentTypeFinderService : BrokeredServiceBase, IRemoteDependentTypeFinderService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteDependentTypeFinderService CreateService(in ServiceConstructionArguments arguments) - => new RemoteDependentTypeFinderService(arguments); - } + protected override IRemoteDependentTypeFinderService CreateService(in ServiceConstructionArguments arguments) + => new RemoteDependentTypeFinderService(arguments); + } - public RemoteDependentTypeFinderService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } - - public ValueTask> FindTypesAsync( - Checksum solutionChecksum, - SerializableSymbolAndProjectId typeAndProjectId, - ImmutableArray projectIdsOpt, - bool transitive, - DependentTypesKind kind, - CancellationToken cancellationToken) + public RemoteDependentTypeFinderService(in ServiceConstructionArguments arguments) + : base(arguments) + { + } + + public ValueTask> FindTypesAsync( + Checksum solutionChecksum, + SerializableSymbolAndProjectId typeAndProjectId, + ImmutableArray projectIdsOpt, + bool transitive, + DependentTypesKind kind, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var symbol = await typeAndProjectId.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false); + var symbol = await typeAndProjectId.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false); - if (symbol is not INamedTypeSymbol namedType) - return ImmutableArray.Empty; + if (symbol is not INamedTypeSymbol namedType) + return ImmutableArray.Empty; - var projects = projectIdsOpt.IsDefault ? null : projectIdsOpt.Select(id => solution.GetRequiredProject(id)).ToImmutableHashSet(); + var projects = projectIdsOpt.IsDefault ? null : projectIdsOpt.Select(id => solution.GetRequiredProject(id)).ToImmutableHashSet(); - var types = await DependentTypeFinder.FindTypesInCurrentProcessAsync(namedType, solution, projects, transitive, kind, cancellationToken).ConfigureAwait(false); + var types = await DependentTypeFinder.FindTypesInCurrentProcessAsync(namedType, solution, projects, transitive, kind, cancellationToken).ConfigureAwait(false); - return types.SelectAsArray( - t => SerializableSymbolAndProjectId.Dehydrate(solution, t, cancellationToken)); - }, cancellationToken); - } + return types.SelectAsArray( + t => SerializableSymbolAndProjectId.Dehydrate(solution, t, cancellationToken)); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs index 9fc7d7494a3a6..f6aaf5c220842 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/DiagnosticComputer.cs @@ -21,559 +21,558 @@ using Roslyn.Utilities; using static Microsoft.VisualStudio.Threading.ThreadingTools; -namespace Microsoft.CodeAnalysis.Remote.Diagnostics +namespace Microsoft.CodeAnalysis.Remote.Diagnostics; + +internal class DiagnosticComputer { - internal class DiagnosticComputer + /// + /// Cache of and a map from analyzer IDs to s + /// for all analyzers for the last project to be analyzed. + /// The instance is shared between all the following document analyses modes for the project: + /// 1. Span-based analysis for active document (lightbulb) + /// 2. Background analysis for active and open documents. + /// + /// NOTE: We do not re-use this cache for project analysis as it leads to significant memory increase in the OOP process. + /// Additionally, we only store the cache entry for the last project to be analyzed instead of maintaining a CWT keyed off + /// each project in the solution, as the CWT does not seem to drop entries until ForceGC happens, leading to significant memory + /// pressure when there are large number of open documents across different projects to be analyzed by background analysis. + /// + private static CompilationWithAnalyzersCacheEntry? s_compilationWithAnalyzersCache = null; + + /// + /// Set of high priority diagnostic computation tasks which are currently executing. + /// Any new high priority diagnostic request is added to this set before the core diagnostics + /// compute call is performed, and removed from this list after the computation finishes. + /// Any new normal priority diagnostic request first waits for all the high priority tasks in this set + /// to complete, and moves ahead only after this list becomes empty. + /// + /// + /// Read/write access to this field is guarded by . + /// + private static ImmutableHashSet s_highPriorityComputeTasks = []; + + /// + /// Set of cancellation token sources for normal priority diagnostic computation tasks which are currently executing. + /// For any new normal priority diagnostic request, a new cancellation token source is created and added to this set + /// before the core diagnostics compute call is performed, and removed from this set after the computation finishes. + /// Any new high priority diagnostic request first fires cancellation on all the cancellation token sources in this set + /// to avoid resource contention between normal and high priority requests. + /// Canceled normal priority diagnostic requests are re-attempted from scratch after all the high priority requests complete. + /// + /// + /// Read/write access to this field is guarded by . + /// + private static ImmutableHashSet s_normalPriorityCancellationTokenSources = []; + + /// + /// Static gate controlling access to following static fields: + /// - + /// - + /// - + /// + private static readonly object s_gate = new(); + + /// + /// Solution checksum for the diagnostic request. + /// We use this checksum and the of the diagnostic request as the key + /// to the . + /// + private readonly Checksum _solutionChecksum; + + private readonly TextDocument? _document; + private readonly Project _project; + private readonly TextSpan? _span; + private readonly AnalysisKind? _analysisKind; + private readonly IPerformanceTrackerService? _performanceTracker; + private readonly DiagnosticAnalyzerInfoCache _analyzerInfoCache; + private readonly HostWorkspaceServices _hostWorkspaceServices; + + private DiagnosticComputer( + TextDocument? document, + Project project, + Checksum solutionChecksum, + TextSpan? span, + AnalysisKind? analysisKind, + DiagnosticAnalyzerInfoCache analyzerInfoCache, + HostWorkspaceServices hostWorkspaceServices) { - /// - /// Cache of and a map from analyzer IDs to s - /// for all analyzers for the last project to be analyzed. - /// The instance is shared between all the following document analyses modes for the project: - /// 1. Span-based analysis for active document (lightbulb) - /// 2. Background analysis for active and open documents. - /// - /// NOTE: We do not re-use this cache for project analysis as it leads to significant memory increase in the OOP process. - /// Additionally, we only store the cache entry for the last project to be analyzed instead of maintaining a CWT keyed off - /// each project in the solution, as the CWT does not seem to drop entries until ForceGC happens, leading to significant memory - /// pressure when there are large number of open documents across different projects to be analyzed by background analysis. - /// - private static CompilationWithAnalyzersCacheEntry? s_compilationWithAnalyzersCache = null; - - /// - /// Set of high priority diagnostic computation tasks which are currently executing. - /// Any new high priority diagnostic request is added to this set before the core diagnostics - /// compute call is performed, and removed from this list after the computation finishes. - /// Any new normal priority diagnostic request first waits for all the high priority tasks in this set - /// to complete, and moves ahead only after this list becomes empty. - /// - /// - /// Read/write access to this field is guarded by . - /// - private static ImmutableHashSet s_highPriorityComputeTasks = []; - - /// - /// Set of cancellation token sources for normal priority diagnostic computation tasks which are currently executing. - /// For any new normal priority diagnostic request, a new cancellation token source is created and added to this set - /// before the core diagnostics compute call is performed, and removed from this set after the computation finishes. - /// Any new high priority diagnostic request first fires cancellation on all the cancellation token sources in this set - /// to avoid resource contention between normal and high priority requests. - /// Canceled normal priority diagnostic requests are re-attempted from scratch after all the high priority requests complete. - /// - /// - /// Read/write access to this field is guarded by . - /// - private static ImmutableHashSet s_normalPriorityCancellationTokenSources = []; - - /// - /// Static gate controlling access to following static fields: - /// - - /// - - /// - - /// - private static readonly object s_gate = new(); - - /// - /// Solution checksum for the diagnostic request. - /// We use this checksum and the of the diagnostic request as the key - /// to the . - /// - private readonly Checksum _solutionChecksum; - - private readonly TextDocument? _document; - private readonly Project _project; - private readonly TextSpan? _span; - private readonly AnalysisKind? _analysisKind; - private readonly IPerformanceTrackerService? _performanceTracker; - private readonly DiagnosticAnalyzerInfoCache _analyzerInfoCache; - private readonly HostWorkspaceServices _hostWorkspaceServices; - - private DiagnosticComputer( - TextDocument? document, - Project project, - Checksum solutionChecksum, - TextSpan? span, - AnalysisKind? analysisKind, - DiagnosticAnalyzerInfoCache analyzerInfoCache, - HostWorkspaceServices hostWorkspaceServices) + _document = document; + _project = project; + _solutionChecksum = solutionChecksum; + _span = span; + _analysisKind = analysisKind; + _analyzerInfoCache = analyzerInfoCache; + _hostWorkspaceServices = hostWorkspaceServices; + _performanceTracker = project.Solution.Services.GetService(); + } + + public static Task GetDiagnosticsAsync( + TextDocument? document, + Project project, + Checksum solutionChecksum, + TextSpan? span, + IEnumerable analyzerIds, + AnalysisKind? analysisKind, + DiagnosticAnalyzerInfoCache analyzerInfoCache, + HostWorkspaceServices hostWorkspaceServices, + bool isExplicit, + bool reportSuppressedDiagnostics, + bool logPerformanceInfo, + bool getTelemetryInfo, + CancellationToken cancellationToken) + { + // PERF: Due to the concept of InFlight solution snapshots in OOP process, we might have been + // handed a Project instance that does not match the Project instance corresponding to our + // cached CompilationWithAnalyzers instance, while the underlying Solution checksum matches + // for our cached entry and the incoming request. + // We detect this case upfront here and re-use the cached CompilationWithAnalyzers and Project + // instance for diagnostic computation, thus improving the performance of analyzer execution. + // This is an important performance optimization for lightbulb diagnostic computation. + // See https://github.com/dotnet/roslyn/issues/66968 for details. + lock (s_gate) { - _document = document; - _project = project; - _solutionChecksum = solutionChecksum; - _span = span; - _analysisKind = analysisKind; - _analyzerInfoCache = analyzerInfoCache; - _hostWorkspaceServices = hostWorkspaceServices; - _performanceTracker = project.Solution.Services.GetService(); + if (s_compilationWithAnalyzersCache?.SolutionChecksum == solutionChecksum && + s_compilationWithAnalyzersCache.Project.Id == project.Id && + s_compilationWithAnalyzersCache.Project != project) + { + project = s_compilationWithAnalyzersCache.Project; + if (document != null) + document = project.GetTextDocument(document.Id); + } + } + + // We execute explicit, user-invoked diagnostics requests with higher priority compared to implicit requests + // from clients such as editor diagnostic tagger to show squiggles, background analysis to populate the error list, etc. + var diagnosticsComputer = new DiagnosticComputer(document, project, solutionChecksum, span, analysisKind, analyzerInfoCache, hostWorkspaceServices); + return isExplicit + ? diagnosticsComputer.GetHighPriorityDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, cancellationToken) + : diagnosticsComputer.GetNormalPriorityDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, cancellationToken); + } + + private async Task GetHighPriorityDiagnosticsAsync( + IEnumerable analyzerIds, + bool reportSuppressedDiagnostics, + bool logPerformanceInfo, + bool getTelemetryInfo, + CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + // Step 1: + // - Create the core 'computeTask' for computing diagnostics. + var computeTask = GetDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, cancellationToken); + + // Step 2: + // - Add this computeTask to the set of currently executing high priority tasks. + // This set of high priority tasks is used in 'GetNormalPriorityDiagnosticsAsync' + // method to ensure that any new or cancelled normal priority task waits for all + // the executing high priority tasks before starting its execution. + // - Note that it is critical to do this step prior to Step 3 below to ensure that + // any canceled normal priority tasks in Step 3 do not resume execution prior to + // completion of this high priority computeTask. + lock (s_gate) + { + Debug.Assert(!s_highPriorityComputeTasks.Contains(computeTask)); + s_highPriorityComputeTasks = s_highPriorityComputeTasks.Add(computeTask); + } + + try + { + // Step 3: + // - Force cancellation of all the executing normal priority tasks + // to minimize resource and CPU contention between normal priority tasks + // and the high priority computeTask in Step 4 below. + CancelNormalPriorityTasks(); + + // Step 4: + // - Execute the core 'computeTask' for diagnostic computation. + return await computeTask.ConfigureAwait(false); + } + finally + { + // Step 5: + // - Remove the 'computeTask' from the set of current executing high priority tasks. + lock (s_gate) + { + Debug.Assert(s_highPriorityComputeTasks.Contains(computeTask)); + s_highPriorityComputeTasks = s_highPriorityComputeTasks.Remove(computeTask); + } } - public static Task GetDiagnosticsAsync( - TextDocument? document, - Project project, - Checksum solutionChecksum, - TextSpan? span, - IEnumerable analyzerIds, - AnalysisKind? analysisKind, - DiagnosticAnalyzerInfoCache analyzerInfoCache, - HostWorkspaceServices hostWorkspaceServices, - bool isExplicit, - bool reportSuppressedDiagnostics, - bool logPerformanceInfo, - bool getTelemetryInfo, - CancellationToken cancellationToken) + static void CancelNormalPriorityTasks() { - // PERF: Due to the concept of InFlight solution snapshots in OOP process, we might have been - // handed a Project instance that does not match the Project instance corresponding to our - // cached CompilationWithAnalyzers instance, while the underlying Solution checksum matches - // for our cached entry and the incoming request. - // We detect this case upfront here and re-use the cached CompilationWithAnalyzers and Project - // instance for diagnostic computation, thus improving the performance of analyzer execution. - // This is an important performance optimization for lightbulb diagnostic computation. - // See https://github.com/dotnet/roslyn/issues/66968 for details. + ImmutableHashSet cancellationTokenSources; lock (s_gate) { - if (s_compilationWithAnalyzersCache?.SolutionChecksum == solutionChecksum && - s_compilationWithAnalyzersCache.Project.Id == project.Id && - s_compilationWithAnalyzersCache.Project != project) + cancellationTokenSources = s_normalPriorityCancellationTokenSources; + } + + foreach (var cancellationTokenSource in cancellationTokenSources) + { + try { - project = s_compilationWithAnalyzersCache.Project; - if (document != null) - document = project.GetTextDocument(document.Id); + cancellationTokenSource.Cancel(); + } + catch (ObjectDisposedException) + { + // CancellationTokenSource might get disposed if the normal priority + // task completes while we were executing this foreach loop. + // Gracefully handle this case and ignore this exception. } } - - // We execute explicit, user-invoked diagnostics requests with higher priority compared to implicit requests - // from clients such as editor diagnostic tagger to show squiggles, background analysis to populate the error list, etc. - var diagnosticsComputer = new DiagnosticComputer(document, project, solutionChecksum, span, analysisKind, analyzerInfoCache, hostWorkspaceServices); - return isExplicit - ? diagnosticsComputer.GetHighPriorityDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, cancellationToken) - : diagnosticsComputer.GetNormalPriorityDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, cancellationToken); } + } - private async Task GetHighPriorityDiagnosticsAsync( - IEnumerable analyzerIds, - bool reportSuppressedDiagnostics, - bool logPerformanceInfo, - bool getTelemetryInfo, - CancellationToken cancellationToken) + private async Task GetNormalPriorityDiagnosticsAsync( + IEnumerable analyzerIds, + bool reportSuppressedDiagnostics, + bool logPerformanceInfo, + bool getTelemetryInfo, + CancellationToken cancellationToken) + { + while (true) { cancellationToken.ThrowIfCancellationRequested(); // Step 1: - // - Create the core 'computeTask' for computing diagnostics. - var computeTask = GetDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, cancellationToken); + // - Normal priority task must wait for all the executing high priority tasks to complete + // before beginning execution. + await WaitForHighPriorityTasksAsync(cancellationToken).ConfigureAwait(false); // Step 2: - // - Add this computeTask to the set of currently executing high priority tasks. - // This set of high priority tasks is used in 'GetNormalPriorityDiagnosticsAsync' - // method to ensure that any new or cancelled normal priority task waits for all - // the executing high priority tasks before starting its execution. - // - Note that it is critical to do this step prior to Step 3 below to ensure that - // any canceled normal priority tasks in Step 3 do not resume execution prior to - // completion of this high priority computeTask. + // - Create a custom 'cancellationTokenSource' associated with the current normal priority + // request and add it to the tracked set of normal priority cancellation token sources. + // This token source allows normal priority computeTasks to be cancelled when + // a subsequent high priority diagnostic request is received. + using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); lock (s_gate) { - Debug.Assert(!s_highPriorityComputeTasks.Contains(computeTask)); - s_highPriorityComputeTasks = s_highPriorityComputeTasks.Add(computeTask); + s_normalPriorityCancellationTokenSources = s_normalPriorityCancellationTokenSources.Add(cancellationTokenSource); } try { // Step 3: - // - Force cancellation of all the executing normal priority tasks - // to minimize resource and CPU contention between normal priority tasks - // and the high priority computeTask in Step 4 below. - CancelNormalPriorityTasks(); - + // - Execute the core compute task for diagnostic computation. + return await GetDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, + cancellationTokenSource.Token).ConfigureAwait(false); + } + catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationTokenSource.Token) + { // Step 4: - // - Execute the core 'computeTask' for diagnostic computation. - return await computeTask.ConfigureAwait(false); + // - Attempt to re-execute this cancelled normal priority task by running the loop again. + continue; } finally { // Step 5: - // - Remove the 'computeTask' from the set of current executing high priority tasks. - lock (s_gate) - { - Debug.Assert(s_highPriorityComputeTasks.Contains(computeTask)); - s_highPriorityComputeTasks = s_highPriorityComputeTasks.Remove(computeTask); - } - } - - static void CancelNormalPriorityTasks() - { - ImmutableHashSet cancellationTokenSources; + // - Remove the 'cancellationTokenSource' for completed or cancelled task. + // For the case where the computeTask was cancelled, we will create a new + // 'cancellationTokenSource' for the retry. lock (s_gate) { - cancellationTokenSources = s_normalPriorityCancellationTokenSources; - } - - foreach (var cancellationTokenSource in cancellationTokenSources) - { - try - { - cancellationTokenSource.Cancel(); - } - catch (ObjectDisposedException) - { - // CancellationTokenSource might get disposed if the normal priority - // task completes while we were executing this foreach loop. - // Gracefully handle this case and ignore this exception. - } + Debug.Assert(s_normalPriorityCancellationTokenSources.Contains(cancellationTokenSource)); + s_normalPriorityCancellationTokenSources = s_normalPriorityCancellationTokenSources.Remove(cancellationTokenSource); } } } - private async Task GetNormalPriorityDiagnosticsAsync( - IEnumerable analyzerIds, - bool reportSuppressedDiagnostics, - bool logPerformanceInfo, - bool getTelemetryInfo, - CancellationToken cancellationToken) + static async Task WaitForHighPriorityTasksAsync(CancellationToken cancellationToken) { + // We loop continuously until we have an empty high priority task queue. while (true) { cancellationToken.ThrowIfCancellationRequested(); - // Step 1: - // - Normal priority task must wait for all the executing high priority tasks to complete - // before beginning execution. - await WaitForHighPriorityTasksAsync(cancellationToken).ConfigureAwait(false); - - // Step 2: - // - Create a custom 'cancellationTokenSource' associated with the current normal priority - // request and add it to the tracked set of normal priority cancellation token sources. - // This token source allows normal priority computeTasks to be cancelled when - // a subsequent high priority diagnostic request is received. - using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + ImmutableHashSet highPriorityTasksToAwait; lock (s_gate) { - s_normalPriorityCancellationTokenSources = s_normalPriorityCancellationTokenSources.Add(cancellationTokenSource); + highPriorityTasksToAwait = s_highPriorityComputeTasks; } - try - { - // Step 3: - // - Execute the core compute task for diagnostic computation. - return await GetDiagnosticsAsync(analyzerIds, reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, - cancellationTokenSource.Token).ConfigureAwait(false); - } - catch (OperationCanceledException ex) when (ex.CancellationToken == cancellationTokenSource.Token) + if (highPriorityTasksToAwait.IsEmpty) { - // Step 4: - // - Attempt to re-execute this cancelled normal priority task by running the loop again. - continue; + return; } - finally - { - // Step 5: - // - Remove the 'cancellationTokenSource' for completed or cancelled task. - // For the case where the computeTask was cancelled, we will create a new - // 'cancellationTokenSource' for the retry. - lock (s_gate) - { - Debug.Assert(s_normalPriorityCancellationTokenSources.Contains(cancellationTokenSource)); - s_normalPriorityCancellationTokenSources = s_normalPriorityCancellationTokenSources.Remove(cancellationTokenSource); - } - } - } - static async Task WaitForHighPriorityTasksAsync(CancellationToken cancellationToken) - { - // We loop continuously until we have an empty high priority task queue. - while (true) + // Wait for all the high priority tasks, ignoring all exceptions from it. Loop directly to avoid + // expensive allocations in Task.WhenAll. + foreach (var task in highPriorityTasksToAwait) { cancellationToken.ThrowIfCancellationRequested(); - - ImmutableHashSet highPriorityTasksToAwait; - lock (s_gate) - { - highPriorityTasksToAwait = s_highPriorityComputeTasks; - } - - if (highPriorityTasksToAwait.IsEmpty) + if (task.IsCompleted) { - return; + // Make sure to yield so continuations of 'task' can make progress. + await TaskScheduler.Default.SwitchTo(alwaysYield: true); } - - // Wait for all the high priority tasks, ignoring all exceptions from it. Loop directly to avoid - // expensive allocations in Task.WhenAll. - foreach (var task in highPriorityTasksToAwait) + else { - cancellationToken.ThrowIfCancellationRequested(); - if (task.IsCompleted) - { - // Make sure to yield so continuations of 'task' can make progress. - await TaskScheduler.Default.SwitchTo(alwaysYield: true); - } - else - { - await task.WithCancellation(cancellationToken).NoThrowAwaitable(false); - } + await task.WithCancellation(cancellationToken).NoThrowAwaitable(false); } } } } + } - private async Task GetDiagnosticsAsync( - IEnumerable analyzerIds, - bool reportSuppressedDiagnostics, - bool logPerformanceInfo, - bool getTelemetryInfo, - CancellationToken cancellationToken) + private async Task GetDiagnosticsAsync( + IEnumerable analyzerIds, + bool reportSuppressedDiagnostics, + bool logPerformanceInfo, + bool getTelemetryInfo, + CancellationToken cancellationToken) + { + var (compilationWithAnalyzers, analyzerToIdMap) = await GetOrCreateCompilationWithAnalyzersAsync(cancellationToken).ConfigureAwait(false); + if (compilationWithAnalyzers == null) { - var (compilationWithAnalyzers, analyzerToIdMap) = await GetOrCreateCompilationWithAnalyzersAsync(cancellationToken).ConfigureAwait(false); - if (compilationWithAnalyzers == null) - { - return SerializableDiagnosticAnalysisResults.Empty; - } + return SerializableDiagnosticAnalysisResults.Empty; + } - var analyzers = GetAnalyzers(analyzerToIdMap, analyzerIds); - if (analyzers.IsEmpty) - { - return SerializableDiagnosticAnalysisResults.Empty; - } + var analyzers = GetAnalyzers(analyzerToIdMap, analyzerIds); + if (analyzers.IsEmpty) + { + return SerializableDiagnosticAnalysisResults.Empty; + } - if (_document == null && analyzers.Length < compilationWithAnalyzers.Analyzers.Length) - { - // PERF: Generate a new CompilationWithAnalyzers with trimmed analyzers for non-document analysis case. - compilationWithAnalyzers = compilationWithAnalyzers.Compilation.WithAnalyzers(analyzers, compilationWithAnalyzers.AnalysisOptions); - } + if (_document == null && analyzers.Length < compilationWithAnalyzers.Analyzers.Length) + { + // PERF: Generate a new CompilationWithAnalyzers with trimmed analyzers for non-document analysis case. + compilationWithAnalyzers = compilationWithAnalyzers.Compilation.WithAnalyzers(analyzers, compilationWithAnalyzers.AnalysisOptions); + } - var skippedAnalyzersInfo = _project.GetSkippedAnalyzersInfo(_analyzerInfoCache); + var skippedAnalyzersInfo = _project.GetSkippedAnalyzersInfo(_analyzerInfoCache); - return await AnalyzeAsync(compilationWithAnalyzers, analyzerToIdMap, analyzers, skippedAnalyzersInfo, - reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, cancellationToken).ConfigureAwait(false); - } + return await AnalyzeAsync(compilationWithAnalyzers, analyzerToIdMap, analyzers, skippedAnalyzersInfo, + reportSuppressedDiagnostics, logPerformanceInfo, getTelemetryInfo, cancellationToken).ConfigureAwait(false); + } - private async Task AnalyzeAsync( - CompilationWithAnalyzers compilationWithAnalyzers, - BidirectionalMap analyzerToIdMap, - ImmutableArray analyzers, - SkippedHostAnalyzersInfo skippedAnalyzersInfo, - bool reportSuppressedDiagnostics, - bool logPerformanceInfo, - bool getTelemetryInfo, - CancellationToken cancellationToken) - { - var documentAnalysisScope = _document != null - ? new DocumentAnalysisScope(_document, _span, analyzers, _analysisKind!.Value) - : null; + private async Task AnalyzeAsync( + CompilationWithAnalyzers compilationWithAnalyzers, + BidirectionalMap analyzerToIdMap, + ImmutableArray analyzers, + SkippedHostAnalyzersInfo skippedAnalyzersInfo, + bool reportSuppressedDiagnostics, + bool logPerformanceInfo, + bool getTelemetryInfo, + CancellationToken cancellationToken) + { + var documentAnalysisScope = _document != null + ? new DocumentAnalysisScope(_document, _span, analyzers, _analysisKind!.Value) + : null; - var (analysisResult, additionalPragmaSuppressionDiagnostics) = await compilationWithAnalyzers.GetAnalysisResultAsync( - documentAnalysisScope, _project, _analyzerInfoCache, cancellationToken).ConfigureAwait(false); + var (analysisResult, additionalPragmaSuppressionDiagnostics) = await compilationWithAnalyzers.GetAnalysisResultAsync( + documentAnalysisScope, _project, _analyzerInfoCache, cancellationToken).ConfigureAwait(false); - if (logPerformanceInfo && _performanceTracker != null) + if (logPerformanceInfo && _performanceTracker != null) + { + // Only log telemetry snapshot is we have an active telemetry session, + // i.e. user has not opted out of reporting telemetry. + var telemetryService = _hostWorkspaceServices.GetRequiredService(); + if (telemetryService.HasActiveSession) { - // Only log telemetry snapshot is we have an active telemetry session, - // i.e. user has not opted out of reporting telemetry. - var telemetryService = _hostWorkspaceServices.GetRequiredService(); - if (telemetryService.HasActiveSession) - { - // +1 to include project itself - var unitCount = 1; - if (documentAnalysisScope == null) - unitCount += _project.DocumentIds.Count; + // +1 to include project itself + var unitCount = 1; + if (documentAnalysisScope == null) + unitCount += _project.DocumentIds.Count; - _performanceTracker.AddSnapshot(analysisResult.AnalyzerTelemetryInfo.ToAnalyzerPerformanceInfo(_analyzerInfoCache), unitCount, forSpanAnalysis: _span.HasValue); - } + _performanceTracker.AddSnapshot(analysisResult.AnalyzerTelemetryInfo.ToAnalyzerPerformanceInfo(_analyzerInfoCache), unitCount, forSpanAnalysis: _span.HasValue); } + } - var builderMap = await analysisResult.ToResultBuilderMapAsync( - additionalPragmaSuppressionDiagnostics, documentAnalysisScope, - _project, VersionStamp.Default, compilationWithAnalyzers.Compilation, - analyzers, skippedAnalyzersInfo, reportSuppressedDiagnostics, cancellationToken).ConfigureAwait(false); + var builderMap = await analysisResult.ToResultBuilderMapAsync( + additionalPragmaSuppressionDiagnostics, documentAnalysisScope, + _project, VersionStamp.Default, compilationWithAnalyzers.Compilation, + analyzers, skippedAnalyzersInfo, reportSuppressedDiagnostics, cancellationToken).ConfigureAwait(false); - var telemetry = getTelemetryInfo - ? GetTelemetryInfo(analysisResult, analyzers, analyzerToIdMap) - : []; + var telemetry = getTelemetryInfo + ? GetTelemetryInfo(analysisResult, analyzers, analyzerToIdMap) + : []; - return new SerializableDiagnosticAnalysisResults(Dehydrate(builderMap, analyzerToIdMap), telemetry); - } + return new SerializableDiagnosticAnalysisResults(Dehydrate(builderMap, analyzerToIdMap), telemetry); + } + + private static ImmutableArray<(string analyzerId, SerializableDiagnosticMap diagnosticMap)> Dehydrate( + ImmutableDictionary builderMap, + BidirectionalMap analyzerToIdMap) + { + var diagnostics = new FixedSizeArrayBuilder<(string analyzerId, SerializableDiagnosticMap diagnosticMap)>(builderMap.Count); - private static ImmutableArray<(string analyzerId, SerializableDiagnosticMap diagnosticMap)> Dehydrate( - ImmutableDictionary builderMap, - BidirectionalMap analyzerToIdMap) + foreach (var (analyzer, analyzerResults) in builderMap) { - var diagnostics = new FixedSizeArrayBuilder<(string analyzerId, SerializableDiagnosticMap diagnosticMap)>(builderMap.Count); + var analyzerId = GetAnalyzerId(analyzerToIdMap, analyzer); + + diagnostics.Add((analyzerId, + new SerializableDiagnosticMap( + analyzerResults.SyntaxLocals.SelectAsArray(entry => (entry.Key, entry.Value)), + analyzerResults.SemanticLocals.SelectAsArray(entry => (entry.Key, entry.Value)), + analyzerResults.NonLocals.SelectAsArray(entry => (entry.Key, entry.Value)), + analyzerResults.Others))); + } - foreach (var (analyzer, analyzerResults) in builderMap) - { - var analyzerId = GetAnalyzerId(analyzerToIdMap, analyzer); + return diagnostics.MoveToImmutable(); + } - diagnostics.Add((analyzerId, - new SerializableDiagnosticMap( - analyzerResults.SyntaxLocals.SelectAsArray(entry => (entry.Key, entry.Value)), - analyzerResults.SemanticLocals.SelectAsArray(entry => (entry.Key, entry.Value)), - analyzerResults.NonLocals.SelectAsArray(entry => (entry.Key, entry.Value)), - analyzerResults.Others))); - } + private static ImmutableArray<(string analyzerId, AnalyzerTelemetryInfo)> GetTelemetryInfo( + AnalysisResult analysisResult, + ImmutableArray analyzers, + BidirectionalMap analyzerToIdMap) + { + Func shouldInclude; + if (analyzers.Length < analysisResult.AnalyzerTelemetryInfo.Count) + { + // Filter the telemetry info to the executed analyzers. + using var _1 = PooledHashSet.GetInstance(out var analyzersSet); + analyzersSet.AddRange(analyzers); - return diagnostics.MoveToImmutable(); + shouldInclude = analyzer => analyzersSet.Contains(analyzer); } - - private static ImmutableArray<(string analyzerId, AnalyzerTelemetryInfo)> GetTelemetryInfo( - AnalysisResult analysisResult, - ImmutableArray analyzers, - BidirectionalMap analyzerToIdMap) + else { - Func shouldInclude; - if (analyzers.Length < analysisResult.AnalyzerTelemetryInfo.Count) - { - // Filter the telemetry info to the executed analyzers. - using var _1 = PooledHashSet.GetInstance(out var analyzersSet); - analyzersSet.AddRange(analyzers); + shouldInclude = _ => true; + } - shouldInclude = analyzer => analyzersSet.Contains(analyzer); - } - else + using var _2 = ArrayBuilder<(string analyzerId, AnalyzerTelemetryInfo)>.GetInstance(out var telemetryBuilder); + foreach (var (analyzer, analyzerTelemetry) in analysisResult.AnalyzerTelemetryInfo) + { + if (shouldInclude(analyzer)) { - shouldInclude = _ => true; + var analyzerId = GetAnalyzerId(analyzerToIdMap, analyzer); + telemetryBuilder.Add((analyzerId, analyzerTelemetry)); } + } - using var _2 = ArrayBuilder<(string analyzerId, AnalyzerTelemetryInfo)>.GetInstance(out var telemetryBuilder); - foreach (var (analyzer, analyzerTelemetry) in analysisResult.AnalyzerTelemetryInfo) - { - if (shouldInclude(analyzer)) - { - var analyzerId = GetAnalyzerId(analyzerToIdMap, analyzer); - telemetryBuilder.Add((analyzerId, analyzerTelemetry)); - } - } + return telemetryBuilder.ToImmutableAndClear(); + } - return telemetryBuilder.ToImmutableAndClear(); - } + private static string GetAnalyzerId(BidirectionalMap analyzerMap, DiagnosticAnalyzer analyzer) + { + var analyzerId = analyzerMap.GetKeyOrDefault(analyzer); + Contract.ThrowIfNull(analyzerId); - private static string GetAnalyzerId(BidirectionalMap analyzerMap, DiagnosticAnalyzer analyzer) - { - var analyzerId = analyzerMap.GetKeyOrDefault(analyzer); - Contract.ThrowIfNull(analyzerId); + return analyzerId; + } - return analyzerId; - } + private static ImmutableArray GetAnalyzers(BidirectionalMap analyzerMap, IEnumerable analyzerIds) + { + // TODO: this probably need to be cached as well in analyzer service? + var builder = ImmutableArray.CreateBuilder(); - private static ImmutableArray GetAnalyzers(BidirectionalMap analyzerMap, IEnumerable analyzerIds) + foreach (var analyzerId in analyzerIds) { - // TODO: this probably need to be cached as well in analyzer service? - var builder = ImmutableArray.CreateBuilder(); - - foreach (var analyzerId in analyzerIds) + if (analyzerMap.TryGetValue(analyzerId, out var analyzer)) { - if (analyzerMap.TryGetValue(analyzerId, out var analyzer)) - { - builder.Add(analyzer); - } + builder.Add(analyzer); } - - return builder.ToImmutableAndClear(); } - private async Task<(CompilationWithAnalyzers? compilationWithAnalyzers, BidirectionalMap analyzerToIdMap)> GetOrCreateCompilationWithAnalyzersAsync(CancellationToken cancellationToken) - { - var cacheEntry = await GetOrCreateCacheEntryAsync().ConfigureAwait(false); - return (cacheEntry.CompilationWithAnalyzers, cacheEntry.AnalyzerToIdMap); + return builder.ToImmutableAndClear(); + } + + private async Task<(CompilationWithAnalyzers? compilationWithAnalyzers, BidirectionalMap analyzerToIdMap)> GetOrCreateCompilationWithAnalyzersAsync(CancellationToken cancellationToken) + { + var cacheEntry = await GetOrCreateCacheEntryAsync().ConfigureAwait(false); + return (cacheEntry.CompilationWithAnalyzers, cacheEntry.AnalyzerToIdMap); - async Task GetOrCreateCacheEntryAsync() + async Task GetOrCreateCacheEntryAsync() + { + if (_document == null) { - if (_document == null) - { - // Only use cache for document analysis. - return await CreateCompilationWithAnalyzersCacheEntryAsync(cancellationToken).ConfigureAwait(false); - } + // Only use cache for document analysis. + return await CreateCompilationWithAnalyzersCacheEntryAsync(cancellationToken).ConfigureAwait(false); + } - lock (s_gate) + lock (s_gate) + { + if (s_compilationWithAnalyzersCache?.SolutionChecksum == _solutionChecksum && + s_compilationWithAnalyzersCache.Project == _project) { - if (s_compilationWithAnalyzersCache?.SolutionChecksum == _solutionChecksum && - s_compilationWithAnalyzersCache.Project == _project) - { - return s_compilationWithAnalyzersCache; - } + return s_compilationWithAnalyzersCache; } + } - var entry = await CreateCompilationWithAnalyzersCacheEntryAsync(cancellationToken).ConfigureAwait(false); + var entry = await CreateCompilationWithAnalyzersCacheEntryAsync(cancellationToken).ConfigureAwait(false); - lock (s_gate) - { - s_compilationWithAnalyzersCache = entry; - } - - return entry; + lock (s_gate) + { + s_compilationWithAnalyzersCache = entry; } + + return entry; } + } - private async Task CreateCompilationWithAnalyzersCacheEntryAsync(CancellationToken cancellationToken) + private async Task CreateCompilationWithAnalyzersCacheEntryAsync(CancellationToken cancellationToken) + { + // We could consider creating a service so that we don't do this repeatedly if this shows up as perf cost + using var pooledObject = SharedPools.Default>().GetPooledObject(); + using var pooledMap = SharedPools.Default>().GetPooledObject(); + var referenceSet = pooledObject.Object; + var analyzerMapBuilder = pooledMap.Object; + + // This follows what we do in DiagnosticAnalyzerInfoCache.CheckAnalyzerReferenceIdentity + using var _ = ArrayBuilder.GetInstance(out var analyzerBuilder); + foreach (var reference in _project.Solution.AnalyzerReferences.Concat(_project.AnalyzerReferences)) { - // We could consider creating a service so that we don't do this repeatedly if this shows up as perf cost - using var pooledObject = SharedPools.Default>().GetPooledObject(); - using var pooledMap = SharedPools.Default>().GetPooledObject(); - var referenceSet = pooledObject.Object; - var analyzerMapBuilder = pooledMap.Object; - - // This follows what we do in DiagnosticAnalyzerInfoCache.CheckAnalyzerReferenceIdentity - using var _ = ArrayBuilder.GetInstance(out var analyzerBuilder); - foreach (var reference in _project.Solution.AnalyzerReferences.Concat(_project.AnalyzerReferences)) + if (!referenceSet.Add(reference.Id)) { - if (!referenceSet.Add(reference.Id)) - { - continue; - } - - var analyzers = reference.GetAnalyzers(_project.Language); - analyzerBuilder.AddRange(analyzers); - analyzerMapBuilder.AppendAnalyzerMap(analyzers); + continue; } - var compilationWithAnalyzers = analyzerBuilder.Count > 0 - ? await CreateCompilationWithAnalyzerAsync(analyzerBuilder.ToImmutable(), cancellationToken).ConfigureAwait(false) - : null; - var analyzerToIdMap = new BidirectionalMap(analyzerMapBuilder); - - return new CompilationWithAnalyzersCacheEntry(_solutionChecksum, _project, compilationWithAnalyzers, analyzerToIdMap); + var analyzers = reference.GetAnalyzers(_project.Language); + analyzerBuilder.AddRange(analyzers); + analyzerMapBuilder.AppendAnalyzerMap(analyzers); } - private async Task CreateCompilationWithAnalyzerAsync(ImmutableArray analyzers, CancellationToken cancellationToken) - { - Contract.ThrowIfFalse(!analyzers.IsEmpty); - - // Always run analyzers concurrently in OOP - const bool concurrentAnalysis = true; - - // Get original compilation - var compilation = await _project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - - // Fork compilation with concurrent build. this is okay since WithAnalyzers will fork compilation - // anyway to attach event queue. This should make compiling compilation concurrent and make things - // faster - compilation = compilation.WithOptions(compilation.Options.WithConcurrentBuild(concurrentAnalysis)); - - // Run analyzers concurrently, with performance logging and reporting suppressed diagnostics. - // This allows all client requests with or without performance data and/or suppressed diagnostics to be satisfied. - // TODO: can we support analyzerExceptionFilter in remote host? - // right now, host doesn't support watson, we might try to use new NonFatal watson API? - var analyzerOptions = new CompilationWithAnalyzersOptions( - options: _project.AnalyzerOptions, - onAnalyzerException: null, - analyzerExceptionFilter: null, - concurrentAnalysis: concurrentAnalysis, - logAnalyzerExecutionTime: true, - reportSuppressedDiagnostics: true); - - return compilation.WithAnalyzers(analyzers, analyzerOptions); - } + var compilationWithAnalyzers = analyzerBuilder.Count > 0 + ? await CreateCompilationWithAnalyzerAsync(analyzerBuilder.ToImmutable(), cancellationToken).ConfigureAwait(false) + : null; + var analyzerToIdMap = new BidirectionalMap(analyzerMapBuilder); - private sealed class CompilationWithAnalyzersCacheEntry - { - public Checksum SolutionChecksum { get; } - public Project Project { get; } - public CompilationWithAnalyzers? CompilationWithAnalyzers { get; } - public BidirectionalMap AnalyzerToIdMap { get; } + return new CompilationWithAnalyzersCacheEntry(_solutionChecksum, _project, compilationWithAnalyzers, analyzerToIdMap); + } - public CompilationWithAnalyzersCacheEntry(Checksum solutionChecksum, Project project, CompilationWithAnalyzers? compilationWithAnalyzers, BidirectionalMap analyzerToIdMap) - { - SolutionChecksum = solutionChecksum; - Project = project; - CompilationWithAnalyzers = compilationWithAnalyzers; - AnalyzerToIdMap = analyzerToIdMap; - } + private async Task CreateCompilationWithAnalyzerAsync(ImmutableArray analyzers, CancellationToken cancellationToken) + { + Contract.ThrowIfFalse(!analyzers.IsEmpty); + + // Always run analyzers concurrently in OOP + const bool concurrentAnalysis = true; + + // Get original compilation + var compilation = await _project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); + + // Fork compilation with concurrent build. this is okay since WithAnalyzers will fork compilation + // anyway to attach event queue. This should make compiling compilation concurrent and make things + // faster + compilation = compilation.WithOptions(compilation.Options.WithConcurrentBuild(concurrentAnalysis)); + + // Run analyzers concurrently, with performance logging and reporting suppressed diagnostics. + // This allows all client requests with or without performance data and/or suppressed diagnostics to be satisfied. + // TODO: can we support analyzerExceptionFilter in remote host? + // right now, host doesn't support watson, we might try to use new NonFatal watson API? + var analyzerOptions = new CompilationWithAnalyzersOptions( + options: _project.AnalyzerOptions, + onAnalyzerException: null, + analyzerExceptionFilter: null, + concurrentAnalysis: concurrentAnalysis, + logAnalyzerExecutionTime: true, + reportSuppressedDiagnostics: true); + + return compilation.WithAnalyzers(analyzers, analyzerOptions); + } + + private sealed class CompilationWithAnalyzersCacheEntry + { + public Checksum SolutionChecksum { get; } + public Project Project { get; } + public CompilationWithAnalyzers? CompilationWithAnalyzers { get; } + public BidirectionalMap AnalyzerToIdMap { get; } + + public CompilationWithAnalyzersCacheEntry(Checksum solutionChecksum, Project project, CompilationWithAnalyzers? compilationWithAnalyzers, BidirectionalMap analyzerToIdMap) + { + SolutionChecksum = solutionChecksum; + Project = project; + CompilationWithAnalyzers = compilationWithAnalyzers; + AnalyzerToIdMap = analyzerToIdMap; } } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/IPerformanceTrackerService.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/IPerformanceTrackerService.cs index 0f95166236b46..5b4c5c34b3a81 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/IPerformanceTrackerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/IPerformanceTrackerService.cs @@ -7,33 +7,32 @@ using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; -namespace Microsoft.CodeAnalysis.Remote.Diagnostics -{ - internal interface IPerformanceTrackerService : IWorkspaceService - { - void AddSnapshot(IEnumerable snapshot, int unitCount, bool forSpanAnalysis); - void GenerateReport(List analyzerInfos, bool forSpanAnalysis); +namespace Microsoft.CodeAnalysis.Remote.Diagnostics; - event EventHandler SnapshotAdded; - } +internal interface IPerformanceTrackerService : IWorkspaceService +{ + void AddSnapshot(IEnumerable snapshot, int unitCount, bool forSpanAnalysis); + void GenerateReport(List analyzerInfos, bool forSpanAnalysis); - internal readonly struct AnalyzerInfoForPerformanceReporting - { - public readonly bool BuiltIn; - public readonly string AnalyzerId; - public readonly string AnalyzerIdHash; - public readonly double Average; - public readonly double AdjustedStandardDeviation; + event EventHandler SnapshotAdded; +} - public AnalyzerInfoForPerformanceReporting(bool builtIn, string analyzerId, double average, double stddev) : this() - { - BuiltIn = builtIn; - AnalyzerId = analyzerId; - AnalyzerIdHash = analyzerId.GetHashCode().ToString(); - Average = average; - AdjustedStandardDeviation = stddev; - } +internal readonly struct AnalyzerInfoForPerformanceReporting +{ + public readonly bool BuiltIn; + public readonly string AnalyzerId; + public readonly string AnalyzerIdHash; + public readonly double Average; + public readonly double AdjustedStandardDeviation; - public string PIISafeAnalyzerId => BuiltIn ? AnalyzerId : AnalyzerIdHash; + public AnalyzerInfoForPerformanceReporting(bool builtIn, string analyzerId, double average, double stddev) : this() + { + BuiltIn = builtIn; + AnalyzerId = analyzerId; + AnalyzerIdHash = analyzerId.GetHashCode().ToString(); + Average = average; + AdjustedStandardDeviation = stddev; } + + public string PIISafeAnalyzerId => BuiltIn ? AnalyzerId : AnalyzerIdHash; } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs index b94154fa9901f..633ff4bc2f275 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceQueue.cs @@ -10,228 +10,227 @@ using Microsoft.CodeAnalysis.Diagnostics; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote.Diagnostics +namespace Microsoft.CodeAnalysis.Remote.Diagnostics; + +/// +/// This queue hold onto raw performance data. this type itself is not thread safe. the one who uses this type +/// should take care of that. +/// +/// +internal class PerformanceQueue { - /// - /// This queue hold onto raw performance data. this type itself is not thread safe. the one who uses this type - /// should take care of that. - /// - /// - internal class PerformanceQueue + private readonly int _maxSampleSize, _minSampleSize; + private readonly LinkedList _snapshots; + + private int _snapshotsSinceLastReport; + + public PerformanceQueue(int minSampleSize) { - private readonly int _maxSampleSize, _minSampleSize; - private readonly LinkedList _snapshots; + // We allow at most 3 times the number of samples in the queue and + // use sliding window algorithm to choose the latest 'minSampleSize' samples. + _maxSampleSize = minSampleSize * 3; - private int _snapshotsSinceLastReport; + _minSampleSize = minSampleSize; + _snapshots = new LinkedList(); + _snapshotsSinceLastReport = 0; + } - public PerformanceQueue(int minSampleSize) + public int Count => _snapshots.Count; + public void Add(IEnumerable<(string analyzerId, TimeSpan timeSpan)> rawData, int unitCount) + { + if (_snapshots.Count < _maxSampleSize) { - // We allow at most 3 times the number of samples in the queue and - // use sliding window algorithm to choose the latest 'minSampleSize' samples. - _maxSampleSize = minSampleSize * 3; - - _minSampleSize = minSampleSize; - _snapshots = new LinkedList(); - _snapshotsSinceLastReport = 0; + _snapshots.AddLast(new Snapshot(rawData, unitCount)); } - - public int Count => _snapshots.Count; - public void Add(IEnumerable<(string analyzerId, TimeSpan timeSpan)> rawData, int unitCount) + else { - if (_snapshots.Count < _maxSampleSize) - { - _snapshots.AddLast(new Snapshot(rawData, unitCount)); - } - else - { - // remove the first one - var first = _snapshots.First; - _snapshots.RemoveFirst(); - - // update data to new data and put it back - first.Value.Update(rawData, unitCount); - _snapshots.AddLast(first); - } + // remove the first one + var first = _snapshots.First; + _snapshots.RemoveFirst(); - _snapshotsSinceLastReport++; + // update data to new data and put it back + first.Value.Update(rawData, unitCount); + _snapshots.AddLast(first); } - public void GetPerformanceData(List<(string analyzerId, double average, double stddev)> aggregatedPerformanceDataPerAnalyzer) + _snapshotsSinceLastReport++; + } + + public void GetPerformanceData(List<(string analyzerId, double average, double stddev)> aggregatedPerformanceDataPerAnalyzer) + { + if (_snapshotsSinceLastReport < _minSampleSize) { - if (_snapshotsSinceLastReport < _minSampleSize) - { - // we don't have enough data to report this - return; - } + // we don't have enough data to report this + return; + } - _snapshotsSinceLastReport = 0; + _snapshotsSinceLastReport = 0; - using var pooledMap = SharedPools.Default>().GetPooledObject(); - using var pooledSet = SharedPools.Default>().GetPooledObject(); - using var pooledList = SharedPools.Default>().GetPooledObject(); + using var pooledMap = SharedPools.Default>().GetPooledObject(); + using var pooledSet = SharedPools.Default>().GetPooledObject(); + using var pooledList = SharedPools.Default>().GetPooledObject(); - var reverseMap = pooledMap.Object; - AnalyzerNumberAssigner.Instance.GetReverseMap(reverseMap); + var reverseMap = pooledMap.Object; + AnalyzerNumberAssigner.Instance.GetReverseMap(reverseMap); - var analyzerSet = pooledSet.Object; + var analyzerSet = pooledSet.Object; - // get all analyzers - foreach (var snapshot in _snapshots) - { - snapshot.AppendAnalyzers(analyzerSet); - } + // get all analyzers + foreach (var snapshot in _snapshots) + { + snapshot.AppendAnalyzers(analyzerSet); + } - var list = pooledList.Object; + var list = pooledList.Object; - // calculate aggregated data per analyzer - foreach (var assignedAnalyzerNumber in analyzerSet) + // calculate aggregated data per analyzer + foreach (var assignedAnalyzerNumber in analyzerSet) + { + foreach (var snapshot in _snapshots) { - foreach (var snapshot in _snapshots) - { - var timeSpan = snapshot.GetTimeSpanInMillisecond(assignedAnalyzerNumber); - if (timeSpan == null) - { - // not all snapshot contains all analyzers - continue; - } - - list.Add(timeSpan.Value); - } - - // data is only stable once we have more than certain set - // of samples - if (list.Count < _minSampleSize) + var timeSpan = snapshot.GetTimeSpanInMillisecond(assignedAnalyzerNumber); + if (timeSpan == null) { + // not all snapshot contains all analyzers continue; } - // set performance data - var analyzerId = reverseMap[assignedAnalyzerNumber]; - var (average, stddev) = GetAverageAndAdjustedStandardDeviation(list); - aggregatedPerformanceDataPerAnalyzer.Add((analyzerId, average, stddev)); + list.Add(timeSpan.Value); + } - list.Clear(); + // data is only stable once we have more than certain set + // of samples + if (list.Count < _minSampleSize) + { + continue; } - } - private static (double average, double stddev) GetAverageAndAdjustedStandardDeviation(List data) - { - var average = data.Average(); - var stddev = Math.Sqrt(data.Select(ms => Math.Pow(ms - average, 2)).Average()); - var squareLength = Math.Sqrt(data.Count); + // set performance data + var analyzerId = reverseMap[assignedAnalyzerNumber]; + var (average, stddev) = GetAverageAndAdjustedStandardDeviation(list); + aggregatedPerformanceDataPerAnalyzer.Add((analyzerId, average, stddev)); - return (average, stddev / squareLength); + list.Clear(); } + } - private class Snapshot - { - /// - /// Raw performance data. - /// Keyed by analyzer unique number got from AnalyzerNumberAssigner. - /// Value is delta (TimeSpan - minSpan) among span in this snapshot - /// - private readonly Dictionary _performanceMap; - - public Snapshot(IEnumerable<(string analyzerId, TimeSpan timeSpan)> snapshot, int unitCount) - : this(Convert(snapshot), unitCount) - { - } - - public Snapshot(IEnumerable<(int assignedAnalyzerNumber, TimeSpan timeSpan)> rawData, int unitCount) - { - _performanceMap = []; + private static (double average, double stddev) GetAverageAndAdjustedStandardDeviation(List data) + { + var average = data.Average(); + var stddev = Math.Sqrt(data.Select(ms => Math.Pow(ms - average, 2)).Average()); + var squareLength = Math.Sqrt(data.Count); - Reset(_performanceMap, rawData, unitCount); - } + return (average, stddev / squareLength); + } - public void Update(IEnumerable<(string analyzerId, TimeSpan timeSpan)> rawData, int unitCount) - => Reset(_performanceMap, Convert(rawData), unitCount); + private class Snapshot + { + /// + /// Raw performance data. + /// Keyed by analyzer unique number got from AnalyzerNumberAssigner. + /// Value is delta (TimeSpan - minSpan) among span in this snapshot + /// + private readonly Dictionary _performanceMap; - public void AppendAnalyzers(HashSet analyzerSet) - => analyzerSet.UnionWith(_performanceMap.Keys); + public Snapshot(IEnumerable<(string analyzerId, TimeSpan timeSpan)> snapshot, int unitCount) + : this(Convert(snapshot), unitCount) + { + } - public double? GetTimeSpanInMillisecond(int assignedAnalyzerNumber) - { - if (!_performanceMap.TryGetValue(assignedAnalyzerNumber, out var value)) - { - return null; - } + public Snapshot(IEnumerable<(int assignedAnalyzerNumber, TimeSpan timeSpan)> rawData, int unitCount) + { + _performanceMap = []; - return value; - } + Reset(_performanceMap, rawData, unitCount); + } - private static void Reset( - Dictionary map, IEnumerable<(int assignedAnalyzerNumber, TimeSpan timeSpan)> rawData, int fileCount) - { - // get smallest timespan in the snapshot - var minSpan = rawData.Select(kv => kv.timeSpan).Min(); + public void Update(IEnumerable<(string analyzerId, TimeSpan timeSpan)> rawData, int unitCount) + => Reset(_performanceMap, Convert(rawData), unitCount); - // for now, we just clear the map, if reusing dictionary blindly became an issue due to - // dictionary grew too big, then we need to do a bit more work to determine such case - // and re-create new dictionary - map.Clear(); + public void AppendAnalyzers(HashSet analyzerSet) + => analyzerSet.UnionWith(_performanceMap.Keys); - // map is normalized to current timespan - min timspan of the snapshot - foreach (var (assignedAnalyzerNumber, timeSpan) in rawData) - { - map[assignedAnalyzerNumber] = (timeSpan.TotalMilliseconds - minSpan.TotalMilliseconds) / fileCount; - } + public double? GetTimeSpanInMillisecond(int assignedAnalyzerNumber) + { + if (!_performanceMap.TryGetValue(assignedAnalyzerNumber, out var value)) + { + return null; } - private static IEnumerable<(int assignedAnalyzerNumber, TimeSpan timeSpan)> Convert(IEnumerable<(string analyzerId, TimeSpan timeSpan)> rawData) - => rawData.Select(kv => (AnalyzerNumberAssigner.Instance.GetUniqueNumber(kv.analyzerId), kv.timeSpan)); + return value; } - /// - /// Assign unique number to diagnostic analyzers - /// - private class AnalyzerNumberAssigner + private static void Reset( + Dictionary map, IEnumerable<(int assignedAnalyzerNumber, TimeSpan timeSpan)> rawData, int fileCount) { - public static readonly AnalyzerNumberAssigner Instance = new AnalyzerNumberAssigner(); + // get smallest timespan in the snapshot + var minSpan = rawData.Select(kv => kv.timeSpan).Min(); - private int _currentId; + // for now, we just clear the map, if reusing dictionary blindly became an issue due to + // dictionary grew too big, then we need to do a bit more work to determine such case + // and re-create new dictionary + map.Clear(); - // use simple approach for now. we don't expect it to grow too much. so entry added - // won't be removed until process goes away - private readonly Dictionary _idMap; - - private AnalyzerNumberAssigner() + // map is normalized to current timespan - min timspan of the snapshot + foreach (var (assignedAnalyzerNumber, timeSpan) in rawData) { - _currentId = 0; - _idMap = []; + map[assignedAnalyzerNumber] = (timeSpan.TotalMilliseconds - minSpan.TotalMilliseconds) / fileCount; } + } + + private static IEnumerable<(int assignedAnalyzerNumber, TimeSpan timeSpan)> Convert(IEnumerable<(string analyzerId, TimeSpan timeSpan)> rawData) + => rawData.Select(kv => (AnalyzerNumberAssigner.Instance.GetUniqueNumber(kv.analyzerId), kv.timeSpan)); + } + + /// + /// Assign unique number to diagnostic analyzers + /// + private class AnalyzerNumberAssigner + { + public static readonly AnalyzerNumberAssigner Instance = new AnalyzerNumberAssigner(); + + private int _currentId; + + // use simple approach for now. we don't expect it to grow too much. so entry added + // won't be removed until process goes away + private readonly Dictionary _idMap; - public int GetUniqueNumber(DiagnosticAnalyzer analyzer) - => GetUniqueNumber(analyzer.GetAnalyzerId()); + private AnalyzerNumberAssigner() + { + _currentId = 0; + _idMap = []; + } + + public int GetUniqueNumber(DiagnosticAnalyzer analyzer) + => GetUniqueNumber(analyzer.GetAnalyzerId()); - public int GetUniqueNumber(string analyzerName) + public int GetUniqueNumber(string analyzerName) + { + // 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) { - // 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) + if (!_idMap.TryGetValue(analyzerName, out var id)) { - if (!_idMap.TryGetValue(analyzerName, out var id)) - { - id = _currentId++; - _idMap.Add(analyzerName, id); - } - - return id; + id = _currentId++; + _idMap.Add(analyzerName, id); } + + return id; } + } - public void GetReverseMap(Dictionary reverseMap) - { - reverseMap.Clear(); + public void GetReverseMap(Dictionary reverseMap) + { + reverseMap.Clear(); - // 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) + // 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) + { + foreach (var kv in _idMap) { - foreach (var kv in _idMap) - { - reverseMap.Add(kv.Value, kv.Key); - } + reverseMap.Add(kv.Value, kv.Key); } } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceTrackerService.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceTrackerService.cs index e92727790e6f9..139d4c086e0d4 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceTrackerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceTrackerService.cs @@ -16,162 +16,161 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Telemetry; -namespace Microsoft.CodeAnalysis.Remote.Diagnostics +namespace Microsoft.CodeAnalysis.Remote.Diagnostics; + +/// +/// Track diagnostic performance +/// +[ExportWorkspaceService(typeof(IPerformanceTrackerService), [WorkspaceKind.RemoteWorkspace]), Shared] +internal class PerformanceTrackerService : IPerformanceTrackerService { - /// - /// Track diagnostic performance - /// - [ExportWorkspaceService(typeof(IPerformanceTrackerService), [WorkspaceKind.RemoteWorkspace]), Shared] - internal class PerformanceTrackerService : IPerformanceTrackerService + // We require at least 100 samples for background document analysis result to be stable. + private const int MinSampleSizeForDocumentAnalysis = 100; + // We require at least 20 samples for span/lightbulb analysis result to be stable. + // Note that each lightbulb invocation produces 4 samples, one for each of the below diagnostic computaion: + // 1. Compiler syntax diagnostics + // 2. Analyzer syntax diagnostics + // 3. Compiler semantic diagnostics + // 4. Analyzer semantic diagnostics + private const int MinSampleSizeForSpanAnalysis = 20; + + private static readonly Func, int, bool, string> s_snapshotLogger = SnapshotLogger; + + private readonly PerformanceQueue _queueForDocumentAnalysis, _queueForSpanAnalysis; + private readonly ConcurrentDictionary _builtInMap = new ConcurrentDictionary(concurrencyLevel: 2, capacity: 10); + + public event EventHandler SnapshotAdded; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public PerformanceTrackerService() + : this(MinSampleSizeForDocumentAnalysis, MinSampleSizeForSpanAnalysis) { - // We require at least 100 samples for background document analysis result to be stable. - private const int MinSampleSizeForDocumentAnalysis = 100; - // We require at least 20 samples for span/lightbulb analysis result to be stable. - // Note that each lightbulb invocation produces 4 samples, one for each of the below diagnostic computaion: - // 1. Compiler syntax diagnostics - // 2. Analyzer syntax diagnostics - // 3. Compiler semantic diagnostics - // 4. Analyzer semantic diagnostics - private const int MinSampleSizeForSpanAnalysis = 20; - - private static readonly Func, int, bool, string> s_snapshotLogger = SnapshotLogger; - - private readonly PerformanceQueue _queueForDocumentAnalysis, _queueForSpanAnalysis; - private readonly ConcurrentDictionary _builtInMap = new ConcurrentDictionary(concurrencyLevel: 2, capacity: 10); - - public event EventHandler SnapshotAdded; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public PerformanceTrackerService() - : this(MinSampleSizeForDocumentAnalysis, MinSampleSizeForSpanAnalysis) - { - } + } - // internal for testing - [SuppressMessage("RoslynDiagnosticsReliability", "RS0034:Exported parts should have [ImportingConstructor]", Justification = "Used incorrectly by tests")] - internal PerformanceTrackerService(int minSampleSizeForDocumentAnalysis, int minSampleSizeForSpanAnalysis) - { - _queueForDocumentAnalysis = new PerformanceQueue(minSampleSizeForDocumentAnalysis); + // internal for testing + [SuppressMessage("RoslynDiagnosticsReliability", "RS0034:Exported parts should have [ImportingConstructor]", Justification = "Used incorrectly by tests")] + internal PerformanceTrackerService(int minSampleSizeForDocumentAnalysis, int minSampleSizeForSpanAnalysis) + { + _queueForDocumentAnalysis = new PerformanceQueue(minSampleSizeForDocumentAnalysis); - _queueForSpanAnalysis = new PerformanceQueue(minSampleSizeForSpanAnalysis); - } + _queueForSpanAnalysis = new PerformanceQueue(minSampleSizeForSpanAnalysis); + } - private PerformanceQueue GetQueue(bool forSpanAnalysis) - => forSpanAnalysis ? _queueForSpanAnalysis : _queueForDocumentAnalysis; + private PerformanceQueue GetQueue(bool forSpanAnalysis) + => forSpanAnalysis ? _queueForSpanAnalysis : _queueForDocumentAnalysis; - public void AddSnapshot(IEnumerable snapshot, int unitCount, bool forSpanAnalysis) + public void AddSnapshot(IEnumerable snapshot, int unitCount, bool forSpanAnalysis) + { + foreach (var perfInfo in snapshot) { - foreach (var perfInfo in snapshot) - { - const int PerformAnalysisTelemetryDelay = 250; + const int PerformAnalysisTelemetryDelay = 250; - var delay = (int)perfInfo.TimeSpan.TotalMilliseconds; + var delay = (int)perfInfo.TimeSpan.TotalMilliseconds; - TelemetryLogging.LogAggregated(FunctionId.PerformAnalysis_Summary, $"IndividualTimes", delay); + TelemetryLogging.LogAggregated(FunctionId.PerformAnalysis_Summary, $"IndividualTimes", delay); - if (delay > PerformAnalysisTelemetryDelay) - { - const string AnalyzerId = nameof(AnalyzerId); - const string Delay = nameof(Delay); - const string ForSpanAnalysis = nameof(ForSpanAnalysis); + if (delay > PerformAnalysisTelemetryDelay) + { + const string AnalyzerId = nameof(AnalyzerId); + const string Delay = nameof(Delay); + const string ForSpanAnalysis = nameof(ForSpanAnalysis); - var analyzerId = perfInfo.BuiltIn ? perfInfo.AnalyzerId : perfInfo.BuiltIn.GetHashCode().ToString(); + var analyzerId = perfInfo.BuiltIn ? perfInfo.AnalyzerId : perfInfo.BuiltIn.GetHashCode().ToString(); - var logMessage = KeyValueLogMessage.Create(m => - { - m[AnalyzerId] = analyzerId; - m[Delay] = delay; - m[ForSpanAnalysis] = forSpanAnalysis; - }); + var logMessage = KeyValueLogMessage.Create(m => + { + m[AnalyzerId] = analyzerId; + m[Delay] = delay; + m[ForSpanAnalysis] = forSpanAnalysis; + }); - TelemetryLogging.Log(FunctionId.PerformAnalysis_Delay, logMessage); - } + TelemetryLogging.Log(FunctionId.PerformAnalysis_Delay, logMessage); } + } - Logger.Log(FunctionId.PerformanceTrackerService_AddSnapshot, s_snapshotLogger, snapshot, unitCount, forSpanAnalysis); - - RecordBuiltInAnalyzers(snapshot); + Logger.Log(FunctionId.PerformanceTrackerService_AddSnapshot, s_snapshotLogger, snapshot, unitCount, forSpanAnalysis); - var queue = GetQueue(forSpanAnalysis); - lock (queue) - { - queue.Add(snapshot.Select(entry => (entry.AnalyzerId, entry.TimeSpan)), unitCount); - } + RecordBuiltInAnalyzers(snapshot); - OnSnapshotAdded(); + var queue = GetQueue(forSpanAnalysis); + lock (queue) + { + queue.Add(snapshot.Select(entry => (entry.AnalyzerId, entry.TimeSpan)), unitCount); } - public void GenerateReport(List analyzerInfos, bool forSpanAnalysis) - { - using var pooledRaw = SharedPools.Default>().GetPooledObject(); + OnSnapshotAdded(); + } - var rawPerformanceData = pooledRaw.Object; + public void GenerateReport(List analyzerInfos, bool forSpanAnalysis) + { + using var pooledRaw = SharedPools.Default>().GetPooledObject(); - var queue = GetQueue(forSpanAnalysis); - lock (queue) - { - // first get raw aggregated peformance data from the queue - queue.GetPerformanceData(rawPerformanceData); - } + var rawPerformanceData = pooledRaw.Object; - // make sure there are some data - if (rawPerformanceData.Count == 0) - { - return; - } - - foreach (var (analyzerId, average, stddev) in rawPerformanceData.OrderByDescending(k => k.average)) - { - analyzerInfos.Add(new AnalyzerInfoForPerformanceReporting(AllowTelemetry(analyzerId), analyzerId, average, stddev)); - } + var queue = GetQueue(forSpanAnalysis); + lock (queue) + { + // first get raw aggregated peformance data from the queue + queue.GetPerformanceData(rawPerformanceData); } - private void RecordBuiltInAnalyzers(IEnumerable snapshot) + // make sure there are some data + if (rawPerformanceData.Count == 0) { - foreach (var entry in snapshot) - { - _builtInMap[entry.AnalyzerId] = entry.BuiltIn; - } + return; } - private bool AllowTelemetry(string analyzerId) + foreach (var (analyzerId, average, stddev) in rawPerformanceData.OrderByDescending(k => k.average)) { - if (_builtInMap.TryGetValue(analyzerId, out var builtIn)) - { - return builtIn; - } - - return false; + analyzerInfos.Add(new AnalyzerInfoForPerformanceReporting(AllowTelemetry(analyzerId), analyzerId, average, stddev)); } + } - private void OnSnapshotAdded() - => SnapshotAdded?.Invoke(this, EventArgs.Empty); + private void RecordBuiltInAnalyzers(IEnumerable snapshot) + { + foreach (var entry in snapshot) + { + _builtInMap[entry.AnalyzerId] = entry.BuiltIn; + } + } - private static string SnapshotLogger(IEnumerable snapshots, int unitCount, bool forSpan) + private bool AllowTelemetry(string analyzerId) + { + if (_builtInMap.TryGetValue(analyzerId, out var builtIn)) { - using var pooledObject = SharedPools.Default().GetPooledObject(); - var sb = pooledObject.Object; + return builtIn; + } - sb.Append(unitCount); + return false; + } - sb.Append('('); - sb.Append(forSpan ? "SpanAnalysis" : "DocumentAnalysis"); - sb.Append(')'); + private void OnSnapshotAdded() + => SnapshotAdded?.Invoke(this, EventArgs.Empty); - foreach (var snapshot in snapshots) - { - sb.Append('|'); - sb.Append(snapshot.AnalyzerId); - sb.Append(':'); - sb.Append(snapshot.BuiltIn); - sb.Append(':'); - sb.Append(snapshot.TimeSpan.TotalMilliseconds); - } + private static string SnapshotLogger(IEnumerable snapshots, int unitCount, bool forSpan) + { + using var pooledObject = SharedPools.Default().GetPooledObject(); + var sb = pooledObject.Object; + + sb.Append(unitCount); - sb.Append('*'); + sb.Append('('); + sb.Append(forSpan ? "SpanAnalysis" : "DocumentAnalysis"); + sb.Append(')'); - return sb.ToString(); + foreach (var snapshot in snapshots) + { + sb.Append('|'); + sb.Append(snapshot.AnalyzerId); + sb.Append(':'); + sb.Append(snapshot.BuiltIn); + sb.Append(':'); + sb.Append(snapshot.TimeSpan.TotalMilliseconds); } + + sb.Append('*'); + + return sb.ToString(); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs index 9cad9fa322c98..3d2715001f177 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DiagnosticAnalyzer/RemoteDiagnosticAnalyzerService.cs @@ -17,113 +17,112 @@ using Roslyn.Utilities; using RoslynLogger = Microsoft.CodeAnalysis.Internal.Log.Logger; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteDiagnosticAnalyzerService : BrokeredServiceBase, IRemoteDiagnosticAnalyzerService { - internal sealed class RemoteDiagnosticAnalyzerService : BrokeredServiceBase, IRemoteDiagnosticAnalyzerService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteDiagnosticAnalyzerService CreateService(in ServiceConstructionArguments arguments) - => new RemoteDiagnosticAnalyzerService(arguments); - } - - private readonly DiagnosticAnalyzerInfoCache _analyzerInfoCache = new(); + protected override IRemoteDiagnosticAnalyzerService CreateService(in ServiceConstructionArguments arguments) + => new RemoteDiagnosticAnalyzerService(arguments); + } - public RemoteDiagnosticAnalyzerService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } + private readonly DiagnosticAnalyzerInfoCache _analyzerInfoCache = new(); - /// - /// Calculate diagnostics. this works differently than other ones such as todo comments or designer attribute scanner - /// since in proc and out of proc runs quite differently due to concurrency and due to possible amount of data - /// that needs to pass through between processes - /// - public async ValueTask CalculateDiagnosticsAsync(Checksum solutionChecksum, DiagnosticArguments arguments, CancellationToken cancellationToken) - { - // Complete RPC right away so the client can start reading from the stream. - // The fire-and forget task starts writing to the output stream and the client will read it until it reads all expected data. + public RemoteDiagnosticAnalyzerService(in ServiceConstructionArguments arguments) + : base(arguments) + { + } - using (TelemetryLogging.LogBlockTimeAggregated(FunctionId.PerformAnalysis_Summary, $"Total")) - using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_CalculateDiagnosticsAsync, arguments.ProjectId.DebugName, cancellationToken)) - { - return await RunWithSolutionAsync( - solutionChecksum, - async solution => - { - var documentId = arguments.DocumentId; - var projectId = arguments.ProjectId; - var project = solution.GetRequiredProject(projectId); - var document = arguments.DocumentId != null - ? solution.GetTextDocument(arguments.DocumentId) ?? await solution.GetSourceGeneratedDocumentAsync(arguments.DocumentId, cancellationToken).ConfigureAwait(false) - : null; - var documentSpan = arguments.DocumentSpan; - var documentAnalysisKind = arguments.DocumentAnalysisKind; - var hostWorkspaceServices = this.GetWorkspace().Services; - - var result = await DiagnosticComputer.GetDiagnosticsAsync( - document, project, solutionChecksum, - documentSpan, - arguments.AnalyzerIds, documentAnalysisKind, - _analyzerInfoCache, hostWorkspaceServices, - isExplicit: arguments.IsExplicit, - reportSuppressedDiagnostics: arguments.ReportSuppressedDiagnostics, - logPerformanceInfo: arguments.LogPerformanceInfo, - getTelemetryInfo: arguments.GetTelemetryInfo, - cancellationToken).ConfigureAwait(false); - - // save log for debugging - var diagnosticCount = result.Diagnostics.Sum( - entry => entry.diagnosticMap.Syntax.Length + entry.diagnosticMap.Semantic.Length + entry.diagnosticMap.NonLocal.Length + entry.diagnosticMap.Other.Length); - - Log(TraceEventType.Information, $"diagnostics: {diagnosticCount}, telemetry: {result.Telemetry.Length}"); - - return result; - }, cancellationToken).ConfigureAwait(false); - } - } + /// + /// Calculate diagnostics. this works differently than other ones such as todo comments or designer attribute scanner + /// since in proc and out of proc runs quite differently due to concurrency and due to possible amount of data + /// that needs to pass through between processes + /// + public async ValueTask CalculateDiagnosticsAsync(Checksum solutionChecksum, DiagnosticArguments arguments, CancellationToken cancellationToken) + { + // Complete RPC right away so the client can start reading from the stream. + // The fire-and forget task starts writing to the output stream and the client will read it until it reads all expected data. - public async ValueTask> GetSourceGeneratorDiagnosticsAsync(Checksum solutionChecksum, ProjectId projectId, CancellationToken cancellationToken) + using (TelemetryLogging.LogBlockTimeAggregated(FunctionId.PerformAnalysis_Summary, $"Total")) + using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_CalculateDiagnosticsAsync, arguments.ProjectId.DebugName, cancellationToken)) { return await RunWithSolutionAsync( solutionChecksum, async solution => { + var documentId = arguments.DocumentId; + var projectId = arguments.ProjectId; var project = solution.GetRequiredProject(projectId); - var diagnostics = await project.GetSourceGeneratorDiagnosticsAsync(cancellationToken).ConfigureAwait(false); - using var builder = TemporaryArray.Empty; - foreach (var diagnostic in diagnostics) - { - var document = solution.GetDocument(diagnostic.Location.SourceTree); - var data = document != null - ? DiagnosticData.Create(diagnostic, document) - : DiagnosticData.Create(solution, diagnostic, project); - builder.Add(data); - } - - return builder.ToImmutableAndClear(); + var document = arguments.DocumentId != null + ? solution.GetTextDocument(arguments.DocumentId) ?? await solution.GetSourceGeneratedDocumentAsync(arguments.DocumentId, cancellationToken).ConfigureAwait(false) + : null; + var documentSpan = arguments.DocumentSpan; + var documentAnalysisKind = arguments.DocumentAnalysisKind; + var hostWorkspaceServices = this.GetWorkspace().Services; + + var result = await DiagnosticComputer.GetDiagnosticsAsync( + document, project, solutionChecksum, + documentSpan, + arguments.AnalyzerIds, documentAnalysisKind, + _analyzerInfoCache, hostWorkspaceServices, + isExplicit: arguments.IsExplicit, + reportSuppressedDiagnostics: arguments.ReportSuppressedDiagnostics, + logPerformanceInfo: arguments.LogPerformanceInfo, + getTelemetryInfo: arguments.GetTelemetryInfo, + cancellationToken).ConfigureAwait(false); + + // save log for debugging + var diagnosticCount = result.Diagnostics.Sum( + entry => entry.diagnosticMap.Syntax.Length + entry.diagnosticMap.Semantic.Length + entry.diagnosticMap.NonLocal.Length + entry.diagnosticMap.Other.Length); + + Log(TraceEventType.Information, $"diagnostics: {diagnosticCount}, telemetry: {result.Telemetry.Length}"); + + return result; }, cancellationToken).ConfigureAwait(false); } + } - public ValueTask ReportAnalyzerPerformanceAsync(ImmutableArray snapshot, int unitCount, bool forSpanAnalysis, CancellationToken cancellationToken) - { - return RunServiceAsync(cancellationToken => + public async ValueTask> GetSourceGeneratorDiagnosticsAsync(Checksum solutionChecksum, ProjectId projectId, CancellationToken cancellationToken) + { + return await RunWithSolutionAsync( + solutionChecksum, + async solution => { - using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_ReportAnalyzerPerformance, cancellationToken)) + var project = solution.GetRequiredProject(projectId); + var diagnostics = await project.GetSourceGeneratorDiagnosticsAsync(cancellationToken).ConfigureAwait(false); + using var builder = TemporaryArray.Empty; + foreach (var diagnostic in diagnostics) { - cancellationToken.ThrowIfCancellationRequested(); + var document = solution.GetDocument(diagnostic.Location.SourceTree); + var data = document != null + ? DiagnosticData.Create(diagnostic, document) + : DiagnosticData.Create(solution, diagnostic, project); + builder.Add(data); + } - var service = GetWorkspace().Services.GetService(); - if (service == null) - { - return default; - } + return builder.ToImmutableAndClear(); + }, cancellationToken).ConfigureAwait(false); + } - service.AddSnapshot(snapshot, unitCount, forSpanAnalysis); + public ValueTask ReportAnalyzerPerformanceAsync(ImmutableArray snapshot, int unitCount, bool forSpanAnalysis, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => + { + using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_ReportAnalyzerPerformance, cancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + + var service = GetWorkspace().Services.GetService(); + if (service == null) + { + return default; } - return default; - }, cancellationToken); - } + service.AddSnapshot(snapshot, unitCount, forSpanAnalysis); + } + + return default; + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/DocumentHighlights/RemoteDocumentHighlightsService.cs b/src/Workspaces/Remote/ServiceHub/Services/DocumentHighlights/RemoteDocumentHighlightsService.cs index e75bccf52ca21..9b8ea911d8432 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/DocumentHighlights/RemoteDocumentHighlightsService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/DocumentHighlights/RemoteDocumentHighlightsService.cs @@ -9,43 +9,42 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteDocumentHighlightsService : BrokeredServiceBase, IRemoteDocumentHighlightsService { - internal sealed class RemoteDocumentHighlightsService : BrokeredServiceBase, IRemoteDocumentHighlightsService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteDocumentHighlightsService CreateService(in ServiceConstructionArguments arguments) - => new RemoteDocumentHighlightsService(arguments); - } + protected override IRemoteDocumentHighlightsService CreateService(in ServiceConstructionArguments arguments) + => new RemoteDocumentHighlightsService(arguments); + } - public RemoteDocumentHighlightsService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } + public RemoteDocumentHighlightsService(in ServiceConstructionArguments arguments) + : base(arguments) + { + } - public ValueTask> GetDocumentHighlightsAsync( - Checksum solutionChecksum, DocumentId documentId, int position, ImmutableArray documentIdsToSearch, HighlightingOptions options, CancellationToken cancellationToken) + public ValueTask> GetDocumentHighlightsAsync( + Checksum solutionChecksum, DocumentId documentId, int position, ImmutableArray documentIdsToSearch, HighlightingOptions options, CancellationToken cancellationToken) + { + // NOTE: In projection scenarios, we might get a set of documents to search + // that are not all the same language and might not exist in the OOP process + // (like the JS parts of a .cshtml file). Filter them out here. This will + // need to be revisited if we someday support FAR between these languages. + return RunServiceAsync(solutionChecksum, async solution => { - // NOTE: In projection scenarios, we might get a set of documents to search - // that are not all the same language and might not exist in the OOP process - // (like the JS parts of a .cshtml file). Filter them out here. This will - // need to be revisited if we someday support FAR between these languages. - return RunServiceAsync(solutionChecksum, async solution => - { - var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); - document = options.FrozenPartialSemantics ? document.WithFrozenPartialSemantics(cancellationToken) : document; - solution = document.Project.Solution; - - var documentsToSearch = await documentIdsToSearch.SelectAsArrayAsync(id => solution.GetDocumentAsync(id, includeSourceGenerated: true, cancellationToken)).ConfigureAwait(false); - var documentsToSearchSet = ImmutableHashSet.CreateRange(documentsToSearch.WhereNotNull()); - - var service = document.GetRequiredLanguageService(); - var result = await service.GetDocumentHighlightsAsync( - document, position, documentsToSearchSet, options, cancellationToken).ConfigureAwait(false); - - return result.SelectAsArray(SerializableDocumentHighlights.Dehydrate); - }, cancellationToken); - } + var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + document = options.FrozenPartialSemantics ? document.WithFrozenPartialSemantics(cancellationToken) : document; + solution = document.Project.Solution; + + var documentsToSearch = await documentIdsToSearch.SelectAsArrayAsync(id => solution.GetDocumentAsync(id, includeSourceGenerated: true, cancellationToken)).ConfigureAwait(false); + var documentsToSearchSet = ImmutableHashSet.CreateRange(documentsToSearch.WhereNotNull()); + + var service = document.GetRequiredLanguageService(); + var result = await service.GetDocumentHighlightsAsync( + document, position, documentsToSearchSet, options, cancellationToken).ConfigureAwait(false); + + return result.SelectAsArray(SerializableDocumentHighlights.Dehydrate); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/RemoteEditAndContinueService.cs b/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/RemoteEditAndContinueService.cs index 89b49c0beb9c3..1f57c7803b213 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/RemoteEditAndContinueService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/EditAndContinue/RemoteEditAndContinueService.cs @@ -14,221 +14,219 @@ using Microsoft.CodeAnalysis.Contracts.EditAndContinue; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.EditAndContinue +namespace Microsoft.CodeAnalysis.EditAndContinue; + +internal sealed class RemoteEditAndContinueService : BrokeredServiceBase, IRemoteEditAndContinueService { - internal sealed class RemoteEditAndContinueService : BrokeredServiceBase, IRemoteEditAndContinueService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteEditAndContinueService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteEditAndContinueService(arguments, callback); - } - - private sealed class ManagedEditAndContinueDebuggerService : IManagedHotReloadService - { - private readonly RemoteCallback _callback; - private readonly RemoteServiceCallbackId _callbackId; - - public ManagedEditAndContinueDebuggerService(RemoteCallback callback, RemoteServiceCallbackId callbackId) - { - _callback = callback; - _callbackId = callbackId; - } - - ValueTask> IManagedHotReloadService.GetActiveStatementsAsync(CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.GetActiveStatementsAsync(_callbackId, cancellationToken), cancellationToken); - - ValueTask IManagedHotReloadService.GetAvailabilityAsync(Guid moduleVersionId, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.GetAvailabilityAsync(_callbackId, moduleVersionId, cancellationToken), cancellationToken); + protected override IRemoteEditAndContinueService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) + => new RemoteEditAndContinueService(arguments, callback); + } - ValueTask> IManagedHotReloadService.GetCapabilitiesAsync(CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.GetCapabilitiesAsync(_callbackId, cancellationToken), cancellationToken); + private sealed class ManagedEditAndContinueDebuggerService : IManagedHotReloadService + { + private readonly RemoteCallback _callback; + private readonly RemoteServiceCallbackId _callbackId; - ValueTask IManagedHotReloadService.PrepareModuleForUpdateAsync(Guid moduleVersionId, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.PrepareModuleForUpdateAsync(_callbackId, moduleVersionId, cancellationToken), cancellationToken); + public ManagedEditAndContinueDebuggerService(RemoteCallback callback, RemoteServiceCallbackId callbackId) + { + _callback = callback; + _callbackId = callbackId; } - private sealed class SourceTextProvider : IPdbMatchingSourceTextProvider - { - private readonly RemoteCallback _callback; - private readonly RemoteServiceCallbackId _callbackId; + ValueTask> IManagedHotReloadService.GetActiveStatementsAsync(CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.GetActiveStatementsAsync(_callbackId, cancellationToken), cancellationToken); - public SourceTextProvider(RemoteCallback callback, RemoteServiceCallbackId callbackId) - { - _callback = callback; - _callbackId = callbackId; - } + ValueTask IManagedHotReloadService.GetAvailabilityAsync(Guid moduleVersionId, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.GetAvailabilityAsync(_callbackId, moduleVersionId, cancellationToken), cancellationToken); - public ValueTask TryGetMatchingSourceTextAsync(string filePath, ImmutableArray requiredChecksum, SourceHashAlgorithm checksumAlgorithm, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.TryGetMatchingSourceTextAsync(_callbackId, filePath, requiredChecksum, checksumAlgorithm, cancellationToken), cancellationToken); - } + ValueTask> IManagedHotReloadService.GetCapabilitiesAsync(CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.GetCapabilitiesAsync(_callbackId, cancellationToken), cancellationToken); + + ValueTask IManagedHotReloadService.PrepareModuleForUpdateAsync(Guid moduleVersionId, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.PrepareModuleForUpdateAsync(_callbackId, moduleVersionId, cancellationToken), cancellationToken); + } + private sealed class SourceTextProvider : IPdbMatchingSourceTextProvider + { private readonly RemoteCallback _callback; + private readonly RemoteServiceCallbackId _callbackId; - public RemoteEditAndContinueService(in ServiceConstructionArguments arguments, RemoteCallback callback) - : base(arguments) + public SourceTextProvider(RemoteCallback callback, RemoteServiceCallbackId callbackId) { _callback = callback; + _callbackId = callbackId; } - private IEditAndContinueService GetService() - => GetWorkspace().Services.GetRequiredService().Service; + public ValueTask TryGetMatchingSourceTextAsync(string filePath, ImmutableArray requiredChecksum, SourceHashAlgorithm checksumAlgorithm, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.TryGetMatchingSourceTextAsync(_callbackId, filePath, requiredChecksum, checksumAlgorithm, cancellationToken), cancellationToken); + } + + private readonly RemoteCallback _callback; + + public RemoteEditAndContinueService(in ServiceConstructionArguments arguments, RemoteCallback callback) + : base(arguments) + { + _callback = callback; + } + + private IEditAndContinueService GetService() + => GetWorkspace().Services.GetRequiredService().Service; - private ActiveStatementSpanProvider CreateActiveStatementSpanProvider(RemoteServiceCallbackId callbackId) - => new((documentId, filePath, cancellationToken) => _callback.InvokeAsync((callback, cancellationToken) => callback.GetSpansAsync(callbackId, documentId, filePath, cancellationToken), cancellationToken)); + private ActiveStatementSpanProvider CreateActiveStatementSpanProvider(RemoteServiceCallbackId callbackId) + => new((documentId, filePath, cancellationToken) => _callback.InvokeAsync((callback, cancellationToken) => callback.GetSpansAsync(callbackId, documentId, filePath, cancellationToken), cancellationToken)); - /// - /// Remote API. - /// - public ValueTask StartDebuggingSessionAsync(Checksum solutionChecksum, RemoteServiceCallbackId callbackId, ImmutableArray captureMatchingDocuments, bool captureAllMatchingDocuments, bool reportDiagnostics, CancellationToken cancellationToken) + /// + /// Remote API. + /// + public ValueTask StartDebuggingSessionAsync(Checksum solutionChecksum, RemoteServiceCallbackId callbackId, ImmutableArray captureMatchingDocuments, bool captureAllMatchingDocuments, bool reportDiagnostics, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var debuggerService = new ManagedEditAndContinueDebuggerService(_callback, callbackId); - var sourceTextProvider = new SourceTextProvider(_callback, callbackId); + var debuggerService = new ManagedEditAndContinueDebuggerService(_callback, callbackId); + var sourceTextProvider = new SourceTextProvider(_callback, callbackId); - var sessionId = await GetService().StartDebuggingSessionAsync(solution, debuggerService, sourceTextProvider, captureMatchingDocuments, captureAllMatchingDocuments, reportDiagnostics, cancellationToken).ConfigureAwait(false); - return sessionId; - }, cancellationToken); - } + var sessionId = await GetService().StartDebuggingSessionAsync(solution, debuggerService, sourceTextProvider, captureMatchingDocuments, captureAllMatchingDocuments, reportDiagnostics, cancellationToken).ConfigureAwait(false); + return sessionId; + }, cancellationToken); + } - /// - /// Remote API. - /// - public ValueTask BreakStateOrCapabilitiesChangedAsync(DebuggingSessionId sessionId, bool? inBreakState, CancellationToken cancellationToken) + /// + /// Remote API. + /// + public ValueTask BreakStateOrCapabilitiesChangedAsync(DebuggingSessionId sessionId, bool? inBreakState, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => { - return RunServiceAsync(cancellationToken => - { - GetService().BreakStateOrCapabilitiesChanged(sessionId, inBreakState); - return ValueTaskFactory.CompletedTask; - }, cancellationToken); - } + GetService().BreakStateOrCapabilitiesChanged(sessionId, inBreakState); + return ValueTaskFactory.CompletedTask; + }, cancellationToken); + } - /// - /// Remote API. - /// - public ValueTask EndDebuggingSessionAsync(DebuggingSessionId sessionId, CancellationToken cancellationToken) + /// + /// Remote API. + /// + public ValueTask EndDebuggingSessionAsync(DebuggingSessionId sessionId, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => { - return RunServiceAsync(cancellationToken => - { - GetService().EndDebuggingSession(sessionId); - return ValueTaskFactory.CompletedTask; - }, cancellationToken); - } + GetService().EndDebuggingSession(sessionId); + return ValueTaskFactory.CompletedTask; + }, cancellationToken); + } - /// - /// Remote API. - /// - public ValueTask> GetDocumentDiagnosticsAsync(Checksum solutionChecksum, RemoteServiceCallbackId callbackId, DocumentId documentId, CancellationToken cancellationToken) + /// + /// Remote API. + /// + public ValueTask> GetDocumentDiagnosticsAsync(Checksum solutionChecksum, RemoteServiceCallbackId callbackId, DocumentId documentId, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => + try { - try - { - var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); - var diagnostics = await GetService().GetDocumentDiagnosticsAsync(document, CreateActiveStatementSpanProvider(callbackId), cancellationToken).ConfigureAwait(false); - return diagnostics.SelectAsArray(diagnostic => DiagnosticData.Create(diagnostic, document)); - } - catch (Exception ex) when (FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken)) - { - throw ExceptionUtilities.Unreachable(); - } - }, cancellationToken); - } + var diagnostics = await GetService().GetDocumentDiagnosticsAsync(document, CreateActiveStatementSpanProvider(callbackId), cancellationToken).ConfigureAwait(false); + return diagnostics.SelectAsArray(diagnostic => DiagnosticData.Create(diagnostic, document)); + } + catch (Exception ex) when (FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken)) + { + throw ExceptionUtilities.Unreachable(); + } + }, cancellationToken); + } - /// - /// Remote API. - /// - public ValueTask EmitSolutionUpdateAsync( - Checksum solutionChecksum, RemoteServiceCallbackId callbackId, DebuggingSessionId sessionId, CancellationToken cancellationToken) + /// + /// Remote API. + /// + public ValueTask EmitSolutionUpdateAsync( + Checksum solutionChecksum, RemoteServiceCallbackId callbackId, DebuggingSessionId sessionId, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var service = GetService(); + var service = GetService(); - try - { - var results = await service.EmitSolutionUpdateAsync(sessionId, solution, CreateActiveStatementSpanProvider(callbackId), cancellationToken).ConfigureAwait(false); - return results.Dehydrate(solution); - } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) + try + { + return (await service.EmitSolutionUpdateAsync(sessionId, solution, CreateActiveStatementSpanProvider(callbackId), cancellationToken).ConfigureAwait(false)).Dehydrate(); + } + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) + { + return new EmitSolutionUpdateResults.Data() { - return new EmitSolutionUpdateResults.Data() - { - ModuleUpdates = new ModuleUpdates(ModuleUpdateStatus.Blocked, []), - Diagnostics = GetUnexpectedUpdateError(solution, e), - RudeEdits = [], - SyntaxError = null, - }; - } - }, cancellationToken); - } + ModuleUpdates = new ModuleUpdates(ModuleUpdateStatus.Blocked, []), + Diagnostics = GetUnexpectedUpdateError(solution, e), + RudeEdits = [], + SyntaxError = null, + }; + } + }, cancellationToken); + } - private static ImmutableArray GetUnexpectedUpdateError(Solution solution, Exception e) - { - var descriptor = EditAndContinueDiagnosticDescriptors.GetDescriptor(EditAndContinueErrorCode.CannotApplyChangesUnexpectedError); - var diagnostic = Diagnostic.Create(descriptor, Location.None, new[] { e.Message }); - return [DiagnosticData.Create(solution, diagnostic, project: null)]; - } + private static ImmutableArray GetUnexpectedUpdateError(Solution solution, Exception e) + { + var descriptor = EditAndContinueDiagnosticDescriptors.GetDescriptor(EditAndContinueErrorCode.CannotApplyChangesUnexpectedError); + var diagnostic = Diagnostic.Create(descriptor, Location.None, [e.Message]); + return [DiagnosticData.Create(solution, diagnostic, project: null)]; + } - /// - /// Remote API. - /// - public ValueTask CommitSolutionUpdateAsync(DebuggingSessionId sessionId, CancellationToken cancellationToken) + /// + /// Remote API. + /// + public ValueTask CommitSolutionUpdateAsync(DebuggingSessionId sessionId, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => { - return RunServiceAsync(cancellationToken => - { - GetService().CommitSolutionUpdate(sessionId); - return ValueTaskFactory.CompletedTask; - }, cancellationToken); - } + GetService().CommitSolutionUpdate(sessionId); + return ValueTaskFactory.CompletedTask; + }, cancellationToken); + } - /// - /// Remote API. - /// - public ValueTask DiscardSolutionUpdateAsync(DebuggingSessionId sessionId, CancellationToken cancellationToken) + /// + /// Remote API. + /// + public ValueTask DiscardSolutionUpdateAsync(DebuggingSessionId sessionId, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => { - return RunServiceAsync(cancellationToken => - { - GetService().DiscardSolutionUpdate(sessionId); - return default; - }, cancellationToken); - } + GetService().DiscardSolutionUpdate(sessionId); + return default; + }, cancellationToken); + } - /// - /// Remote API. - /// - public ValueTask>> GetBaseActiveStatementSpansAsync(Checksum solutionChecksum, DebuggingSessionId sessionId, ImmutableArray documentIds, CancellationToken cancellationToken) + /// + /// Remote API. + /// + public ValueTask>> GetBaseActiveStatementSpansAsync(Checksum solutionChecksum, DebuggingSessionId sessionId, ImmutableArray documentIds, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - return await GetService().GetBaseActiveStatementSpansAsync(sessionId, solution, documentIds, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + return await GetService().GetBaseActiveStatementSpansAsync(sessionId, solution, documentIds, cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } - /// - /// Remote API. - /// - public ValueTask> GetAdjustedActiveStatementSpansAsync(Checksum solutionChecksum, RemoteServiceCallbackId callbackId, DebuggingSessionId sessionId, DocumentId documentId, CancellationToken cancellationToken) + /// + /// Remote API. + /// + public ValueTask> GetAdjustedActiveStatementSpansAsync(Checksum solutionChecksum, RemoteServiceCallbackId callbackId, DebuggingSessionId sessionId, DocumentId documentId, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var document = await solution.GetRequiredTextDocumentAsync(documentId, cancellationToken).ConfigureAwait(false); - return await GetService().GetAdjustedActiveStatementSpansAsync(sessionId, document, CreateActiveStatementSpanProvider(callbackId), cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + var document = await solution.GetRequiredTextDocumentAsync(documentId, cancellationToken).ConfigureAwait(false); + return await GetService().GetAdjustedActiveStatementSpansAsync(sessionId, document, CreateActiveStatementSpanProvider(callbackId), cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } - /// - /// Remote API. - /// - public ValueTask SetFileLoggingDirectoryAsync(string? logDirectory, CancellationToken cancellationToken) + /// + /// Remote API. + /// + public ValueTask SetFileLoggingDirectoryAsync(string? logDirectory, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => { - return RunServiceAsync(cancellationToken => - { - GetService().SetFileLoggingDirectory(logDirectory); - return default; - }, cancellationToken); - } + GetService().SetFileLoggingDirectory(logDirectory); + return default; + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs b/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs index 846177c6f65b8..2dfe968997cd7 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/EncapsulateField/RemoteEncapsulateFieldService.cs @@ -12,48 +12,47 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteEncapsulateFieldService(in BrokeredServiceBase.ServiceConstructionArguments arguments) + : BrokeredServiceBase(arguments), IRemoteEncapsulateFieldService { - internal sealed class RemoteEncapsulateFieldService(in BrokeredServiceBase.ServiceConstructionArguments arguments) - : BrokeredServiceBase(arguments), IRemoteEncapsulateFieldService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteEncapsulateFieldService CreateService(in ServiceConstructionArguments arguments) - => new RemoteEncapsulateFieldService(arguments); - } - - public ValueTask)>> EncapsulateFieldsAsync( - Checksum solutionChecksum, - DocumentId documentId, - ImmutableArray fieldSymbolKeys, - bool updateReferences, - CancellationToken cancellationToken) + protected override IRemoteEncapsulateFieldService CreateService(in ServiceConstructionArguments arguments) + => new RemoteEncapsulateFieldService(arguments); + } + + public ValueTask)>> EncapsulateFieldsAsync( + Checksum solutionChecksum, + DocumentId documentId, + ImmutableArray fieldSymbolKeys, + bool updateReferences, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var document = solution.GetRequiredDocument(documentId); + var document = solution.GetRequiredDocument(documentId); - using var _ = ArrayBuilder.GetInstance(out var fields); - var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); + using var _ = ArrayBuilder.GetInstance(out var fields); + var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - foreach (var key in fieldSymbolKeys) - { - var resolved = SymbolKey.ResolveString(key, compilation, cancellationToken: cancellationToken).GetAnySymbol() as IFieldSymbol; - if (resolved == null) - return ImmutableArray<(DocumentId, ImmutableArray)>.Empty; + foreach (var key in fieldSymbolKeys) + { + var resolved = SymbolKey.ResolveString(key, compilation, cancellationToken: cancellationToken).GetAnySymbol() as IFieldSymbol; + if (resolved == null) + return ImmutableArray<(DocumentId, ImmutableArray)>.Empty; - fields.Add(resolved); - } + fields.Add(resolved); + } - var service = document.GetRequiredLanguageService(); + var service = document.GetRequiredLanguageService(); - var newSolution = await service.EncapsulateFieldsAsync( - document, fields.ToImmutable(), updateReferences, cancellationToken).ConfigureAwait(false); + var newSolution = await service.EncapsulateFieldsAsync( + document, fields.ToImmutable(), updateReferences, cancellationToken).ConfigureAwait(false); - return await RemoteUtilities.GetDocumentTextChangesAsync( - solution, newSolution, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + return await RemoteUtilities.GetDocumentTextChangesAsync( + solution, newSolution, cancellationToken).ConfigureAwait(false); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/ExtensionMethodImportCompletion/RemoteExtensionMethodImportCompletionService.cs b/src/Workspaces/Remote/ServiceHub/Services/ExtensionMethodImportCompletion/RemoteExtensionMethodImportCompletionService.cs index ffb23beb91f65..0010d9bb24954 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ExtensionMethodImportCompletion/RemoteExtensionMethodImportCompletionService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ExtensionMethodImportCompletion/RemoteExtensionMethodImportCompletionService.cs @@ -12,71 +12,70 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteExtensionMethodImportCompletionService : BrokeredServiceBase, IRemoteExtensionMethodImportCompletionService { - internal sealed class RemoteExtensionMethodImportCompletionService : BrokeredServiceBase, IRemoteExtensionMethodImportCompletionService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteExtensionMethodImportCompletionService CreateService(in ServiceConstructionArguments arguments) - => new RemoteExtensionMethodImportCompletionService(arguments); - } + protected override IRemoteExtensionMethodImportCompletionService CreateService(in ServiceConstructionArguments arguments) + => new RemoteExtensionMethodImportCompletionService(arguments); + } - public RemoteExtensionMethodImportCompletionService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } + public RemoteExtensionMethodImportCompletionService(in ServiceConstructionArguments arguments) + : base(arguments) + { + } - public ValueTask GetUnimportedExtensionMethodsAsync( - Checksum solutionChecksum, - DocumentId documentId, - int position, - string receiverTypeSymbolKeyData, - ImmutableArray namespaceInScope, - ImmutableArray targetTypesSymbolKeyData, - bool forceCacheCreation, - bool hideAdvancedMembers, - CancellationToken cancellationToken) + public ValueTask GetUnimportedExtensionMethodsAsync( + Checksum solutionChecksum, + DocumentId documentId, + int position, + string receiverTypeSymbolKeyData, + ImmutableArray namespaceInScope, + ImmutableArray targetTypesSymbolKeyData, + bool forceCacheCreation, + bool hideAdvancedMembers, + CancellationToken cancellationToken) + { + var stopwatch = SharedStopwatch.StartNew(); + return RunServiceAsync(solutionChecksum, async solution => { - var stopwatch = SharedStopwatch.StartNew(); - return RunServiceAsync(solutionChecksum, async solution => - { - var assetSyncTime = stopwatch.Elapsed; + var assetSyncTime = stopwatch.Elapsed; - // Completion always uses frozen-partial semantic in-proc, which is not automatically passed to OOP, so enable it explicitly - var document = solution.GetRequiredDocument(documentId).WithFrozenPartialSemantics(cancellationToken); - var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - var symbol = SymbolKey.ResolveString(receiverTypeSymbolKeyData, compilation, cancellationToken: cancellationToken).GetAnySymbol(); + // Completion always uses frozen-partial semantic in-proc, which is not automatically passed to OOP, so enable it explicitly + var document = solution.GetRequiredDocument(documentId).WithFrozenPartialSemantics(cancellationToken); + var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); + var symbol = SymbolKey.ResolveString(receiverTypeSymbolKeyData, compilation, cancellationToken: cancellationToken).GetAnySymbol(); - if (symbol is ITypeSymbol receiverTypeSymbol) - { - var syntaxFacts = document.GetRequiredLanguageService(); - var namespaceInScopeSet = new HashSet(namespaceInScope, syntaxFacts.StringComparer); - var targetTypes = targetTypesSymbolKeyData - .Select(symbolKey => SymbolKey.ResolveString(symbolKey, compilation, cancellationToken: cancellationToken).GetAnySymbol() as ITypeSymbol) - .WhereNotNull().ToImmutableArray(); + if (symbol is ITypeSymbol receiverTypeSymbol) + { + var syntaxFacts = document.GetRequiredLanguageService(); + var namespaceInScopeSet = new HashSet(namespaceInScope, syntaxFacts.StringComparer); + var targetTypes = targetTypesSymbolKeyData + .Select(symbolKey => SymbolKey.ResolveString(symbolKey, compilation, cancellationToken: cancellationToken).GetAnySymbol() as ITypeSymbol) + .WhereNotNull().ToImmutableArray(); - var intialGetSymbolsTime = stopwatch.Elapsed - assetSyncTime; + var intialGetSymbolsTime = stopwatch.Elapsed - assetSyncTime; - var result = await ExtensionMethodImportCompletionHelper.GetUnimportedExtensionMethodsInCurrentProcessAsync( - document, semanticModel: null, position, receiverTypeSymbol, namespaceInScopeSet, targetTypes, forceCacheCreation, hideAdvancedMembers, assetSyncTime, cancellationToken).ConfigureAwait(false); + var result = await ExtensionMethodImportCompletionHelper.GetUnimportedExtensionMethodsInCurrentProcessAsync( + document, semanticModel: null, position, receiverTypeSymbol, namespaceInScopeSet, targetTypes, forceCacheCreation, hideAdvancedMembers, assetSyncTime, cancellationToken).ConfigureAwait(false); - result.GetSymbolsTime += intialGetSymbolsTime; - return result; - } + result.GetSymbolsTime += intialGetSymbolsTime; + return result; + } - return null; - }, cancellationToken); - } + return null; + }, cancellationToken); + } - public ValueTask WarmUpCacheAsync(Checksum solutionChecksum, ProjectId projectId, CancellationToken cancellationToken) + public ValueTask WarmUpCacheAsync(Checksum solutionChecksum, ProjectId projectId, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, solution => { - return RunServiceAsync(solutionChecksum, solution => - { - var project = solution.GetRequiredProject(projectId); - ExtensionMethodImportCompletionHelper.WarmUpCacheInCurrentProcess(project); - return ValueTaskFactory.CompletedTask; - }, cancellationToken); - } + var project = solution.GetRequiredProject(projectId); + ExtensionMethodImportCompletionHelper.WarmUpCacheInCurrentProcess(project); + return ValueTaskFactory.CompletedTask; + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/FindUsages/RemoteFindUsagesService.cs b/src/Workspaces/Remote/ServiceHub/Services/FindUsages/RemoteFindUsagesService.cs index c0705bf10468e..1948462558784 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/FindUsages/RemoteFindUsagesService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/FindUsages/RemoteFindUsagesService.cs @@ -14,137 +14,136 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteFindUsagesService(in BrokeredServiceBase.ServiceConstructionArguments arguments, RemoteCallback callback) + : BrokeredServiceBase(arguments), IRemoteFindUsagesService { - internal sealed class RemoteFindUsagesService(in BrokeredServiceBase.ServiceConstructionArguments arguments, RemoteCallback callback) - : BrokeredServiceBase(arguments), IRemoteFindUsagesService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteFindUsagesService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteFindUsagesService(arguments, callback); - } + protected override IRemoteFindUsagesService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) + => new RemoteFindUsagesService(arguments, callback); + } - public ValueTask FindReferencesAsync( - Checksum solutionChecksum, - RemoteServiceCallbackId callbackId, - SerializableSymbolAndProjectId symbolAndProjectId, - FindReferencesSearchOptions options, - CancellationToken cancellationToken) + public ValueTask FindReferencesAsync( + Checksum solutionChecksum, + RemoteServiceCallbackId callbackId, + SerializableSymbolAndProjectId symbolAndProjectId, + FindReferencesSearchOptions options, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var project = solution.GetRequiredProject(symbolAndProjectId.ProjectId); + var project = solution.GetRequiredProject(symbolAndProjectId.ProjectId); - var symbol = await symbolAndProjectId.TryRehydrateAsync( - solution, cancellationToken).ConfigureAwait(false); + var symbol = await symbolAndProjectId.TryRehydrateAsync( + solution, cancellationToken).ConfigureAwait(false); - if (symbol == null) - return; + if (symbol == null) + return; - var context = new RemoteFindUsageContext(callback, callbackId); - var classificationOptions = GetClientOptionsProvider(callback, callbackId); + var context = new RemoteFindUsageContext(callback, callbackId); + var classificationOptions = GetClientOptionsProvider(callback, callbackId); - await AbstractFindUsagesService.FindReferencesAsync( - context, symbol, project, options, classificationOptions, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + await AbstractFindUsagesService.FindReferencesAsync( + context, symbol, project, options, classificationOptions, cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } - public ValueTask FindImplementationsAsync( - Checksum solutionChecksum, - RemoteServiceCallbackId callbackId, - SerializableSymbolAndProjectId symbolAndProjectId, - CancellationToken cancellationToken) + public ValueTask FindImplementationsAsync( + Checksum solutionChecksum, + RemoteServiceCallbackId callbackId, + SerializableSymbolAndProjectId symbolAndProjectId, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var project = solution.GetRequiredProject(symbolAndProjectId.ProjectId); + var project = solution.GetRequiredProject(symbolAndProjectId.ProjectId); - var symbol = await symbolAndProjectId.TryRehydrateAsync( - solution, cancellationToken).ConfigureAwait(false); - if (symbol == null) - return; + var symbol = await symbolAndProjectId.TryRehydrateAsync( + solution, cancellationToken).ConfigureAwait(false); + if (symbol == null) + return; - var context = new RemoteFindUsageContext(callback, callbackId); - var classificationOptions = GetClientOptionsProvider(callback, callbackId); + var context = new RemoteFindUsageContext(callback, callbackId); + var classificationOptions = GetClientOptionsProvider(callback, callbackId); - await AbstractFindUsagesService.FindImplementationsAsync( - context, symbol, project, classificationOptions, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + await AbstractFindUsagesService.FindImplementationsAsync( + context, symbol, project, classificationOptions, cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } - private sealed class RemoteFindUsageContext : IFindUsagesContext, IStreamingProgressTracker - { - private readonly RemoteCallback _callback; - private readonly RemoteServiceCallbackId _callbackId; - private readonly Dictionary _definitionItemToId = []; + private sealed class RemoteFindUsageContext : IFindUsagesContext, IStreamingProgressTracker + { + private readonly RemoteCallback _callback; + private readonly RemoteServiceCallbackId _callbackId; + private readonly Dictionary _definitionItemToId = []; - public RemoteFindUsageContext(RemoteCallback callback, RemoteServiceCallbackId callbackId) - { - _callback = callback; - _callbackId = callbackId; - } + public RemoteFindUsageContext(RemoteCallback callback, RemoteServiceCallbackId callbackId) + { + _callback = callback; + _callbackId = callbackId; + } - #region IStreamingProgressTracker + #region IStreamingProgressTracker - public ValueTask AddItemsAsync(int count, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.AddItemsAsync(_callbackId, count, cancellationToken), cancellationToken); + public ValueTask AddItemsAsync(int count, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.AddItemsAsync(_callbackId, count, cancellationToken), cancellationToken); - public ValueTask ItemsCompletedAsync(int count, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.ItemsCompletedAsync(_callbackId, count, cancellationToken), cancellationToken); + public ValueTask ItemsCompletedAsync(int count, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.ItemsCompletedAsync(_callbackId, count, cancellationToken), cancellationToken); - #endregion + #endregion - #region IFindUsagesContext + #region IFindUsagesContext - public IStreamingProgressTracker ProgressTracker => this; + public IStreamingProgressTracker ProgressTracker => this; - public ValueTask ReportNoResultsAsync(string message, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.ReportMessageAsync(_callbackId, message, cancellationToken), cancellationToken); + public ValueTask ReportNoResultsAsync(string message, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.ReportMessageAsync(_callbackId, message, cancellationToken), cancellationToken); - public ValueTask ReportMessageAsync(string message, NotificationSeverity severity, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.ReportInformationalMessageAsync(_callbackId, message, cancellationToken), cancellationToken); + public ValueTask ReportMessageAsync(string message, NotificationSeverity severity, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.ReportInformationalMessageAsync(_callbackId, message, cancellationToken), cancellationToken); - public ValueTask SetSearchTitleAsync(string title, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.SetSearchTitleAsync(_callbackId, title, cancellationToken), cancellationToken); + public ValueTask SetSearchTitleAsync(string title, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.SetSearchTitleAsync(_callbackId, title, cancellationToken), cancellationToken); - public ValueTask OnDefinitionFoundAsync(DefinitionItem definition, CancellationToken cancellationToken) - { - var id = GetOrAddDefinitionItemId(definition); - var dehydratedDefinition = SerializableDefinitionItem.Dehydrate(id, definition); - return _callback.InvokeAsync((callback, cancellationToken) => callback.OnDefinitionFoundAsync(_callbackId, dehydratedDefinition, cancellationToken), cancellationToken); - } + public ValueTask OnDefinitionFoundAsync(DefinitionItem definition, CancellationToken cancellationToken) + { + var id = GetOrAddDefinitionItemId(definition); + var dehydratedDefinition = SerializableDefinitionItem.Dehydrate(id, definition); + return _callback.InvokeAsync((callback, cancellationToken) => callback.OnDefinitionFoundAsync(_callbackId, dehydratedDefinition, cancellationToken), cancellationToken); + } - private int GetOrAddDefinitionItemId(DefinitionItem item) + private int GetOrAddDefinitionItemId(DefinitionItem item) + { + lock (_definitionItemToId) { - lock (_definitionItemToId) + if (!_definitionItemToId.TryGetValue(item, out var id)) { - if (!_definitionItemToId.TryGetValue(item, out var id)) - { - id = _definitionItemToId.Count; - _definitionItemToId.Add(item, id); - } - - return id; + id = _definitionItemToId.Count; + _definitionItemToId.Add(item, id); } + + return id; } + } - public async ValueTask OnReferencesFoundAsync(IAsyncEnumerable references, CancellationToken cancellationToken) + public async ValueTask OnReferencesFoundAsync(IAsyncEnumerable references, CancellationToken cancellationToken) + { + using var _ = ArrayBuilder.GetInstance(out var dehydrated); + await foreach (var reference in references) { - using var _ = ArrayBuilder.GetInstance(out var dehydrated); - await foreach (var reference in references) - { - var dehydratedReference = SerializableSourceReferenceItem.Dehydrate( - GetOrAddDefinitionItemId(reference.Definition), reference); - dehydrated.Add(dehydratedReference); - } - - var dehydratedReferences = dehydrated.ToImmutableAndClear(); - await _callback.InvokeAsync((callback, cancellationToken) => callback.OnReferencesFoundAsync( - _callbackId, dehydratedReferences, cancellationToken), cancellationToken).ConfigureAwait(false); + var dehydratedReference = SerializableSourceReferenceItem.Dehydrate( + GetOrAddDefinitionItemId(reference.Definition), reference); + dehydrated.Add(dehydratedReference); } - #endregion + var dehydratedReferences = dehydrated.ToImmutableAndClear(); + await _callback.InvokeAsync((callback, cancellationToken) => callback.OnReferencesFoundAsync( + _callbackId, dehydratedReferences, cancellationToken), cancellationToken).ConfigureAwait(false); } + + #endregion } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/FullyQualify/RemoteFullyQualifyService.cs b/src/Workspaces/Remote/ServiceHub/Services/FullyQualify/RemoteFullyQualifyService.cs index 38dd4101afbf7..3a43c914dc1a4 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/FullyQualify/RemoteFullyQualifyService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/FullyQualify/RemoteFullyQualifyService.cs @@ -10,31 +10,30 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteFullyQualifyService : BrokeredServiceBase, IRemoteFullyQualifyService { - internal sealed class RemoteFullyQualifyService : BrokeredServiceBase, IRemoteFullyQualifyService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteFullyQualifyService CreateService(in ServiceConstructionArguments arguments) - => new RemoteFullyQualifyService(arguments); - } + protected override IRemoteFullyQualifyService CreateService(in ServiceConstructionArguments arguments) + => new RemoteFullyQualifyService(arguments); + } - public RemoteFullyQualifyService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } + public RemoteFullyQualifyService(in ServiceConstructionArguments arguments) + : base(arguments) + { + } - public ValueTask GetFixDataAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan span, CancellationToken cancellationToken) + public ValueTask GetFixDataAsync(Checksum solutionChecksum, DocumentId documentId, TextSpan span, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var document = solution.GetRequiredDocument(documentId); + var document = solution.GetRequiredDocument(documentId); - var service = document.GetRequiredLanguageService(); + var service = document.GetRequiredLanguageService(); - return await service.GetFixDataAsync(document, span, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + return await service.GetFixDataAsync(document, span, cancellationToken).ConfigureAwait(false); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/InheritanceMargin/RemoteInheritanceMarginService.cs b/src/Workspaces/Remote/ServiceHub/Services/InheritanceMargin/RemoteInheritanceMarginService.cs index a6990e52752e6..1824d07b3fce5 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/InheritanceMargin/RemoteInheritanceMarginService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/InheritanceMargin/RemoteInheritanceMarginService.cs @@ -9,43 +9,42 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteInheritanceMarginService : BrokeredServiceBase, IRemoteInheritanceMarginService { - internal sealed class RemoteInheritanceMarginService : BrokeredServiceBase, IRemoteInheritanceMarginService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase + protected override IRemoteInheritanceMarginService CreateService(in ServiceConstructionArguments arguments) { - protected override IRemoteInheritanceMarginService CreateService(in ServiceConstructionArguments arguments) - { - return new RemoteInheritanceMarginService(arguments); - } + return new RemoteInheritanceMarginService(arguments); } + } - public RemoteInheritanceMarginService(in ServiceConstructionArguments arguments) : base(in arguments) - { - } + public RemoteInheritanceMarginService(in ServiceConstructionArguments arguments) : base(in arguments) + { + } - public ValueTask> GetInheritanceMarginItemsAsync( - Checksum solutionChecksum, - DocumentId documentId, - TextSpan spanToSearch, - bool includeGlobalImports, - bool frozenPartialSemantics, - CancellationToken cancellationToken) + public ValueTask> GetInheritanceMarginItemsAsync( + Checksum solutionChecksum, + DocumentId documentId, + TextSpan spanToSearch, + bool includeGlobalImports, + bool frozenPartialSemantics, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - // Explicitly disabling frozen partial on the OOP size. This flag was passed in, but had no actual - // effect (since OOP didn't support frozen partial semantics initially). When OOP gained real support - // for frozen-partial, this started breaking inheritance margin. So, until that is figured out, we just - // disable this to keep the pre-existing behavior. - // - // Tracked by https://github.com/dotnet/roslyn/issues/67065. - frozenPartialSemantics = false; - var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); - var service = document.GetRequiredLanguageService(); - return await service.GetInheritanceMemberItemsAsync(document, spanToSearch, includeGlobalImports, frozenPartialSemantics, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + // Explicitly disabling frozen partial on the OOP size. This flag was passed in, but had no actual + // effect (since OOP didn't support frozen partial semantics initially). When OOP gained real support + // for frozen-partial, this started breaking inheritance margin. So, until that is figured out, we just + // disable this to keep the pre-existing behavior. + // + // Tracked by https://github.com/dotnet/roslyn/issues/67065. + frozenPartialSemantics = false; + var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + var service = document.GetRequiredLanguageService(); + return await service.GetInheritanceMemberItemsAsync(document, spanToSearch, includeGlobalImports, frozenPartialSemantics, cancellationToken).ConfigureAwait(false); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/KeepAlive/RemoteKeepAliveService.cs b/src/Workspaces/Remote/ServiceHub/Services/KeepAlive/RemoteKeepAliveService.cs index 46d7fe7062274..749dc0c6b9128 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/KeepAlive/RemoteKeepAliveService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/KeepAlive/RemoteKeepAliveService.cs @@ -5,34 +5,33 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed partial class RemoteKeepAliveService : BrokeredServiceBase, IRemoteKeepAliveService { - internal sealed partial class RemoteKeepAliveService : BrokeredServiceBase, IRemoteKeepAliveService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteKeepAliveService CreateService(in ServiceConstructionArguments arguments) - => new RemoteKeepAliveService(arguments); - } + protected override IRemoteKeepAliveService CreateService(in ServiceConstructionArguments arguments) + => new RemoteKeepAliveService(arguments); + } - public RemoteKeepAliveService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } + public RemoteKeepAliveService(in ServiceConstructionArguments arguments) + : base(arguments) + { + } - public ValueTask KeepAliveAsync( - Checksum solutionChecksum, - CancellationToken cancellationToken) + public ValueTask KeepAliveAsync( + Checksum solutionChecksum, + CancellationToken cancellationToken) + { + // First get the solution, ensuring that it is currently pinned. + return RunServiceAsync(solutionChecksum, async solution => { - // First get the solution, ensuring that it is currently pinned. - return RunServiceAsync(solutionChecksum, async solution => - { - // Wait for our caller to tell us to cancel. That way we can release this solution and allow it - // to be collected if not needed anymore. - // - // This was provided by stoub as an idiomatic way to wait indefinitely until a cancellation token triggers. - await Task.Delay(-1, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + // Wait for our caller to tell us to cancel. That way we can release this solution and allow it + // to be collected if not needed anymore. + // + // This was provided by stoub as an idiomatic way to wait indefinitely until a cancellation token triggers. + await Task.Delay(-1, cancellationToken).ConfigureAwait(false); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/LegacySolutionEvents/RemoteLegacySolutionEventsAggregationService.cs b/src/Workspaces/Remote/ServiceHub/Services/LegacySolutionEvents/RemoteLegacySolutionEventsAggregationService.cs index 8c330c8e48538..bfa385fe18bc0 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/LegacySolutionEvents/RemoteLegacySolutionEventsAggregationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/LegacySolutionEvents/RemoteLegacySolutionEventsAggregationService.cs @@ -10,48 +10,47 @@ using Microsoft.CodeAnalysis.LegacySolutionEvents; using Microsoft.CodeAnalysis.Shared.Extensions; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteLegacySolutionEventsAggregationService : BrokeredServiceBase, IRemoteLegacySolutionEventsAggregationService { - internal sealed class RemoteLegacySolutionEventsAggregationService : BrokeredServiceBase, IRemoteLegacySolutionEventsAggregationService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteLegacySolutionEventsAggregationService CreateService(in ServiceConstructionArguments arguments) - => new RemoteLegacySolutionEventsAggregationService(arguments); - } + protected override IRemoteLegacySolutionEventsAggregationService CreateService(in ServiceConstructionArguments arguments) + => new RemoteLegacySolutionEventsAggregationService(arguments); + } - public RemoteLegacySolutionEventsAggregationService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } + public RemoteLegacySolutionEventsAggregationService(in ServiceConstructionArguments arguments) + : base(arguments) + { + } - public ValueTask ShouldReportChangesAsync(CancellationToken cancellationToken) - { - return RunServiceImplAsync( - cancellationToken => - { - var services = this.GetWorkspaceServices(); - var aggregationService = services.GetRequiredService(); - return new ValueTask(aggregationService.ShouldReportChanges(services)); - }, - cancellationToken); - } + public ValueTask ShouldReportChangesAsync(CancellationToken cancellationToken) + { + return RunServiceImplAsync( + cancellationToken => + { + var services = this.GetWorkspaceServices(); + var aggregationService = services.GetRequiredService(); + return new ValueTask(aggregationService.ShouldReportChanges(services)); + }, + cancellationToken); + } - public ValueTask OnWorkspaceChangedAsync( - Checksum oldSolutionChecksum, - Checksum newSolutionChecksum, - WorkspaceChangeKind kind, - ProjectId? projectId, - DocumentId? documentId, - CancellationToken cancellationToken) - { - return RunServiceAsync(oldSolutionChecksum, newSolutionChecksum, - async (oldSolution, newSolution) => - { - var aggregationService = oldSolution.Services.GetRequiredService(); - await aggregationService.OnWorkspaceChangedAsync( - new WorkspaceChangeEventArgs(kind, oldSolution, newSolution, projectId, documentId), cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + public ValueTask OnWorkspaceChangedAsync( + Checksum oldSolutionChecksum, + Checksum newSolutionChecksum, + WorkspaceChangeKind kind, + ProjectId? projectId, + DocumentId? documentId, + CancellationToken cancellationToken) + { + return RunServiceAsync(oldSolutionChecksum, newSolutionChecksum, + async (oldSolution, newSolution) => + { + var aggregationService = oldSolution.Services.GetRequiredService(); + await aggregationService.OnWorkspaceChangedAsync( + new WorkspaceChangeEventArgs(kind, oldSolution, newSolution, projectId, documentId), cancellationToken).ConfigureAwait(false); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs b/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs index 80390ae4768d0..ce5eefcae2312 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/MissingImportDiscovery/RemoteMissingImportDiscoveryService.cs @@ -11,108 +11,107 @@ using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteMissingImportDiscoveryService : BrokeredServiceBase, IRemoteMissingImportDiscoveryService { - internal sealed class RemoteMissingImportDiscoveryService : BrokeredServiceBase, IRemoteMissingImportDiscoveryService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteMissingImportDiscoveryService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteMissingImportDiscoveryService(arguments, callback); - } + protected override IRemoteMissingImportDiscoveryService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) + => new RemoteMissingImportDiscoveryService(arguments, callback); + } - private readonly RemoteCallback _callback; + private readonly RemoteCallback _callback; - public RemoteMissingImportDiscoveryService(in ServiceConstructionArguments arguments, RemoteCallback callback) - : base(arguments) - { - _callback = callback; - } + public RemoteMissingImportDiscoveryService(in ServiceConstructionArguments arguments, RemoteCallback callback) + : base(arguments) + { + _callback = callback; + } - public ValueTask> GetFixesAsync( - Checksum solutionChecksum, - RemoteServiceCallbackId callbackId, - DocumentId documentId, - TextSpan span, - string diagnosticId, - int maxResults, - AddImportOptions options, - ImmutableArray packageSources, - CancellationToken cancellationToken) + public ValueTask> GetFixesAsync( + Checksum solutionChecksum, + RemoteServiceCallbackId callbackId, + DocumentId documentId, + TextSpan span, + string diagnosticId, + int maxResults, + AddImportOptions options, + ImmutableArray packageSources, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var document = solution.GetRequiredDocument(documentId); + var document = solution.GetRequiredDocument(documentId); - var service = document.GetRequiredLanguageService(); + var service = document.GetRequiredLanguageService(); - var symbolSearchService = new SymbolSearchService(_callback, callbackId); + var symbolSearchService = new SymbolSearchService(_callback, callbackId); - var result = await service.GetFixesAsync( - document, span, diagnosticId, maxResults, - symbolSearchService, options, - packageSources, cancellationToken).ConfigureAwait(false); + var result = await service.GetFixesAsync( + document, span, diagnosticId, maxResults, + symbolSearchService, options, + packageSources, cancellationToken).ConfigureAwait(false); - return result; - }, cancellationToken); - } + return result; + }, cancellationToken); + } - public ValueTask> GetUniqueFixesAsync( - Checksum solutionChecksum, - RemoteServiceCallbackId callbackId, - DocumentId documentId, - TextSpan span, - ImmutableArray diagnosticIds, - AddImportOptions options, - ImmutableArray packageSources, - CancellationToken cancellationToken) + public ValueTask> GetUniqueFixesAsync( + Checksum solutionChecksum, + RemoteServiceCallbackId callbackId, + DocumentId documentId, + TextSpan span, + ImmutableArray diagnosticIds, + AddImportOptions options, + ImmutableArray packageSources, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var document = solution.GetRequiredDocument(documentId); + var document = solution.GetRequiredDocument(documentId); - var service = document.GetRequiredLanguageService(); + var service = document.GetRequiredLanguageService(); - var symbolSearchService = new SymbolSearchService(_callback, callbackId); + var symbolSearchService = new SymbolSearchService(_callback, callbackId); - var result = await service.GetUniqueFixesAsync( - document, span, diagnosticIds, - symbolSearchService, options, - packageSources, cancellationToken).ConfigureAwait(false); + var result = await service.GetUniqueFixesAsync( + document, span, diagnosticIds, + symbolSearchService, options, + packageSources, cancellationToken).ConfigureAwait(false); - return result; - }, cancellationToken); - } + return result; + }, cancellationToken); + } - /// - /// Provides an implementation of the on the remote side so that - /// Add-Import can find results in nuget packages/reference assemblies. This works - /// by remoting *from* the OOP server back to the host, which can then forward this - /// appropriately to wherever the real is running. This is necessary - /// because it's not guaranteed that the real will be running in - /// the same process that is supplying the . - /// - /// Ideally we would not need to bounce back to the host for this. - /// - private sealed class SymbolSearchService : ISymbolSearchService - { - private readonly RemoteCallback _callback; - private readonly RemoteServiceCallbackId _callbackId; + /// + /// Provides an implementation of the on the remote side so that + /// Add-Import can find results in nuget packages/reference assemblies. This works + /// by remoting *from* the OOP server back to the host, which can then forward this + /// appropriately to wherever the real is running. This is necessary + /// because it's not guaranteed that the real will be running in + /// the same process that is supplying the . + /// + /// Ideally we would not need to bounce back to the host for this. + /// + private sealed class SymbolSearchService : ISymbolSearchService + { + private readonly RemoteCallback _callback; + private readonly RemoteServiceCallbackId _callbackId; - public SymbolSearchService(RemoteCallback callback, RemoteServiceCallbackId callbackId) - { - _callback = callback; - _callbackId = callbackId; - } + public SymbolSearchService(RemoteCallback callback, RemoteServiceCallbackId callbackId) + { + _callback = callback; + _callbackId = callbackId; + } - public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.FindPackagesWithTypeAsync(_callbackId, source, name, arity, cancellationToken), cancellationToken); + public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.FindPackagesWithTypeAsync(_callbackId, source, name, arity, cancellationToken), cancellationToken); - public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.FindPackagesWithAssemblyAsync(_callbackId, source, assemblyName, cancellationToken), cancellationToken); + public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.FindPackagesWithAssemblyAsync(_callbackId, source, assemblyName, cancellationToken), cancellationToken); - public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.FindReferenceAssembliesWithTypeAsync(_callbackId, name, arity, cancellationToken), cancellationToken); - } + public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.FindReferenceAssembliesWithTypeAsync(_callbackId, name, arity, cancellationToken), cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs b/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs index 27ea35c52107e..a22cacfb58b09 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs @@ -11,114 +11,113 @@ using Microsoft.CodeAnalysis.Storage; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteNavigateToSearchService( + in BrokeredServiceBase.ServiceConstructionArguments arguments, + RemoteCallback callback) + : BrokeredServiceBase(arguments), IRemoteNavigateToSearchService { - internal sealed class RemoteNavigateToSearchService( - in BrokeredServiceBase.ServiceConstructionArguments arguments, - RemoteCallback callback) - : BrokeredServiceBase(arguments), IRemoteNavigateToSearchService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteNavigateToSearchService CreateService( - in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteNavigateToSearchService(arguments, callback); - } + protected override IRemoteNavigateToSearchService CreateService( + in ServiceConstructionArguments arguments, RemoteCallback callback) + => new RemoteNavigateToSearchService(arguments, callback); + } - private readonly RemoteCallback _callback = callback; + private readonly RemoteCallback _callback = callback; - private (Func, VoidResult, CancellationToken, Task> onItemsFound, Func onProjectCompleted) GetCallbacks( - RemoteServiceCallbackId callbackId, CancellationToken cancellationToken) - { - return ( - async (array, _, cancellationToken) => await _callback.InvokeAsync((callback, cancellationToken) => callback.OnItemsFoundAsync(callbackId, array), cancellationToken).ConfigureAwait(false), - async () => await _callback.InvokeAsync((callback, cancellationToken) => callback.OnProjectCompletedAsync(callbackId), cancellationToken).ConfigureAwait(false)); - } + private (Func, VoidResult, CancellationToken, Task> onItemsFound, Func onProjectCompleted) GetCallbacks( + RemoteServiceCallbackId callbackId, CancellationToken cancellationToken) + { + return ( + async (array, _, cancellationToken) => await _callback.InvokeAsync((callback, cancellationToken) => callback.OnItemsFoundAsync(callbackId, array), cancellationToken).ConfigureAwait(false), + async () => await _callback.InvokeAsync((callback, cancellationToken) => callback.OnProjectCompletedAsync(callbackId), cancellationToken).ConfigureAwait(false)); + } - public ValueTask HydrateAsync(Checksum solutionChecksum, CancellationToken cancellationToken) - { - // All we need to do is request the solution. This will ensure that all assets are - // pulled over from the host side to the remote side. Once this completes, the next - // call to SearchFullyLoadedDocumentAsync or SearchFullyLoadedProjectAsync will be - // quick as very little will need to by sync'ed over. - return RunServiceAsync(solutionChecksum, solution => ValueTaskFactory.CompletedTask, cancellationToken); - } + public ValueTask HydrateAsync(Checksum solutionChecksum, CancellationToken cancellationToken) + { + // All we need to do is request the solution. This will ensure that all assets are + // pulled over from the host side to the remote side. Once this completes, the next + // call to SearchFullyLoadedDocumentAsync or SearchFullyLoadedProjectAsync will be + // quick as very little will need to by sync'ed over. + return RunServiceAsync(solutionChecksum, solution => ValueTaskFactory.CompletedTask, cancellationToken); + } - public ValueTask SearchDocumentAsync( - Checksum solutionChecksum, - DocumentId documentId, - string searchPattern, - ImmutableArray kinds, - RemoteServiceCallbackId callbackId, - CancellationToken cancellationToken) + public ValueTask SearchDocumentAsync( + Checksum solutionChecksum, + DocumentId documentId, + string searchPattern, + ImmutableArray kinds, + RemoteServiceCallbackId callbackId, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var document = solution.GetRequiredDocument(documentId); - var (onItemsFound, onProjectCompleted) = GetCallbacks(callbackId, cancellationToken); + var document = solution.GetRequiredDocument(documentId); + var (onItemsFound, onProjectCompleted) = GetCallbacks(callbackId, cancellationToken); - await AbstractNavigateToSearchService.SearchDocumentInCurrentProcessAsync( - document, searchPattern, kinds.ToImmutableHashSet(), onItemsFound, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + await AbstractNavigateToSearchService.SearchDocumentInCurrentProcessAsync( + document, searchPattern, kinds.ToImmutableHashSet(), onItemsFound, cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } - public ValueTask SearchProjectsAsync( - Checksum solutionChecksum, - ImmutableArray projectIds, - ImmutableArray priorityDocumentIds, - string searchPattern, - ImmutableArray kinds, - RemoteServiceCallbackId callbackId, - CancellationToken cancellationToken) + public ValueTask SearchProjectsAsync( + Checksum solutionChecksum, + ImmutableArray projectIds, + ImmutableArray priorityDocumentIds, + string searchPattern, + ImmutableArray kinds, + RemoteServiceCallbackId callbackId, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var projects = projectIds.SelectAsArray(solution.GetRequiredProject); - var (onItemsFound, onProjectCompleted) = GetCallbacks(callbackId, cancellationToken); + var projects = projectIds.SelectAsArray(solution.GetRequiredProject); + var (onItemsFound, onProjectCompleted) = GetCallbacks(callbackId, cancellationToken); - var priorityDocuments = priorityDocumentIds.SelectAsArray(d => solution.GetRequiredDocument(d)); + var priorityDocuments = priorityDocumentIds.SelectAsArray(d => solution.GetRequiredDocument(d)); - await AbstractNavigateToSearchService.SearchProjectsInCurrentProcessAsync( - projects, priorityDocuments, searchPattern, kinds.ToImmutableHashSet(), onItemsFound, onProjectCompleted, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + await AbstractNavigateToSearchService.SearchProjectsInCurrentProcessAsync( + projects, priorityDocuments, searchPattern, kinds.ToImmutableHashSet(), onItemsFound, onProjectCompleted, cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } - public ValueTask SearchGeneratedDocumentsAsync( - Checksum solutionChecksum, - ImmutableArray projectIds, - string searchPattern, - ImmutableArray kinds, - RemoteServiceCallbackId callbackId, - CancellationToken cancellationToken) + public ValueTask SearchGeneratedDocumentsAsync( + Checksum solutionChecksum, + ImmutableArray projectIds, + string searchPattern, + ImmutableArray kinds, + RemoteServiceCallbackId callbackId, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var projects = projectIds.SelectAsArray(solution.GetRequiredProject); - var (onItemsFound, onProjectCompleted) = GetCallbacks(callbackId, cancellationToken); + var projects = projectIds.SelectAsArray(solution.GetRequiredProject); + var (onItemsFound, onProjectCompleted) = GetCallbacks(callbackId, cancellationToken); - await AbstractNavigateToSearchService.SearchGeneratedDocumentsInCurrentProcessAsync( - projects, searchPattern, kinds.ToImmutableHashSet(), onItemsFound, onProjectCompleted, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + await AbstractNavigateToSearchService.SearchGeneratedDocumentsInCurrentProcessAsync( + projects, searchPattern, kinds.ToImmutableHashSet(), onItemsFound, onProjectCompleted, cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } - public ValueTask SearchCachedDocumentsAsync( - ImmutableArray documentKeys, - ImmutableArray priorityDocumentKeys, - string searchPattern, - ImmutableArray kinds, - RemoteServiceCallbackId callbackId, - CancellationToken cancellationToken) + public ValueTask SearchCachedDocumentsAsync( + ImmutableArray documentKeys, + ImmutableArray priorityDocumentKeys, + string searchPattern, + ImmutableArray kinds, + RemoteServiceCallbackId callbackId, + CancellationToken cancellationToken) + { + return RunServiceAsync(async cancellationToken => { - return RunServiceAsync(async cancellationToken => - { - // Intentionally do not call GetSolutionAsync here. We do not want the cost of - // synchronizing the solution over to the remote side. Instead, we just directly - // check whatever cached data we have from the previous vs session. - var (onItemsFound, onProjectCompleted) = GetCallbacks(callbackId, cancellationToken); - var storageService = GetWorkspaceServices().GetPersistentStorageService(); - await AbstractNavigateToSearchService.SearchCachedDocumentsInCurrentProcessAsync( - storageService, documentKeys, priorityDocumentKeys, searchPattern, kinds.ToImmutableHashSet(), onItemsFound, onProjectCompleted, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + // Intentionally do not call GetSolutionAsync here. We do not want the cost of + // synchronizing the solution over to the remote side. Instead, we just directly + // check whatever cached data we have from the previous vs session. + var (onItemsFound, onProjectCompleted) = GetCallbacks(callbackId, cancellationToken); + var storageService = GetWorkspaceServices().GetPersistentStorageService(); + await AbstractNavigateToSearchService.SearchCachedDocumentsInCurrentProcessAsync( + storageService, documentKeys, priorityDocumentKeys, searchPattern, kinds.ToImmutableHashSet(), onItemsFound, onProjectCompleted, cancellationToken).ConfigureAwait(false); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteProcessTelemetryService.cs b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteProcessTelemetryService.cs index 68dc14bacabfc..5f29640ef50e3 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteProcessTelemetryService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteProcessTelemetryService.cs @@ -19,105 +19,101 @@ using Roslyn.Utilities; using RoslynLogger = Microsoft.CodeAnalysis.Internal.Log.Logger; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed partial class RemoteProcessTelemetryService( + BrokeredServiceBase.ServiceConstructionArguments arguments) + : BrokeredServiceBase(arguments), IRemoteProcessTelemetryService { - internal sealed partial class RemoteProcessTelemetryService : BrokeredServiceBase, IRemoteProcessTelemetryService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteProcessTelemetryService CreateService(in ServiceConstructionArguments arguments) - => new RemoteProcessTelemetryService(arguments); - } + protected override IRemoteProcessTelemetryService CreateService(in ServiceConstructionArguments arguments) + => new RemoteProcessTelemetryService(arguments); + } - private readonly CancellationTokenSource _shutdownCancellationSource = new(); + private readonly CancellationTokenSource _shutdownCancellationSource = new(); #pragma warning disable IDE0052 // Remove unread private members - private PerformanceReporter? _performanceReporter; + private PerformanceReporter? _performanceReporter; #pragma warning restore - public RemoteProcessTelemetryService(ServiceConstructionArguments arguments) - : base(arguments) + /// + /// Remote API. Initializes ServiceHub process global state. + /// + public ValueTask InitializeTelemetrySessionAsync(int hostProcessId, string serializedSession, bool logDelta, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => { - } + var services = GetWorkspace().Services; - /// - /// Remote API. Initializes ServiceHub process global state. - /// - public ValueTask InitializeTelemetrySessionAsync(int hostProcessId, string serializedSession, bool logDelta, CancellationToken cancellationToken) - { - return RunServiceAsync(cancellationToken => + var telemetryService = (RemoteWorkspaceTelemetryService)services.GetRequiredService(); + var telemetrySession = new TelemetrySession(serializedSession); + telemetrySession.Start(); + + telemetryService.InitializeTelemetrySession(telemetrySession, logDelta); + telemetryService.RegisterUnexpectedExceptionLogger(TraceLogger); + FaultReporter.InitializeFatalErrorHandlers(); + + // log telemetry that service hub started + RoslynLogger.Log(FunctionId.RemoteHost_Connect, KeyValueLogMessage.Create(m => { - var services = GetWorkspace().Services; - - var telemetryService = (RemoteWorkspaceTelemetryService)services.GetRequiredService(); - var telemetrySession = new TelemetrySession(serializedSession); - telemetrySession.Start(); - - telemetryService.InitializeTelemetrySession(telemetrySession, logDelta); - telemetryService.RegisterUnexpectedExceptionLogger(TraceLogger); - FaultReporter.InitializeFatalErrorHandlers(); - - // log telemetry that service hub started - RoslynLogger.Log(FunctionId.RemoteHost_Connect, KeyValueLogMessage.Create(m => - { - m["Host"] = hostProcessId; - m["Framework"] = RuntimeInformation.FrameworkDescription; - })); - - // start performance reporter - var diagnosticAnalyzerPerformanceTracker = services.GetService(); - if (diagnosticAnalyzerPerformanceTracker != null) - { - // We know in the remote layer that this type must exist. - _performanceReporter = new PerformanceReporter(telemetrySession, diagnosticAnalyzerPerformanceTracker, _shutdownCancellationSource.Token); - } - - return ValueTaskFactory.CompletedTask; - }, cancellationToken); - } + m["Host"] = hostProcessId; + m["Framework"] = RuntimeInformation.FrameworkDescription; + })); - /// - /// Remote API. - /// - public ValueTask EnableLoggingAsync(ImmutableArray loggerTypeNames, ImmutableArray functionIds, CancellationToken cancellationToken) - { - return RunServiceAsync(cancellationToken => + // start performance reporter + var diagnosticAnalyzerPerformanceTracker = services.GetService(); + if (diagnosticAnalyzerPerformanceTracker != null) { - var functionIdsSet = new HashSet(functionIds); - bool logChecker(FunctionId id) => functionIdsSet.Contains(id); + // We know in the remote layer that this type must exist. + _performanceReporter = new PerformanceReporter(telemetrySession, diagnosticAnalyzerPerformanceTracker, _shutdownCancellationSource.Token); + } - // we only support 2 types of loggers - SetRoslynLogger(loggerTypeNames, () => new EtwLogger(logChecker)); - SetRoslynLogger(loggerTypeNames, () => new TraceLogger(logChecker)); + return ValueTaskFactory.CompletedTask; + }, cancellationToken); + } - return ValueTaskFactory.CompletedTask; - }, cancellationToken); - } + /// + /// Remote API. + /// + public ValueTask EnableLoggingAsync(ImmutableArray loggerTypeNames, ImmutableArray functionIds, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => + { + var functionIdsSet = new HashSet(functionIds); + bool logChecker(FunctionId id) => functionIdsSet.Contains(id); + + // we only support 2 types of loggers + SetRoslynLogger(loggerTypeNames, () => new EtwLogger(logChecker)); + SetRoslynLogger(loggerTypeNames, () => new TraceLogger(logChecker)); + + return ValueTaskFactory.CompletedTask; + }, cancellationToken); + } - private static void SetRoslynLogger(ImmutableArray loggerTypes, Func creator) where T : ILogger + private static void SetRoslynLogger(ImmutableArray loggerTypes, Func creator) where T : ILogger + { + if (loggerTypes.Contains(typeof(T).Name)) { - if (loggerTypes.Contains(typeof(T).Name)) - { - RoslynLogger.SetLogger(AggregateLogger.AddOrReplace(creator(), RoslynLogger.GetLogger(), l => l is T)); - } - else - { - RoslynLogger.SetLogger(AggregateLogger.Remove(RoslynLogger.GetLogger(), l => l is T)); - } + RoslynLogger.SetLogger(AggregateLogger.AddOrReplace(creator(), RoslynLogger.GetLogger(), l => l is T)); + } + else + { + RoslynLogger.SetLogger(AggregateLogger.Remove(RoslynLogger.GetLogger(), l => l is T)); } + } - /// - /// Remote API. - /// - public ValueTask InitializeAsync(WorkspaceConfigurationOptions options, CancellationToken cancellationToken) + /// + /// Remote API. + /// + public ValueTask InitializeAsync(WorkspaceConfigurationOptions options, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => { - return RunServiceAsync(cancellationToken => - { - var service = (RemoteWorkspaceConfigurationService)GetWorkspaceServices().GetRequiredService(); - service.InitializeOptions(options); + var service = (RemoteWorkspaceConfigurationService)GetWorkspaceServices().GetRequiredService(); + service.InitializeOptions(options); - return ValueTaskFactory.FromResult(Process.GetCurrentProcess().Id); - }, cancellationToken); - } + return ValueTaskFactory.FromResult(Process.GetCurrentProcess().Id); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs index 5acccbc75aacb..528ddd7abaa31 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceConfigurationService.cs @@ -9,31 +9,30 @@ using Microsoft.CodeAnalysis.Storage; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Host +namespace Microsoft.CodeAnalysis.Host; + +[ExportWorkspaceService(typeof(IWorkspaceConfigurationService), ServiceLayer.Host), Shared] +internal sealed class RemoteWorkspaceConfigurationService : IWorkspaceConfigurationService { - [ExportWorkspaceService(typeof(IWorkspaceConfigurationService), ServiceLayer.Host), Shared] - internal sealed class RemoteWorkspaceConfigurationService : IWorkspaceConfigurationService - { - private WorkspaceConfigurationOptions? _options; + private WorkspaceConfigurationOptions? _options; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RemoteWorkspaceConfigurationService() - { - } + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public RemoteWorkspaceConfigurationService() + { + } - /// - /// Returns default values until the options are initialized. - /// - public WorkspaceConfigurationOptions Options - => _options ?? WorkspaceConfigurationOptions.RemoteDefault; + /// + /// Returns default values until the options are initialized. + /// + public WorkspaceConfigurationOptions Options + => _options ?? WorkspaceConfigurationOptions.RemoteDefault; - public void InitializeOptions(WorkspaceConfigurationOptions options) - { - // can only be set once: - Contract.ThrowIfFalse(_options == null); + public void InitializeOptions(WorkspaceConfigurationOptions options) + { + // can only be set once: + Contract.ThrowIfFalse(_options == null); - _options = options; - } + _options = options; } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceTelemetryService.cs b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceTelemetryService.cs index 10418a10b72f8..2444da5f4ffab 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceTelemetryService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ProcessTelemetry/RemoteWorkspaceTelemetryService.cs @@ -9,20 +9,15 @@ using Microsoft.CodeAnalysis.Telemetry; using Microsoft.VisualStudio.Telemetry; -namespace Microsoft.VisualStudio.LanguageServices.Telemetry -{ - [ExportWorkspaceService(typeof(IWorkspaceTelemetryService)), Shared] - internal sealed class RemoteWorkspaceTelemetryService : AbstractWorkspaceTelemetryService - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RemoteWorkspaceTelemetryService() - { - } +namespace Microsoft.VisualStudio.LanguageServices.Telemetry; - protected override ILogger CreateLogger(TelemetrySession telemetrySession, bool logDelta) - => AggregateLogger.Create( - TelemetryLogger.Create(telemetrySession, logDelta), - Logger.GetLogger()); - } +[ExportWorkspaceService(typeof(IWorkspaceTelemetryService)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class RemoteWorkspaceTelemetryService() : AbstractWorkspaceTelemetryService +{ + protected override ILogger CreateLogger(TelemetrySession telemetrySession, bool logDelta) + => AggregateLogger.Create( + TelemetryLogger.Create(telemetrySession, logDelta), + Logger.GetLogger()); } diff --git a/src/Workspaces/Remote/ServiceHub/Services/RelatedDocuments/RemoteRelatedDocumentsService.cs b/src/Workspaces/Remote/ServiceHub/Services/RelatedDocuments/RemoteRelatedDocumentsService.cs new file mode 100644 index 0000000000000..16e795809acfb --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Services/RelatedDocuments/RemoteRelatedDocumentsService.cs @@ -0,0 +1,50 @@ +// 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 System.Threading.Tasks; +using Microsoft.CodeAnalysis.RelatedDocuments; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteRelatedDocumentsService( + in BrokeredServiceBase.ServiceConstructionArguments arguments, + RemoteCallback callback) + : BrokeredServiceBase(arguments), IRemoteRelatedDocumentsService +{ + internal sealed class Factory : FactoryBase + { + protected override IRemoteRelatedDocumentsService CreateService( + in ServiceConstructionArguments arguments, RemoteCallback callback) + => new RemoteRelatedDocumentsService(arguments, callback); + } + + private readonly RemoteCallback _callback = callback; + + private Func, CancellationToken, ValueTask> GetCallbackFunction(RemoteServiceCallbackId callbackId) + // When the callback is invoked on our side (the remote side), forward the values back to the host. + => async (documentIds, cancellationToken) => await _callback.InvokeAsync( + async (callback, cancellationToken) => await callback.ReportRelatedDocumentAsync(callbackId, documentIds, cancellationToken).ConfigureAwait(false), + cancellationToken).ConfigureAwait(false); + + public ValueTask GetRelatedDocumentIdsAsync( + Checksum solutionChecksum, + DocumentId documentId, + int position, + RemoteServiceCallbackId callbackId, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => + { + var document = solution.GetRequiredDocument(documentId); + var service = document.GetRequiredLanguageService(); + + await service.GetRelatedDocumentIdsAsync( + document, position, GetCallbackFunction(callbackId), cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } +} diff --git a/src/Workspaces/Remote/ServiceHub/Services/Renamer/RemoteRenamerService.cs b/src/Workspaces/Remote/ServiceHub/Services/Renamer/RemoteRenamerService.cs index 25496392fd701..3d146b0a4ef91 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/Renamer/RemoteRenamerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/Renamer/RemoteRenamerService.cs @@ -8,88 +8,87 @@ using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Rename.ConflictEngine; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed partial class RemoteRenamerService(in BrokeredServiceBase.ServiceConstructionArguments arguments) + : BrokeredServiceBase(arguments), IRemoteRenamerService { - internal sealed partial class RemoteRenamerService(in BrokeredServiceBase.ServiceConstructionArguments arguments) - : BrokeredServiceBase(arguments), IRemoteRenamerService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteRenamerService CreateService(in ServiceConstructionArguments arguments) - => new RemoteRenamerService(arguments); - } + protected override IRemoteRenamerService CreateService(in ServiceConstructionArguments arguments) + => new RemoteRenamerService(arguments); + } - public ValueTask RenameSymbolAsync( - Checksum solutionChecksum, - SerializableSymbolAndProjectId symbolAndProjectId, - string newName, - SymbolRenameOptions options, - ImmutableArray nonConflictSymbolKeys, - CancellationToken cancellationToken) + public ValueTask RenameSymbolAsync( + Checksum solutionChecksum, + SerializableSymbolAndProjectId symbolAndProjectId, + string newName, + SymbolRenameOptions options, + ImmutableArray nonConflictSymbolKeys, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var symbol = await symbolAndProjectId.TryRehydrateAsync( - solution, cancellationToken).ConfigureAwait(false); + var symbol = await symbolAndProjectId.TryRehydrateAsync( + solution, cancellationToken).ConfigureAwait(false); - if (symbol == null) - return null; + if (symbol == null) + return null; - var result = await Renamer.RenameSymbolAsync( - solution, symbol, newName, options, nonConflictSymbolKeys, cancellationToken).ConfigureAwait(false); + var result = await Renamer.RenameSymbolAsync( + solution, symbol, newName, options, nonConflictSymbolKeys, cancellationToken).ConfigureAwait(false); - return await result.DehydrateAsync(cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + return await result.DehydrateAsync(cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } - public ValueTask FindRenameLocationsAsync( - Checksum solutionChecksum, - SerializableSymbolAndProjectId symbolAndProjectId, - SymbolRenameOptions options, - CancellationToken cancellationToken) + public ValueTask FindRenameLocationsAsync( + Checksum solutionChecksum, + SerializableSymbolAndProjectId symbolAndProjectId, + SymbolRenameOptions options, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var symbol = await symbolAndProjectId.TryRehydrateAsync( - solution, cancellationToken).ConfigureAwait(false); + var symbol = await symbolAndProjectId.TryRehydrateAsync( + solution, cancellationToken).ConfigureAwait(false); - if (symbol == null) - return null; + if (symbol == null) + return null; - var renameLocations = await SymbolicRenameLocations.FindLocationsInCurrentProcessAsync( - symbol, solution, options, cancellationToken).ConfigureAwait(false); + var renameLocations = await SymbolicRenameLocations.FindLocationsInCurrentProcessAsync( + symbol, solution, options, cancellationToken).ConfigureAwait(false); - return new SerializableRenameLocations( - options, - renameLocations.Locations.SelectAsArray(SerializableRenameLocation.Dehydrate), - renameLocations.ImplicitLocations.SelectAsArray(loc => SerializableReferenceLocation.Dehydrate(loc, cancellationToken)), - renameLocations.ReferencedSymbols.SelectAsArray(sym => SerializableSymbolAndProjectId.Dehydrate(solution, sym, cancellationToken))); - }, cancellationToken); - } + return new SerializableRenameLocations( + options, + renameLocations.Locations.SelectAsArray(SerializableRenameLocation.Dehydrate), + renameLocations.ImplicitLocations.SelectAsArray(loc => SerializableReferenceLocation.Dehydrate(loc, cancellationToken)), + renameLocations.ReferencedSymbols.SelectAsArray(sym => SerializableSymbolAndProjectId.Dehydrate(solution, sym, cancellationToken))); + }, cancellationToken); + } - public ValueTask ResolveConflictsAsync( - Checksum solutionChecksum, - SerializableSymbolAndProjectId symbolAndProjectId, - SerializableRenameLocations serializableLocations, - string replacementText, - ImmutableArray nonConflictSymbolKeys, - CancellationToken cancellationToken) + public ValueTask ResolveConflictsAsync( + Checksum solutionChecksum, + SerializableSymbolAndProjectId symbolAndProjectId, + SerializableRenameLocations serializableLocations, + string replacementText, + ImmutableArray nonConflictSymbolKeys, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var symbol = await symbolAndProjectId.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false); - if (symbol is null) - return null; + var symbol = await symbolAndProjectId.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false); + if (symbol is null) + return null; - var locations = await SymbolicRenameLocations.TryRehydrateAsync( - symbol, solution, serializableLocations, cancellationToken).ConfigureAwait(false); - if (locations is null) - return null; + var locations = await SymbolicRenameLocations.TryRehydrateAsync( + symbol, solution, serializableLocations, cancellationToken).ConfigureAwait(false); + if (locations is null) + return null; - var result = await ConflictResolver.ResolveSymbolicLocationConflictsInCurrentProcessAsync( - locations, replacementText, nonConflictSymbolKeys, cancellationToken).ConfigureAwait(false); - return await result.DehydrateAsync(cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + var result = await ConflictResolver.ResolveSymbolicLocationConflictsInCurrentProcessAsync( + locations, replacementText, nonConflictSymbolKeys, cancellationToken).ConfigureAwait(false); + return await result.DehydrateAsync(cancellationToken).ConfigureAwait(false); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.Caching.cs b/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.Caching.cs index 37af8b88a1cae..07e30f33df3e7 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.Caching.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.Caching.cs @@ -19,317 +19,316 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed partial class RemoteSemanticClassificationService : BrokeredServiceBase, IRemoteSemanticClassificationService { - internal sealed partial class RemoteSemanticClassificationService : BrokeredServiceBase, IRemoteSemanticClassificationService + /// + /// Key we use to look this up in the persistence store for a particular document. + /// + private const string s_semanticPersistenceName = ""; + private const string s_embeddedLanguagePersistenceName = ""; + + /// + /// Our current persistence version. If we ever change the on-disk format, this should be changed so that we + /// skip over persisted data that we cannot read. + /// + private const int ClassificationFormat = 4; + + private const int MaxCachedDocumentCount = 8; + + /// + /// Cache of the previously requested classified spans for a particular document. We use this so that during + /// loading, if we're asking about the same documents multiple times by the classification service, we can just + /// return what we have already loaded and not go back to the persistence store to read/decode. + /// + /// This can be read and updated from different threads. To keep things safe, we use this object itself + /// as the lock that is taken to serialize access. + /// + private readonly LinkedList<(DocumentId id, ClassificationType type, Checksum checksum, ImmutableArray classifiedSpans)> _cachedData = new(); + + /// + /// Queue where we place documents we want to compute and cache full semantic classifications for. Note: the + /// same document may appear multiple times inside of this queue (for different versions of the document). + /// However, we'll only process the last version of any document added. + /// + private readonly AsyncBatchingWorkQueue<(Document, ClassificationType type, ClassificationOptions)> _workQueue; + private readonly CancellationTokenSource _cancellationTokenSource = new(); + + public RemoteSemanticClassificationService(in ServiceConstructionArguments arguments) + : base(arguments) { - /// - /// Key we use to look this up in the persistence store for a particular document. - /// - private const string s_semanticPersistenceName = ""; - private const string s_embeddedLanguagePersistenceName = ""; - - /// - /// Our current persistence version. If we ever change the on-disk format, this should be changed so that we - /// skip over persisted data that we cannot read. - /// - private const int ClassificationFormat = 4; - - private const int MaxCachedDocumentCount = 8; - - /// - /// Cache of the previously requested classified spans for a particular document. We use this so that during - /// loading, if we're asking about the same documents multiple times by the classification service, we can just - /// return what we have already loaded and not go back to the persistence store to read/decode. - /// - /// This can be read and updated from different threads. To keep things safe, we use this object itself - /// as the lock that is taken to serialize access. - /// - private readonly LinkedList<(DocumentId id, ClassificationType type, Checksum checksum, ImmutableArray classifiedSpans)> _cachedData = new(); - - /// - /// Queue where we place documents we want to compute and cache full semantic classifications for. Note: the - /// same document may appear multiple times inside of this queue (for different versions of the document). - /// However, we'll only process the last version of any document added. - /// - private readonly AsyncBatchingWorkQueue<(Document, ClassificationType type, ClassificationOptions)> _workQueue; - private readonly CancellationTokenSource _cancellationTokenSource = new(); - - public RemoteSemanticClassificationService(in ServiceConstructionArguments arguments) - : base(arguments) - { - _workQueue = new AsyncBatchingWorkQueue<(Document, ClassificationType, ClassificationOptions)>( - DelayTimeSpan.NonFocus, - CacheClassificationsAsync, - EqualityComparer<(Document, ClassificationType, ClassificationOptions)>.Default, - AsynchronousOperationListenerProvider.NullListener, - _cancellationTokenSource.Token); - } - - public override void Dispose() - { - _cancellationTokenSource.Cancel(); - base.Dispose(); - } + _workQueue = new AsyncBatchingWorkQueue<(Document, ClassificationType, ClassificationOptions)>( + DelayTimeSpan.NonFocus, + CacheClassificationsAsync, + EqualityComparer<(Document, ClassificationType, ClassificationOptions)>.Default, + AsynchronousOperationListenerProvider.NullListener, + _cancellationTokenSource.Token); + } - private static string GetPersistenceName(ClassificationType type) - => type switch - { - ClassificationType.Semantic => s_semanticPersistenceName, - ClassificationType.EmbeddedLanguage => s_embeddedLanguagePersistenceName, - _ => throw ExceptionUtilities.UnexpectedValue(type), - }; + public override void Dispose() + { + _cancellationTokenSource.Cancel(); + base.Dispose(); + } - public async ValueTask GetCachedClassificationsAsync( - DocumentKey documentKey, ImmutableArray textSpans, ClassificationType type, Checksum checksum, CancellationToken cancellationToken) + private static string GetPersistenceName(ClassificationType type) + => type switch { - var classifiedSpans = await TryGetOrReadCachedSemanticClassificationsAsync( - documentKey, type, checksum, cancellationToken).ConfigureAwait(false); - var textSpanIntervalTree = new TextSpanMutableIntervalTree(textSpans); - return classifiedSpans.IsDefault - ? null - : SerializableClassifiedSpans.Dehydrate(classifiedSpans.WhereAsArray(c => textSpanIntervalTree.HasIntervalThatIntersectsWith(c.TextSpan))); - } + ClassificationType.Semantic => s_semanticPersistenceName, + ClassificationType.EmbeddedLanguage => s_embeddedLanguagePersistenceName, + _ => throw ExceptionUtilities.UnexpectedValue(type), + }; - private static async ValueTask CacheClassificationsAsync( - ImmutableSegmentedList<(Document document, ClassificationType type, ClassificationOptions options)> documents, - CancellationToken cancellationToken) + public async ValueTask GetCachedClassificationsAsync( + DocumentKey documentKey, ImmutableArray textSpans, ClassificationType type, Checksum checksum, CancellationToken cancellationToken) + { + var classifiedSpans = await TryGetOrReadCachedSemanticClassificationsAsync( + documentKey, type, checksum, cancellationToken).ConfigureAwait(false); + var textSpanIntervalTree = new TextSpanMutableIntervalTree(textSpans); + return classifiedSpans.IsDefault + ? null + : SerializableClassifiedSpans.Dehydrate(classifiedSpans.WhereAsArray(c => textSpanIntervalTree.HasIntervalThatIntersectsWith(c.TextSpan))); + } + + private static async ValueTask CacheClassificationsAsync( + ImmutableSegmentedList<(Document document, ClassificationType type, ClassificationOptions options)> documents, + CancellationToken cancellationToken) + { + // First group by type. That way we process the last semantic and last embedded-lang classifications per document. + foreach (var typeGroup in documents.GroupBy(t => t.type)) { - // First group by type. That way we process the last semantic and last embedded-lang classifications per document. - foreach (var typeGroup in documents.GroupBy(t => t.type)) + // Then, group all those requests by document (as we may have gotten many requests for the same + // document). Then, only process the last document from each group (we don't need to bother stale + // versions of a particular document). + foreach (var group in typeGroup.GroupBy(d => d.document.Id)) { - // Then, group all those requests by document (as we may have gotten many requests for the same - // document). Then, only process the last document from each group (we don't need to bother stale - // versions of a particular document). - foreach (var group in typeGroup.GroupBy(d => d.document.Id)) - { - var (document, type, options) = group.Last(); - await CacheClassificationsAsync( - document, type, options, cancellationToken).ConfigureAwait(false); - } + var (document, type, options) = group.Last(); + await CacheClassificationsAsync( + document, type, options, cancellationToken).ConfigureAwait(false); } } + } - private static async Task CacheClassificationsAsync( - Document document, ClassificationType type, ClassificationOptions options, CancellationToken cancellationToken) - { - var solution = document.Project.Solution; - var persistenceService = solution.Services.GetPersistentStorageService(); - - var storage = await persistenceService.GetStorageAsync(SolutionKey.ToSolutionKey(solution), cancellationToken).ConfigureAwait(false); - if (storage == null) - return; - - var classificationService = document.GetLanguageService(); - if (classificationService == null) - return; + private static async Task CacheClassificationsAsync( + Document document, ClassificationType type, ClassificationOptions options, CancellationToken cancellationToken) + { + var solution = document.Project.Solution; + var persistenceService = solution.Services.GetPersistentStorageService(); - // Very intentionally do our lookup with a special document key. This doc key stores info independent of - // project config. So we can still lookup data regardless of things like if the project is in DEBUG or - // RELEASE mode. - var (documentKey, checksum) = await SemanticClassificationCacheUtilities.GetDocumentKeyAndChecksumAsync( - document, cancellationToken).ConfigureAwait(false); + var storage = await persistenceService.GetStorageAsync(SolutionKey.ToSolutionKey(solution), cancellationToken).ConfigureAwait(false); + if (storage == null) + return; - var persistenceName = GetPersistenceName(type); - var matches = await storage.ChecksumMatchesAsync(documentKey, persistenceName, checksum, cancellationToken).ConfigureAwait(false); - if (matches) - return; + var classificationService = document.GetLanguageService(); + if (classificationService == null) + return; - using var _2 = Classifier.GetPooledList(out var classifiedSpans); + // Very intentionally do our lookup with a special document key. This doc key stores info independent of + // project config. So we can still lookup data regardless of things like if the project is in DEBUG or + // RELEASE mode. + var (documentKey, checksum) = await SemanticClassificationCacheUtilities.GetDocumentKeyAndChecksumAsync( + document, cancellationToken).ConfigureAwait(false); - // Compute classifications for the full span. - var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); + var persistenceName = GetPersistenceName(type); + var matches = await storage.ChecksumMatchesAsync(documentKey, persistenceName, checksum, cancellationToken).ConfigureAwait(false); + if (matches) + return; - var fullSpan = new TextSpan(0, text.Length); - if (type == ClassificationType.Semantic) - { - await classificationService.AddSemanticClassificationsAsync(document, fullSpan, options, classifiedSpans, cancellationToken).ConfigureAwait(false); - } - else if (type == ClassificationType.EmbeddedLanguage) - { - await classificationService.AddEmbeddedLanguageClassificationsAsync(document, fullSpan, options, classifiedSpans, cancellationToken).ConfigureAwait(false); - } - else - { - throw ExceptionUtilities.UnexpectedValue(type); - } + using var _2 = Classifier.GetPooledList(out var classifiedSpans); - using var stream = SerializableBytes.CreateWritableStream(); - using (var writer = new ObjectWriter(stream, leaveOpen: true)) - { - WriteTo(classifiedSpans, writer); - } + // Compute classifications for the full span. + var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false); - stream.Position = 0; - await storage.WriteStreamAsync(documentKey, persistenceName, stream, checksum, cancellationToken).ConfigureAwait(false); + var fullSpan = new TextSpan(0, text.Length); + if (type == ClassificationType.Semantic) + { + await classificationService.AddSemanticClassificationsAsync(document, fullSpan, options, classifiedSpans, cancellationToken).ConfigureAwait(false); + } + else if (type == ClassificationType.EmbeddedLanguage) + { + await classificationService.AddEmbeddedLanguageClassificationsAsync(document, fullSpan, options, classifiedSpans, cancellationToken).ConfigureAwait(false); + } + else + { + throw ExceptionUtilities.UnexpectedValue(type); } - private static void WriteTo(SegmentedList classifiedSpans, ObjectWriter writer) + using var stream = SerializableBytes.CreateWritableStream(); + using (var writer = new ObjectWriter(stream, leaveOpen: true)) { - writer.WriteInt32(ClassificationFormat); + WriteTo(classifiedSpans, writer); + } - // First, look through all the spans and determine which classification types are used. For efficiency, - // we'll emit the unique types up front and then only refer to them by index for all the actual classified - // spans we emit. + stream.Position = 0; + await storage.WriteStreamAsync(documentKey, persistenceName, stream, checksum, cancellationToken).ConfigureAwait(false); + } - using var _1 = ArrayBuilder.GetInstance(out var classificationTypes); - using var _2 = PooledDictionary.GetInstance(out var seenClassificationTypes); + private static void WriteTo(SegmentedList classifiedSpans, ObjectWriter writer) + { + writer.WriteInt32(ClassificationFormat); - foreach (var classifiedSpan in classifiedSpans) - { - var classificationType = classifiedSpan.ClassificationType; - if (!seenClassificationTypes.ContainsKey(classificationType)) - { - seenClassificationTypes.Add(classificationType, classificationTypes.Count); - classificationTypes.Add(classificationType); - } - } + // First, look through all the spans and determine which classification types are used. For efficiency, + // we'll emit the unique types up front and then only refer to them by index for all the actual classified + // spans we emit. - writer.WriteInt32(classificationTypes.Count); - foreach (var type in classificationTypes) - writer.WriteString(type); - - // Now emit each classified span as a triple of it's start, length, type. - // - // In general, the latter two will all be a single byte as tokens tend to be short and we don't have many - // classification types. - // - // We do need to store the start (as opposed to a delta) as we may have multiple items starting at the same - // position and we cannot encode a negative delta. - writer.WriteInt32(classifiedSpans.Count); - foreach (var classifiedSpan in classifiedSpans) + using var _1 = ArrayBuilder.GetInstance(out var classificationTypes); + using var _2 = PooledDictionary.GetInstance(out var seenClassificationTypes); + + foreach (var classifiedSpan in classifiedSpans) + { + var classificationType = classifiedSpan.ClassificationType; + if (!seenClassificationTypes.ContainsKey(classificationType)) { - checked - { - writer.WriteInt32(classifiedSpan.TextSpan.Start); - writer.WriteCompressedUInt((uint)classifiedSpan.TextSpan.Length); - writer.WriteCompressedUInt((uint)seenClassificationTypes[classifiedSpan.ClassificationType]); - } + seenClassificationTypes.Add(classificationType, classificationTypes.Count); + classificationTypes.Add(classificationType); } } - private async Task> TryGetOrReadCachedSemanticClassificationsAsync( - DocumentKey documentKey, - ClassificationType type, - Checksum checksum, - CancellationToken cancellationToken) + writer.WriteInt32(classificationTypes.Count); + foreach (var type in classificationTypes) + writer.WriteString(type); + + // Now emit each classified span as a triple of it's start, length, type. + // + // In general, the latter two will all be a single byte as tokens tend to be short and we don't have many + // classification types. + // + // We do need to store the start (as opposed to a delta) as we may have multiple items starting at the same + // position and we cannot encode a negative delta. + writer.WriteInt32(classifiedSpans.Count); + foreach (var classifiedSpan in classifiedSpans) { - // See if we've loaded this into memory first. - if (TryGetFromInMemoryCache(documentKey, checksum, out var classifiedSpans)) - return classifiedSpans; - - // Otherwise, attempt to read in classifications from persistence store. - classifiedSpans = await TryReadCachedSemanticClassificationsAsync( - documentKey, type, checksum, cancellationToken).ConfigureAwait(false); - if (classifiedSpans.IsDefault) - return default; + checked + { + writer.WriteInt32(classifiedSpan.TextSpan.Start); + writer.WriteCompressedUInt((uint)classifiedSpan.TextSpan.Length); + writer.WriteCompressedUInt((uint)seenClassificationTypes[classifiedSpan.ClassificationType]); + } + } + } - UpdateInMemoryCache(documentKey, type, checksum, classifiedSpans); + private async Task> TryGetOrReadCachedSemanticClassificationsAsync( + DocumentKey documentKey, + ClassificationType type, + Checksum checksum, + CancellationToken cancellationToken) + { + // See if we've loaded this into memory first. + if (TryGetFromInMemoryCache(documentKey, checksum, out var classifiedSpans)) return classifiedSpans; - } - private bool TryGetFromInMemoryCache(DocumentKey documentKey, Checksum checksum, out ImmutableArray classifiedSpans) + // Otherwise, attempt to read in classifications from persistence store. + classifiedSpans = await TryReadCachedSemanticClassificationsAsync( + documentKey, type, checksum, cancellationToken).ConfigureAwait(false); + if (classifiedSpans.IsDefault) + return default; + + UpdateInMemoryCache(documentKey, type, checksum, classifiedSpans); + return classifiedSpans; + } + + private bool TryGetFromInMemoryCache(DocumentKey documentKey, Checksum checksum, out ImmutableArray classifiedSpans) + { + lock (_cachedData) { - lock (_cachedData) + var data = _cachedData.FirstOrNull(d => d.id == documentKey.Id && d.checksum == checksum); + if (data != null) { - var data = _cachedData.FirstOrNull(d => d.id == documentKey.Id && d.checksum == checksum); - if (data != null) - { - classifiedSpans = data.Value.classifiedSpans; - return true; - } + classifiedSpans = data.Value.classifiedSpans; + return true; } - - classifiedSpans = default; - return false; } - private void UpdateInMemoryCache( - DocumentKey documentKey, - ClassificationType type, - Checksum checksum, - ImmutableArray classifiedSpans) + classifiedSpans = default; + return false; + } + + private void UpdateInMemoryCache( + DocumentKey documentKey, + ClassificationType type, + Checksum checksum, + ImmutableArray classifiedSpans) + { + lock (_cachedData) { - lock (_cachedData) + // First, remove any existing info for this doc. + for (var currentNode = _cachedData.First; currentNode != null; currentNode = currentNode.Next) { - // First, remove any existing info for this doc. - for (var currentNode = _cachedData.First; currentNode != null; currentNode = currentNode.Next) + if (currentNode.Value.id == documentKey.Id) { - if (currentNode.Value.id == documentKey.Id) - { - _cachedData.Remove(currentNode); - break; - } + _cachedData.Remove(currentNode); + break; } - - // Then place the cached information for this doc at the end. - _cachedData.AddLast((documentKey.Id, type, checksum, classifiedSpans)); - - // And ensure we don't cache too many docs. - if (_cachedData.Count > MaxCachedDocumentCount) - _cachedData.RemoveFirst(); } - } - - private async Task> TryReadCachedSemanticClassificationsAsync( - DocumentKey documentKey, - ClassificationType type, - Checksum checksum, - CancellationToken cancellationToken) - { - var persistenceService = GetWorkspaceServices().GetPersistentStorageService(); - var storage = await persistenceService.GetStorageAsync(documentKey.Project.Solution, cancellationToken).ConfigureAwait(false); - if (storage == null) - return default; - var persistenceName = GetPersistenceName(type); - using var stream = await storage.ReadStreamAsync(documentKey, persistenceName, checksum, cancellationToken).ConfigureAwait(false); - using var reader = ObjectReader.TryGetReader(stream); - if (reader == null) - return default; + // Then place the cached information for this doc at the end. + _cachedData.AddLast((documentKey.Id, type, checksum, classifiedSpans)); - return Read(reader); + // And ensure we don't cache too many docs. + if (_cachedData.Count > MaxCachedDocumentCount) + _cachedData.RemoveFirst(); } + } - private static ImmutableArray Read(ObjectReader reader) + private async Task> TryReadCachedSemanticClassificationsAsync( + DocumentKey documentKey, + ClassificationType type, + Checksum checksum, + CancellationToken cancellationToken) + { + var persistenceService = GetWorkspaceServices().GetPersistentStorageService(); + var storage = await persistenceService.GetStorageAsync(documentKey.Project.Solution, cancellationToken).ConfigureAwait(false); + if (storage == null) + return default; + + var persistenceName = GetPersistenceName(type); + using var stream = await storage.ReadStreamAsync(documentKey, persistenceName, checksum, cancellationToken).ConfigureAwait(false); + using var reader = ObjectReader.TryGetReader(stream); + if (reader == null) + return default; + + return Read(reader); + } + + private static ImmutableArray Read(ObjectReader reader) + { + try { - try - { - // if the format doesn't match, we def can't read this. - if (reader.ReadInt32() != ClassificationFormat) - return default; + // if the format doesn't match, we def can't read this. + if (reader.ReadInt32() != ClassificationFormat) + return default; - // For space efficiency, the unique classification types are emitted in one array up front, and then the - // specific classification type is referred to by index when emitting the individual spans. - var classificationTypesCount = reader.ReadInt32(); - using var _1 = ArrayBuilder.GetInstance(classificationTypesCount, out var classificationTypes); + // For space efficiency, the unique classification types are emitted in one array up front, and then the + // specific classification type is referred to by index when emitting the individual spans. + var classificationTypesCount = reader.ReadInt32(); + using var _1 = ArrayBuilder.GetInstance(classificationTypesCount, out var classificationTypes); - for (var i = 0; i < classificationTypesCount; i++) - classificationTypes.Add(reader.ReadRequiredString()); + for (var i = 0; i < classificationTypesCount; i++) + classificationTypes.Add(reader.ReadRequiredString()); - var classifiedSpanCount = reader.ReadInt32(); - var classifiedSpans = new FixedSizeArrayBuilder(classifiedSpanCount); + var classifiedSpanCount = reader.ReadInt32(); + var classifiedSpans = new FixedSizeArrayBuilder(classifiedSpanCount); - for (var i = 0; i < classifiedSpanCount; i++) + for (var i = 0; i < classifiedSpanCount; i++) + { + checked { - checked - { - var start = reader.ReadInt32(); - var length = (int)reader.ReadCompressedUInt(); - var typeIndex = (int)reader.ReadCompressedUInt(); - - classifiedSpans.Add(new ClassifiedSpan(classificationTypes[typeIndex], new TextSpan(start, length))); - } - } + var start = reader.ReadInt32(); + var length = (int)reader.ReadCompressedUInt(); + var typeIndex = (int)reader.ReadCompressedUInt(); - return classifiedSpans.MoveToImmutable(); - } - catch - { - // We're reading and interpreting arbitrary data from disk. This may be invalid for any reason. - Internal.Log.Logger.Log(FunctionId.RemoteSemanticClassificationCacheService_ExceptionInCacheRead); - return default; + classifiedSpans.Add(new ClassifiedSpan(classificationTypes[typeIndex], new TextSpan(start, length))); + } } + + return classifiedSpans.MoveToImmutable(); + } + catch + { + // We're reading and interpreting arbitrary data from disk. This may be invalid for any reason. + Internal.Log.Logger.Log(FunctionId.RemoteSemanticClassificationCacheService_ExceptionInCacheRead); + return default; } } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs b/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs index 11708587d8c9f..26c46f8ed5060 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SemanticClassification/RemoteSemanticClassificationService.cs @@ -10,55 +10,54 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed partial class RemoteSemanticClassificationService : BrokeredServiceBase, IRemoteSemanticClassificationService { - internal sealed partial class RemoteSemanticClassificationService : BrokeredServiceBase, IRemoteSemanticClassificationService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteSemanticClassificationService CreateService(in ServiceConstructionArguments arguments) - => new RemoteSemanticClassificationService(arguments); - } + protected override IRemoteSemanticClassificationService CreateService(in ServiceConstructionArguments arguments) + => new RemoteSemanticClassificationService(arguments); + } - public ValueTask GetClassificationsAsync( - Checksum solutionChecksum, - DocumentId documentId, - ImmutableArray spans, - ClassificationType type, - ClassificationOptions options, - bool isFullyLoaded, - CancellationToken cancellationToken) + public ValueTask GetClassificationsAsync( + Checksum solutionChecksum, + DocumentId documentId, + ImmutableArray spans, + ClassificationType type, + ClassificationOptions options, + bool isFullyLoaded, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var document = solution.GetDocument(documentId) ?? await solution.GetSourceGeneratedDocumentAsync(documentId, cancellationToken).ConfigureAwait(false); - Contract.ThrowIfNull(document); + var document = solution.GetDocument(documentId) ?? await solution.GetSourceGeneratedDocumentAsync(documentId, cancellationToken).ConfigureAwait(false); + Contract.ThrowIfNull(document); - // Frozen partial semantics is not automatically passed to OOP, so enable it explicitly when desired - document = options.FrozenPartialSemantics ? document.WithFrozenPartialSemantics(cancellationToken) : document; - solution = document.Project.Solution; + // Frozen partial semantics is not automatically passed to OOP, so enable it explicitly when desired + document = options.FrozenPartialSemantics ? document.WithFrozenPartialSemantics(cancellationToken) : document; + solution = document.Project.Solution; - using var _ = Classifier.GetPooledList(out var temp); + using var _ = Classifier.GetPooledList(out var temp); - // Safe to do this. The remote classification service only runs for C#/VB. So we know we'll always - // have this service and it will always be this type. - var classificationService = (AbstractClassificationService)document.GetRequiredLanguageService(); - await classificationService.AddClassificationsAsync( - document, spans, options, type, temp, cancellationToken).ConfigureAwait(false); + // Safe to do this. The remote classification service only runs for C#/VB. So we know we'll always + // have this service and it will always be this type. + var classificationService = (AbstractClassificationService)document.GetRequiredLanguageService(); + await classificationService.AddClassificationsAsync( + document, spans, options, type, temp, cancellationToken).ConfigureAwait(false); - if (isFullyLoaded) - { - // Once fully loaded, there's no need for us to keep around any of the data we cached in-memory - // during the time the solution was loading. - lock (_cachedData) - _cachedData.Clear(); + if (isFullyLoaded) + { + // Once fully loaded, there's no need for us to keep around any of the data we cached in-memory + // during the time the solution was loading. + lock (_cachedData) + _cachedData.Clear(); - // Enqueue this document into our work queue to fully classify and cache. - _workQueue.AddWork((document, type, options)); - } + // Enqueue this document into our work queue to fully classify and cache. + _workQueue.AddWork((document, type, options)); + } - return SerializableClassifiedSpans.Dehydrate([.. temp]); - }, cancellationToken); - } + return SerializableClassifiedSpans.Dehydrate([.. temp]); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs b/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs index f1cd430234c82..76272ef377613 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SourceGeneration/RemoteSourceGenerationService.cs @@ -29,7 +29,7 @@ protected override IRemoteSourceGenerationService CreateService(in ServiceConstr => new RemoteSourceGenerationService(arguments); } - public ValueTask> GetSourceGeneratedDocumentInfoAsync( + public ValueTask> GetSourceGeneratedDocumentInfoAsync( Checksum solutionChecksum, ProjectId projectId, bool withFrozenSourceGeneratedDocuments, CancellationToken cancellationToken) { return RunServiceAsync(solutionChecksum, async solution => @@ -38,7 +38,7 @@ public ValueTask> GetSourceGeneratedD var documentStates = await solution.CompilationState.GetSourceGeneratedDocumentStatesAsync( project.State, withFrozenSourceGeneratedDocuments, cancellationToken).ConfigureAwait(false); - var result = new FixedSizeArrayBuilder(documentStates.States.Count); + var result = new FixedSizeArrayBuilder(documentStates.States.Count); foreach (var (id, state) in documentStates.States) { Contract.ThrowIfFalse(id.IsSourceGenerated); @@ -132,4 +132,36 @@ await assetProvider.GetAssetHelper().GetAssetsAsync( return false; } + + public ValueTask> GetSourceGeneratorIdentitiesAsync( + Checksum solutionChecksum, + ProjectId projectId, + string analyzerReferenceFullPath, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, solution => + { + var project = solution.GetRequiredProject(projectId); + var analyzerReference = project.AnalyzerReferences + .First(r => r.FullPath == analyzerReferenceFullPath); + + return ValueTaskFactory.FromResult(SourceGeneratorIdentity.GetIdentities(analyzerReference, project.Language)); + }, cancellationToken); + } + + public ValueTask HasAnalyzersOrSourceGeneratorsAsync( + Checksum solutionChecksum, + ProjectId projectId, + string analyzerReferenceFullPath, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, solution => + { + var project = solution.GetRequiredProject(projectId); + var analyzerReference = project.AnalyzerReferences + .First(r => r.FullPath == analyzerReferenceFullPath); + + return ValueTaskFactory.FromResult(analyzerReference.HasAnalyzersOrSourceGenerators(project.Language)); + }, cancellationToken); + } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/StackTraceExplorer/RemoteStackTraceExplorerService.cs b/src/Workspaces/Remote/ServiceHub/Services/StackTraceExplorer/RemoteStackTraceExplorerService.cs index e53112d95eddd..cc8b87063837f 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/StackTraceExplorer/RemoteStackTraceExplorerService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/StackTraceExplorer/RemoteStackTraceExplorerService.cs @@ -8,38 +8,37 @@ using Microsoft.CodeAnalysis.FindUsages; using Microsoft.CodeAnalysis.StackTraceExplorer; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteStackTraceExplorerService : BrokeredServiceBase, IRemoteStackTraceExplorerService { - internal sealed class RemoteStackTraceExplorerService : BrokeredServiceBase, IRemoteStackTraceExplorerService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteStackTraceExplorerService CreateService(in ServiceConstructionArguments arguments) - => new RemoteStackTraceExplorerService(arguments); - } + protected override IRemoteStackTraceExplorerService CreateService(in ServiceConstructionArguments arguments) + => new RemoteStackTraceExplorerService(arguments); + } - public RemoteStackTraceExplorerService(in ServiceConstructionArguments arguments) : base(arguments) - { - } + public RemoteStackTraceExplorerService(in ServiceConstructionArguments arguments) : base(arguments) + { + } - public ValueTask TryFindDefinitionAsync(Checksum solutionChecksum, string frameString, StackFrameSymbolPart symbolPart, CancellationToken cancellationToken) + public ValueTask TryFindDefinitionAsync(Checksum solutionChecksum, string frameString, StackFrameSymbolPart symbolPart, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => + var result = await StackTraceAnalyzer.AnalyzeAsync(frameString, cancellationToken).ConfigureAwait(false); + if (result.ParsedFrames.Length != 1 || result.ParsedFrames[0] is not ParsedStackFrame parsedFrame) { - var result = await StackTraceAnalyzer.AnalyzeAsync(frameString, cancellationToken).ConfigureAwait(false); - if (result.ParsedFrames.Length != 1 || result.ParsedFrames[0] is not ParsedStackFrame parsedFrame) - { - throw new InvalidOperationException(); - } + throw new InvalidOperationException(); + } - var definition = await StackTraceExplorerUtilities.GetDefinitionAsync(solution, parsedFrame.Root, symbolPart, cancellationToken).ConfigureAwait(false); - if (definition is null) - { - return (SerializableDefinitionItem?)null; - } + var definition = await StackTraceExplorerUtilities.GetDefinitionAsync(solution, parsedFrame.Root, symbolPart, cancellationToken).ConfigureAwait(false); + if (definition is null) + { + return (SerializableDefinitionItem?)null; + } - return SerializableDefinitionItem.Dehydrate(id: 0, definition); - }, cancellationToken); - } + return SerializableDefinitionItem.Dehydrate(id: 0, definition); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/SymbolFinder/RemoteSymbolFinderService.cs b/src/Workspaces/Remote/ServiceHub/Services/SymbolFinder/RemoteSymbolFinderService.cs index 66667d55651c5..2c9c8ad1438c3 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SymbolFinder/RemoteSymbolFinderService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SymbolFinder/RemoteSymbolFinderService.cs @@ -16,237 +16,236 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteSymbolFinderService : BrokeredServiceBase, IRemoteSymbolFinderService { - internal sealed class RemoteSymbolFinderService : BrokeredServiceBase, IRemoteSymbolFinderService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteSymbolFinderService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) - => new RemoteSymbolFinderService(arguments, callback); - } + protected override IRemoteSymbolFinderService CreateService(in ServiceConstructionArguments arguments, RemoteCallback callback) + => new RemoteSymbolFinderService(arguments, callback); + } - private readonly RemoteCallback _callback; + private readonly RemoteCallback _callback; - public RemoteSymbolFinderService(in ServiceConstructionArguments arguments, RemoteCallback callback) - : base(arguments) - { - _callback = callback; - } + public RemoteSymbolFinderService(in ServiceConstructionArguments arguments, RemoteCallback callback) + : base(arguments) + { + _callback = callback; + } - public ValueTask FindReferencesAsync( - Checksum solutionChecksum, - RemoteServiceCallbackId callbackId, - SerializableSymbolAndProjectId symbolAndProjectIdArg, - ImmutableArray documentArgs, - FindReferencesSearchOptions options, - CancellationToken cancellationToken) + public ValueTask FindReferencesAsync( + Checksum solutionChecksum, + RemoteServiceCallbackId callbackId, + SerializableSymbolAndProjectId symbolAndProjectIdArg, + ImmutableArray documentArgs, + FindReferencesSearchOptions options, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var symbol = await symbolAndProjectIdArg.TryRehydrateAsync( - solution, cancellationToken).ConfigureAwait(false); - - var progressCallback = new FindReferencesProgressCallback(solution, _callback, callbackId); - - if (symbol == null) - { - await progressCallback.OnStartedAsync(cancellationToken).ConfigureAwait(false); - await progressCallback.OnCompletedAsync(cancellationToken).ConfigureAwait(false); - return; - } - - // NOTE: In projection scenarios, we might get a set of documents to search - // that are not all the same language and might not exist in the OOP process - // (like the JS parts of a .cshtml file). Filter them out here. This will - // need to be revisited if we someday support FAR between these languages. - var documents = documentArgs.IsDefault ? null : - documentArgs.Select(solution.GetDocument).WhereNotNull().ToImmutableHashSet(); - - await SymbolFinder.FindReferencesInCurrentProcessAsync( - symbol, solution, progressCallback, - documents, options, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + var symbol = await symbolAndProjectIdArg.TryRehydrateAsync( + solution, cancellationToken).ConfigureAwait(false); - public ValueTask FindLiteralReferencesAsync(Checksum solutionChecksum, RemoteServiceCallbackId callbackId, object value, TypeCode typeCode, CancellationToken cancellationToken) - { - return RunServiceAsync(solutionChecksum, async solution => + var progressCallback = new FindReferencesProgressCallback(solution, _callback, callbackId); + + if (symbol == null) { - var convertedType = System.Convert.ChangeType(value, typeCode); + await progressCallback.OnStartedAsync(cancellationToken).ConfigureAwait(false); + await progressCallback.OnCompletedAsync(cancellationToken).ConfigureAwait(false); + return; + } - var progressCallback = new FindLiteralReferencesProgressCallback(_callback, callbackId); - await SymbolFinder.FindLiteralReferencesInCurrentProcessAsync( - convertedType, solution, progressCallback, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + // NOTE: In projection scenarios, we might get a set of documents to search + // that are not all the same language and might not exist in the OOP process + // (like the JS parts of a .cshtml file). Filter them out here. This will + // need to be revisited if we someday support FAR between these languages. + var documents = documentArgs.IsDefault ? null : + documentArgs.Select(solution.GetDocument).WhereNotNull().ToImmutableHashSet(); + + await SymbolFinder.FindReferencesInCurrentProcessAsync( + symbol, solution, progressCallback, + documents, options, cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } - private static ImmutableArray Convert(ImmutableArray items, Solution solution, CancellationToken cancellationToken) + public ValueTask FindLiteralReferencesAsync(Checksum solutionChecksum, RemoteServiceCallbackId callbackId, object value, TypeCode typeCode, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - var result = new FixedSizeArrayBuilder(items.Length); + var convertedType = System.Convert.ChangeType(value, typeCode); - foreach (var item in items) - result.Add(SerializableSymbolAndProjectId.Dehydrate(solution, item, cancellationToken)); + var progressCallback = new FindLiteralReferencesProgressCallback(_callback, callbackId); + await SymbolFinder.FindLiteralReferencesInCurrentProcessAsync( + convertedType, solution, progressCallback, cancellationToken).ConfigureAwait(false); + }, cancellationToken); + } - return result.MoveToImmutable(); - } + private static ImmutableArray Convert(ImmutableArray items, Solution solution, CancellationToken cancellationToken) + { + var result = new FixedSizeArrayBuilder(items.Length); - public ValueTask> FindAllDeclarationsWithNormalQueryAsync( - Checksum solutionChecksum, - ProjectId projectId, - string name, - SearchKind searchKind, - SymbolFilter criteria, - CancellationToken cancellationToken) + foreach (var item in items) + result.Add(SerializableSymbolAndProjectId.Dehydrate(solution, item, cancellationToken)); + + return result.MoveToImmutable(); + } + + public ValueTask> FindAllDeclarationsWithNormalQueryAsync( + Checksum solutionChecksum, + ProjectId projectId, + string name, + SearchKind searchKind, + SymbolFilter criteria, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var project = solution.GetRequiredProject(projectId); + var project = solution.GetRequiredProject(projectId); - using var query = SearchQuery.Create(name, searchKind); + using var query = SearchQuery.Create(name, searchKind); - var result = await DeclarationFinder.FindAllDeclarationsWithNormalQueryInCurrentProcessAsync( - project, query, criteria, cancellationToken).ConfigureAwait(false); + var result = await DeclarationFinder.FindAllDeclarationsWithNormalQueryInCurrentProcessAsync( + project, query, criteria, cancellationToken).ConfigureAwait(false); - return Convert(result, solution, cancellationToken); - }, cancellationToken); - } + return Convert(result, solution, cancellationToken); + }, cancellationToken); + } - public ValueTask> FindSolutionSourceDeclarationsWithNormalQueryAsync( - Checksum solutionChecksum, - string name, - bool ignoreCase, - SymbolFilter criteria, - CancellationToken cancellationToken) + public ValueTask> FindSolutionSourceDeclarationsWithNormalQueryAsync( + Checksum solutionChecksum, + string name, + bool ignoreCase, + SymbolFilter criteria, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var result = await DeclarationFinder.FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync( - solution, name, ignoreCase, criteria, cancellationToken).ConfigureAwait(false); + var result = await DeclarationFinder.FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync( + solution, name, ignoreCase, criteria, cancellationToken).ConfigureAwait(false); - return Convert(result, solution, cancellationToken); - }, cancellationToken); - } + return Convert(result, solution, cancellationToken); + }, cancellationToken); + } - public ValueTask> FindProjectSourceDeclarationsWithNormalQueryAsync( - Checksum solutionChecksum, - ProjectId projectId, - string name, - bool ignoreCase, - SymbolFilter criteria, - CancellationToken cancellationToken) + public ValueTask> FindProjectSourceDeclarationsWithNormalQueryAsync( + Checksum solutionChecksum, + ProjectId projectId, + string name, + bool ignoreCase, + SymbolFilter criteria, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var project = solution.GetRequiredProject(projectId); + var project = solution.GetRequiredProject(projectId); - var result = await DeclarationFinder.FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync( - project, name, ignoreCase, criteria, cancellationToken).ConfigureAwait(false); + var result = await DeclarationFinder.FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync( + project, name, ignoreCase, criteria, cancellationToken).ConfigureAwait(false); - return Convert(result, solution, cancellationToken); - }, cancellationToken); - } + return Convert(result, solution, cancellationToken); + }, cancellationToken); + } - public ValueTask> FindSolutionSourceDeclarationsWithPatternAsync( - Checksum solutionChecksum, string pattern, SymbolFilter criteria, CancellationToken cancellationToken) + public ValueTask> FindSolutionSourceDeclarationsWithPatternAsync( + Checksum solutionChecksum, string pattern, SymbolFilter criteria, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var result = await DeclarationFinder.FindSourceDeclarationsWithPatternInCurrentProcessAsync( - solution, pattern, criteria, cancellationToken).ConfigureAwait(false); + var result = await DeclarationFinder.FindSourceDeclarationsWithPatternInCurrentProcessAsync( + solution, pattern, criteria, cancellationToken).ConfigureAwait(false); - return Convert(result, solution, cancellationToken); - }, cancellationToken); - } + return Convert(result, solution, cancellationToken); + }, cancellationToken); + } - public ValueTask> FindProjectSourceDeclarationsWithPatternAsync( - Checksum solutionChecksum, ProjectId projectId, string pattern, SymbolFilter criteria, CancellationToken cancellationToken) + public ValueTask> FindProjectSourceDeclarationsWithPatternAsync( + Checksum solutionChecksum, ProjectId projectId, string pattern, SymbolFilter criteria, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var project = solution.GetRequiredProject(projectId); + var project = solution.GetRequiredProject(projectId); - var result = await DeclarationFinder.FindSourceDeclarationsWithPatternInCurrentProcessAsync( - project, pattern, criteria, cancellationToken).ConfigureAwait(false); + var result = await DeclarationFinder.FindSourceDeclarationsWithPatternInCurrentProcessAsync( + project, pattern, criteria, cancellationToken).ConfigureAwait(false); - return Convert(result, solution, cancellationToken); - }, cancellationToken); - } + return Convert(result, solution, cancellationToken); + }, cancellationToken); + } - private sealed class FindLiteralReferencesProgressCallback : IStreamingFindLiteralReferencesProgress, IStreamingProgressTracker - { - private readonly RemoteCallback _callback; - private readonly RemoteServiceCallbackId _callbackId; + private sealed class FindLiteralReferencesProgressCallback : IStreamingFindLiteralReferencesProgress, IStreamingProgressTracker + { + private readonly RemoteCallback _callback; + private readonly RemoteServiceCallbackId _callbackId; - public IStreamingProgressTracker ProgressTracker { get; } + public IStreamingProgressTracker ProgressTracker { get; } - public FindLiteralReferencesProgressCallback(RemoteCallback callback, RemoteServiceCallbackId callbackId) - { - _callback = callback; - _callbackId = callbackId; - ProgressTracker = this; - } + public FindLiteralReferencesProgressCallback(RemoteCallback callback, RemoteServiceCallbackId callbackId) + { + _callback = callback; + _callbackId = callbackId; + ProgressTracker = this; + } - public ValueTask OnReferenceFoundAsync(Document document, TextSpan span, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.OnLiteralReferenceFoundAsync(_callbackId, document.Id, span, cancellationToken), cancellationToken); + public ValueTask OnReferenceFoundAsync(Document document, TextSpan span, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.OnLiteralReferenceFoundAsync(_callbackId, document.Id, span, cancellationToken), cancellationToken); - public ValueTask AddItemsAsync(int count, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.AddLiteralItemsAsync(_callbackId, count, cancellationToken), cancellationToken); + public ValueTask AddItemsAsync(int count, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.AddLiteralItemsAsync(_callbackId, count, cancellationToken), cancellationToken); - public ValueTask ItemsCompletedAsync(int count, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.LiteralItemsCompletedAsync(_callbackId, count, cancellationToken), cancellationToken); - } + public ValueTask ItemsCompletedAsync(int count, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.LiteralItemsCompletedAsync(_callbackId, count, cancellationToken), cancellationToken); + } - private sealed class FindReferencesProgressCallback : IStreamingFindReferencesProgress, IStreamingProgressTracker - { - private readonly Solution _solution; - private readonly RemoteCallback _callback; - private readonly RemoteServiceCallbackId _callbackId; + private sealed class FindReferencesProgressCallback : IStreamingFindReferencesProgress, IStreamingProgressTracker + { + private readonly Solution _solution; + private readonly RemoteCallback _callback; + private readonly RemoteServiceCallbackId _callbackId; - public IStreamingProgressTracker ProgressTracker { get; } + public IStreamingProgressTracker ProgressTracker { get; } - public FindReferencesProgressCallback(Solution solution, RemoteCallback callback, RemoteServiceCallbackId callbackId) - { - _solution = solution; - _callback = callback; - _callbackId = callbackId; - ProgressTracker = this; - } + public FindReferencesProgressCallback(Solution solution, RemoteCallback callback, RemoteServiceCallbackId callbackId) + { + _solution = solution; + _callback = callback; + _callbackId = callbackId; + ProgressTracker = this; + } - public ValueTask OnStartedAsync(CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.OnStartedAsync(_callbackId, cancellationToken), cancellationToken); + public ValueTask OnStartedAsync(CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.OnStartedAsync(_callbackId, cancellationToken), cancellationToken); - public ValueTask OnCompletedAsync(CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.OnCompletedAsync(_callbackId, cancellationToken), cancellationToken); + public ValueTask OnCompletedAsync(CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.OnCompletedAsync(_callbackId, cancellationToken), cancellationToken); - public ValueTask OnDefinitionFoundAsync(SymbolGroup group, CancellationToken cancellationToken) - { - var dehydratedGroup = SerializableSymbolGroup.Dehydrate(_solution, group, cancellationToken); - return _callback.InvokeAsync( - (callback, cancellationToken) => callback.OnDefinitionFoundAsync(_callbackId, dehydratedGroup, cancellationToken), cancellationToken); - } + public ValueTask OnDefinitionFoundAsync(SymbolGroup group, CancellationToken cancellationToken) + { + var dehydratedGroup = SerializableSymbolGroup.Dehydrate(_solution, group, cancellationToken); + return _callback.InvokeAsync( + (callback, cancellationToken) => callback.OnDefinitionFoundAsync(_callbackId, dehydratedGroup, cancellationToken), cancellationToken); + } - public async ValueTask OnReferencesFoundAsync( - ImmutableArray<(SymbolGroup group, ISymbol symbol, ReferenceLocation location)> references, - CancellationToken cancellationToken) - { - var dehydrated = references.SelectAsArray( - static (reference, tuple) => ( - SerializableSymbolGroup.Dehydrate(tuple.solution, reference.group, tuple.cancellationToken), - SerializableSymbolAndProjectId.Dehydrate(tuple.solution, reference.symbol, tuple.cancellationToken), - SerializableReferenceLocation.Dehydrate(reference.location, tuple.cancellationToken)), - (solution: _solution, cancellationToken)); - - await _callback.InvokeAsync( - (callback, cancellationToken) => callback.OnReferencesFoundAsync( - _callbackId, dehydrated, cancellationToken), cancellationToken).ConfigureAwait(false); - } + public async ValueTask OnReferencesFoundAsync( + ImmutableArray<(SymbolGroup group, ISymbol symbol, ReferenceLocation location)> references, + CancellationToken cancellationToken) + { + var dehydrated = references.SelectAsArray( + static (reference, tuple) => ( + SerializableSymbolGroup.Dehydrate(tuple.solution, reference.group, tuple.cancellationToken), + SerializableSymbolAndProjectId.Dehydrate(tuple.solution, reference.symbol, tuple.cancellationToken), + SerializableReferenceLocation.Dehydrate(reference.location, tuple.cancellationToken)), + (solution: _solution, cancellationToken)); + + await _callback.InvokeAsync( + (callback, cancellationToken) => callback.OnReferencesFoundAsync( + _callbackId, dehydrated, cancellationToken), cancellationToken).ConfigureAwait(false); + } - public ValueTask AddItemsAsync(int count, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.AddReferenceItemsAsync(_callbackId, count, cancellationToken), cancellationToken); + public ValueTask AddItemsAsync(int count, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.AddReferenceItemsAsync(_callbackId, count, cancellationToken), cancellationToken); - public ValueTask ItemsCompletedAsync(int count, CancellationToken cancellationToken) - => _callback.InvokeAsync((callback, cancellationToken) => callback.ReferenceItemsCompletedAsync(_callbackId, count, cancellationToken), cancellationToken); - } + public ValueTask ItemsCompletedAsync(int count, CancellationToken cancellationToken) + => _callback.InvokeAsync((callback, cancellationToken) => callback.ReferenceItemsCompletedAsync(_callbackId, count, cancellationToken), cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdate/RemoteSymbolSearchUpdateService.cs b/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdate/RemoteSymbolSearchUpdateService.cs index b066b14c1d1ce..98ff512306b03 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdate/RemoteSymbolSearchUpdateService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SymbolSearchUpdate/RemoteSymbolSearchUpdateService.cs @@ -8,50 +8,49 @@ using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.VisualStudio.LanguageServices.Storage; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteSymbolSearchUpdateService : BrokeredServiceBase, IRemoteSymbolSearchUpdateService { - internal sealed class RemoteSymbolSearchUpdateService : BrokeredServiceBase, IRemoteSymbolSearchUpdateService + internal sealed class Factory : FactoryBase + { + protected override IRemoteSymbolSearchUpdateService CreateService(in ServiceConstructionArguments arguments) + => new RemoteSymbolSearchUpdateService(arguments); + } + + private readonly ISymbolSearchUpdateEngine _updateEngine; + + public RemoteSymbolSearchUpdateService(in ServiceConstructionArguments arguments) + : base(arguments) + { + _updateEngine = SymbolSearchUpdateEngineFactory.CreateEngineInProcess(FileDownloader.Factory.Instance); + } + + public ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => + _updateEngine.UpdateContinuouslyAsync(sourceName, localSettingsDirectory, cancellationToken), + cancellationToken); + } + + public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => + _updateEngine.FindPackagesWithTypeAsync(source, name, arity, cancellationToken), + cancellationToken); + } + + public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) + { + return RunServiceAsync(cancellationToken => + _updateEngine.FindPackagesWithAssemblyAsync(source, assemblyName, cancellationToken), + cancellationToken); + } + + public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) { - internal sealed class Factory : FactoryBase - { - protected override IRemoteSymbolSearchUpdateService CreateService(in ServiceConstructionArguments arguments) - => new RemoteSymbolSearchUpdateService(arguments); - } - - private readonly ISymbolSearchUpdateEngine _updateEngine; - - public RemoteSymbolSearchUpdateService(in ServiceConstructionArguments arguments) - : base(arguments) - { - _updateEngine = SymbolSearchUpdateEngineFactory.CreateEngineInProcess(FileDownloader.Factory.Instance); - } - - public ValueTask UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory, CancellationToken cancellationToken) - { - return RunServiceAsync(cancellationToken => - _updateEngine.UpdateContinuouslyAsync(sourceName, localSettingsDirectory, cancellationToken), - cancellationToken); - } - - public ValueTask> FindPackagesWithTypeAsync(string source, string name, int arity, CancellationToken cancellationToken) - { - return RunServiceAsync(cancellationToken => - _updateEngine.FindPackagesWithTypeAsync(source, name, arity, cancellationToken), - cancellationToken); - } - - public ValueTask> FindPackagesWithAssemblyAsync(string source, string assemblyName, CancellationToken cancellationToken) - { - return RunServiceAsync(cancellationToken => - _updateEngine.FindPackagesWithAssemblyAsync(source, assemblyName, cancellationToken), - cancellationToken); - } - - public ValueTask> FindReferenceAssembliesWithTypeAsync(string name, int arity, CancellationToken cancellationToken) - { - return RunServiceAsync(cancellationToken => - _updateEngine.FindReferenceAssembliesWithTypeAsync(name, arity, cancellationToken), - cancellationToken); - } + return RunServiceAsync(cancellationToken => + _updateEngine.FindReferenceAssembliesWithTypeAsync(name, arity, cancellationToken), + cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/TaskList/RemoteTaskListService.cs b/src/Workspaces/Remote/ServiceHub/Services/TaskList/RemoteTaskListService.cs index ba8fe1b0de46e..72deab8b83e9b 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/TaskList/RemoteTaskListService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/TaskList/RemoteTaskListService.cs @@ -10,30 +10,29 @@ using Microsoft.CodeAnalysis.TaskList; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal partial class RemoteTaskListService : BrokeredServiceBase, IRemoteTaskListService { - internal partial class RemoteTaskListService : BrokeredServiceBase, IRemoteTaskListService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteTaskListService CreateService(in ServiceConstructionArguments arguments) - => new RemoteTaskListService(arguments); - } + protected override IRemoteTaskListService CreateService(in ServiceConstructionArguments arguments) + => new RemoteTaskListService(arguments); + } - public RemoteTaskListService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } + public RemoteTaskListService(in ServiceConstructionArguments arguments) + : base(arguments) + { + } - public ValueTask> GetTaskListItemsAsync( - Checksum solutionChecksum, DocumentId documentId, ImmutableArray descriptors, CancellationToken cancellationToken) + public ValueTask> GetTaskListItemsAsync( + Checksum solutionChecksum, DocumentId documentId, ImmutableArray descriptors, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); - var service = document.GetRequiredLanguageService(); - return await service.GetTaskListItemsAsync(document, descriptors, cancellationToken).ConfigureAwait(false); - }, cancellationToken); - } + var document = await solution.GetRequiredDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + var service = document.GetRequiredLanguageService(); + return await service.GetTaskListItemsAsync(document, descriptors, cancellationToken).ConfigureAwait(false); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/UnitTesting/RemoteUnitTestingSearchService.cs b/src/Workspaces/Remote/ServiceHub/Services/UnitTesting/RemoteUnitTestingSearchService.cs index 14e7fe07e9d7b..5ddc85b4c398a 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/UnitTesting/RemoteUnitTestingSearchService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/UnitTesting/RemoteUnitTestingSearchService.cs @@ -9,59 +9,58 @@ using Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api; using Microsoft.CodeAnalysis.Shared.Extensions; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteUnitTestingSearchService : BrokeredServiceBase, IRemoteUnitTestingSearchService { - internal sealed class RemoteUnitTestingSearchService : BrokeredServiceBase, IRemoteUnitTestingSearchService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteUnitTestingSearchService CreateService(in ServiceConstructionArguments arguments) - => new RemoteUnitTestingSearchService(arguments); - } + protected override IRemoteUnitTestingSearchService CreateService(in ServiceConstructionArguments arguments) + => new RemoteUnitTestingSearchService(arguments); + } - public RemoteUnitTestingSearchService(in ServiceConstructionArguments arguments) - : base(arguments) - { - } + public RemoteUnitTestingSearchService(in ServiceConstructionArguments arguments) + : base(arguments) + { + } - public ValueTask GetSourceLocationAsync( - Checksum solutionChecksum, - ProjectId projectId, - UnitTestingSearchQuery query, - CancellationToken cancellationToken) + public ValueTask GetSourceLocationAsync( + Checksum solutionChecksum, + ProjectId projectId, + UnitTestingSearchQuery query, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var project = solution.GetRequiredProject(projectId); + var project = solution.GetRequiredProject(projectId); - var resultOpt = await UnitTestingSearchHelpers.GetSourceLocationAsync(project, query, cancellationToken).ConfigureAwait(false); - if (resultOpt is null) - return null; + var resultOpt = await UnitTestingSearchHelpers.GetSourceLocationAsync(project, query, cancellationToken).ConfigureAwait(false); + if (resultOpt is null) + return null; - var result = resultOpt.Value; + var result = resultOpt.Value; - return new UnitTestingSourceLocation( - new DocumentIdSpan(result.DocumentSpan.Document.Id, result.DocumentSpan.SourceSpan), - result.Span); - }, cancellationToken); - } + return new UnitTestingSourceLocation( + new DocumentIdSpan(result.DocumentSpan.Document.Id, result.DocumentSpan.SourceSpan), + result.Span); + }, cancellationToken); + } - public ValueTask> GetSourceLocationsAsync( - Checksum solutionChecksum, - ProjectId projectId, - UnitTestingSearchQuery query, - CancellationToken cancellationToken) + public ValueTask> GetSourceLocationsAsync( + Checksum solutionChecksum, + ProjectId projectId, + UnitTestingSearchQuery query, + CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - var project = solution.GetRequiredProject(projectId); + var project = solution.GetRequiredProject(projectId); - var results = await UnitTestingSearchHelpers.GetSourceLocationsAsync(project, query, cancellationToken).ConfigureAwait(false); + var results = await UnitTestingSearchHelpers.GetSourceLocationsAsync(project, query, cancellationToken).ConfigureAwait(false); - return results.SelectAsArray(r => new UnitTestingSourceLocation( - new DocumentIdSpan(r.DocumentSpan.Document.Id, r.DocumentSpan.SourceSpan), - r.Span)); - }, cancellationToken); - } + return results.SelectAsArray(r => new UnitTestingSourceLocation( + new DocumentIdSpan(r.DocumentSpan.Document.Id, r.DocumentSpan.SourceSpan), + r.Span)); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/UnusedReferences/RemoteUnusedReferenceAnalysisService.cs b/src/Workspaces/Remote/ServiceHub/Services/UnusedReferences/RemoteUnusedReferenceAnalysisService.cs index 04523be7d8226..a4a73d4471b88 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/UnusedReferences/RemoteUnusedReferenceAnalysisService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/UnusedReferences/RemoteUnusedReferenceAnalysisService.cs @@ -8,34 +8,33 @@ using Microsoft.CodeAnalysis.UnusedReferences; using Microsoft.CodeAnalysis.UnusedReferences.ProjectAssets; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteUnusedReferenceAnalysisService : BrokeredServiceBase, IRemoteUnusedReferenceAnalysisService { - internal sealed class RemoteUnusedReferenceAnalysisService : BrokeredServiceBase, IRemoteUnusedReferenceAnalysisService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteUnusedReferenceAnalysisService CreateService(in ServiceConstructionArguments arguments) - => new RemoteUnusedReferenceAnalysisService(arguments); - } + protected override IRemoteUnusedReferenceAnalysisService CreateService(in ServiceConstructionArguments arguments) + => new RemoteUnusedReferenceAnalysisService(arguments); + } - public RemoteUnusedReferenceAnalysisService(ServiceConstructionArguments arguments) - : base(arguments) - { - } + public RemoteUnusedReferenceAnalysisService(ServiceConstructionArguments arguments) + : base(arguments) + { + } - public ValueTask> GetUnusedReferencesAsync(Checksum solutionChecksum, string projectFilePath, string projectAssetsFilePath, ImmutableArray projectReferences, CancellationToken cancellationToken) + public ValueTask> GetUnusedReferencesAsync(Checksum solutionChecksum, string projectFilePath, string projectAssetsFilePath, ImmutableArray projectReferences, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => - { - // Read specified references with dependency information from the project assets file. - var references = await ProjectAssetsFileReader.ReadReferencesAsync(projectReferences, projectAssetsFilePath).ConfigureAwait(false); + // Read specified references with dependency information from the project assets file. + var references = await ProjectAssetsFileReader.ReadReferencesAsync(projectReferences, projectAssetsFilePath).ConfigureAwait(false); - // Determine unused references - var unusedReferences = await UnusedReferencesRemover.GetUnusedReferencesAsync(solution, projectFilePath, references, cancellationToken).ConfigureAwait(false); + // Determine unused references + var unusedReferences = await UnusedReferencesRemover.GetUnusedReferencesAsync(solution, projectFilePath, references, cancellationToken).ConfigureAwait(false); - // Remove dependency information before returning. - return unusedReferences.SelectAsArray(reference => reference.WithDependencies(null)); - }, cancellationToken); - } + // Remove dependency information before returning. + return unusedReferences.SelectAsArray(reference => reference.WithDependencies(null)); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/ValueTracking/RemoteValueTrackingService.cs b/src/Workspaces/Remote/ServiceHub/Services/ValueTracking/RemoteValueTrackingService.cs index be84f69a1124b..6226e1fceabe0 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/ValueTracking/RemoteValueTrackingService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/ValueTracking/RemoteValueTrackingService.cs @@ -10,61 +10,60 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.ValueTracking; -namespace Microsoft.CodeAnalysis.Remote +namespace Microsoft.CodeAnalysis.Remote; + +internal sealed class RemoteValueTrackingService : BrokeredServiceBase, IRemoteValueTrackingService { - internal sealed class RemoteValueTrackingService : BrokeredServiceBase, IRemoteValueTrackingService + internal sealed class Factory : FactoryBase { - internal sealed class Factory : FactoryBase - { - protected override IRemoteValueTrackingService CreateService(in ServiceConstructionArguments arguments) - => new RemoteValueTrackingService(arguments); - } + protected override IRemoteValueTrackingService CreateService(in ServiceConstructionArguments arguments) + => new RemoteValueTrackingService(arguments); + } - public RemoteValueTrackingService(ServiceConstructionArguments arguments) - : base(arguments) - { - } + public RemoteValueTrackingService(ServiceConstructionArguments arguments) + : base(arguments) + { + } - public ValueTask> TrackValueSourceAsync(Checksum solutionChecksum, TextSpan selection, DocumentId documentId, CancellationToken cancellationToken) + public ValueTask> TrackValueSourceAsync(Checksum solutionChecksum, TextSpan selection, DocumentId documentId, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => + if (solution is null) { - if (solution is null) - { - throw new InvalidOperationException(); - } + throw new InvalidOperationException(); + } - var document = solution.GetRequiredDocument(documentId); + var document = solution.GetRequiredDocument(documentId); - var progress = new ValueTrackingProgressCollector(); - await ValueTracker.TrackValueSourceAsync(selection, document, progress, cancellationToken).ConfigureAwait(false); + var progress = new ValueTrackingProgressCollector(); + await ValueTracker.TrackValueSourceAsync(selection, document, progress, cancellationToken).ConfigureAwait(false); - var items = progress.GetItems(); - return items.SelectAsArray(item => SerializableValueTrackedItem.Dehydrate(solution, item, cancellationToken)); - }, cancellationToken); - } + var items = progress.GetItems(); + return items.SelectAsArray(item => SerializableValueTrackedItem.Dehydrate(solution, item, cancellationToken)); + }, cancellationToken); + } - public ValueTask> TrackValueSourceAsync(Checksum solutionChecksum, SerializableValueTrackedItem previousTrackedItem, CancellationToken cancellationToken) + public ValueTask> TrackValueSourceAsync(Checksum solutionChecksum, SerializableValueTrackedItem previousTrackedItem, CancellationToken cancellationToken) + { + return RunServiceAsync(solutionChecksum, async solution => { - return RunServiceAsync(solutionChecksum, async solution => + if (solution is null) { - if (solution is null) - { - throw new InvalidOperationException(); - } + throw new InvalidOperationException(); + } - var previousItem = await previousTrackedItem.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false); - if (previousItem is null) - { - return ImmutableArray.Empty; - } + var previousItem = await previousTrackedItem.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false); + if (previousItem is null) + { + return ImmutableArray.Empty; + } - var progress = new ValueTrackingProgressCollector(); - await ValueTracker.TrackValueSourceAsync(solution, previousItem, progress, cancellationToken).ConfigureAwait(false); + var progress = new ValueTrackingProgressCollector(); + await ValueTracker.TrackValueSourceAsync(solution, previousItem, progress, cancellationToken).ConfigureAwait(false); - var items = progress.GetItems(); - return items.SelectAsArray(item => SerializableValueTrackedItem.Dehydrate(solution, item, cancellationToken)); - }, cancellationToken); - } + var items = progress.GetItems(); + return items.SelectAsArray(item => SerializableValueTrackedItem.Dehydrate(solution, item, cancellationToken)); + }, cancellationToken); } } diff --git a/src/Workspaces/Remote/ServiceHubTest/RemoteAnalyzerAssemblyLoaderTests.cs b/src/Workspaces/Remote/ServiceHubTest/RemoteAnalyzerAssemblyLoaderTests.cs index 4e25bf0c20b42..5eaf725e8399c 100644 --- a/src/Workspaces/Remote/ServiceHubTest/RemoteAnalyzerAssemblyLoaderTests.cs +++ b/src/Workspaces/Remote/ServiceHubTest/RemoteAnalyzerAssemblyLoaderTests.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. -#if NETCOREAPP +#if NET using System.IO; using System.Reflection; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensions.projitems index 159427b6df1da..a567cd03b6aca 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensions.projitems @@ -30,7 +30,6 @@ - diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensionsResources.resx b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensionsResources.resx index 66e63f1c3edf0..dc36bf2f7cf41 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensionsResources.resx +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CSharpCompilerExtensionsResources.resx @@ -139,4 +139,7 @@ Expected string or char literal + + EditorConfig option '{0}' contains unrecognized value '{1}' + \ No newline at end of file diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpCodeGenerationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpCodeGenerationOptions.cs index a428cc68f2dde..55bef9fbf4b22 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpCodeGenerationOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeGeneration/CSharpCodeGenerationOptions.cs @@ -2,20 +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.Runtime.Serialization; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions_Parsing.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions_Parsing.cs index 6fb5ff3fe5075..f7cbf796f684f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions_Parsing.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions_Parsing.cs @@ -84,7 +84,7 @@ public static CodeStyleOption2 ParseNamespaceDec { "block_scoped" => new(NamespaceDeclarationPreference.BlockScoped, notification), "file_scoped" => new(NamespaceDeclarationPreference.FileScoped, notification), - _ => throw new NotSupportedException(), + _ => throw new NotSupportedException(string.Format(CSharpCompilerExtensionsResources.EditorConfig_option_0_contains_unrecognized_value_1, "csharp_style_namespace_declarations", value)), }; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs index ae491e6c78840..5f5a71587dcfa 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs @@ -243,21 +243,15 @@ public static bool IsOnlyWrittenTo([NotNullWhen(true)] this ExpressionSyntax? ex if (expression != null) { if (expression.IsInOutContext()) - { return true; - } if (expression.Parent != null) { if (expression.IsLeftSideOfAssignExpression()) - { return true; - } if (expression.IsAttributeNamedArgumentIdentifier()) - { return true; - } } if (IsExpressionOfArgumentInDeconstruction(expression)) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ForEachStatementSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ForEachStatementSyntaxExtensions.cs deleted file mode 100644 index 70d6a69c756ea..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ForEachStatementSyntaxExtensions.cs +++ /dev/null @@ -1,26 +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 Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace Microsoft.CodeAnalysis.CSharp.Extensions; - -internal static class ForEachStatementSyntaxExtensions -{ - public static bool IsTypeInferred(this CommonForEachStatementSyntax forEachStatement, SemanticModel semanticModel) - { - switch (forEachStatement.Kind()) - { - case SyntaxKind.ForEachStatement: - return ((ForEachStatementSyntax)forEachStatement).Type.IsTypeInferred(semanticModel); - case SyntaxKind.ForEachVariableStatement: - return (((ForEachVariableStatementSyntax)forEachStatement).Variable as DeclarationExpressionSyntax)?.Type - .IsTypeInferred(semanticModel) == true; - default: - return false; - } - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SemanticModelExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SemanticModelExtensions.cs index 43c0af76af764..477782ad8e6ca 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SemanticModelExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SemanticModelExtensions.cs @@ -488,4 +488,10 @@ public static ISymbol GetRequiredDeclaredSymbol(this SemanticModel semanticModel return semanticModel.GetDeclaredSymbol(syntax, cancellationToken) ?? throw new InvalidOperationException(); } + + public static ISymbol GetRequiredDeclaredSymbol(this SemanticModel semanticModel, SingleVariableDesignationSyntax syntax, CancellationToken cancellationToken) + { + return semanticModel.GetDeclaredSymbol(syntax, cancellationToken) + ?? throw new InvalidOperationException(); + } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs index 59c702c08cac1..9507a6b00bcbe 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs @@ -757,15 +757,29 @@ public static SyntaxTokenList GetModifiers(this SyntaxNode? member) _ => null, }; - public static IEnumerable GetMembers(this SyntaxNode? node) - => node switch + public static void ForEachMember(this SyntaxNode? node, Action callback, TArg arg) + { + // Separated out to allow for struct-based enumeration. + switch (node) { - CompilationUnitSyntax compilation => compilation.Members, - BaseNamespaceDeclarationSyntax @namespace => @namespace.Members, - TypeDeclarationSyntax type => type.Members, - EnumDeclarationSyntax @enum => @enum.Members, - _ => [], - }; + case CompilationUnitSyntax compilation: + foreach (var member in compilation.Members) + callback(member, arg); + break; + case BaseNamespaceDeclarationSyntax @namespace: + foreach (var member in @namespace.Members) + callback(member, arg); + break; + case TypeDeclarationSyntax type: + foreach (var member in type.Members) + callback(member, arg); + break; + case EnumDeclarationSyntax @enum: + foreach (var member in @enum.Members) + callback(member, arg); + break; + } + } public static bool IsInExpressionTree( [NotNullWhen(true)] this SyntaxNode? node, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaExtensions.cs index 18f5fc755f53e..b6578e031091d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTriviaExtensions.cs @@ -89,7 +89,7 @@ public static string GetCommentText(this SyntaxTrivia trivia) commentText = commentText.Trim(); var newLine = Environment.NewLine; - var lines = commentText.Split(new[] { newLine }, StringSplitOptions.None); + var lines = commentText.Split([newLine], StringSplitOptions.None); foreach (var line in lines) { var trimmedLine = line.Trim(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs index 66e973d451995..62669e9750b21 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/CSharpFormattingOptions2.cs @@ -3,14 +3,12 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using System.Diagnostics; using Roslyn.Utilities; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Formatting; #if CODE_STYLE using CSharpWorkspaceResources = Microsoft.CodeAnalysis.CSharp.CSharpCodeStyleResources; -using WorkspacesResources = Microsoft.CodeAnalysis.CodeStyleResources; #endif namespace Microsoft.CodeAnalysis.CSharp.Formatting; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs index fe2d500f90490..cebd1153d3b37 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs @@ -19,18 +19,15 @@ using Roslyn.Utilities; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; -#if CODE_STYLE -using Microsoft.CodeAnalysis.Internal.Editing; -#else -using Microsoft.CodeAnalysis.Editing; -#endif - namespace Microsoft.CodeAnalysis.CSharp.LanguageService; internal class CSharpSyntaxFacts : ISyntaxFacts { internal static readonly CSharpSyntaxFacts Instance = new(); + // Specifies false for trimOnFree as these objects commonly exceed the default ObjectPool threshold + private static readonly ObjectPool> s_syntaxNodeListPool = new ObjectPool>(() => [], trimOnFree: false); + protected CSharpSyntaxFacts() { } @@ -896,18 +893,24 @@ private static void AppendTypeParameterList(StringBuilder builder, TypeParameter } } - public List GetTopLevelAndMethodLevelMembers(SyntaxNode? root) + public PooledObject> GetTopLevelAndMethodLevelMembers(SyntaxNode? root) { - var list = new List(); + var pooledObject = s_syntaxNodeListPool.GetPooledObject(); + var list = pooledObject.Object; + AppendMembers(root, list, topLevel: true, methodLevel: true); - return list; + + return pooledObject; } - public List GetMethodLevelMembers(SyntaxNode? root) + public PooledObject> GetMethodLevelMembers(SyntaxNode? root) { - var list = new List(); + var pooledObject = s_syntaxNodeListPool.GetPooledObject(); + var list = pooledObject.Object; + AppendMembers(root, list, topLevel: false, methodLevel: true); - return list; + + return pooledObject; } public SyntaxList GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration) @@ -917,24 +920,24 @@ private void AppendMembers(SyntaxNode? node, List list, bool topLeve { Debug.Assert(topLevel || methodLevel); - foreach (var member in node.GetMembers()) - { - if (IsTopLevelNodeWithMembers(member)) + node.ForEachMember(static (member, arg) => { - if (topLevel) + var (@this, list, topLevel, methodLevel) = arg; + if (@this.IsTopLevelNodeWithMembers(member)) + { + if (topLevel) + { + list.Add(member); + } + + @this.AppendMembers(member, list, topLevel, methodLevel); + } + else if (methodLevel && @this.IsMethodLevelMember(member)) { list.Add(member); } - - AppendMembers(member, list, topLevel, methodLevel); - continue; - } - - if (methodLevel && IsMethodLevelMember(member)) - { - list.Add(member); - } - } + }, + (this, list, topLevel, methodLevel)); } public TextSpan GetMemberBodySpanForSpeculativeBinding(SyntaxNode node) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs index 9d9214224d6d5..251d02fcc361a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs @@ -1105,6 +1105,35 @@ private static bool IntroducedAmbiguity( if (newSymbolInfo.Symbol is null) return true; } + + if (currentOld is InterpolatedStringExpressionSyntax && currentNew is InterpolatedStringExpressionSyntax) + { + // In the case of interpolations, we need to dive into the operation level to determine if the meaning + // of the the interpolation stayed the same in the case of interpolation handlers. + if (originalSemanticModel.GetOperation(currentOld, cancellationToken) is not IInterpolatedStringOperation oldInterpolationOperation) + return true; + + if (rewrittenSemanticModel.GetOperation(currentNew, cancellationToken) is not IInterpolatedStringOperation newInterpolationOperation) + return true; + + if (oldInterpolationOperation.Parts.Length != newInterpolationOperation.Parts.Length) + return true; + + for (int i = 0, n = oldInterpolationOperation.Parts.Length; i < n; i++) + { + var oldInterpolationPart = oldInterpolationOperation.Parts[i]; + var newInterpolationPart = newInterpolationOperation.Parts[i]; + if (oldInterpolationPart.Kind != newInterpolationPart.Kind) + return true; + + // If we were calling some interpolation AppendFormatted helper, and now we're not, we introduced a problem. + if (oldInterpolationPart is IInterpolatedStringAppendOperation { AppendCall: not IInvalidOperation } && + newInterpolationPart is IInterpolatedStringAppendOperation { AppendCall: IInvalidOperation }) + { + return true; + } + } + } } return false; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/SpeculationAnalyzer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/SpeculationAnalyzer.cs index 3c8f9c36452cc..cd36ada0d4bf2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/SpeculationAnalyzer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/SpeculationAnalyzer.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -639,7 +640,12 @@ protected override ExpressionSyntax GetThrowStatementExpression(ThrowStatementSy => throwStatement.Expression; protected override bool IsForEachTypeInferred(CommonForEachStatementSyntax forEachStatement, SemanticModel semanticModel) - => forEachStatement.IsTypeInferred(semanticModel); + => forEachStatement switch + { + ForEachStatementSyntax foreachStatement => foreachStatement.Type.IsTypeInferred(semanticModel), + ForEachVariableStatementSyntax { Variable: DeclarationExpressionSyntax declarationExpression } => declarationExpression.Type.IsTypeInferred(semanticModel), + _ => false, + }; protected override bool IsParenthesizedExpression(SyntaxNode node) => node.IsKind(SyntaxKind.ParenthesizedExpression); @@ -864,11 +870,50 @@ protected override bool ForEachConversionsAreCompatible(SemanticModel originalMo && ConversionsAreCompatible(originalInfo.ElementConversion, newInfo.ElementConversion); } - protected override void GetForEachSymbols(SemanticModel model, CommonForEachStatementSyntax forEach, out IMethodSymbol getEnumeratorMethod, out ITypeSymbol elementType) + protected override void GetForEachSymbols( + SemanticModel model, + CommonForEachStatementSyntax forEach, + out IMethodSymbol getEnumeratorMethod, + out ITypeSymbol elementType, + out ImmutableArray localVariables) { var info = model.GetForEachStatementInfo(forEach); getEnumeratorMethod = info.GetEnumeratorMethod; elementType = info.ElementType; + + if (forEach is ForEachStatementSyntax foreachStatement) + { + localVariables = [(ILocalSymbol)model.GetRequiredDeclaredSymbol(foreachStatement, this.CancellationToken)]; + } + else if (forEach is ForEachVariableStatementSyntax { Variable: DeclarationExpressionSyntax declarationExpression }) + { + using var variables = TemporaryArray.Empty; + AddVariables(declarationExpression.Designation, ref variables.AsRef()); + + localVariables = variables.ToImmutableAndClear(); + } + else + { + localVariables = []; + } + + return; + + void AddVariables(VariableDesignationSyntax designation, ref TemporaryArray variables) + { + switch (designation) + { + case SingleVariableDesignationSyntax singleVariableDesignation: + variables.Add((ILocalSymbol)model.GetRequiredDeclaredSymbol(singleVariableDesignation, CancellationToken)); + break; + + case ParenthesizedVariableDesignationSyntax parenthesizedVariableDesignation: + foreach (var child in parenthesizedVariableDesignation.Variables) + AddVariables(child, ref variables); + + break; + } + } } protected override bool IsReferenceConversion(Compilation compilation, ITypeSymbol sourceType, ITypeSymbol targetType) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf index fa634e3a893ac..d32fa26eedbfb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.cs.xlf @@ -7,6 +7,11 @@ Předvolby bloků kódu + + EditorConfig option '{0}' contains unrecognized value '{1}' + Možnost EditorConfig {0} obsahuje nerozpoznanou hodnotu {1}. + + Expected string or char literal Očekával se řetězcový nebo znakový literál. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf index ee365d944ffd6..b85e143ec80b7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.de.xlf @@ -7,6 +7,11 @@ Einstellungen für Codeblöcke + + EditorConfig option '{0}' contains unrecognized value '{1}' + Die EditorConfig-Option „{0}“ enthält den unbekannten Wert „{1}“ + + Expected string or char literal Erwartete Zeichenfolge oder Zeichenliteral diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf index ac4000bbeb7a6..788a8f9574971 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.es.xlf @@ -7,6 +7,11 @@ Preferencias de bloque de código + + EditorConfig option '{0}' contains unrecognized value '{1}' + La opción EditorConfig "{0}" contiene un valor no reconocido "{1}" + + Expected string or char literal Cadena o carácter literal esperados diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf index 5ba49bd52c4e9..07772c15d1958 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.fr.xlf @@ -7,6 +7,11 @@ Préférences de bloc de code + + EditorConfig option '{0}' contains unrecognized value '{1}' + L'option EditorConfig '{0}' contient une valeur non reconnue '{1}' + + Expected string or char literal Littéral char ou string attendu diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf index ff9a9076c2da0..f235d51396d01 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.it.xlf @@ -7,6 +7,11 @@ Preferenze per blocchi di codice + + EditorConfig option '{0}' contains unrecognized value '{1}' + L'opzione EditorConfig '{0}' contiene un valore non riconosciuto '{1}' + + Expected string or char literal È previsto un valore letterale di tipo stringa o char diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf index b321177375f57..aba490097239f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ja.xlf @@ -7,6 +7,11 @@ コード ブロックの設定 + + EditorConfig option '{0}' contains unrecognized value '{1}' + EditorConfig オプション '{0}' に認識できない値 '{1}' が含まれています + + Expected string or char literal 文字列または文字リテラルが必要です diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf index 6b3c8f3a5d364..20c86bb508b72 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ko.xlf @@ -7,6 +7,11 @@ 코드 블록 기본 설정 + + EditorConfig option '{0}' contains unrecognized value '{1}' + EditorConfig 옵션 '{0}'에 인식할 수 없는 값 '{1}'이(가) 있습니다. + + Expected string or char literal 문자열 또는 문자 리터럴이 필요합니다. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf index 9afa0ebccaf45..a88315e954e08 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pl.xlf @@ -7,6 +7,11 @@ Preferencje bloku kodu + + EditorConfig option '{0}' contains unrecognized value '{1}' + Opcja konfiguracji EditorConfig „{0}” zawiera nierozpoznaną wartość „{1}” + + Expected string or char literal Oczekiwano ciągu lub literału znakowego diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pt-BR.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pt-BR.xlf index 22bfa1e1b75cc..a892025e17056 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pt-BR.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.pt-BR.xlf @@ -7,6 +7,11 @@ Preferências do bloco de código + + EditorConfig option '{0}' contains unrecognized value '{1}' + A opção EditorConfig '{0}' contém um valor não reconhecido '{1}' + + Expected string or char literal Cadeia de caracteres esperada ou literal char diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf index 2102a5e803e06..46a9cb21a9c94 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.ru.xlf @@ -7,6 +7,11 @@ Предпочтения для блоков кода + + EditorConfig option '{0}' contains unrecognized value '{1}' + Параметр EditorConfig "{0}" содержит нераспознанное значение "{1}" + + Expected string or char literal Требуется строка или знаковый литерал diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf index c9e54c73fa46c..3d57cea68c8ca 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.tr.xlf @@ -7,6 +7,11 @@ Kod bloğu tercihleri + + EditorConfig option '{0}' contains unrecognized value '{1}' + ‘{0}’ EditorConfig seçeneği tanınmayan ‘{1}’ değerini içeriyor + + Expected string or char literal Beklenen dize veya karakter sabiti değeri diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf index e179a0b322aec..d29b4437bd71c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hans.xlf @@ -7,6 +7,11 @@ 代码块首选项 + + EditorConfig option '{0}' contains unrecognized value '{1}' + EditorConfig 选项 '{0}' 包含无法识别的值 '{1}' + + Expected string or char literal 预期的字符串或字符文本 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hant.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hant.xlf index 55ee733e947ad..2977802093cab 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hant.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/xlf/CSharpCompilerExtensionsResources.zh-Hant.xlf @@ -7,6 +7,11 @@ 程式碼區塊喜好設定 + + EditorConfig option '{0}' contains unrecognized value '{1}' + EditorConfig 選項 '{0}' 包含無法辨識的值 '{1}' + + Expected string or char literal 必須是字串或字元常值 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/AddImport/AddImportPlacementOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/AddImport/AddImportPlacementOptions.cs index b06105cca50e2..e9497203663d9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/AddImport/AddImportPlacementOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/AddImport/AddImportPlacementOptions.cs @@ -3,16 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Runtime.Serialization; -using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Options; - -#if !CODE_STYLE -using Microsoft.CodeAnalysis.Host; -#endif namespace Microsoft.CodeAnalysis.AddImport; @@ -38,23 +29,3 @@ internal sealed record class AddImportPlacementOptions public static readonly AddImportPlacementOptions Default = new(); } - -internal static partial class AddImportPlacementOptionsProviders -{ -#if !CODE_STYLE - public static AddImportPlacementOptions GetAddImportPlacementOptions(this IOptionsReader options, LanguageServices languageServices, bool? allowInHiddenRegions) - => languageServices.GetRequiredService().GetAddImportOptions(options, allowInHiddenRegions ?? AddImportPlacementOptions.Default.AllowInHiddenRegions); - - public static async ValueTask GetAddImportPlacementOptionsAsync(this Document document, CancellationToken cancellationToken) - { - var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return configOptions.GetAddImportPlacementOptions(document.Project.Services, document.AllowImportsInHiddenRegions()); - } - - // Normally we don't allow generation into a hidden region in the file. However, if we have a - // modern span mapper at our disposal, we do allow it as that host span mapper can handle mapping - // our edit to their domain appropriate. - public static bool AllowImportsInHiddenRegions(this Document document) - => document.Services.GetService()?.SupportsMappingImportDirectives == true; -#endif -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeCleanup/CodeCleanupOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeCleanup/CodeCleanupOptions.cs index d9faeb67b65c6..243677ebb6796 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeCleanup/CodeCleanupOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeCleanup/CodeCleanupOptions.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.Threading; -using System.Threading.Tasks; using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.Options; -using Roslyn.Utilities; - -#if !CODE_STYLE -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.OrganizeImports; -#endif namespace Microsoft.CodeAnalysis.CodeCleanup; @@ -26,14 +18,6 @@ internal sealed record class CodeCleanupOptions [DataMember] public AddImportPlacementOptions AddImportOptions { get; init; } = AddImportPlacementOptions.Default; [DataMember] public DocumentFormattingOptions DocumentFormattingOptions { get; init; } = DocumentFormattingOptions.Default; -#if !CODE_STYLE - public static CodeCleanupOptions GetDefault(LanguageServices languageServices) - => new() - { - FormattingOptions = SyntaxFormattingOptions.GetDefault(languageServices), - SimplifierOptions = SimplifierOptions.GetDefault(languageServices) - }; - public OrganizeImportsOptions GetOrganizeImportsOptions() => new() { @@ -41,26 +25,4 @@ public OrganizeImportsOptions GetOrganizeImportsOptions() PlaceSystemNamespaceFirst = AddImportOptions.PlaceSystemNamespaceFirst, NewLine = FormattingOptions.LineFormatting.NewLine, }; -#endif } - -internal static class CodeCleanupOptionsProviders -{ -#if !CODE_STYLE - public static CodeCleanupOptions GetCodeCleanupOptions(this IOptionsReader options, LanguageServices languageServices, bool? allowImportsInHiddenRegions = null) - => new() - { - FormattingOptions = options.GetSyntaxFormattingOptions(languageServices), - SimplifierOptions = options.GetSimplifierOptions(languageServices), - AddImportOptions = options.GetAddImportPlacementOptions(languageServices, allowImportsInHiddenRegions), - DocumentFormattingOptions = options.GetDocumentFormattingOptions(), - }; - - public static async ValueTask GetCodeCleanupOptionsAsync(this Document document, CancellationToken cancellationToken) - { - var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return configOptions.GetCodeCleanupOptions(document.Project.Services, document.AllowImportsInHiddenRegions()); - } -#endif -} - diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeAndImportGenerationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeAndImportGenerationOptions.cs new file mode 100644 index 0000000000000..36c8a758344f6 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeAndImportGenerationOptions.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.Serialization; +using Microsoft.CodeAnalysis.AddImport; + +namespace Microsoft.CodeAnalysis.CodeGeneration; + +[DataContract] +internal readonly record struct CodeAndImportGenerationOptions +{ + [DataMember] + public required CodeGenerationOptions GenerationOptions { get; init; } + + [DataMember] + public required AddImportPlacementOptions AddImportOptions { get; init; } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs index a0df454f12d47..0061f26bf1b40 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CodeGenerationOptions.cs @@ -3,18 +3,10 @@ // See the LICENSE file in the project root for more information. using System.Runtime.Serialization; -using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImport; -using Roslyn.Utilities; -using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.CodeCleanup; - -#if !CODE_STYLE -using Microsoft.CodeAnalysis.Host; -#endif namespace Microsoft.CodeAnalysis.CodeGeneration; @@ -38,65 +30,4 @@ private protected CodeGenerationOptions(IOptionsReader options, string language) { NamingStyle = options.GetOption(NamingStyleOptions.NamingPreferences, language); } - -#if !CODE_STYLE - public static CodeGenerationOptions GetDefault(LanguageServices languageServices) - => languageServices.GetRequiredService().DefaultOptions; -#endif -} - -[DataContract] -internal readonly record struct CodeAndImportGenerationOptions -{ - [DataMember] - public required CodeGenerationOptions GenerationOptions { get; init; } - - [DataMember] - public required AddImportPlacementOptions AddImportOptions { get; init; } - -#if !CODE_STYLE - internal static CodeAndImportGenerationOptions GetDefault(LanguageServices languageServices) - => new() - { - GenerationOptions = CodeGenerationOptions.GetDefault(languageServices), - AddImportOptions = AddImportPlacementOptions.Default - }; -#endif -} - -internal static class CodeGenerationOptionsProviders -{ -#if !CODE_STYLE - public static CodeGenerationOptions GetCodeGenerationOptions(this IOptionsReader options, LanguageServices languageServices) - => languageServices.GetRequiredService().GetCodeGenerationOptions(options); - - public static CodeAndImportGenerationOptions GetCodeAndImportGenerationOptions(this IOptionsReader options, LanguageServices languageServices, bool? allowImportsInHiddenRegions = null) - => new() - { - GenerationOptions = options.GetCodeGenerationOptions(languageServices), - AddImportOptions = options.GetAddImportPlacementOptions(languageServices, allowImportsInHiddenRegions) - }; - - public static CleanCodeGenerationOptions GetCleanCodeGenerationOptions(this IOptionsReader options, LanguageServices languageServices, bool? allowImportsInHiddenRegions = null) - => new() - { - GenerationOptions = options.GetCodeGenerationOptions(languageServices), - CleanupOptions = options.GetCodeCleanupOptions(languageServices, allowImportsInHiddenRegions) - }; - - public static async ValueTask GetCodeGenerationOptionsAsync(this Document document, CancellationToken cancellationToken) - { - var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return configOptions.GetCodeGenerationOptions(document.Project.Services); - } - - public static async ValueTask GetCodeGenerationInfoAsync(this Document document, CodeGenerationContext context, CancellationToken cancellationToken) - { - Contract.ThrowIfNull(document.Project.ParseOptions); - - var options = await GetCodeGenerationOptionsAsync(document, cancellationToken).ConfigureAwait(false); - var service = document.Project.Services.GetRequiredService(); - return service.GetInfo(context, options, document.Project.ParseOptions); - } -#endif } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/NormalizedTextSpanCollection.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/NormalizedTextSpanCollection.cs index 941fcf4ac552d..418bc5887ad41 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/NormalizedTextSpanCollection.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Collections/NormalizedTextSpanCollection.cs @@ -623,7 +623,7 @@ private static IList NormalizeSpans(IEnumerable spans) } } - private class OrderedSpanList : List + private sealed class OrderedSpanList : List { } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index c00a31249fe65..6b6714a96ee97 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -149,7 +149,7 @@ InternalUtilities\OneOrMany.cs - + InternalUtilities\PerformanceSensitiveAttribute.cs @@ -190,8 +190,8 @@ InternalUtilities\UnicodeCharacterUtilities.cs + - @@ -256,6 +256,14 @@ + + + + + + + + @@ -273,6 +281,7 @@ + @@ -484,6 +493,8 @@ + + @@ -507,7 +518,9 @@ + + @@ -551,6 +564,8 @@ + + @@ -627,6 +642,7 @@ + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensionsResources.resx b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensionsResources.resx index 4030a16719092..7e4f99739d401 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensionsResources.resx +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensionsResources.resx @@ -273,4 +273,7 @@ New line preferences + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + \ No newline at end of file diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Editing/GenerationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Editing/GenerationOptions.cs index a0d475298a14d..a57132d83733f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Editing/GenerationOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Editing/GenerationOptions.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Editing; -internal class GenerationOptions +internal sealed class GenerationOptions { public static readonly PerLanguageOption2 PlaceSystemNamespaceFirst = new( "dotnet_sort_system_directives_first", diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/NamingStyles/NamingStyleOptionAccumulator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/NamingStyles/NamingStyleOptionAccumulator.cs index d244c4acc9cad..8ff1b76fc3814 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/NamingStyles/NamingStyleOptionAccumulator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EditorConfig/Parsing/NamingStyles/NamingStyleOptionAccumulator.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.EditorConfig.Parsing.NamingStyles; -internal class NamingStyleOptionAccumulator : IEditorConfigOptionAccumulator +internal sealed class NamingStyleOptionAccumulator : IEditorConfigOptionAccumulator { private ArrayBuilder? _rules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.Chunks.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.Chunks.cs index 42684a12ad55d..04fea4f3aa879 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.Chunks.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/EmbeddedLanguages/VirtualChars/VirtualCharSequence.Chunks.cs @@ -34,7 +34,7 @@ protected Chunk() /// This will be the common construct we generate when getting the /// for a string token that has escapes in it. /// - private class ImmutableSegmentedListChunk(ImmutableSegmentedList array) : Chunk + private sealed class ImmutableSegmentedListChunk(ImmutableSegmentedList array) : Chunk { public override int Length => array.Count; public override VirtualChar this[int index] => array[index]; @@ -78,7 +78,7 @@ private class ImmutableSegmentedListChunk(ImmutableSegmentedList ar /// do not want that should then ask for an appropriate /// back that does not include those characters. /// - private class StringChunk(int firstVirtualCharPosition, string data) : Chunk + private sealed class StringChunk(int firstVirtualCharPosition, string data) : Chunk { public override int Length => data.Length; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs index b6c2e8e03d430..d4f598d420175 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/AnalyzerConfigOptionsExtensions.cs @@ -53,6 +53,15 @@ public static bool TryGetEditorConfigOption(this AnalyzerConfigOptions analyz return false; } + public static bool IsCodeStyleSeverityEnabled(this AnalyzerConfigOptions analyzerConfigOptions) + { + const string EnableCodeStyleSeverityKey = "build_property.EnableCodeStyleSeverity"; + + return analyzerConfigOptions.TryGetValue(EnableCodeStyleSeverityKey, out var value) + && bool.TryParse(value, out var parsedValue) + && parsedValue; + } + public static bool IsAnalysisLevelGreaterThanOrEquals(this AnalyzerConfigOptions analyzerConfigOptions, int minAnalysisLevel) { // See https://github.com/dotnet/roslyn/pull/70794 for details. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs index ec6176941dd79..ca5e10666e4c4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs @@ -254,4 +254,7 @@ public static ImmutableArray GetReferencedAssemblySymbols(this public static INamedTypeSymbol? SpanOfTType(this Compilation compilation) => compilation.GetTypeByMetadataName(typeof(Span<>).FullName!); + + public static INamedTypeSymbol? InterpolatedStringHandlerAttributeType(this Compilation compilation) + => compilation.GetTypeByMetadataName(typeof(InterpolatedStringHandlerAttribute).FullName!); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs index 80f330f63f35f..87a272da45712 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/IMethodSymbolExtensions.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis.LanguageService; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.RequiresUnsafeModifierVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.RequiresUnsafeModifierVisitor.cs index 68a5d4165a727..ad3b45dc69800 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.RequiresUnsafeModifierVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.RequiresUnsafeModifierVisitor.cs @@ -8,14 +8,14 @@ namespace Microsoft.CodeAnalysis.Shared.Extensions; -internal partial class ISymbolExtensions +internal static partial class ISymbolExtensions { /// /// Visits types or members that have signatures (i.e. methods, fields, etc.) and determines /// if any of them reference a pointer type and should thus have the modifier on them. /// - private class RequiresUnsafeModifierVisitor : SymbolVisitor + private sealed class RequiresUnsafeModifierVisitor : SymbolVisitor { private readonly HashSet _visited = []; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/ITypeGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeGenerator.cs similarity index 100% rename from src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/ITypeGenerator.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeGenerator.cs diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeParameterSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeParameterSymbolExtensions.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/Extensions/ITypeParameterSymbolExtensions.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeParameterSymbolExtensions.cs diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.AnonymousTypeRemover.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.AnonymousTypeRemover.cs similarity index 93% rename from src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.AnonymousTypeRemover.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.AnonymousTypeRemover.cs index f929abc39b74d..b44ed192b6f9b 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.AnonymousTypeRemover.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.AnonymousTypeRemover.cs @@ -9,9 +9,9 @@ namespace Microsoft.CodeAnalysis.Shared.Extensions; -internal partial class ITypeSymbolExtensions +internal static partial class ITypeSymbolExtensions { - private class AnonymousTypeRemover(Compilation compilation) : SymbolVisitor + private sealed class AnonymousTypeRemover(Compilation compilation) : SymbolVisitor { public override ITypeSymbol DefaultVisit(ISymbol node) => throw new NotImplementedException(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs similarity index 95% rename from src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs index a0adc6feb3879..054a38b5a4d15 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CollectTypeParameterSymbolsVisitor.cs @@ -9,9 +9,9 @@ namespace Microsoft.CodeAnalysis.Shared.Extensions; -internal partial class ITypeSymbolExtensions +internal static partial class ITypeSymbolExtensions { - private class CollectTypeParameterSymbolsVisitor( + private sealed class CollectTypeParameterSymbolsVisitor( IList typeParameters, bool onlyMethodTypeParameters) : SymbolVisitor { diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs similarity index 83% rename from src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs index c268562bdbbe1..39c5c0d5682d7 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.CompilationTypeGenerator.cs @@ -6,9 +6,9 @@ namespace Microsoft.CodeAnalysis.Shared.Extensions; -internal partial class ITypeSymbolExtensions +internal static partial class ITypeSymbolExtensions { - private class CompilationTypeGenerator(Compilation compilation) : ITypeGenerator + private sealed class CompilationTypeGenerator(Compilation compilation) : ITypeGenerator { public ITypeSymbol CreateArrayTypeSymbol(ITypeSymbol elementType, int rank) => compilation.CreateArrayTypeSymbol(elementType, rank); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.MinimalAccessibilityVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.MinimalAccessibilityVisitor.cs index d4206f6be109b..6cfe7ad9e619f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.MinimalAccessibilityVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.MinimalAccessibilityVisitor.cs @@ -6,9 +6,9 @@ namespace Microsoft.CodeAnalysis.Shared.Extensions; -internal partial class ITypeSymbolExtensions +internal static partial class ITypeSymbolExtensions { - private class MinimalAccessibilityVisitor : SymbolVisitor + private sealed class MinimalAccessibilityVisitor : SymbolVisitor { public static readonly SymbolVisitor Instance = new MinimalAccessibilityVisitor(); diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs similarity index 96% rename from src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs index 90dc0cb155d51..2114faae37b16 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.SubstituteTypesVisitor.cs @@ -10,9 +10,9 @@ namespace Microsoft.CodeAnalysis.Shared.Extensions; -internal partial class ITypeSymbolExtensions +internal static partial class ITypeSymbolExtensions { - private class SubstituteTypesVisitor : SymbolVisitor + private sealed class SubstituteTypesVisitor : SymbolVisitor where TType1 : ITypeSymbol where TType2 : ITypeSymbol { diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.UnavailableTypeParameterRemover.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.UnavailableTypeParameterRemover.cs similarity index 93% rename from src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.UnavailableTypeParameterRemover.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.UnavailableTypeParameterRemover.cs index b591d1c9d2818..65c22bba4a2a5 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.UnavailableTypeParameterRemover.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.UnavailableTypeParameterRemover.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Shared.Extensions; internal static partial class ITypeSymbolExtensions { - private class UnavailableTypeParameterRemover(Compilation compilation, ISet availableTypeParameterNames) : SymbolVisitor + private sealed class UnavailableTypeParameterRemover(Compilation compilation, ISet availableTypeParameterNames) : SymbolVisitor { public override ITypeSymbol DefaultVisit(ISymbol node) => throw new NotImplementedException(); diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.UnnamedErrorTypeRemover.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.UnnamedErrorTypeRemover.cs similarity index 93% rename from src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.UnnamedErrorTypeRemover.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.UnnamedErrorTypeRemover.cs index 93bde82d583ef..cc0f49324a9b2 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.UnnamedErrorTypeRemover.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.UnnamedErrorTypeRemover.cs @@ -9,9 +9,9 @@ namespace Microsoft.CodeAnalysis.Shared.Extensions; -internal partial class ITypeSymbolExtensions +internal static partial class ITypeSymbolExtensions { - private class UnnamedErrorTypeRemover(Compilation compilation) : SymbolVisitor + private sealed class UnnamedErrorTypeRemover(Compilation compilation) : SymbolVisitor { public override ITypeSymbol DefaultVisit(ISymbol node) => throw new NotImplementedException(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs index 47fea31801a29..c3db3f7a06779 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ITypeSymbolExtensions.cs @@ -751,8 +751,8 @@ public static bool IsSpan([NotNullWhen(true)] this ITypeSymbol? type) ContainingNamespace: { Name: nameof(System), ContainingNamespace.IsGlobalNamespace: true } }; - public static bool IsReadOnlySpan([NotNullWhen(true)] this ITypeSymbol? type) - => type is INamedTypeSymbol + public static bool IsReadOnlySpan([NotNullWhen(true)] this ISymbol? symbol) + => symbol is INamedTypeSymbol { Name: nameof(ReadOnlySpan), TypeArguments.Length: 1, @@ -762,4 +762,75 @@ public static bool IsReadOnlySpan([NotNullWhen(true)] this ITypeSymbol? type) public static bool IsInlineArray([NotNullWhen(true)] this ITypeSymbol? type) => type is INamedTypeSymbol namedType && namedType.OriginalDefinition.GetAttributes().Any(static a => a.AttributeClass?.SpecialType == SpecialType.System_Runtime_CompilerServices_InlineArrayAttribute); + + [return: NotNullIfNotNull(parameterName: nameof(type))] + public static ITypeSymbol? RemoveUnavailableTypeParameters( + this ITypeSymbol? type, + Compilation compilation, + IEnumerable availableTypeParameters) + { + return type?.RemoveUnavailableTypeParameters(compilation, availableTypeParameters.Select(t => t.Name).ToSet()); + } + + [return: NotNullIfNotNull(parameterName: nameof(type))] + private static ITypeSymbol? RemoveUnavailableTypeParameters( + this ITypeSymbol? type, + Compilation compilation, + ISet availableTypeParameterNames) + { + return type?.Accept(new UnavailableTypeParameterRemover(compilation, availableTypeParameterNames)); + } + + [return: NotNullIfNotNull(parameterName: nameof(type))] + public static ITypeSymbol? RemoveAnonymousTypes( + this ITypeSymbol? type, + Compilation compilation) + { + return type?.Accept(new AnonymousTypeRemover(compilation)); + } + + [return: NotNullIfNotNull(parameterName: nameof(type))] + public static ITypeSymbol? RemoveUnnamedErrorTypes( + this ITypeSymbol? type, + Compilation compilation) + { + return type?.Accept(new UnnamedErrorTypeRemover(compilation)); + } + public static IList GetReferencedMethodTypeParameters( + this ITypeSymbol? type, IList? result = null) + { + result ??= []; + type?.Accept(new CollectTypeParameterSymbolsVisitor(result, onlyMethodTypeParameters: true)); + return result; + } + + public static IList GetReferencedTypeParameters( + this ITypeSymbol? type, IList? result = null) + { + result ??= []; + type?.Accept(new CollectTypeParameterSymbolsVisitor(result, onlyMethodTypeParameters: false)); + return result; + } + + [return: NotNullIfNotNull(parameterName: nameof(type))] + public static ITypeSymbol? SubstituteTypes( + this ITypeSymbol? type, + IDictionary mapping, + Compilation compilation) + where TType1 : ITypeSymbol + where TType2 : ITypeSymbol + { + return type.SubstituteTypes(mapping, new CompilationTypeGenerator(compilation)); + } + + [return: NotNullIfNotNull(parameterName: nameof(type))] + public static ITypeSymbol? SubstituteTypes( + this ITypeSymbol? type, + IDictionary mapping, + ITypeGenerator typeGenerator) + where TType1 : ITypeSymbol + where TType2 : ITypeSymbol + { + return type?.Accept(new SubstituteTypesVisitor(mapping, typeGenerator)); + } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ImmutableArrayExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ImmutableArrayExtensions.cs index e0f157f5b4333..127ecf928a193 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ImmutableArrayExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ImmutableArrayExtensions.cs @@ -11,6 +11,10 @@ internal static partial class ImmutableArrayExtensions { public static ImmutableArray ToImmutableArray(this HashSet set) { + // [.. set] currently allocates, even for the empty case. Workaround that until that is solved by the compiler. + if (set.Count == 0) + return []; + return [.. set]; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/BottomUpBaseIndentationFinder.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/BottomUpBaseIndentationFinder.cs index d0a46391100f9..4d9d3758cba5f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/BottomUpBaseIndentationFinder.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/BottomUpBaseIndentationFinder.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.Formatting; -internal class BottomUpBaseIndentationFinder +internal sealed class BottomUpBaseIndentationFinder { private readonly TokenStream? _tokenStream; private readonly ChainedFormattingRules _formattingRules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.AnchorData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.AnchorData.cs index 5a8a60636e7aa..1a8bac0e1d4a0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.AnchorData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.AnchorData.cs @@ -8,12 +8,12 @@ namespace Microsoft.CodeAnalysis.Formatting; -internal partial class FormattingContext +internal sealed partial class FormattingContext { /// /// data that will be used in an interval tree related to Anchor. /// - private class AnchorData(AnchorIndentationOperation operation, SyntaxToken anchorToken, int originalColumn) + private sealed class AnchorData(AnchorIndentationOperation operation, SyntaxToken anchorToken, int originalColumn) { public TextSpan TextSpan => operation.TextSpan; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.IndentationData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.IndentationData.cs index 34895bda99fdd..823d39dd0d745 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.IndentationData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.IndentationData.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Formatting; -internal partial class FormattingContext +internal sealed partial class FormattingContext { /// /// data that will be used in an interval tree related to indentation. @@ -119,8 +119,8 @@ private sealed class AdjustedIndentationData : IndentationData public AdjustedIndentationData(TextSpan textSpan, IndentationData baseIndentationData, int adjustment) : base(textSpan) { - Debug.Assert(adjustment != 0, $"Indentation with no adjustment should be represented by {nameof(BaseIndentationData)} directly."); - Debug.Assert(baseIndentationData is not AdjustedIndentationData, $"Indentation data should only involve one layer of adjustment (multiples can be combined by adding the {nameof(Adjustment)} fields."); + RoslynDebug.Assert(adjustment != 0, $"Indentation with no adjustment should be represented by {nameof(BaseIndentationData)} directly."); + RoslynDebug.Assert(baseIndentationData is not AdjustedIndentationData, $"Indentation data should only involve one layer of adjustment (multiples can be combined by adding the {nameof(Adjustment)} fields."); BaseIndentationData = baseIndentationData; Adjustment = adjustment; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.InitialContextFinder.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.InitialContextFinder.cs index 641931ca4e693..bc847a5e2e56f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.InitialContextFinder.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.InitialContextFinder.cs @@ -19,9 +19,9 @@ namespace Microsoft.CodeAnalysis.Formatting; -internal partial class FormattingContext +internal sealed partial class FormattingContext { - private class InitialContextFinder + private sealed class InitialContextFinder { private readonly TokenStream _tokenStream; private readonly ChainedFormattingRules _formattingRules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.cs index c8b089dba4893..16d91559bef3d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/FormattingContext.cs @@ -21,10 +21,9 @@ namespace Microsoft.CodeAnalysis.Formatting; /// this class maintain contextual information such as /// indentation of current position, based token to follow in current position and etc. /// -internal partial class FormattingContext +internal sealed partial class FormattingContext { private readonly AbstractFormatEngine _engine; - private readonly TokenStream _tokenStream; // interval tree for inseparable regions (Span to indentation data) // due to dependencies, each region defined in the data can't be formatted independently. @@ -60,7 +59,7 @@ public FormattingContext(AbstractFormatEngine engine, TokenStream tokenStream) Contract.ThrowIfNull(tokenStream); _engine = engine; - _tokenStream = tokenStream; + TokenStream = tokenStream; _relativeIndentationTree = new ContextMutableIntervalTree(new FormattingContextIntervalIntrospector()); @@ -78,7 +77,7 @@ public void Initialize( CancellationToken cancellationToken) { var rootNode = this.TreeData.Root; - if (_tokenStream.IsFormattingWholeDocument) + if (TokenStream.IsFormattingWholeDocument) { // if we are trying to format whole document, there is no reason to get initial context. just set // initial indentation. @@ -88,7 +87,7 @@ public void Initialize( return; } - var initialContextFinder = new InitialContextFinder(_tokenStream, formattingRules, rootNode); + var initialContextFinder = new InitialContextFinder(TokenStream, formattingRules, rootNode); var (indentOperations, suppressOperations) = initialContextFinder.Do(startToken, endToken); if (indentOperations != null) @@ -100,12 +99,12 @@ public void Initialize( formattingRules, Options.TabSize, Options.IndentationSize, - _tokenStream, + TokenStream, _engine.HeaderFacts); var initialIndentation = baseIndentationFinder.GetIndentationOfCurrentPosition( rootNode, initialOperation, - _tokenStream.GetCurrentColumn, cancellationToken); + TokenStream.GetCurrentColumn, cancellationToken); var data = new SimpleIndentationData(initialOperation.TextSpan, initialIndentation); _indentationTree.AddIntervalInPlace(data); @@ -192,7 +191,7 @@ public void AddIndentBlockOperation(IndentBlockOperation operation) if (operation.IsRelativeIndentation) { Func effectiveBaseTokenGetter = operation.Option.IsOn(IndentBlockOption.RelativeToFirstTokenOnBaseTokenLine) - ? static (self, operation) => self._tokenStream.FirstTokenOfBaseTokenLine(operation.BaseToken) + ? static (self, operation) => self.TokenStream.FirstTokenOfBaseTokenLine(operation.BaseToken) : static (self, operation) => operation.BaseToken; Func relativeIndentationDeltaGetter = static (self, operation, effectiveBaseToken) => @@ -203,7 +202,7 @@ public void AddIndentBlockOperation(IndentBlockOperation operation) // baseIndentation is calculated for the adjusted token if option is RelativeToFirstTokenOnBaseTokenLine Func relativeIndentationBaseIndentationGetter = - static (self, effectiveBaseToken) => self._tokenStream.GetCurrentColumn(effectiveBaseToken); + static (self, effectiveBaseToken) => self.TokenStream.GetCurrentColumn(effectiveBaseToken); // set new indentation var inseparableRegionStartingPosition = effectiveBaseTokenGetter(this, operation).FullSpan.Start; @@ -268,7 +267,7 @@ public void AddInitialSuppressOperation(SuppressOperation operation) if (operation.TextSpan.IsEmpty) return; - var onSameLine = _tokenStream.TwoTokensOriginallyOnSameLine(operation.StartToken, operation.EndToken); + var onSameLine = TokenStream.TwoTokensOriginallyOnSameLine(operation.StartToken, operation.EndToken); AddSuppressOperation(operation, onSameLine); } @@ -283,10 +282,10 @@ public void AddSuppressOperations( // if an operation contains elastic trivia itself and the operation is not marked to ignore the elastic trivia // ignore the operation - if (operation.ContainsElasticTrivia(_tokenStream) && !operation.Option.IsOn(SuppressOption.IgnoreElasticWrapping)) + if (operation.ContainsElasticTrivia(TokenStream) && !operation.Option.IsOn(SuppressOption.IgnoreElasticWrapping)) continue; - var onSameLine = _tokenStream.TwoTokensOriginallyOnSameLine(operation.StartToken, operation.EndToken); + var onSameLine = TokenStream.TwoTokensOriginallyOnSameLine(operation.StartToken, operation.EndToken); AddSuppressOperation(operation, onSameLine); } } @@ -367,7 +366,7 @@ private void AddWrappingSuppressOperation(SuppressOperation operation, bool twoT } var ignoreElastic = option.IsMaskOn(SuppressOption.IgnoreElasticWrapping) || - !operation.ContainsElasticTrivia(_tokenStream); + !operation.ContainsElasticTrivia(TokenStream); var data = new SuppressWrappingData(operation.TextSpan, ignoreElastic: ignoreElastic); @@ -397,8 +396,8 @@ public void AddAnchorIndentationOperation(AnchorIndentationOperation operation) // // The calculation of true anchor token (which is always the first token on a line) is delayed to account // for cases where the original anchor token is moved to a new line during a formatting operation. - var anchorToken = _tokenStream.FirstTokenOfBaseTokenLine(operation.AnchorToken); - var originalSpace = _tokenStream.GetOriginalColumn(anchorToken); + var anchorToken = TokenStream.FirstTokenOfBaseTokenLine(operation.AnchorToken); + var originalSpace = TokenStream.GetOriginalColumn(anchorToken); var data = new AnchorData(operation, anchorToken, originalSpace); _anchorTree.AddIntervalInPlace(data); @@ -489,7 +488,7 @@ public int GetAnchorDeltaFromOriginalColumn(SyntaxToken token) return 0; } - var currentColumn = _tokenStream.GetCurrentColumn(anchorData.AnchorToken); + var currentColumn = TokenStream.GetCurrentColumn(anchorData.AnchorToken); return currentColumn - anchorData.OriginalColumn; } @@ -512,7 +511,7 @@ public int GetDeltaFromPreviousChangesMap(SyntaxToken token, Dictionary _engine.TreeData; - public TokenStream TokenStream => _tokenStream; + public TokenStream TokenStream { get; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/SuppressSpacingData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/SuppressSpacingData.cs index a62f47ad1eca4..dcf4da17d9fac 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/SuppressSpacingData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/SuppressSpacingData.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Formatting; /// /// data that will be used in an interval tree related to suppressing spacing operations. /// -internal class SuppressSpacingData(TextSpan textSpan) +internal sealed class SuppressSpacingData(TextSpan textSpan) { public TextSpan TextSpan { get; } = textSpan; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/SuppressWrappingData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/SuppressWrappingData.cs index 8e1695c64bdd1..dec67c2565654 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/SuppressWrappingData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Context/SuppressWrappingData.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Formatting; /// /// data that will be used in an interval tree related to suppressing wrapping operations. /// -internal class SuppressWrappingData(TextSpan textSpan, bool ignoreElastic) +internal sealed class SuppressWrappingData(TextSpan textSpan, bool ignoreElastic) { public TextSpan TextSpan { get; } = textSpan; public bool IgnoreElastic { get; } = ignoreElastic; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs index 6495f54bcdacb..8480f2cd540d2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/DocumentFormattingOptions.cs @@ -18,21 +18,3 @@ internal sealed record class DocumentFormattingOptions [DataMember] public string FileHeaderTemplate { get; init; } = ""; [DataMember] public bool InsertFinalNewLine { get; init; } = false; } - -internal static class DocumentFormattingOptionsProviders -{ - public static DocumentFormattingOptions GetDocumentFormattingOptions(this IOptionsReader options) - => new() - { - FileHeaderTemplate = options.GetOption(CodeStyleOptions2.FileHeaderTemplate), - InsertFinalNewLine = options.GetOption(FormattingOptions2.InsertFinalNewLine) - }; - -#if !CODE_STYLE - public static async ValueTask GetDocumentFormattingOptionsAsync(this Document document, CancellationToken cancellationToken) - { - var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return configOptions.GetDocumentFormattingOptions(); - } -#endif -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractFormatEngine.OperationApplier.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractFormatEngine.OperationApplier.cs index 3664cf017b63c..a6e14e9eb4228 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractFormatEngine.OperationApplier.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractFormatEngine.OperationApplier.cs @@ -18,7 +18,7 @@ internal abstract partial class AbstractFormatEngine /// /// this actually applies formatting operations to trivia between two tokens /// - private class OperationApplier(FormattingContext context, ChainedFormattingRules formattingRules) + private sealed class OperationApplier(FormattingContext context, ChainedFormattingRules formattingRules) { public bool Apply(AdjustSpacesOperation operation, int pairIndex) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.AbstractComplexTrivia.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.AbstractComplexTrivia.cs index c081c5813c4b4..51c35aff5e931 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.AbstractComplexTrivia.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/AbstractTriviaDataFactory.AbstractComplexTrivia.cs @@ -12,9 +12,6 @@ internal abstract partial class AbstractTriviaDataFactory { protected abstract class AbstractComplexTrivia : TriviaDataWithList { - private readonly SyntaxToken _token1; - private readonly SyntaxToken _token2; - public TreeData TreeInfo { get; } public string OriginalString { get; } @@ -25,8 +22,8 @@ public AbstractComplexTrivia(LineFormattingOptions options, TreeData treeInfo, S { Contract.ThrowIfNull(treeInfo); - _token1 = token1; - _token2 = token2; + Token1 = token1; + Token2 = token2; _treatAsElastic = CommonFormattingHelpers.HasAnyWhitespaceElasticTrivia(token1, token2); @@ -44,9 +41,9 @@ public AbstractComplexTrivia(LineFormattingOptions options, TreeData treeInfo, S protected abstract TriviaDataWithList Format(FormattingContext context, ChainedFormattingRules formattingRules, int lines, int spaces, CancellationToken cancellationToken); protected abstract bool ContainsSkippedTokensOrText(TriviaList list); - public SyntaxToken Token1 => _token1; + public SyntaxToken Token1 { get; } - public SyntaxToken Token2 => _token2; + public SyntaxToken Token2 { get; } public override bool TreatAsElastic => _treatAsElastic; @@ -132,7 +129,7 @@ public override TriviaData WithIndentation( // do expansive check // we need to actually format here to find out indentation - var list = new TriviaList(_token1.TrailingTrivia, _token2.LeadingTrivia); + var list = new TriviaList(Token1.TrailingTrivia, Token2.LeadingTrivia); Contract.ThrowIfFalse(list.Count > 0); if (ContainsSkippedTokensOrText(list)) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/ChainedFormattingRules.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/ChainedFormattingRules.cs index 68f2d1c86db2d..b22e34f0e2904 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/ChainedFormattingRules.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/ChainedFormattingRules.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.Formatting; -internal class ChainedFormattingRules +internal sealed class ChainedFormattingRules { private static readonly ConcurrentDictionary<(Type type, string name), Type?> s_typeImplementingMethod = []; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Changes.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Changes.cs index a3f7e3a434a24..fd7544dfefa3e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Changes.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Changes.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.Formatting; -internal partial class TokenStream +internal sealed partial class TokenStream { /// /// Thread-safe collection that holds onto changes diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Iterator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Iterator.cs index 9a225e6af5d77..c3ede8c54e751 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Iterator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.Iterator.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Formatting; -internal partial class TokenStream +internal sealed partial class TokenStream { // gain of having hand written iterator seems about 50-100ms over auto generated one. // not sure whether it is worth it. but I already wrote it to test, so going to just keep it. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.cs index 4f98e4a619d02..7fc5e874ff56c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TokenStream.cs @@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.Formatting; /// It will maintain information changed compared to original token information. and answers /// information about tokens. /// -internal partial class TokenStream +internal sealed partial class TokenStream { // number to guess number of tokens in a formatting span private const int MagicTextLengthToTokensRatio = 10; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Debug.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Debug.cs index 800630689cf4a..9afc40db1754b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Debug.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Debug.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Formatting; internal abstract partial class TreeData { - private class Debug(SyntaxNode root, SourceText text) : NodeAndText(root, text) + private sealed class Debug(SyntaxNode root, SourceText text) : NodeAndText(root, text) { private readonly TreeData _debugNodeData = new Node(root); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Node.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Node.cs index 6a04a8639801d..0569ec47103ee 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Node.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.Node.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Formatting; internal abstract partial class TreeData { - private class Node : TreeData + private sealed class Node : TreeData { public Node(SyntaxNode root) : base(root) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.StructuredTrivia.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.StructuredTrivia.cs index 26a8581db38a1..c11ac58f56781 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.StructuredTrivia.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.StructuredTrivia.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Formatting; internal abstract partial class TreeData { - private class StructuredTrivia : TreeData + private sealed class StructuredTrivia : TreeData { private readonly int _initialColumn; private readonly SyntaxTrivia _trivia; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.cs index c1dd2485b989a..af1e22a020df9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Engine/TreeData.cs @@ -33,23 +33,22 @@ public static TreeData Create(SyntaxNode root) public static TreeData Create(SyntaxTrivia trivia, int initialColumn) => new StructuredTrivia(trivia, initialColumn); - private readonly SyntaxNode _root; private readonly SyntaxToken _firstToken; private readonly SyntaxToken _lastToken; public TreeData(SyntaxNode root) { Contract.ThrowIfNull(root); - _root = root; + Root = root; - _firstToken = _root.GetFirstToken(includeZeroWidth: true); - _lastToken = _root.GetLastToken(includeZeroWidth: true); + _firstToken = Root.GetFirstToken(includeZeroWidth: true); + _lastToken = Root.GetLastToken(includeZeroWidth: true); } public abstract string GetTextBetween(SyntaxToken token1, SyntaxToken token2); public abstract int GetOriginalColumn(int tabSize, SyntaxToken token); - public SyntaxNode Root => _root; + public SyntaxNode Root { get; } public bool IsFirstToken(SyntaxToken token) => _firstToken == token; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.IndentStyle.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.IndentStyle.cs index 7de654ef7817c..295ce1e1311ee 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.IndentStyle.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/FormattingOptions2.IndentStyle.cs @@ -4,7 +4,7 @@ namespace Microsoft.CodeAnalysis.Formatting; -internal partial class FormattingOptions2 +internal sealed partial class FormattingOptions2 { /// /// For use in the shared CodeStyle layer. Keep in syntax with FormattingOptions.IndentStyle. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/LineFormattingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/LineFormattingOptions.cs index 6e034d7b50492..794d03784b3f6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/LineFormattingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/LineFormattingOptions.cs @@ -4,15 +4,12 @@ using System; using System.Runtime.Serialization; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.Formatting; [DataContract] -internal sealed record class LineFormattingOptions +internal sealed record class LineFormattingOptions() { public static readonly LineFormattingOptions Default = new(); @@ -20,25 +17,14 @@ internal sealed record class LineFormattingOptions [DataMember] public int TabSize { get; init; } = 4; [DataMember] public int IndentationSize { get; init; } = 4; [DataMember] public string NewLine { get; init; } = Environment.NewLine; -} - -internal static partial class LineFormattingOptionsProviders -{ - public static LineFormattingOptions GetLineFormattingOptions(this IOptionsReader options, string language) - => new() - { - UseTabs = options.GetOption(FormattingOptions2.UseTabs, language), - TabSize = options.GetOption(FormattingOptions2.TabSize, language), - IndentationSize = options.GetOption(FormattingOptions2.IndentationSize, language), - NewLine = options.GetOption(FormattingOptions2.NewLine, language), - }; -#if !CODE_STYLE - public static async ValueTask GetLineFormattingOptionsAsync(this Document document, CancellationToken cancellationToken) + public LineFormattingOptions(IOptionsReader options, string language) + : this() { - var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return configOptions.GetLineFormattingOptions(document.Project.Language); + UseTabs = options.GetOption(FormattingOptions2.UseTabs, language); + TabSize = options.GetOption(FormattingOptions2.TabSize, language); + IndentationSize = options.GetOption(FormattingOptions2.IndentationSize, language); + NewLine = options.GetOption(FormattingOptions2.NewLine, language); } -#endif } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/BaseIndentationFormattingRule.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/BaseIndentationFormattingRule.cs index f277f55232823..01c1aeec49bd0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/BaseIndentationFormattingRule.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/Rules/BaseIndentationFormattingRule.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Formatting.Rules; -internal class BaseIndentationFormattingRule : AbstractFormattingRule +internal sealed class BaseIndentationFormattingRule : AbstractFormattingRule { private readonly AbstractFormattingRule? _vbHelperFormattingRule; private readonly int _baseIndentation; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/SyntaxFormattingOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/SyntaxFormattingOptions.cs index f97d20a65fc66..390e8ea2e7509 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/SyntaxFormattingOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Formatting/SyntaxFormattingOptions.cs @@ -7,12 +7,6 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Options; -#if !CODE_STYLE -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; -#endif - namespace Microsoft.CodeAnalysis.Formatting; internal record class SyntaxFormattingOptions @@ -34,7 +28,7 @@ private protected SyntaxFormattingOptions() private protected SyntaxFormattingOptions(IOptionsReader options, string language) { - LineFormatting = options.GetLineFormattingOptions(language); + LineFormatting = new LineFormattingOptions(options, language); SeparateImportDirectiveGroups = options.GetOption(GenerationOptions.SeparateImportDirectiveGroups, language); AccessibilityModifiersRequired = options.GetOptionValue(CodeStyleOptions2.AccessibilityModifiersRequired, language); WrappingColumn = options.GetOption(FormattingOptions2.WrappingColumn, language); @@ -45,23 +39,4 @@ private protected SyntaxFormattingOptions(IOptionsReader options, string languag public int TabSize => LineFormatting.TabSize; public int IndentationSize => LineFormatting.IndentationSize; public string NewLine => LineFormatting.NewLine; - -#if !CODE_STYLE - public static SyntaxFormattingOptions GetDefault(LanguageServices languageServices) - => languageServices.GetRequiredService().DefaultOptions; -#endif -} - -internal static partial class SyntaxFormattingOptionsProviders -{ -#if !CODE_STYLE - public static SyntaxFormattingOptions GetSyntaxFormattingOptions(this IOptionsReader options, LanguageServices languageServices) - => languageServices.GetRequiredService().GetFormattingOptions(options); - - public static async ValueTask GetSyntaxFormattingOptionsAsync(this Document document, CancellationToken cancellationToken) - { - var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return configOptions.GetSyntaxFormattingOptions(document.Project.Services); - } -#endif } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/AbstractIndentation.Indenter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/AbstractIndentation.Indenter.cs index bf6a206807d3e..9c2e9583ece61 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/AbstractIndentation.Indenter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/AbstractIndentation.Indenter.cs @@ -41,6 +41,7 @@ protected readonly struct Indenter public Indenter( AbstractIndentation service, SyntaxTree tree, + SourceText text, ImmutableArray rules, IndentationOptions options, TextLine lineToBeIndented, @@ -51,8 +52,8 @@ public Indenter( _syntaxFacts = service.SyntaxFacts; Options = options; Tree = tree; - Text = tree.GetText(cancellationToken); Root = (TSyntaxRoot)tree.GetRoot(cancellationToken); + Text = text; LineToBeIndented = lineToBeIndented; _tabSize = options.FormattingOptions.TabSize; SmartTokenFormatter = smartTokenFormatter; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/IndentationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/IndentationOptions.cs index 368be8c83f237..44979917caeef 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/IndentationOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Indentation/IndentationOptions.cs @@ -5,10 +5,6 @@ using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Formatting; -#if !CODE_STYLE -using Microsoft.CodeAnalysis.Host; -#endif - namespace Microsoft.CodeAnalysis.Indentation; [DataContract] @@ -19,9 +15,4 @@ internal readonly record struct IndentationOptions( [DataMember(Order = 2)] public FormattingOptions2.IndentStyle IndentStyle { get; init; } = DefaultIndentStyle; public const FormattingOptions2.IndentStyle DefaultIndentStyle = FormattingOptions2.IndentStyle.Smart; - -#if !CODE_STYLE - public static IndentationOptions GetDefault(LanguageServices languageServices) - => new(SyntaxFormattingOptions.GetDefault(languageServices)); -#endif } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs index bae882174e5d4..77c0c94bde897 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs @@ -592,6 +592,7 @@ internal enum FunctionId // 670-680 for newer rename ids Rename_TryApplyRename_WorkspaceChanged = 670, Rename_InlineSession_Cancel_NonDocumentChangedWorkspaceChange = 671, + InlineRenameAdornmentChoice = 672, // 680-690 LSP Initialization info ids. LSP_Initialize = 680, @@ -632,5 +633,6 @@ internal enum FunctionId Copilot_On_The_Fly_Docs_Error_Displayed = 813, Copilot_On_The_Fly_Docs_Results_Canceled = 814, Copilot_On_The_Fly_Docs_Get_Counts = 815, + Copilot_On_The_Fly_Docs_Content_Excluded = 816, Copilot_Rename = 851 } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/Logger.LogBlock.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/Logger.LogBlock.cs index 2052e3f7afb06..68d2da639566f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/Logger.LogBlock.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/Logger.LogBlock.cs @@ -29,7 +29,7 @@ private static IDisposable CreateLogBlock(FunctionId functionId, LogMessage mess /// This tracks the logged message. On instantiation, it logs 'Started block' with other event data. /// On dispose, it logs 'Ended block' with the same event data so we can track which block started and ended when looking at logs. /// - private class RoslynLogBlock(ObjectPool pool) : IDisposable + private sealed class RoslynLogBlock(ObjectPool pool) : IDisposable { // these need to be cleared before putting back to pool diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.cs index 8c05c39b1b602..9e64f37819f53 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyle.cs @@ -391,7 +391,7 @@ private string FinishFixingName(string name) if (!string.IsNullOrEmpty(WordSeparator)) { - words = name.Split(new[] { WordSeparator }, StringSplitOptions.RemoveEmptyEntries); + words = name.Split([WordSeparator], StringSplitOptions.RemoveEmptyEntries); // Edge case: the only character(s) in the name is(are) the WordSeparator if (!words.Any()) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleOptions.cs index a317ecb0a3637..fbeeeceb2af82 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleOptions.cs @@ -33,14 +33,3 @@ internal interface NamingStylePreferencesProvider #endif { } - -#if !CODE_STYLE -internal static class NamingStylePreferencesProviders -{ - public static async ValueTask GetNamingStylePreferencesAsync(this Document document, CancellationToken cancellationToken) - { - var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return configOptions.GetEditorConfigOption(NamingStyleOptions.NamingPreferences, NamingStylePreferences.Default); - } -} -#endif diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleRules.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleRules.cs index 51b377017dc16..c70501242743d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleRules.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/NamingStyles/NamingStyleRules.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; -internal class NamingStyleRules(ImmutableArray namingRules) +internal sealed class NamingStyleRules(ImmutableArray namingRules) { public ImmutableArray NamingRules { get; } = namingRules; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/ArrayBuilder.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/ArrayBuilder.cs index 4d3f1fe101e08..c40663de34f02 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/ArrayBuilder.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/ArrayBuilder.cs @@ -4,7 +4,7 @@ namespace Microsoft.CodeAnalysis.PooledObjects; -internal partial class ArrayBuilder : IPooled +internal sealed partial class ArrayBuilder : IPooled { public static PooledDisposer> GetInstance(out ArrayBuilder instance) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/Extensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/Extensions.cs index 136483231f399..bc0e4d46f8f98 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/Extensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/Extensions.cs @@ -79,6 +79,14 @@ public static PooledObject> GetPooledObject> GetPooledObject(this ObjectPool> pool, out ConcurrentSet set) + where T : notnull + { + var pooledObject = PooledObject>.Create(pool); + set = pooledObject.Object; + return pooledObject; + } + public static PooledObject GetPooledObject(this ObjectPool pool) where T : class => new(pool, p => p.Allocate(), (p, o) => p.Free(o)); @@ -114,6 +122,14 @@ public static HashSet AllocateAndClear(this ObjectPool> pool) return set; } + public static ConcurrentSet AllocateAndClear(this ObjectPool> pool) where T : notnull + { + var set = pool.Allocate(); + set.Clear(); + + return set; + } + public static SegmentedHashSet AllocateAndClear(this ObjectPool> pool) { var set = pool.Allocate(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledHashSet.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledHashSet.cs index 6d2fed91394d0..7c68246ee11ae 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledHashSet.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledHashSet.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.PooledObjects; -internal partial class PooledHashSet : IPooled, IReadOnlySet +internal sealed partial class PooledHashSet : IPooled, IReadOnlySet { public static PooledDisposer> GetInstance(out PooledHashSet instance) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledObject.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledObject.cs index ef54742c83385..4bc05dd6b601b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledObject.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledObject.cs @@ -7,6 +7,7 @@ using System.Text; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis; @@ -17,23 +18,22 @@ internal struct PooledObject : IDisposable where T : class { private readonly Action, T> _releaser; private readonly ObjectPool _pool; - private T _pooledObject; public PooledObject(ObjectPool pool, Func, T> allocator, Action, T> releaser) : this() { _pool = pool; - _pooledObject = allocator(pool); + Object = allocator(pool); _releaser = releaser; } - public readonly T Object => _pooledObject; + public T Object { get; private set; } public void Dispose() { - if (_pooledObject != null) + if (Object != null) { - _releaser(_pool, _pooledObject); - _pooledObject = null!; + _releaser(_pool, Object); + Object = null!; } } @@ -70,6 +70,14 @@ public static PooledObject> Create(ObjectPool Releaser(p, v)); } + public static PooledObject> Create(ObjectPool> pool) where TItem : notnull + { + return new PooledObject>( + pool, + static p => Allocator(p), + static (p, v) => Releaser(p, v)); + } + public static PooledObject> Create(ObjectPool> pool) where TKey : notnull { @@ -119,9 +127,15 @@ private static void Releaser(ObjectPool> pool, Queue private static HashSet Allocator(ObjectPool> pool) => pool.AllocateAndClear(); + private static ConcurrentSet Allocator(ObjectPool> pool) where TItem : notnull + => pool.AllocateAndClear(); + private static void Releaser(ObjectPool> pool, HashSet obj) => pool.ClearAndFree(obj); + private static void Releaser(ObjectPool> pool, ConcurrentSet obj) where TItem : notnull + => pool.ClearAndFree(obj); + private static Dictionary Allocator(ObjectPool> pool) where TKey : notnull => pool.AllocateAndClear(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledStringBuilder.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledStringBuilder.cs index 191075506ef09..2d18c1ee3ed89 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledStringBuilder.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/ObjectPools/PooledStringBuilder.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.PooledObjects; -internal partial class PooledStringBuilder : IPooled +internal sealed partial class PooledStringBuilder : IPooled { public static PooledDisposer GetInstance(out StringBuilder instance) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer.cs index e65d814e6e0ad..56bc217d99dc4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer.cs @@ -3,7 +3,9 @@ // See the LICENSE file in the project root for more information. using System; -using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; using Microsoft.CodeAnalysis.CodeStyle; using Roslyn.Utilities; @@ -93,11 +95,41 @@ public static EditorConfigValueSerializer> CodeStyle(Co => new(parseValue: str => CodeStyleHelpers.TryParseStringEditorConfigCodeStyleOption(str, defaultValue, out var result) ? result : new Optional>(), serializeValue: value => value.Value.ToLowerInvariant() + CodeStyleHelpers.GetEditorConfigStringNotificationPart(value, defaultValue)); + /// + /// Creates a serializer for an enum value that uses the enum field names. + /// public static EditorConfigValueSerializer CreateSerializerForEnum() where T : struct, Enum => new( parseValue: str => TryParseEnum(str, out var result) ? new Optional(result) : new Optional(), serializeValue: value => value.ToString()); + /// + /// Creates a serializer for an enum value given a between value names and the corresponding enum values. + /// + public static EditorConfigValueSerializer CreateSerializerForEnum(BidirectionalMap map) where T : struct, Enum + => CreateSerializerForEnum(map, ImmutableDictionary.Empty); + + /// + /// Creates a serializer for an enum value given a between value names and the corresponding enum values. + /// specifies alternative value representations for backward compatibility. + /// + public static EditorConfigValueSerializer CreateSerializerForEnum(BidirectionalMap map, ImmutableDictionary alternative) where T : struct, Enum + => new(parseValue: str => map.TryGetValue(str, out var result) || alternative.TryGetValue(str, out result) ? new Optional(result) : new Optional(), + serializeValue: value => map.TryGetKey(value, out var key) ? key : throw ExceptionUtilities.UnexpectedValue(value)); + + /// + /// Creates a serializer for an enum value given a between value names and the corresponding enum values. + /// specifies alternative value representations for backward compatibility. + /// + public static EditorConfigValueSerializer CreateSerializerForEnum(IEnumerable<(string name, T value)> entries, IEnumerable<(string name, T value)> alternativeEntries) where T : struct, Enum + { + var map = new BidirectionalMap(entries, StringComparer.OrdinalIgnoreCase); + var alternativeMap = ImmutableDictionary.Empty.WithComparers(keyComparer: StringComparer.OrdinalIgnoreCase) + .AddRange(alternativeEntries.Select(static p => KeyValuePairUtil.Create(p.name, p.value))); + + return CreateSerializerForEnum(map, alternativeMap); + } + public static EditorConfigValueSerializer CreateSerializerForNullableEnum() where T : struct, Enum { return new EditorConfigValueSerializer( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer`1.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer`1.cs index 75a7fd29b7226..d6575265c3869 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer`1.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/EditorConfigValueSerializer`1.cs @@ -19,6 +19,7 @@ internal sealed class EditorConfigValueSerializer( 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 ConcurrentDictionary> _cachedValues = []; bool IEditorConfigValueSerializer.TryParse(string value, out object? result) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2.cs index 663ce4c5c47b0..01e7d62ba20fe 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/Option2.cs @@ -33,7 +33,7 @@ internal interface ISingleValuedOption : ISingleValuedOption { } -internal partial class Option2 : ISingleValuedOption +internal sealed partial class Option2 : ISingleValuedOption { public OptionDefinition Definition { get; } public IPublicOption? PublicOption { get; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PerLanguageOption2.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PerLanguageOption2.cs index 5663d2046d519..d386d13f47bbd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PerLanguageOption2.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/PerLanguageOption2.cs @@ -25,7 +25,7 @@ internal interface IPerLanguageValuedOption : IPerLanguageValuedOption /// An option that can be specified once per language. /// /// -internal partial class PerLanguageOption2 : IPerLanguageValuedOption +internal sealed partial class PerLanguageOption2 : IPerLanguageValuedOption { public OptionDefinition Definition { get; } public IPublicOption? PublicOption { get; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/OrganizeImports/OrganizeImportsOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/OrganizeImports/OrganizeImportsOptions.cs new file mode 100644 index 0000000000000..88527f96513e3 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/OrganizeImports/OrganizeImportsOptions.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.Serialization; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.Formatting; + +namespace Microsoft.CodeAnalysis.OrganizeImports; + +[DataContract] +internal readonly record struct OrganizeImportsOptions +{ + [DataMember] public bool PlaceSystemNamespaceFirst { get; init; } = AddImportPlacementOptions.Default.PlaceSystemNamespaceFirst; + [DataMember] public bool SeparateImportDirectiveGroups { get; init; } = SyntaxFormattingOptions.CommonDefaults.SeparateImportDirectiveGroups; + [DataMember] public string NewLine { get; init; } = LineFormattingOptions.Default.NewLine; + + public OrganizeImportsOptions() + { + } + + public static readonly OrganizeImportsOptions Default = new(); +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectReader.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectReader.cs index bf40076c353dc..c5984782232f1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectReader.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectReader.cs @@ -73,7 +73,7 @@ private ObjectReader(Stream stream, bool leaveOpen) // PipeReaderStream wraps any exception it throws in an AggregateException, which is not expected by // callers treating it as a normal stream. Unwrap and rethrow the inner exception for clarity. // https://github.com/dotnet/runtime/issues/70206 -#if NETCOREAPP +#if NET ExceptionDispatchInfo.Throw(ex.InnerException); #else ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.cs index fd03f06cfe9f2..93ba501d46f77 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/ObjectWriter.cs @@ -27,8 +27,10 @@ internal sealed partial class ObjectWriter : IDisposable { private static class BufferPool { + public const int BufferSize = 32768; + // Large arrays that will not go into the LOH (even with System.Char). - public static ObjectPool Shared = new(() => new T[32768], 512); + public static ObjectPool Shared = new(() => new T[BufferSize], 512); } /// @@ -273,10 +275,31 @@ public void WriteByteArray(byte[] array) _writer.Write(array); } - public void WriteCharArray(char[] array) + public void WriteCharArray(char[] array, int index, int count) { - WriteArrayLength(array.Length); - _writer.Write(array); + WriteArrayLength(count); + +#if !NETCOREAPP + // BinaryWriter in .NET Framework allocates via the following: + // byte[] bytes = _encoding.GetBytes(chars, 0, chars.Length); + // + // Instead, emulate the .net core code which has the GetBytes + // call fill up a pooled array instead + var maxByteCount = Encoding.UTF8.GetMaxByteCount(count); + + if (maxByteCount <= BufferPool.BufferSize) + { + using var pooledObj = BufferPool.Shared.GetPooledObject(); + var buffer = pooledObj.Object; + + var actualByteCount = Encoding.UTF8.GetBytes(array, index, count, buffer, 0); + _writer.Write(buffer, 0, actualByteCount); + + return; + } +#endif + + _writer.Write(array, index, count); } /// @@ -288,7 +311,7 @@ public void WriteSpan(ReadOnlySpan span) { WriteArrayLength(span.Length); -#if NETCOREAPP +#if NET _writer.Write(span); #else // BinaryWriter in .NET Framework does not support ReadOnlySpan, so we use a temporary buffer to write @@ -297,24 +320,6 @@ public void WriteSpan(ReadOnlySpan span) #endif } - /// - /// Write an array of chars. The array data is provided as a ReadOnlySpan<>, and deserialized to a char array. - /// - /// The array data. - public void WriteSpan(ReadOnlySpan span) - { - WriteArrayLength(span.Length); - -#if NETCOREAPP - _writer.Write(span); -#else - // BinaryWriter in .NET Framework does not support ReadOnlySpan, so we use a temporary buffer to write - // arrays of data. - WriteSpanPieces(span, static (writer, buffer, length) => writer.Write(buffer, 0, length)); -#endif - } - private void WriteArrayLength(int length) { switch (length) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/TextEncodingKind.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/TextEncodingKind.cs index aad44498e65ae..092aaa2bb709e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/TextEncodingKind.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Serialization/TextEncodingKind.cs @@ -90,7 +90,7 @@ public static bool TryGetEncodingKind(this Encoding encoding, out TextEncodingKi } public static bool HasPreamble(this Encoding encoding) -#if NETCOREAPP +#if NET => !encoding.Preamble.IsEmpty; #else => !encoding.GetPreamble().IsEmpty(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/AbstractDocumentationCommentService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/AbstractDocumentationCommentService.cs index 6c75e926003b1..535cdc8f2fea2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/AbstractDocumentationCommentService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/AbstractDocumentationCommentService.cs @@ -139,7 +139,7 @@ private void HandleNode(SyntaxNode node, StringBuilder sb) AppendTextTokens(sb, GetTextTokens(xmlTextAttribute)); break; default: - Debug.Assert(false, $"Unexpected XML syntax kind {attribute.RawKind}"); + RoslynDebug.Assert(false, $"Unexpected XML syntax kind {attribute.RawKind}"); break; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs index 830a3652a5f3a..6bd812470edbe 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SyntaxFacts/ISyntaxFacts.cs @@ -8,12 +8,6 @@ using System.Threading; using Microsoft.CodeAnalysis.Text; -#if CODE_STYLE -using Microsoft.CodeAnalysis.Internal.Editing; -#else -using Microsoft.CodeAnalysis.Editing; -#endif - namespace Microsoft.CodeAnalysis.LanguageService; /// @@ -409,9 +403,9 @@ void GetPartsOfTupleExpression(SyntaxNode node, SyntaxNode? ConvertToSingleLine(SyntaxNode? node, bool useElasticTrivia = false); // Violation. This is a feature level API. - List GetTopLevelAndMethodLevelMembers(SyntaxNode? root); + PooledObject> GetTopLevelAndMethodLevelMembers(SyntaxNode? root); // Violation. This is a feature level API. - List GetMethodLevelMembers(SyntaxNode? root); + PooledObject> GetMethodLevelMembers(SyntaxNode? root); SyntaxList GetMembersOfTypeDeclaration(SyntaxNode typeDeclaration); // Violation. This is a feature level API. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/DoNotAddImportsAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/DoNotAddImportsAnnotation.cs index 7f9386b7ef558..ac0ca89da18c4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/DoNotAddImportsAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/DoNotAddImportsAnnotation.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.Simplification; // SymbolAnnotation. However that would require additional substring operations to retrieve // SymbolAnnotation symbols even in the common case where we don't need to suppress add imports. // This is therefore implemented as a separate annotation. -internal class DoNotAddImportsAnnotation +internal sealed class DoNotAddImportsAnnotation { public static readonly SyntaxAnnotation Annotation = new(Kind); public const string Kind = "DoNotAddImports"; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/DoNotAllowVarAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/DoNotAllowVarAnnotation.cs index 649a849a7249e..b3cbc500121a1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/DoNotAllowVarAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/DoNotAllowVarAnnotation.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.Simplification; /// /// When applied to a SyntaxNode, prevents the simplifier from converting a type to 'var'. /// -internal class DoNotAllowVarAnnotation +internal sealed class DoNotAllowVarAnnotation { public static readonly SyntaxAnnotation Annotation = new(Kind); public const string Kind = "DoNotAllowVar"; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs index c0d000aa20b0a..42ba4b36ca865 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SimplifierOptions.cs @@ -7,12 +7,6 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Options; -#if !CODE_STYLE -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; -#endif - namespace Microsoft.CodeAnalysis.Simplification; internal record class SimplifierOptions @@ -58,23 +52,4 @@ public bool TryGetQualifyMemberAccessOption(SymbolKind symbolKind, [NotNullWhen( return option != null; } - -#if !CODE_STYLE - public static SimplifierOptions GetDefault(LanguageServices languageServices) - => languageServices.GetRequiredService().DefaultOptions; -#endif -} - -internal static partial class SimplifierOptionsProviders -{ -#if !CODE_STYLE - public static SimplifierOptions GetSimplifierOptions(this IOptionsReader options, LanguageServices languageServices) - => languageServices.GetService()?.GetSimplifierOptions(options) ?? SimplifierOptions.CommonDefaults; - - public static async ValueTask GetSimplifierOptionsAsync(this Document document, CancellationToken cancellationToken) - { - var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return configOptions.GetSimplifierOptions(document.Project.Services); - } -#endif } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SpecialTypeAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SpecialTypeAnnotation.cs index 067a600ed114b..444aad69a4129 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SpecialTypeAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SpecialTypeAnnotation.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.Simplification; -internal class SpecialTypeAnnotation +internal sealed class SpecialTypeAnnotation { public const string Kind = "SpecialType"; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SymbolAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SymbolAnnotation.cs index e58e02c81b983..d356e2b45a816 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SymbolAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Simplification/SymbolAnnotation.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Simplification; /// /// An annotation that holds onto information about a type or namespace symbol. /// -internal class SymbolAnnotation +internal sealed class SymbolAnnotation { public const string Kind = "SymbolId"; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ModuleSymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ModuleSymbolKey.cs index 93f0bfd3d42d7..259382c0c495c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ModuleSymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.ModuleSymbolKey.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Immutable; + namespace Microsoft.CodeAnalysis; internal partial struct SymbolKey @@ -24,12 +26,26 @@ protected sealed override SymbolKeyResolution Resolve( return default; } - using var result = PooledArrayBuilder.GetInstance(); - foreach (var assembly in containingSymbolResolution.OfType()) + using var result = PooledArrayBuilder.GetInstance(containingSymbolResolution.SymbolCount); + foreach (var symbol in containingSymbolResolution) { + if (symbol is not IAssemblySymbol assembly) + continue; + // Don't check ModuleIds for equality because in practice, no-one uses them, // and there is no way to set netmodule name programmatically using Roslyn - result.AddValuesIfNotNull(assembly.Modules); + var assemblyModules = assembly.Modules; + if (assemblyModules is ImmutableArray modules) + { + // Avoid allocations if possible + // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2136177 + result.AddValuesIfNotNull(modules); + } + else + { + // Otherwise fall back to generic enumeration + result.AddValuesIfNotNull(assemblyModules); + } } return CreateResolution(result, $"({nameof(ModuleSymbolKey)} failed)", out failureReason); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyComparer.cs index 65ccc2ac27be2..84487fbe9935d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyComparer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyComparer.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis; internal partial struct SymbolKey { - private class SymbolKeyComparer : IEqualityComparer + private sealed class SymbolKeyComparer : IEqualityComparer { private readonly ComparisonOptions _options; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyReader.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyReader.cs index 00839df11d14c..4ee4ab1341c10 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyReader.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyReader.cs @@ -236,7 +236,7 @@ public RefKind ReadRefKind(out string? failureReason) } } - private class RemoveAssemblySymbolKeysReader : Reader + private sealed class RemoveAssemblySymbolKeysReader : Reader { private readonly StringBuilder _builder = new(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyWriter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyWriter.cs index fa33b1cebae1c..a0145d6ffd2d5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyWriter.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.SymbolKeyWriter.cs @@ -50,7 +50,7 @@ private enum SymbolKeyType TypeParameterOrdinal = '@', } - private class SymbolKeyWriter : SymbolVisitor, IDisposable + private sealed class SymbolKeyWriter : SymbolVisitor, IDisposable { private static readonly ObjectPool s_writerPool = SharedPools.Default(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs index 615bd90fb4467..3412917555406 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/SymbolKey/SymbolKey.cs @@ -235,6 +235,7 @@ public readonly SymbolKeyResolution Resolve( public override readonly string ToString() => _symbolKeyData; + // Note: this method may clear 'symbols' before returning. private static SymbolKeyResolution CreateResolution( PooledArrayBuilder symbols, string reasonIfFailed, out string? failureReason) where TSymbol : class, ISymbol @@ -253,7 +254,7 @@ private static SymbolKeyResolution CreateResolution( { failureReason = null; return new SymbolKeyResolution( - ImmutableArray.CastUp(symbols.Builder.ToImmutable()), + ImmutableArray.CastUp(symbols.Builder.ToImmutableAndClear()), CandidateReason.Ambiguous); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AbstractSpeculationAnalyzer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AbstractSpeculationAnalyzer.cs index 9180cdccbb51e..e255b20b7af62 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AbstractSpeculationAnalyzer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AbstractSpeculationAnalyzer.cs @@ -11,7 +11,6 @@ using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.LanguageService; -using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -42,10 +41,7 @@ internal abstract class AbstractSpeculationAnalyzer< where TInvocationExpressionSyntax : TExpressionSyntax where TConversion : struct { - private readonly TExpressionSyntax _expression; private readonly TExpressionSyntax _newExpressionForReplace; - private readonly SemanticModel _semanticModel; - private readonly CancellationToken _cancellationToken; private readonly bool _skipVerificationForReplacedNode; private readonly bool _failOnOverloadResolutionFailuresInOriginalCode; private readonly bool _isNewSemanticModelSpeculativeModel; @@ -56,7 +52,9 @@ internal abstract class AbstractSpeculationAnalyzer< private SemanticModel? _lazySpeculativeSemanticModel; private static readonly SymbolEquivalenceComparer s_includeNullabilityComparer = - SymbolEquivalenceComparer.Create(distinguishRefFromOut: true, tupleNamesMustMatch: true, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: false); + SymbolEquivalenceComparer.Create(distinguishRefFromOut: true, tupleNamesMustMatch: true, ignoreNullableAnnotations: false, objectAndDynamicCompareEqually: false, arrayAndReadOnlySpanCompareEqually: false); + + private static readonly SymbolEquivalenceComparer s_arrayAndReadOnlySpanCompareEqually = s_includeNullabilityComparer.With(arrayAndReadOnlySpanCompareEqually: true); /// /// Creates a semantic analyzer for speculative syntax replacement. @@ -81,10 +79,10 @@ public AbstractSpeculationAnalyzer( bool skipVerificationForReplacedNode = false, bool failOnOverloadResolutionFailuresInOriginalCode = false) { - _expression = expression; + OriginalExpression = expression; _newExpressionForReplace = newExpression; - _semanticModel = semanticModel; - _cancellationToken = cancellationToken; + OriginalSemanticModel = semanticModel; + CancellationToken = cancellationToken; _skipVerificationForReplacedNode = skipVerificationForReplacedNode; _failOnOverloadResolutionFailuresInOriginalCode = failOnOverloadResolutionFailuresInOriginalCode; _isNewSemanticModelSpeculativeModel = true; @@ -95,12 +93,39 @@ public AbstractSpeculationAnalyzer( } protected abstract ISyntaxFacts SyntaxFactsService { get; } + + protected abstract SyntaxNode GetSemanticRootForSpeculation(TExpressionSyntax expression); + protected abstract SemanticModel CreateSpeculativeSemanticModel(SyntaxNode originalNode, SyntaxNode nodeToSpeculate, SemanticModel semanticModel); + + protected abstract bool IsInNamespaceOrTypeContext(TExpressionSyntax node); + protected abstract bool ExpressionMightReferenceMember([NotNullWhen(true)] SyntaxNode? node); protected abstract bool CanAccessInstanceMemberThrough(TExpressionSyntax? expression); + protected abstract TConversion ClassifyConversion(SemanticModel model, TExpressionSyntax expression, ITypeSymbol targetType); + protected abstract TConversion ClassifyConversion(SemanticModel model, ITypeSymbol originalType, ITypeSymbol targetType); + protected abstract bool ConversionsAreCompatible(SemanticModel model1, TExpressionSyntax expression1, SemanticModel model2, TExpressionSyntax expression2); + protected abstract bool ConversionsAreCompatible(TExpressionSyntax originalExpression, ITypeSymbol originalTargetType, TExpressionSyntax newExpression, ITypeSymbol newTargetType); + protected abstract bool IsReferenceConversion(Compilation model, ITypeSymbol sourceType, ITypeSymbol targetType); + + protected abstract TExpressionSyntax GetForEachStatementExpression(TForEachStatementSyntax forEachStatement); + protected abstract bool IsForEachTypeInferred(TForEachStatementSyntax forEachStatement, SemanticModel semanticModel); + protected abstract bool ForEachConversionsAreCompatible(SemanticModel originalModel, TForEachStatementSyntax originalForEach, SemanticModel newModel, TForEachStatementSyntax newForEach); + protected abstract void GetForEachSymbols( + SemanticModel model, TForEachStatementSyntax forEach, out IMethodSymbol getEnumeratorMethod, out ITypeSymbol elementType, out ImmutableArray localVariables); + + protected abstract bool ReplacementChangesSemanticsForNodeLanguageSpecific(SyntaxNode currentOriginalNode, SyntaxNode currentReplacedNode, SyntaxNode? previousOriginalNode, SyntaxNode? previousReplacedNode); + + protected abstract bool IsParenthesizedExpression([NotNullWhen(true)] SyntaxNode? node); + protected abstract bool IsNamedArgument(TArgumentSyntax argument); + protected abstract string GetNamedArgumentIdentifierValueText(TArgumentSyntax argument); + protected abstract TExpressionSyntax GetThrowStatementExpression(TThrowStatementSyntax throwStatement); + protected abstract ImmutableArray GetArguments(TExpressionSyntax expression); + protected abstract TExpressionSyntax GetReceiver(TExpressionSyntax expression); + /// /// Original expression to be replaced. /// - public TExpressionSyntax OriginalExpression => _expression; + public TExpressionSyntax OriginalExpression { get; } SyntaxNode ISpeculationAnalyzer.OriginalExpression => OriginalExpression; @@ -126,7 +151,7 @@ public SyntaxNode SemanticRootOfOriginalExpression /// /// Semantic model for the syntax tree corresponding to /// - public SemanticModel OriginalSemanticModel => _semanticModel; + public SemanticModel OriginalSemanticModel { get; } /// /// Node which replaces the . @@ -170,9 +195,7 @@ public SemanticModel SpeculativeSemanticModel } } - public CancellationToken CancellationToken => _cancellationToken; - - protected abstract SyntaxNode GetSemanticRootForSpeculation(TExpressionSyntax expression); + public CancellationToken CancellationToken { get; } protected virtual SyntaxNode GetSemanticRootOfReplacedExpression(SyntaxNode semanticRootOfOriginalExpression, TExpressionSyntax annotatedReplacedExpression) => semanticRootOfOriginalExpression.ReplaceNode(this.OriginalExpression, annotatedReplacedExpression); @@ -205,13 +228,11 @@ private void EnsureSpeculativeSemanticModel() if (_lazySpeculativeSemanticModel == null) { var nodeToSpeculate = this.SemanticRootOfReplacedExpression; - _lazySpeculativeSemanticModel = CreateSpeculativeSemanticModel(this.SemanticRootOfOriginalExpression, nodeToSpeculate, _semanticModel); + _lazySpeculativeSemanticModel = CreateSpeculativeSemanticModel(this.SemanticRootOfOriginalExpression, nodeToSpeculate, OriginalSemanticModel); ValidateSpeculativeSemanticModel(_lazySpeculativeSemanticModel, nodeToSpeculate); } } - protected abstract SemanticModel CreateSpeculativeSemanticModel(SyntaxNode originalNode, SyntaxNode nodeToSpeculate, SemanticModel semanticModel); - #region Semantic comparison helpers protected virtual bool ReplacementIntroducesDisallowedNullType( @@ -292,9 +313,6 @@ private bool ImplicitConversionsAreCompatible(TExpressionSyntax originalExpressi return ConversionsAreCompatible(originalExpression, originalTargetType, newExpression, newTargetType); } - protected abstract bool ConversionsAreCompatible(SemanticModel model1, TExpressionSyntax expression1, SemanticModel model2, TExpressionSyntax expression2); - protected abstract bool ConversionsAreCompatible(TExpressionSyntax originalExpression, ITypeSymbol originalTargetType, TExpressionSyntax newExpression, ITypeSymbol newTargetType); - protected bool SymbolsAreCompatible(SyntaxNode originalNode, SyntaxNode newNode, bool requireNonNullSymbols = false) { RoslynDebug.AssertNotNull(originalNode); @@ -406,6 +424,19 @@ private static bool SymbolsAreCompatibleCore( } } } + + // We consider two method overloads compatible if one takes a T[] array for a particular parameter, and the + // other takes a ReadOnlySpan for the same parameter. This is a considered a supported and desirable API + // upgrade story for API authors. Specifically, they start with an array-based method, and then add a + // sibling ROS method. In that case, the language will prefer the latter when both are applicable. So if + // we make a code change that makes the second compatible, then we are ok with that, as the expectation is + // that the new method has the same semantics and it is desirable for code to now call that. + // + // Note: this comparer will check the method kinds, name, containing type, arity, and virtually everything + // else about the methods. The only difference it will allow between the methods is that parameter types + // can be different if they are an array vs a ReadOnlySpan. + if (s_arrayAndReadOnlySpanCompareEqually.Equals(methodSymbol, newMethodSymbol)) + return true; } return false; @@ -443,10 +474,8 @@ newSymbol is IParameterSymbol newParameterSymbol && CompareAcrossSemanticModels(parameterSymbol.Type, newParameterSymbol.Type); } - if (symbol is IMethodSymbol methodSymbol && - newSymbol is IMethodSymbol newMethodSymbol && - methodSymbol.IsLocalFunction() && - newMethodSymbol.IsLocalFunction()) + if (symbol is IMethodSymbol { MethodKind: MethodKind.LocalFunction } methodSymbol && + newSymbol is IMethodSymbol { MethodKind: MethodKind.LocalFunction } newMethodSymbol) { return symbol.Name == newSymbol.Name && methodSymbol.Parameters.Length == newMethodSymbol.Parameters.Length && @@ -486,8 +515,6 @@ public bool ReplacementChangesSemantics() skipVerificationForCurrentNode: _skipVerificationForReplacedNode); } - protected abstract bool IsParenthesizedExpression([NotNullWhen(true)] SyntaxNode? node); - protected bool ReplacementChangesSemantics(SyntaxNode currentOriginalNode, SyntaxNode currentReplacedNode, SyntaxNode originalRoot, bool skipVerificationForCurrentNode) { if (this.SpeculativeSemanticModel == null) @@ -541,8 +568,6 @@ public bool SymbolsForOriginalAndReplacedNodesAreCompatible() return SymbolsAreCompatible(this.OriginalExpression, this.ReplacedExpression, requireNonNullSymbols: true); } - protected abstract bool ReplacementChangesSemanticsForNodeLanguageSpecific(SyntaxNode currentOriginalNode, SyntaxNode currentReplacedNode, SyntaxNode? previousOriginalNode, SyntaxNode? previousReplacedNode); - private bool ReplacementChangesSemanticsForNode(SyntaxNode currentOriginalNode, SyntaxNode currentReplacedNode, SyntaxNode? previousOriginalNode, SyntaxNode? previousReplacedNode) { Debug.Assert(previousOriginalNode == null || previousOriginalNode.Parent == currentOriginalNode); @@ -650,7 +675,7 @@ private bool MemberAccessesAreCompatible(TExpressionSyntax? originalExpression, // semantics. We could potentially support this, but we'd have to do the analysis the instance invoked // on and the instance passed as the first parameter are identical. - var originalIsStaticAccess = IsStaticAccess(_semanticModel.GetSymbolInfo(originalExpression, CancellationToken).Symbol); + var originalIsStaticAccess = IsStaticAccess(OriginalSemanticModel.GetSymbolInfo(originalExpression, CancellationToken).Symbol); var replacedIsStaticAccess = IsStaticAccess(this.SpeculativeSemanticModel.GetSymbolInfo(newExpression, CancellationToken).Symbol); if (originalIsStaticAccess != replacedIsStaticAccess) return false; @@ -743,33 +768,31 @@ private bool ReplacementBreaksAttribute(TAttributeSyntax attribute, TAttributeSy return !SymbolsAreCompatible(attributeSym, newAttributeSym); } - protected abstract TExpressionSyntax GetForEachStatementExpression(TForEachStatementSyntax forEachStatement); - - protected abstract bool IsForEachTypeInferred(TForEachStatementSyntax forEachStatement, SemanticModel semanticModel); - private bool ReplacementBreaksForEachStatement(TForEachStatementSyntax forEachStatement, TForEachStatementSyntax newForEachStatement) { var forEachExpression = GetForEachStatementExpression(forEachStatement); if (forEachExpression.IsMissing || - !forEachExpression.Span.Contains(_expression.SpanStart)) + !forEachExpression.Span.Contains(OriginalExpression.SpanStart)) { return false; } + GetForEachSymbols(this.OriginalSemanticModel, forEachStatement, out var originalGetEnumerator, out var originalElementType, out var originalLocalVariables); + GetForEachSymbols(this.SpeculativeSemanticModel, newForEachStatement, out var newGetEnumerator, out var newElementType, out var newLocalVariables); + // inferred variable type compatible - if (IsForEachTypeInferred(forEachStatement, _semanticModel)) + if (IsForEachTypeInferred(forEachStatement, OriginalSemanticModel)) { - var local = (ILocalSymbol)_semanticModel.GetRequiredDeclaredSymbol(forEachStatement, _cancellationToken); - var newLocal = (ILocalSymbol)this.SpeculativeSemanticModel.GetRequiredDeclaredSymbol(newForEachStatement, _cancellationToken); - if (!SymbolsAreCompatible(local.Type, newLocal.Type)) - { + if (originalLocalVariables.Length != newLocalVariables.Length) return true; + + for (int i = 0, n = originalLocalVariables.Length; i < n; i++) + { + if (!SymbolsAreCompatible(originalLocalVariables[i].Type, newLocalVariables[i].Type)) + return true; } } - GetForEachSymbols(this.OriginalSemanticModel, forEachStatement, out var originalGetEnumerator, out var originalElementType); - GetForEachSymbols(this.SpeculativeSemanticModel, newForEachStatement, out var newGetEnumerator, out var newElementType); - var newForEachExpression = GetForEachStatementExpression(newForEachStatement); if (ReplacementBreaksForEachGetEnumerator(originalGetEnumerator, newGetEnumerator, newForEachExpression) || @@ -782,10 +805,6 @@ private bool ReplacementBreaksForEachStatement(TForEachStatementSyntax forEachSt return false; } - protected abstract bool ForEachConversionsAreCompatible(SemanticModel originalModel, TForEachStatementSyntax originalForEach, SemanticModel newModel, TForEachStatementSyntax newForEach); - - protected abstract void GetForEachSymbols(SemanticModel model, TForEachStatementSyntax forEach, out IMethodSymbol getEnumeratorMethod, out ITypeSymbol elementType); - private bool ReplacementBreaksForEachGetEnumerator(IMethodSymbol getEnumerator, IMethodSymbol newGetEnumerator, TExpressionSyntax newForEachStatementExpression) { if (getEnumerator == null && newGetEnumerator == null) @@ -804,7 +823,7 @@ private bool ReplacementBreaksForEachGetEnumerator(IMethodSymbol getEnumerator, // GetEnumerator method on a specific type. if (getEnumerator.IsImplementableMember()) { - var expressionType = this.SpeculativeSemanticModel.GetTypeInfo(newForEachStatementExpression, _cancellationToken).ConvertedType; + var expressionType = this.SpeculativeSemanticModel.GetTypeInfo(newForEachStatementExpression, CancellationToken).ConvertedType; if (expressionType != null) { var implementationMember = expressionType.FindImplementationForInterfaceMember(getEnumerator); @@ -824,8 +843,6 @@ private bool ReplacementBreaksForEachGetEnumerator(IMethodSymbol getEnumerator, return false; } - protected abstract TExpressionSyntax GetThrowStatementExpression(TThrowStatementSyntax throwStatement); - private bool ReplacementBreaksThrowStatement(TThrowStatementSyntax originalThrowStatement, TThrowStatementSyntax newThrowStatement) { var originalThrowExpression = GetThrowStatementExpression(originalThrowStatement); @@ -838,8 +855,6 @@ private bool ReplacementBreaksThrowStatement(TThrowStatementSyntax originalThrow newThrowExpressionType.IsOrDerivesFromExceptionType(this.SpeculativeSemanticModel.Compilation); } - protected abstract bool IsInNamespaceOrTypeContext(TExpressionSyntax node); - private bool ReplacementBreaksTypeResolution(TTypeSyntax type, TTypeSyntax newType, bool useSpeculativeModel = true) { var symbol = this.OriginalSemanticModel.GetSymbolInfo(type).Symbol; @@ -847,7 +862,7 @@ private bool ReplacementBreaksTypeResolution(TTypeSyntax type, TTypeSyntax newTy ISymbol? newSymbol; if (useSpeculativeModel) { - newSymbol = this.SpeculativeSemanticModel.GetSymbolInfo(newType, _cancellationToken).Symbol; + newSymbol = this.SpeculativeSemanticModel.GetSymbolInfo(newType, CancellationToken).Symbol; } else { @@ -858,8 +873,6 @@ private bool ReplacementBreaksTypeResolution(TTypeSyntax type, TTypeSyntax newTy return symbol != null && !SymbolsAreCompatible(symbol, newSymbol); } - protected abstract bool ExpressionMightReferenceMember([NotNullWhen(true)] SyntaxNode? node); - private static bool IsDelegateInvoke(ISymbol symbol) { return symbol.Kind == SymbolKind.Method && @@ -875,7 +888,7 @@ private static bool IsAnonymousDelegateInvoke(ISymbol symbol) private bool ReplacementBreaksExpression(TExpressionSyntax expression, TExpressionSyntax newExpression) { - var originalSymbolInfo = _semanticModel.GetSymbolInfo(expression); + var originalSymbolInfo = OriginalSemanticModel.GetSymbolInfo(expression); if (_failOnOverloadResolutionFailuresInOriginalCode && originalSymbolInfo.CandidateReason == CandidateReason.OverloadResolutionFailure) { return true; @@ -959,8 +972,6 @@ protected bool ReplacementBreaksCompoundAssignment( return false; } - protected abstract bool IsReferenceConversion(Compilation model, ITypeSymbol sourceType, ITypeSymbol targetType); - private bool IsCompatibleInterfaceMemberImplementation( ISymbol symbol, ISymbol newSymbol, @@ -1050,9 +1061,6 @@ private static bool IsReceiverUniqueInstance(TExpressionSyntax receiver, Semanti receiverSymbol.IsKind(SymbolKind.Property); } - protected abstract ImmutableArray GetArguments(TExpressionSyntax expression); - protected abstract TExpressionSyntax GetReceiver(TExpressionSyntax expression); - private bool SymbolsHaveCompatibleParameterLists(ISymbol originalSymbol, ISymbol newSymbol, TExpressionSyntax originalInvocation) { if (originalSymbol.IsKind(SymbolKind.Method) || originalSymbol.IsIndexer()) @@ -1069,9 +1077,6 @@ private bool SymbolsHaveCompatibleParameterLists(ISymbol originalSymbol, ISymbol return true; } - protected abstract bool IsNamedArgument(TArgumentSyntax argument); - protected abstract string GetNamedArgumentIdentifierValueText(TArgumentSyntax argument); - private bool AreCompatibleParameterLists( ImmutableArray specifiedArguments, ImmutableArray signature1Parameters, @@ -1221,7 +1226,4 @@ protected void GetConversions( } } } - - protected abstract TConversion ClassifyConversion(SemanticModel model, TExpressionSyntax expression, ITypeSymbol targetType); - protected abstract TConversion ClassifyConversion(SemanticModel model, ITypeSymbol originalType, ITypeSymbol targetType); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AnnotationTable.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AnnotationTable.cs index 761b916329541..affa0452d4617 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AnnotationTable.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/AnnotationTable.cs @@ -24,7 +24,7 @@ namespace Roslyn.Utilities; /// /// also, note that this table is not thread safe. /// -internal class AnnotationTable(string annotationKind) where TAnnotation : class +internal sealed class AnnotationTable(string annotationKind) where TAnnotation : class { private int _globalId; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/BKTree.Serialization.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/BKTree.Serialization.cs index 44f3418cf29b0..918b942c25484 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/BKTree.Serialization.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/BKTree.Serialization.cs @@ -11,7 +11,7 @@ internal readonly partial struct BKTree { internal void WriteTo(ObjectWriter writer) { - writer.WriteCharArray(_concatenatedLowerCaseWords); + writer.WriteCharArray(_concatenatedLowerCaseWords, 0, _concatenatedLowerCaseWords.Length); writer.WriteArray(_nodes, static (w, n) => n.WriteTo(w)); writer.WriteArray(_edges, static (w, n) => n.WriteTo(w)); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/BidirectionalMap.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/BidirectionalMap.cs index bfbef9cf4a522..d6b4dfafeb387 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/BidirectionalMap.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/BidirectionalMap.cs @@ -10,7 +10,7 @@ namespace Roslyn.Utilities; -internal class BidirectionalMap : IBidirectionalMap +internal sealed class BidirectionalMap : IBidirectionalMap where TKey : notnull where TValue : notnull { @@ -20,10 +20,16 @@ internal class BidirectionalMap : IBidirectionalMap private readonly ImmutableDictionary _forwardMap; private readonly ImmutableDictionary _backwardMap; - public BidirectionalMap(IEnumerable> pairs) + public BidirectionalMap(IEnumerable> pairs, IEqualityComparer? keyComparer = null, IEqualityComparer? valueComparer = null) + : this(forwardMap: ImmutableDictionary.CreateRange(keyComparer, pairs), + backwardMap: ImmutableDictionary.CreateRange(valueComparer, pairs.Select(static p => KeyValuePairUtil.Create(p.Value, p.Key)))) + { + } + + public BidirectionalMap(IEnumerable<(TKey key, TValue value)> pairs, IEqualityComparer? keyComparer = null, IEqualityComparer? valueComparer = null) + : this(forwardMap: ImmutableDictionary.CreateRange(keyComparer, pairs.Select(static p => KeyValuePairUtil.Create(p.key, p.value))), + backwardMap: ImmutableDictionary.CreateRange(valueComparer, pairs.Select(static p => KeyValuePairUtil.Create(p.value, p.key)))) { - _forwardMap = ImmutableDictionary.CreateRange(pairs); - _backwardMap = ImmutableDictionary.CreateRange(pairs.Select(p => KeyValuePairUtil.Create(p.Value, p.Key))); } private BidirectionalMap(ImmutableDictionary forwardMap, ImmutableDictionary backwardMap) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/CancellableLazy`1.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/CancellableLazy`1.cs index c051fd27c7a01..77d46ccfbee35 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/CancellableLazy`1.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/CancellableLazy`1.cs @@ -8,7 +8,7 @@ namespace Roslyn.Utilities; -internal class CancellableLazy +internal sealed class CancellableLazy { private NonReentrantLock? _gate; private Func? _valueFactory; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EditDistance.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EditDistance.cs index e32225e85e0a0..d207b4448c88c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EditDistance.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EditDistance.cs @@ -601,7 +601,7 @@ private static void SetValue(int[,] matrix, int i, int j, int val) } } -internal class SimplePool(Func allocate) where T : class +internal sealed class SimplePool(Func allocate) where T : class { private readonly object _gate = new(); private readonly Stack _values = new(); diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/EnumValueUtilities.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EnumValueUtilities.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/Utilities/EnumValueUtilities.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EnumValueUtilities.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EventMap.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EventMap.cs index c68c696ee365e..35ca9ae0fc338 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EventMap.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/EventMap.cs @@ -10,7 +10,7 @@ namespace Roslyn.Utilities; -internal class EventMap +internal sealed class EventMap { private readonly NonReentrantLock _guard = new(); @@ -93,7 +93,7 @@ private void SetRegistries_NoLock(string eventName, ImmutableArra _eventNameToRegistries[eventName] = registries; } - internal class Registry(TEventHandler handler) : IEquatable?> + internal sealed class Registry(TEventHandler handler) : IEquatable?> where TEventHandler : class { private TEventHandler? _handler = handler; diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/IAsyncEnumerableExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/IAsyncEnumerableExtensions.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/Extensions/IAsyncEnumerableExtensions.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/IAsyncEnumerableExtensions.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/IReadOnlyListExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/IReadOnlyListExtensions.cs index 715de9a194cfa..4656496d911ec 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/IReadOnlyListExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/IReadOnlyListExtensions.cs @@ -35,7 +35,7 @@ public static int IndexOf(this IReadOnlyList list, T value, int startIndex return -1; } - private class ReadOnlyList(IList list) : IReadOnlyList + private sealed class ReadOnlyList(IList list) : IReadOnlyList { public T this[int index] => list[index]; public int Count => list.Count; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/IReferenceCountedDisposable.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/IReferenceCountedDisposable.cs index f751e0c8898e1..e8805de937baa 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/IReferenceCountedDisposable.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/IReferenceCountedDisposable.cs @@ -12,10 +12,7 @@ namespace Roslyn.Utilities; /// disposing directly. /// /// -internal interface IReferenceCountedDisposable : IDisposable -#if !CODE_STYLE - , IAsyncDisposable -#endif +internal interface IReferenceCountedDisposable : IDisposable, IAsyncDisposable where T : class { /// diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.ChoiceMatcher.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.ChoiceMatcher.cs index 139ae03e602a3..24743a6937cfe 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.ChoiceMatcher.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.ChoiceMatcher.cs @@ -6,9 +6,9 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; -internal partial class Matcher +internal abstract partial class Matcher { - private class ChoiceMatcher(params Matcher[] matchers) : Matcher + private sealed class ChoiceMatcher(params Matcher[] matchers) : Matcher { private readonly IEnumerable> _matchers = matchers; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.RepeatMatcher.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.RepeatMatcher.cs index 91206c049ab35..2885dc11e0aaf 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.RepeatMatcher.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.RepeatMatcher.cs @@ -6,9 +6,9 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; -internal partial class Matcher +internal abstract partial class Matcher { - private class RepeatMatcher(Matcher matcher) : Matcher + private sealed class RepeatMatcher(Matcher matcher) : Matcher { public override bool TryMatch(IList sequence, ref int index) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.SequenceMatcher.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.SequenceMatcher.cs index e326d1d7fa3ef..bca95e8f803b6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.SequenceMatcher.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.SequenceMatcher.cs @@ -6,9 +6,9 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; -internal partial class Matcher +internal abstract partial class Matcher { - private class SequenceMatcher(params Matcher[] matchers) : Matcher + private sealed class SequenceMatcher(params Matcher[] matchers) : Matcher { public override bool TryMatch(IList sequence, ref int index) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.SingleMatcher.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.SingleMatcher.cs index 555eca9a11ffe..dad26133f4223 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.SingleMatcher.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.SingleMatcher.cs @@ -7,9 +7,9 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; -internal partial class Matcher +internal abstract partial class Matcher { - private class SingleMatcher(Func predicate, string description) : Matcher + private sealed class SingleMatcher(Func predicate, string description) : Matcher { public override bool TryMatch(IList sequence, ref int index) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.cs index c1a499089a249..7700ab7b15bfa 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/Matcher.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; -internal class Matcher +internal sealed class Matcher { /// /// Matcher equivalent to (m*) diff --git a/src/Workspaces/Core/Portable/Utilities/ParameterName.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ParameterName.cs similarity index 100% rename from src/Workspaces/Core/Portable/Utilities/ParameterName.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ParameterName.cs diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/ProducerConsumer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ProducerConsumer.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/Utilities/ProducerConsumer.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ProducerConsumer.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposable.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposable.cs index 6d636c7529e52..11eaafe676ce9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposable.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/ReferenceCountedDisposable.cs @@ -186,10 +186,8 @@ public ValueTask DisposeAsync() if (instanceToDispose == null) return ValueTaskFactory.CompletedTask; -#if !CODE_STYLE if (instanceToDispose is IAsyncDisposable asyncDisposable) return asyncDisposable.DisposeAsync(); -#endif instanceToDispose.Dispose(); return ValueTaskFactory.CompletedTask; diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/RoslynParallel.NetFramework.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/RoslynParallel.NetFramework.cs similarity index 99% rename from src/Workspaces/Core/Portable/Shared/Utilities/RoslynParallel.NetFramework.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/RoslynParallel.NetFramework.cs index d24e62bb1e4eb..dd626976d8108 100644 --- a/src/Workspaces/Core/Portable/Shared/Utilities/RoslynParallel.NetFramework.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/RoslynParallel.NetFramework.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +// + #if !NET #pragma warning disable CA1068 // CancellationToken parameters must come last @@ -401,12 +403,12 @@ private abstract class ForEachAsyncState : TaskCompletionSourceSemaphore used to provide exclusive access to the enumerator. - private readonly SemaphoreSlim? _lock; + private readonly SemaphoreSlim _lock; /// The number of outstanding workers. When this hits 0, the operation has completed. private int _completionRefCount; /// Any exceptions incurred during execution. - private List? _exceptions; + private List _exceptions; /// The number of workers that may still be created. private int _remainingDop; diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/RoslynParallel.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/RoslynParallel.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/Utilities/RoslynParallel.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/RoslynParallel.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SerializableBytes.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SerializableBytes.cs index b0e1e7f090ca1..70b9041991463 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SerializableBytes.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SerializableBytes.cs @@ -272,7 +272,7 @@ public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); } - private class ReadStream(long length, byte[][] chunks) : PooledStream(length, new List(chunks)) + private sealed class ReadStream(long length, byte[][] chunks) : PooledStream(length, new List(chunks)) { } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SoftCrashException.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SoftCrashException.cs index f7c10902f7f91..ee6944a4d0638 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SoftCrashException.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SoftCrashException.cs @@ -27,7 +27,7 @@ namespace Roslyn.Utilities; /// /// as we use soft-crash in more places, we should come up with more general framework. /// -internal class SoftCrashException : OperationCanceledException +internal sealed class SoftCrashException : OperationCanceledException { public SoftCrashException() : base() { } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.AssemblyComparers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.AssemblyComparers.cs index f770efb9062c6..ad27b6f181e84 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.AssemblyComparers.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.AssemblyComparers.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; -internal partial class SymbolEquivalenceComparer +internal sealed partial class SymbolEquivalenceComparer { private sealed class SimpleNameAssemblyComparer : IEqualityComparer { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs index 64c2f3e0110d5..9c664d0c861c0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -11,25 +12,19 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; -internal partial class SymbolEquivalenceComparer +internal sealed partial class SymbolEquivalenceComparer { - private class EquivalenceVisitor( + private sealed class EquivalenceVisitor( SymbolEquivalenceComparer symbolEquivalenceComparer, - bool compareMethodTypeParametersByIndex, - bool objectAndDynamicCompareEqually) + bool compareMethodTypeParametersByIndex) { - public bool AreEquivalent(ISymbol? x, ISymbol? y, Dictionary? equivalentTypesWithDifferingAssemblies) { if (ReferenceEquals(x, y)) - { return true; - } if (x == null || y == null) - { return false; - } var xKind = GetKindAndUnwrapAlias(ref x); var yKind = GetKindAndUnwrapAlias(ref y); @@ -37,13 +32,27 @@ public bool AreEquivalent(ISymbol? x, ISymbol? y, Dictionary? equivalentTypesWithDifferingAssemblies) + { + if (array.Rank != 1) + return false; + + return AreEquivalent(array.ElementType, readOnlySpanType.TypeArguments.Single(), equivalentTypesWithDifferingAssemblies); + } + internal bool AreEquivalent(CustomModifier x, CustomModifier y, Dictionary? equivalentTypesWithDifferingAssemblies) => x.IsOptional == y.IsOptional && AreEquivalent(x.Modifier, y.Modifier, equivalentTypesWithDifferingAssemblies); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.GetHashCodeVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.GetHashCodeVisitor.cs index f54b8bc87d787..35d260e471a12 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.GetHashCodeVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.GetHashCodeVisitor.cs @@ -11,24 +11,21 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; -internal partial class SymbolEquivalenceComparer +internal sealed partial class SymbolEquivalenceComparer { - private class GetHashCodeVisitor + private sealed class GetHashCodeVisitor { private readonly SymbolEquivalenceComparer _symbolEquivalenceComparer; private readonly bool _compareMethodTypeParametersByIndex; - private readonly bool _objectAndDynamicCompareEqually; private readonly Func _parameterAggregator; private readonly Func _symbolAggregator; public GetHashCodeVisitor( SymbolEquivalenceComparer symbolEquivalenceComparer, - bool compareMethodTypeParametersByIndex, - bool objectAndDynamicCompareEqually) + bool compareMethodTypeParametersByIndex) { _symbolEquivalenceComparer = symbolEquivalenceComparer; _compareMethodTypeParametersByIndex = compareMethodTypeParametersByIndex; - _objectAndDynamicCompareEqually = objectAndDynamicCompareEqually; _parameterAggregator = (acc, sym) => Hash.Combine(symbolEquivalenceComparer.ParameterEquivalenceComparer.GetHashCode(sym), acc); _symbolAggregator = (acc, sym) => GetHashCode(sym, acc); } @@ -45,7 +42,7 @@ public int GetHashCode(ISymbol? x, int currentHash) // want to bail out using the above check. if (x.Kind == SymbolKind.DynamicType || - (_objectAndDynamicCompareEqually && IsObjectType(x))) + (_symbolEquivalenceComparer._objectAndDynamicCompareEqually && IsObjectType(x))) { return Hash.Combine(GetNullableAnnotationsHashCode((ITypeSymbol)x), Hash.Combine(typeof(IDynamicTypeSymbol), currentHash)); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.ParameterSymbolEqualityComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.ParameterSymbolEqualityComparer.cs index 934f571069747..f29c926f6f036 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.ParameterSymbolEqualityComparer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.ParameterSymbolEqualityComparer.cs @@ -9,9 +9,9 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; -internal partial class SymbolEquivalenceComparer +internal sealed partial class SymbolEquivalenceComparer { - internal class ParameterSymbolEqualityComparer( + internal sealed class ParameterSymbolEqualityComparer( SymbolEquivalenceComparer symbolEqualityComparer, bool distinguishRefFromOut) : IEqualityComparer { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.SignatureTypeSymbolEquivalenceComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.SignatureTypeSymbolEquivalenceComparer.cs index 1f533427ebda7..3af31cab7fb03 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.SignatureTypeSymbolEquivalenceComparer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.SignatureTypeSymbolEquivalenceComparer.cs @@ -6,17 +6,17 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities; -internal partial class SymbolEquivalenceComparer +internal sealed partial class SymbolEquivalenceComparer { - internal class SignatureTypeSymbolEquivalenceComparer(SymbolEquivalenceComparer symbolEquivalenceComparer) : IEqualityComparer + internal sealed class SignatureTypeSymbolEquivalenceComparer(SymbolEquivalenceComparer symbolEquivalenceComparer) : IEqualityComparer { public bool Equals(ITypeSymbol? x, ITypeSymbol? y) => this.Equals(x, y, null); public bool Equals(ITypeSymbol? x, ITypeSymbol? y, Dictionary? equivalentTypesWithDifferingAssemblies) - => symbolEquivalenceComparer.GetEquivalenceVisitor(compareMethodTypeParametersByIndex: true, symbolEquivalenceComparer._objectAndDynamicCompareEqually).AreEquivalent(x, y, equivalentTypesWithDifferingAssemblies); + => symbolEquivalenceComparer.GetEquivalenceVisitor(compareMethodTypeParametersByIndex: true).AreEquivalent(x, y, equivalentTypesWithDifferingAssemblies); public int GetHashCode(ITypeSymbol? x) - => symbolEquivalenceComparer.GetGetHashCodeVisitor(compareMethodTypeParametersByIndex: true, symbolEquivalenceComparer._objectAndDynamicCompareEqually).GetHashCode(x, currentHash: 0); + => symbolEquivalenceComparer.GetGetHashCodeVisitor(compareMethodTypeParametersByIndex: true).GetHashCode(x, currentHash: 0); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs index 9a5192089d6a1..e761cf68b93ef 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs @@ -41,14 +41,17 @@ internal sealed partial class SymbolEquivalenceComparer : IEqualityComparer _equivalenceVisitors; private readonly ImmutableArray _getHashCodeVisitors; - public static readonly SymbolEquivalenceComparer Instance = Create(distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true); - public static readonly SymbolEquivalenceComparer TupleNamesMustMatchInstance = Create(distinguishRefFromOut: false, tupleNamesMustMatch: true, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true); - public static readonly SymbolEquivalenceComparer IgnoreAssembliesInstance = new(assemblyComparer: null, distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true); + public static readonly SymbolEquivalenceComparer Instance = Create(distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); + public static readonly SymbolEquivalenceComparer TupleNamesMustMatchInstance = Create(distinguishRefFromOut: false, tupleNamesMustMatch: true, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); + public static readonly SymbolEquivalenceComparer IgnoreAssembliesInstance = new(assemblyComparer: null, distinguishRefFromOut: false, tupleNamesMustMatch: false, ignoreNullableAnnotations: true, objectAndDynamicCompareEqually: true, arrayAndReadOnlySpanCompareEqually: false); private readonly IEqualityComparer? _assemblyComparer; + + private readonly bool _distinguishRefFromOut; private readonly bool _tupleNamesMustMatch; private readonly bool _ignoreNullableAnnotations; private readonly bool _objectAndDynamicCompareEqually; + private readonly bool _arrayAndReadOnlySpanCompareEqually; public ParameterSymbolEqualityComparer ParameterEquivalenceComparer { get; } public SignatureTypeSymbolEquivalenceComparer SignatureTypeEquivalenceComparer { get; } @@ -58,12 +61,15 @@ public SymbolEquivalenceComparer( bool distinguishRefFromOut, bool tupleNamesMustMatch, bool ignoreNullableAnnotations, - bool objectAndDynamicCompareEqually) + bool objectAndDynamicCompareEqually, + bool arrayAndReadOnlySpanCompareEqually) { _assemblyComparer = assemblyComparer; + _distinguishRefFromOut = distinguishRefFromOut; _tupleNamesMustMatch = tupleNamesMustMatch; _ignoreNullableAnnotations = ignoreNullableAnnotations; _objectAndDynamicCompareEqually = objectAndDynamicCompareEqually; + _arrayAndReadOnlySpanCompareEqually = arrayAndReadOnlySpanCompareEqually; this.ParameterEquivalenceComparer = new ParameterSymbolEqualityComparer(this, distinguishRefFromOut); this.SignatureTypeEquivalenceComparer = new SignatureTypeSymbolEquivalenceComparer(this); @@ -73,20 +79,18 @@ public SymbolEquivalenceComparer( using var equivalenceVisitors = TemporaryArray.Empty; using var getHashCodeVisitors = TemporaryArray.Empty; - AddVisitors(compareMethodTypeParametersByIndex: true, objectAndDynamicCompareEqually: true); - AddVisitors(compareMethodTypeParametersByIndex: true, objectAndDynamicCompareEqually: false); - AddVisitors(compareMethodTypeParametersByIndex: false, objectAndDynamicCompareEqually: true); - AddVisitors(compareMethodTypeParametersByIndex: false, objectAndDynamicCompareEqually: false); + AddVisitors(compareMethodTypeParametersByIndex: true); + AddVisitors(compareMethodTypeParametersByIndex: false); _equivalenceVisitors = equivalenceVisitors.ToImmutableAndClear(); _getHashCodeVisitors = getHashCodeVisitors.ToImmutableAndClear(); return; - void AddVisitors(bool compareMethodTypeParametersByIndex, bool objectAndDynamicCompareEqually) + void AddVisitors(bool compareMethodTypeParametersByIndex) { - equivalenceVisitors.Add(new(this, compareMethodTypeParametersByIndex, objectAndDynamicCompareEqually)); - getHashCodeVisitors.Add(new(this, compareMethodTypeParametersByIndex, objectAndDynamicCompareEqually)); + equivalenceVisitors.Add(new(this, compareMethodTypeParametersByIndex)); + getHashCodeVisitors.Add(new(this, compareMethodTypeParametersByIndex)); } } @@ -94,9 +98,26 @@ public static SymbolEquivalenceComparer Create( bool distinguishRefFromOut, bool tupleNamesMustMatch, bool ignoreNullableAnnotations, - bool objectAndDynamicCompareEqually) + bool objectAndDynamicCompareEqually, + bool arrayAndReadOnlySpanCompareEqually) { - return new(SimpleNameAssemblyComparer.Instance, distinguishRefFromOut, tupleNamesMustMatch, ignoreNullableAnnotations, objectAndDynamicCompareEqually); + return new(SimpleNameAssemblyComparer.Instance, distinguishRefFromOut, tupleNamesMustMatch, ignoreNullableAnnotations, objectAndDynamicCompareEqually, arrayAndReadOnlySpanCompareEqually); + } + + public SymbolEquivalenceComparer With( + Optional distinguishRefFromOut = default, + Optional tupleNamesMustMatch = default, + Optional ignoreNullableAnnotations = default, + Optional objectAndDynamicCompareEqually = default, + Optional arrayAndReadOnlySpanCompareEqually = default) + { + var newDistinguishRefFromOut = distinguishRefFromOut.HasValue ? distinguishRefFromOut.Value : _distinguishRefFromOut; + var newTupleNamesMustMatch = tupleNamesMustMatch.HasValue ? tupleNamesMustMatch.Value : _tupleNamesMustMatch; + var newIgnoreNullableAnnotations = ignoreNullableAnnotations.HasValue ? ignoreNullableAnnotations.Value : _ignoreNullableAnnotations; + var newObjectAndDynamicCompareEqually = objectAndDynamicCompareEqually.HasValue ? objectAndDynamicCompareEqually.Value : _objectAndDynamicCompareEqually; + var newArrayAndReadOnlySpanCompareEqually = arrayAndReadOnlySpanCompareEqually.HasValue ? arrayAndReadOnlySpanCompareEqually.Value : _arrayAndReadOnlySpanCompareEqually; + + return new(_assemblyComparer, newDistinguishRefFromOut, newTupleNamesMustMatch, newIgnoreNullableAnnotations, newObjectAndDynamicCompareEqually, newArrayAndReadOnlySpanCompareEqually); } // Very subtle logic here. When checking if two parameters are the same, we can end up with @@ -107,27 +128,21 @@ public static SymbolEquivalenceComparer Create( // here. So, instead, when asking if parameters are equal, we pass an appropriate flag so // that method type parameters are just compared by index and nothing else. private EquivalenceVisitor GetEquivalenceVisitor( - bool compareMethodTypeParametersByIndex = false, bool objectAndDynamicCompareEqually = false) + bool compareMethodTypeParametersByIndex = false) { - var visitorIndex = GetVisitorIndex(compareMethodTypeParametersByIndex, objectAndDynamicCompareEqually); + var visitorIndex = GetVisitorIndex(compareMethodTypeParametersByIndex); return _equivalenceVisitors[visitorIndex]; } private GetHashCodeVisitor GetGetHashCodeVisitor( - bool compareMethodTypeParametersByIndex, bool objectAndDynamicCompareEqually) + bool compareMethodTypeParametersByIndex) { - var visitorIndex = GetVisitorIndex(compareMethodTypeParametersByIndex, objectAndDynamicCompareEqually); + var visitorIndex = GetVisitorIndex(compareMethodTypeParametersByIndex); return _getHashCodeVisitors[visitorIndex]; } - private static int GetVisitorIndex(bool compareMethodTypeParametersByIndex, bool objectAndDynamicCompareEqually) - => (compareMethodTypeParametersByIndex, objectAndDynamicCompareEqually) switch - { - (true, true) => 0, - (true, false) => 1, - (false, true) => 2, - (false, false) => 3, - }; + private static int GetVisitorIndex(bool compareMethodTypeParametersByIndex) + => compareMethodTypeParametersByIndex ? 0 : 1; public bool ReturnTypeEquals(IMethodSymbol x, IMethodSymbol y, Dictionary? equivalentTypesWithDifferingAssemblies = null) => GetEquivalenceVisitor().ReturnTypesAreEquivalent(x, y, equivalentTypesWithDifferingAssemblies); @@ -154,7 +169,7 @@ private bool EqualsCore(ISymbol? x, ISymbol? y, Dictionary GetEquivalenceVisitor().AreEquivalent(x, y, equivalentTypesWithDifferingAssemblies); public int GetHashCode(ISymbol? x) - => GetGetHashCodeVisitor(compareMethodTypeParametersByIndex: false, objectAndDynamicCompareEqually: false).GetHashCode(x, currentHash: 0); + => GetGetHashCodeVisitor(compareMethodTypeParametersByIndex: false).GetHashCode(x, currentHash: 0); private static ISymbol UnwrapAlias(ISymbol symbol) => symbol.IsKind(SymbolKind.Alias, out IAliasSymbol? alias) ? alias.Target : symbol; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf index 89e9d8c506442..237585e76b2b6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.cs.xlf @@ -52,6 +52,11 @@ Předvolby polí + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + Části v instancích vrátily výjimky z metody IDisposable.Dispose(). + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf index e0390f34dd746..834aac1a19100 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.de.xlf @@ -52,6 +52,11 @@ Einstellungen für Felder + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + Instanziierte Teile haben Ausnahmen aus IDisposable.Dispose() ausgelöst. + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf index 17a039d847328..6b8aaca0e0cbe 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.es.xlf @@ -52,6 +52,11 @@ Preferencias de campo + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + Los elementos con instancias produjeron excepciones desde IDisposable.Dispose(). + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf index 170fa2ee5c9c1..0ae3c56734669 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.fr.xlf @@ -52,6 +52,11 @@ Préférences de champ + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + La ou les parties instanciées ont levé une ou plusieurs exceptions à partir de IDisposable.Dispose(). + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf index cd83e2d2838cc..826fadff9c091 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.it.xlf @@ -52,6 +52,11 @@ Preferenze per campi + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + Le parti di cui è stata creata un'istanza hanno generato eccezioni da IDisposable.Dispose(). + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf index 4d089882ead11..4b26c3ab7d2b3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ja.xlf @@ -52,6 +52,11 @@ フィールド設定 + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + インスタンス化されたパーツが IDisposable.Dispose() から例外をスローしました。 + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf index 0c796dcbc28c3..ee02f41cd9d3b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ko.xlf @@ -52,6 +52,11 @@ 필드 기본 설정 + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + IDisposable.Dispose()의 인스턴스화된 파트에서 예외가 발생했습니다. + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf index 8a5d33eb6818c..ef85ef2b0ecb0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pl.xlf @@ -52,6 +52,11 @@ Preferencje pól + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + Części z utworzonymi wystąpieniami zgłosiły wyjątki z elementu IDisposable.Dispose(). + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pt-BR.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pt-BR.xlf index 459b4259f8b35..fd27315e14805 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pt-BR.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.pt-BR.xlf @@ -52,6 +52,11 @@ Preferências de campo + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + As partes instanciadas geraram exceções por meio de IDisposable.Dispose(). + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf index 63bdcffa02244..72f203b535b63 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.ru.xlf @@ -52,6 +52,11 @@ Предпочтения для полей + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + Возникли исключения в частях с созданными экземплярами из IDisposable.Dispose(). + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf index 9f94de03e8e92..7093ab6cb8ac2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.tr.xlf @@ -52,6 +52,11 @@ Alan tercihleri + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + Örneği oluşturulan bölümler, IDisposable.Dispose() öğesinden özel durumlar oluşturdu. + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hans.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hans.xlf index 31c56e08bc8e9..b54d25a42c326 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hans.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hans.xlf @@ -52,6 +52,11 @@ 字段首选项 + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + 实例化的部件从 IDisposable.Dispose() 中引发异常。 + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hant.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hant.xlf index c1b0f5c1cb043..c3f574e61b0ad 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hant.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/xlf/CompilerExtensionsResources.zh-Hant.xlf @@ -52,6 +52,11 @@ 欄位喜好設定 + + Instantiated part(s) threw exception(s) from IDisposable.Dispose(). + 從 IDisposable.Dispose() 執行個體化的部分擲回的例外狀況。 + + Interface Interface diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb index 6f044dd2fa92c..bc31c6403f9a3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SyntaxFacts/VisualBasicSyntaxFacts.vb @@ -27,6 +27,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Public Shared ReadOnly Property Instance As New VisualBasicSyntaxFacts + ' Specifies false for trimOnFree as these objects commonly exceed the default ObjectPool threshold + Private Shared ReadOnly s_syntaxNodeListPool As ObjectPool(Of List(Of SyntaxNode)) = New ObjectPool(Of List(Of SyntaxNode))(Function() New List(Of SyntaxNode), trimOnFree:=False) + Protected Sub New() End Sub @@ -895,16 +898,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageService Return TextSpan.FromBounds(list.First.SpanStart, list.Last.Span.End) End Function - Public Function GetTopLevelAndMethodLevelMembers(root As SyntaxNode) As List(Of SyntaxNode) Implements ISyntaxFacts.GetTopLevelAndMethodLevelMembers - Dim list = New List(Of SyntaxNode)() + Public Function GetTopLevelAndMethodLevelMembers(root As SyntaxNode) As PooledObject(Of List(Of SyntaxNode)) Implements ISyntaxFacts.GetTopLevelAndMethodLevelMembers + Dim pooledList = PooledObject(Of List(Of SyntaxNode)).Create(s_syntaxNodeListPool) + Dim list = pooledList.Object + AppendMembers(root, list, topLevel:=True, methodLevel:=True) - Return list + + Return pooledList End Function - Public Function GetMethodLevelMembers(root As SyntaxNode) As List(Of SyntaxNode) Implements ISyntaxFacts.GetMethodLevelMembers - Dim list = New List(Of SyntaxNode)() + Public Function GetMethodLevelMembers(root As SyntaxNode) As PooledObject(Of List(Of SyntaxNode)) Implements ISyntaxFacts.GetMethodLevelMembers + Dim pooledList = PooledObject(Of List(Of SyntaxNode)).Create(s_syntaxNodeListPool) + Dim list = pooledList.Object + AppendMembers(root, list, topLevel:=False, methodLevel:=True) - Return list + + Return pooledList End Function Public Function GetMembersOfTypeDeclaration(typeDeclaration As SyntaxNode) As SyntaxList(Of SyntaxNode) Implements ISyntaxFacts.GetMembersOfTypeDeclaration diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Utilities/SpeculationAnalyzer.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Utilities/SpeculationAnalyzer.vb index c5a5e3936813a..e83f145797bcf 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Utilities/SpeculationAnalyzer.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Utilities/SpeculationAnalyzer.vb @@ -593,10 +593,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Utilities Return ConversionsAreCompatible(originalInfo.CurrentConversion, newInfo.CurrentConversion) AndAlso ConversionsAreCompatible(originalInfo.ElementConversion, newInfo.ElementConversion) End Function - Protected Overrides Sub GetForEachSymbols(model As SemanticModel, forEach As ForEachStatementSyntax, ByRef getEnumeratorMethod As IMethodSymbol, ByRef elementType As ITypeSymbol) + Protected Overrides Sub GetForEachSymbols( + model As SemanticModel, + forEach As ForEachStatementSyntax, + ByRef getEnumeratorMethod As IMethodSymbol, + ByRef elementType As ITypeSymbol, + ByRef localVariables As ImmutableArray(Of ILocalSymbol)) Dim info = model.GetForEachStatementInfo(forEach) getEnumeratorMethod = info.GetEnumeratorMethod elementType = info.ElementType + localVariables = ImmutableArray.Create(DirectCast(model.GetDeclaredSymbol(forEach), ILocalSymbol)) End Sub Protected Overrides Function IsReferenceConversion(compilation As Compilation, sourceType As ITypeSymbol, targetType As ITypeSymbol) As Boolean diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems index f2cba6f9d9789..1ee3201aed7fb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CSharpWorkspaceExtensions.projitems @@ -9,7 +9,6 @@ Microsoft.CodeAnalysis.CSharp.Shared - @@ -17,6 +16,7 @@ + @@ -32,6 +32,8 @@ + + @@ -40,7 +42,6 @@ - @@ -53,6 +54,7 @@ + @@ -87,6 +89,8 @@ + + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeActions/CSharpCodeFixOptionsProvider.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeActions/CSharpCodeFixOptionsProvider.cs deleted file mode 100644 index 985ac67a657e5..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeActions/CSharpCodeFixOptionsProvider.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.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.Formatting; -using Microsoft.CodeAnalysis.CSharp.Simplification; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Simplification; - -namespace Microsoft.CodeAnalysis.CodeActions; - -internal readonly struct CSharpCodeFixOptionsProvider(IOptionsReader options, HostLanguageServices languageServices) -{ - // LineFormattingOptions - - public string NewLine => GetOption(FormattingOptions2.NewLine); - - // SimplifierOptions - - public CodeStyleOption2 VarForBuiltInTypes => GetOption(CSharpCodeStyleOptions.VarForBuiltInTypes); - public CodeStyleOption2 VarElsewhere => GetOption(CSharpCodeStyleOptions.VarElsewhere); - - public SimplifierOptions GetSimplifierOptions() - => new CSharpSimplifierOptions(options); - - // FormattingOptions - - public CodeStyleOption2 NamespaceDeclarations => GetOption(CSharpCodeStyleOptions.NamespaceDeclarations); - public CodeStyleOption2 PreferTopLevelStatements => GetOption(CSharpCodeStyleOptions.PreferTopLevelStatements); - - internal CSharpSyntaxFormattingOptions GetFormattingOptions() - => new(options); - - // AddImportPlacementOptions - - public CodeStyleOption2 UsingDirectivePlacement => GetOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement); - - // CodeStyleOptions - - public CodeStyleOption2 PreferredModifierOrder => GetOption(CSharpCodeStyleOptions.PreferredModifierOrder); - public CodeStyleOption2 AccessibilityModifiersRequired => GetOption(CodeStyleOptions2.AccessibilityModifiersRequired); - - private TValue GetOption(Option2 option) - => options.GetOption(option); - - private TValue GetOption(PerLanguageOption2 option) - => options.GetOption(option, languageServices.Language); -} - -internal static class CSharpCodeFixOptionsProviders -{ - public static async ValueTask GetCSharpCodeFixOptionsProviderAsync(this Document document, CancellationToken cancellationToken) - { - var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return new CSharpCodeFixOptionsProvider(configOptions.GetOptionsReader(), document.Project.GetExtendedLanguageServices()); - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationService.cs index e642587180e98..fcc39d5ffff17 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationService.cs @@ -25,13 +25,9 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; using static CSharpSyntaxTokens; using static SyntaxFactory; -internal partial class CSharpCodeGenerationService : AbstractCodeGenerationService +internal sealed partial class CSharpCodeGenerationService(LanguageServices languageServices) + : AbstractCodeGenerationService(languageServices) { - public CSharpCodeGenerationService(LanguageServices languageServices) - : base(languageServices) - { - } - public override CodeGenerationOptions DefaultOptions => CSharpCodeGenerationOptions.Default; diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationServiceFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationServiceFactory.cs similarity index 100% rename from src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationServiceFactory.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeGeneration/CSharpCodeGenerationServiceFactory.cs diff --git a/src/Features/CSharp/Portable/CodeRefactorings/CSharpRefactoringHelpersService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeRefactorings/CSharpRefactoringHelpersService.cs similarity index 92% rename from src/Features/CSharp/Portable/CodeRefactorings/CSharpRefactoringHelpersService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeRefactorings/CSharpRefactoringHelpersService.cs index 5a690e4083cab..d6f17829e39d6 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/CSharpRefactoringHelpersService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/CodeRefactorings/CSharpRefactoringHelpersService.cs @@ -20,14 +20,10 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings; [ExportLanguageService(typeof(IRefactoringHelpersService), LanguageNames.CSharp), Shared] -internal class CSharpRefactoringHelpersService : AbstractRefactoringHelpersService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpRefactoringHelpersService() : AbstractRefactoringHelpersService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpRefactoringHelpersService() - { - } - protected override IHeaderFacts HeaderFacts => CSharpHeaderFacts.Instance; public override bool IsBetweenTypeMembers(SourceText sourceText, SyntaxNode root, int position, [NotNullWhen(true)] out SyntaxNode? typeDeclaration) diff --git a/src/Workspaces/CSharp/Portable/Editing/CSharpImportAdder.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Editing/CSharpImportAdder.cs similarity index 98% rename from src/Workspaces/CSharp/Portable/Editing/CSharpImportAdder.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Editing/CSharpImportAdder.cs index 88e35a0adefb7..d27ef36a0f7b3 100644 --- a/src/Workspaces/CSharp/Portable/Editing/CSharpImportAdder.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Editing/CSharpImportAdder.cs @@ -21,14 +21,10 @@ namespace Microsoft.CodeAnalysis.CSharp.Editing; [ExportLanguageService(typeof(ImportAdderService), LanguageNames.CSharp), Shared] -internal class CSharpImportAdder : ImportAdderService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpImportAdder() : ImportAdderService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpImportAdder() - { - } - protected override INamespaceSymbol? GetExplicitNamespaceSymbol(SyntaxNode node, SemanticModel model) { switch (node) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContextService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContextService.cs index dfc69d00ffad9..0cd91a3ccf0bf 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContextService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContextService.cs @@ -11,14 +11,10 @@ namespace Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; [ExportLanguageService(typeof(ISyntaxContextService), LanguageNames.CSharp), Shared] -internal class CSharpSyntaxContextService : ISyntaxContextService +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class CSharpSyntaxContextService() : ISyntaxContextService { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpSyntaxContextService() - { - } - public SyntaxContext CreateContext(Document document, SemanticModel semanticModel, int position, CancellationToken cancellationToken) => CSharpSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxNodeExtensions.cs deleted file mode 100644 index 637d13074cb08..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxNodeExtensions.cs +++ /dev/null @@ -1,32 +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; - -namespace Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; - -internal static class SyntaxNodeExtensions -{ - public static bool IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParameterList([NotNullWhen(true)] this SyntaxNode? node, bool includeOperators) - { - if (!node.IsKind(SyntaxKind.ParameterList)) - { - return false; - } - - if (node?.Parent?.Kind() - is SyntaxKind.MethodDeclaration - or SyntaxKind.LocalFunctionStatement - or SyntaxKind.ConstructorDeclaration - or SyntaxKind.DelegateDeclaration) - { - return true; - } - - if (includeOperators) - return node?.Parent?.Kind() is SyntaxKind.OperatorDeclaration or SyntaxKind.ConversionOperatorDeclaration; - - return false; - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs index 3c89ae633d151..e35591ee10129 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs @@ -1061,7 +1061,8 @@ public static bool IsParameterModifierContext( previousModifier = SyntaxKind.None; if (token.IsKind(SyntaxKind.OpenParenToken) && - token.Parent.IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParameterList(includeOperators)) + token.Parent is ParameterListSyntax parameterList1 && + IsSuitableParameterList(parameterList1, includeOperators)) { parameterIndex = 0; return true; @@ -1074,10 +1075,10 @@ public static bool IsParameterModifierContext( } if (token.IsKind(SyntaxKind.CommaToken) && - token.Parent is ParameterListSyntax parameterList && - parameterList.IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParameterList(includeOperators)) + token.Parent is ParameterListSyntax parameterList2 && + IsSuitableParameterList(parameterList2, includeOperators)) { - var commaIndex = parameterList.Parameters.GetWithSeparators().IndexOf(token); + var commaIndex = parameterList2.Parameters.GetWithSeparators().IndexOf(token); parameterIndex = commaIndex / 2 + 1; return true; @@ -1094,34 +1095,42 @@ token.Parent is ParameterListSyntax parameterList && if (token.IsKind(SyntaxKind.CloseBracketToken) && token.Parent.IsKind(SyntaxKind.AttributeList) && - token.Parent.Parent is ParameterSyntax parameter2 && - parameter2.Parent is ParameterListSyntax parameterList2 && - parameterList2.IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParameterList(includeOperators)) + token.Parent.Parent is ParameterSyntax parameter3 && + parameter3.Parent is ParameterListSyntax parameterList3 && + IsSuitableParameterList(parameterList3, includeOperators)) { - parameterIndex = parameterList2.Parameters.IndexOf(parameter2); + parameterIndex = parameterList3.Parameters.IndexOf(parameter3); return true; } - ParameterSyntax? parameter3 = null; + ParameterSyntax? parameter4 = null; if (token.Kind() is SyntaxKind.RefKeyword or SyntaxKind.InKeyword or SyntaxKind.ReadOnlyKeyword or SyntaxKind.OutKeyword or SyntaxKind.ThisKeyword or SyntaxKind.ParamsKeyword or SyntaxKind.ScopedKeyword) { - parameter3 = token.Parent as ParameterSyntax; + parameter4 = token.Parent as ParameterSyntax; previousModifier = token.Kind(); } else if (token.IsKind(SyntaxKind.IdentifierToken) && token.Text == "scoped" && token.Parent is IdentifierNameSyntax scopedIdentifierName) { - parameter3 = scopedIdentifierName.Parent as ParameterSyntax; + parameter4 = scopedIdentifierName.Parent as ParameterSyntax; previousModifier = SyntaxKind.ScopedKeyword; } - if (parameter3 is { Parent: ParameterListSyntax parameterList3 } && - parameterList3.IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParameterList(includeOperators)) + if (parameter4 is { Parent: ParameterListSyntax parameterList4 } && + IsSuitableParameterList(parameterList4, includeOperators)) { - parameterIndex = parameterList3.Parameters.IndexOf(parameter3); + parameterIndex = parameterList4.Parameters.IndexOf(parameter4); return true; } return false; + + static bool IsSuitableParameterList(ParameterListSyntax parameterList, bool includeOperators) + => parameterList.Parent switch + { + MethodDeclarationSyntax or LocalFunctionStatementSyntax or ConstructorDeclarationSyntax or DelegateDeclarationSyntax or TypeDeclarationSyntax => true, + OperatorDeclarationSyntax or ConversionOperatorDeclarationSyntax when includeOperators => true, + _ => false, + }; } public static bool IsParamsModifierContext( @@ -1185,11 +1194,8 @@ public static bool IsImplicitOrExplicitOperatorTypeContext( public static bool IsParameterTypeContext(this SyntaxTree syntaxTree, int position, SyntaxToken tokenOnLeftOfPosition) { var token = tokenOnLeftOfPosition.GetPreviousTokenIfTouchingWord(position); - if (syntaxTree.IsParameterModifierContext(position, tokenOnLeftOfPosition, includeOperators: true, out _, out _)) - { return true; - } // int this[ | // int this[int i, | diff --git a/src/Workspaces/CSharp/Portable/Extensions/SemanticModelExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SemanticModelExtensions.cs similarity index 100% rename from src/Workspaces/CSharp/Portable/Extensions/SemanticModelExtensions.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SemanticModelExtensions.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Formatting/CSharpSyntaxFormattingOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Formatting/CSharpSyntaxFormattingOptionsProviders.cs new file mode 100644 index 0000000000000..29a385575213a --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Formatting/CSharpSyntaxFormattingOptionsProviders.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.CSharp.Formatting; + +internal static class CSharpSyntaxFormattingOptionsProviders +{ + public static async ValueTask GetCSharpSyntaxFormattingOptionsAsync(this Document document, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + return new CSharpSyntaxFormattingOptions(configOptions); + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpRemoveUnnecessaryImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpRemoveUnnecessaryImportsService.cs index f59a9424eb31b..f014b6b6ce952 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpRemoveUnnecessaryImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpRemoveUnnecessaryImportsService.cs @@ -5,29 +5,20 @@ using System; using System.Collections.Generic; using System.Composition; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CSharp.Formatting; -using Microsoft.CodeAnalysis.CSharp.LanguageService; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.LanguageService; using Microsoft.CodeAnalysis.RemoveUnnecessaryImports; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -#if CODE_STYLE -using Formatter = Microsoft.CodeAnalysis.Formatting.FormatterHelper; -#else -using Formatter = Microsoft.CodeAnalysis.Formatting.Formatter; -#endif - namespace Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryImports; [ExportLanguageService(typeof(IRemoveUnnecessaryImportsService), LanguageNames.CSharp), Shared] @@ -40,10 +31,8 @@ public CSharpRemoveUnnecessaryImportsService() { } -#if CODE_STYLE - private static ISyntaxFormatting GetSyntaxFormatting() + private static ISyntaxFormatting SyntaxFormatting => CSharpSyntaxFormatting.Instance; -#endif protected override IUnnecessaryImportsProvider UnnecessaryImportsProvider => CSharpUnnecessaryImportsProvider.Instance; @@ -51,11 +40,8 @@ protected override IUnnecessaryImportsProvider Unnecessary public override async Task RemoveUnnecessaryImportsAsync( Document document, Func? predicate, - SyntaxFormattingOptions? formattingOptions, CancellationToken cancellationToken) { - Contract.ThrowIfNull(formattingOptions); - predicate ??= Functions.True; using (Logger.LogBlock(FunctionId.Refactoring_RemoveUnnecessaryImports_CSharp, cancellationToken)) { @@ -72,14 +58,12 @@ public override async Task RemoveUnnecessaryImportsAsync( var newRoot = (CompilationUnitSyntax)new Rewriter(unnecessaryImports, cancellationToken).Visit(oldRoot); cancellationToken.ThrowIfCancellationRequested(); -#if CODE_STYLE - var provider = GetSyntaxFormatting(); -#else - var provider = document.Project.Solution.Services; -#endif - var spans = new List(); - AddFormattingSpans(newRoot, spans, cancellationToken); - var formattedRoot = Formatter.Format(newRoot, spans, provider, formattingOptions, rules: default, cancellationToken); + + var spansToFormat = new List(); + AddFormattingSpans(newRoot, spansToFormat, cancellationToken); + + var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(SyntaxFormatting, cancellationToken).ConfigureAwait(false); + var formattedRoot = SyntaxFormatting.GetFormattingResult(newRoot, spansToFormat, formattingOptions, rules: default, cancellationToken).GetFormattedRoot(cancellationToken); return document.WithSyntaxRoot(formattedRoot); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs index e92cff2ad9f08..3d1893fcdf224 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSyntaxGeneratorInternal.cs @@ -30,11 +30,27 @@ public CSharpSyntaxGeneratorInternal() public static readonly SyntaxGeneratorInternal Instance = new CSharpSyntaxGeneratorInternal(); - public override ISyntaxFacts SyntaxFacts => CSharpSyntaxFacts.Instance; + public override ISyntaxFacts SyntaxFacts + => CSharpSyntaxFacts.Instance; + + public override SyntaxTrivia CarriageReturnLineFeed + => SyntaxFactory.CarriageReturnLineFeed; + + public override SyntaxTrivia ElasticCarriageReturnLineFeed + => SyntaxFactory.ElasticCarriageReturnLineFeed; + + public override bool SupportsThrowExpression() + => true; + + public override bool RequiresExplicitImplementationForInterfaceMembers + => false; public override SyntaxTrivia EndOfLine(string text) => SyntaxFactory.EndOfLine(text); + public override SyntaxTrivia SingleLineComment(string text) + => SyntaxFactory.Comment("//" + text); + public override SyntaxNode LocalDeclarationStatement(SyntaxNode? type, SyntaxToken name, SyntaxNode? initializer, bool isConst) { return SyntaxFactory.LocalDeclarationStatement( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Simplification/CSharpSimplifierOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Simplification/CSharpSimplifierOptionsProviders.cs new file mode 100644 index 0000000000000..b7a8e7688ef50 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Simplification/CSharpSimplifierOptionsProviders.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.CSharp.Simplification; + +internal static class CSharpSimplifierOptionsProviders +{ + public static async ValueTask GetCSharpSimplifierOptionsAsync(this Document document, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + return new CSharpSimplifierOptions(configOptions); + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/AddImport/AddImportPlacementOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/AddImport/AddImportPlacementOptionsProviders.cs index 44ee410c56294..a429e50635098 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/AddImport/AddImportPlacementOptionsProviders.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/AddImport/AddImportPlacementOptionsProviders.cs @@ -4,21 +4,30 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.AddImport; -internal static partial class AddImportPlacementOptionsProviders +internal static class AddImportPlacementOptionsProviders { - internal static async ValueTask GetAddImportPlacementOptionsAsync(this Document document, IAddImportsService addImportsService, CancellationToken cancellationToken) - { + // Normally we don't allow generation into a hidden region in the file. However, if we have a + // modern span mapper at our disposal, we do allow it as that host span mapper can handle mapping + // our edit to their domain appropriate. + public static bool AllowImportsInHiddenRegions(this Document document) #if CODE_STYLE - var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var configOptions = document.Project.AnalyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree).GetOptionsReader(); - return addImportsService.GetAddImportOptions(configOptions, allowInHiddenRegions: false); + => AddImportPlacementOptions.Default.AllowInHiddenRegions; #else - return await document.GetAddImportPlacementOptionsAsync(cancellationToken).ConfigureAwait(false); + => document.DocumentServiceProvider.GetService()?.SupportsMappingImportDirectives == true; #endif + + public static AddImportPlacementOptions GetAddImportPlacementOptions(this IOptionsReader options, Host.LanguageServices languageServices, bool? allowInHiddenRegions) + => languageServices.GetRequiredService().GetAddImportOptions(options, allowInHiddenRegions ?? AddImportPlacementOptions.Default.AllowInHiddenRegions); + + public static async ValueTask GetAddImportPlacementOptionsAsync(this Document document, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + var service = document.GetRequiredLanguageService(); + return service.GetAddImportOptions(configOptions, document.AllowImportsInHiddenRegions()); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeActions/CodeFixOptionsProvider.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeActions/CodeFixOptionsProvider.cs deleted file mode 100644 index 521f11283500d..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeActions/CodeFixOptionsProvider.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.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; - -namespace Microsoft.CodeAnalysis.CodeActions; - -internal readonly struct CodeFixOptionsProvider(IOptionsReader options, string language) -{ - // LineFormattingOptions - - public string NewLine => GetOption(FormattingOptions2.NewLine); - - public LineFormattingOptions GetLineFormattingOptions() - => options.GetLineFormattingOptions(language); - - // SyntaxFormattingOptions - - public SyntaxFormattingOptions GetFormattingOptions(ISyntaxFormatting formatting) - => formatting.GetFormattingOptions(options); - - public AccessibilityModifiersRequired AccessibilityModifiersRequired => options.GetOptionValue(CodeStyleOptions2.AccessibilityModifiersRequired, language); - - private TValue GetOption(PerLanguageOption2 option) - => options.GetOption(option, language); -} - -internal static class CodeFixOptionsProviders -{ - public static async ValueTask GetCodeFixOptionsAsync(this Document document, CancellationToken cancellationToken) - { - var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - return new CodeFixOptionsProvider(configOptions.GetOptionsReader(), document.Project.Language); - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeCleanup/CodeCleanupOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeCleanup/CodeCleanupOptionsProviders.cs new file mode 100644 index 0000000000000..babba8c1cefbc --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeCleanup/CodeCleanupOptionsProviders.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; + +namespace Microsoft.CodeAnalysis.CodeCleanup; + +internal static class CodeCleanupOptionsProviders +{ + public static CodeCleanupOptions GetCodeCleanupOptions(this IOptionsReader options, LanguageServices languageServices, bool? allowImportsInHiddenRegions = null) + => new() + { + FormattingOptions = options.GetSyntaxFormattingOptions(languageServices), + SimplifierOptions = options.GetSimplifierOptions(languageServices), + AddImportOptions = options.GetAddImportPlacementOptions(languageServices, allowImportsInHiddenRegions), + DocumentFormattingOptions = options.GetDocumentFormattingOptions(), + }; + + public static async ValueTask GetCodeCleanupOptionsAsync(this Document document, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + return configOptions.GetCodeCleanupOptions(document.Project.GetExtendedLanguageServices().LanguageServices, document.AllowImportsInHiddenRegions()); + } + + public static CodeCleanupOptions GetDefault(LanguageServices languageServices) + => new() + { + FormattingOptions = SyntaxFormattingOptionsProviders.GetDefault(languageServices), + SimplifierOptions = SimplifierOptionsProviders.GetDefault(languageServices) + }; +} + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/CodeActionOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/CodeActionOptions.cs deleted file mode 100644 index 2aaecca37662f..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeFixes/CodeActionOptions.cs +++ /dev/null @@ -1,66 +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.Runtime.Serialization; -using Microsoft.CodeAnalysis.CodeCleanup; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; -using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.ImplementType; -using Microsoft.CodeAnalysis.SymbolSearch; - -namespace Microsoft.CodeAnalysis.CodeActions; - -/// -/// Options available to code fixes that are supplied by the IDE (i.e. not stored in editorconfig). -/// -[DataContract] -internal sealed record class CodeActionOptions -{ - public static readonly CodeActionOptions Default = new(); - public static readonly CodeActionOptionsProvider DefaultProvider = Default.CreateProvider(); - -#if !CODE_STYLE - [DataMember] public SymbolSearchOptions SearchOptions { get; init; } = SymbolSearchOptions.Default; - [DataMember] public ImplementTypeOptions ImplementTypeOptions { get; init; } = ImplementTypeOptions.Default; -#endif - public CodeActionOptionsProvider CreateProvider() - => new DelegatingCodeActionOptionsProvider(_ => this); -} - -internal interface CodeActionOptionsProvider -{ - CodeActionOptions GetOptions(LanguageServices languageService); -} - -internal abstract class AbstractCodeActionOptionsProvider : CodeActionOptionsProvider -{ - public abstract CodeActionOptions GetOptions(LanguageServices languageServices); -} - -internal sealed class DelegatingCodeActionOptionsProvider(Func @delegate) : AbstractCodeActionOptionsProvider -{ - public override CodeActionOptions GetOptions(LanguageServices languageService) - => @delegate(languageService); -} - -internal static class CodeActionOptionsProviders -{ - internal static CodeActionOptionsProvider GetOptionsProvider(this CodeFixContext context) -#if CODE_STYLE - => CodeActionOptions.DefaultProvider; -#else - => context.Options; -#endif - -#if CODE_STYLE - internal static CodeActionOptionsProvider GetOptionsProvider(this FixAllContext _) - => CodeActionOptions.DefaultProvider; -#else - internal static CodeActionOptionsProvider GetOptionsProvider(this IFixAllContext context) - => context.State.CodeActionOptionsProvider; -#endif -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService.cs index 0c95e62352596..b3bed594d27ac 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/AbstractCodeGenerationService.cs @@ -6,11 +6,11 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Reflection.Metadata; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.AddImport; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageService; @@ -237,18 +237,14 @@ private async Task GetEditAsync( await FindMostRelevantDeclarationAsync(context.Solution, destination, context.Context.BestLocation, cancellationToken).ConfigureAwait(false); if (destinationDeclaration == null) - { throw new ArgumentException(WorkspaceExtensionsResources.Could_not_find_location_to_generation_symbol_into); - } var destinationTree = destinationDeclaration.SyntaxTree; var oldDocument = context.Solution.GetRequiredDocument(destinationTree); -#if CODE_STYLE - var codeGenOptions = CodeGenerationOptions.CommonDefaults; -#else + var codeGenOptions = await oldDocument.GetCodeGenerationOptionsAsync(cancellationToken).ConfigureAwait(false); -#endif var info = GetInfo(context.Context, codeGenOptions, destinationDeclaration.SyntaxTree.Options); + var transformedDeclaration = declarationTransform(destinationDeclaration, info, availableIndices, cancellationToken); var root = await destinationTree.GetRootAsync(cancellationToken).ConfigureAwait(false); @@ -256,13 +252,17 @@ private async Task GetEditAsync( var newDocument = oldDocument.WithSyntaxRoot(currentRoot); -#if !CODE_STYLE if (context.Context.AddImports) { var addImportsOptions = await newDocument.GetAddImportPlacementOptionsAsync(cancellationToken).ConfigureAwait(false); - newDocument = await ImportAdder.AddImportsFromSymbolAnnotationAsync(newDocument, addImportsOptions, cancellationToken).ConfigureAwait(false); + var service = newDocument.GetRequiredLanguageService(); + newDocument = await service.AddImportsAsync( + newDocument, + [currentRoot.FullSpan], + ImportAdderService.Strategy.AddImportsFromSymbolAnnotations, + addImportsOptions, + cancellationToken).ConfigureAwait(false); } -#endif return newDocument; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CleanCodeGenerationOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CleanCodeGenerationOptions.cs similarity index 83% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CleanCodeGenerationOptions.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CleanCodeGenerationOptions.cs index 1acef75129fa3..eba41e6db113d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CodeGeneration/CleanCodeGenerationOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CleanCodeGenerationOptions.cs @@ -6,11 +6,7 @@ using System.Threading; 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; @@ -23,26 +19,23 @@ internal readonly record struct CleanCodeGenerationOptions [DataMember] public required CodeCleanupOptions CleanupOptions { get; init; } -#if !CODE_STYLE - public static CleanCodeGenerationOptions GetDefault(LanguageServices languageServices) - => new() - { - GenerationOptions = CodeGenerationOptions.GetDefault(languageServices), - CleanupOptions = CodeCleanupOptions.GetDefault(languageServices) - }; - public CodeAndImportGenerationOptions CodeAndImportGenerationOptions => new() { GenerationOptions = GenerationOptions, AddImportOptions = CleanupOptions.AddImportOptions }; -#endif } -#if !CODE_STYLE internal static class CleanCodeGenerationOptionsProviders { + public static CleanCodeGenerationOptions GetDefault(LanguageServices languageServices) + => new() + { + GenerationOptions = CodeGenerationOptionsProviders.GetDefault(languageServices), + CleanupOptions = CodeCleanupOptionsProviders.GetDefault(languageServices) + }; + public static async ValueTask GetCleanCodeGenerationOptionsAsync(this Document document, CancellationToken cancellationToken) => new() { @@ -50,4 +43,3 @@ public static async ValueTask GetCleanCodeGeneration CleanupOptions = await document.GetCodeCleanupOptionsAsync(cancellationToken).ConfigureAwait(false) }; } -#endif diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeAndImportGenerationOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeAndImportGenerationOptionsProviders.cs new file mode 100644 index 0000000000000..6123361bdd32c --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeAndImportGenerationOptionsProviders.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.CodeGeneration; + +internal static class CodeAndImportGenerationOptionsProviders +{ + internal static CodeAndImportGenerationOptions GetDefault(LanguageServices languageServices) + => new() + { + GenerationOptions = CodeGenerationOptionsProviders.GetDefault(languageServices), + AddImportOptions = AddImportPlacementOptions.Default + }; +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationOptionsProviders.cs new file mode 100644 index 0000000000000..c305e949c7a4e --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerationOptionsProviders.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CodeGeneration; + +internal static class CodeGenerationOptionsProviders +{ + public static CodeGenerationOptions GetCodeGenerationOptions(this IOptionsReader options, LanguageServices languageServices) + => languageServices.GetRequiredService().GetCodeGenerationOptions(options); + + public static CodeAndImportGenerationOptions GetCodeAndImportGenerationOptions(this IOptionsReader options, LanguageServices languageServices, bool? allowImportsInHiddenRegions = null) + => new() + { + GenerationOptions = options.GetCodeGenerationOptions(languageServices), + AddImportOptions = options.GetAddImportPlacementOptions(languageServices, allowImportsInHiddenRegions) + }; + + public static CleanCodeGenerationOptions GetCleanCodeGenerationOptions(this IOptionsReader options, LanguageServices languageServices, bool? allowImportsInHiddenRegions = null) + => new() + { + GenerationOptions = options.GetCodeGenerationOptions(languageServices), + CleanupOptions = options.GetCodeCleanupOptions(languageServices, allowImportsInHiddenRegions) + }; + + public static async ValueTask GetCodeGenerationOptionsAsync(this Document document, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + return configOptions.GetCodeGenerationOptions(document.Project.GetExtendedLanguageServices().LanguageServices); + } + + public static async ValueTask GetCodeGenerationInfoAsync(this Document document, CodeGenerationContext context, CancellationToken cancellationToken) + { + Contract.ThrowIfNull(document.Project.ParseOptions); + + var options = await GetCodeGenerationOptionsAsync(document, cancellationToken).ConfigureAwait(false); + var service = document.GetRequiredLanguageService(); + return service.GetInfo(context, options, document.Project.ParseOptions); + } + + public static CodeGenerationOptions GetDefault(LanguageServices languageServices) + => languageServices.GetRequiredService().DefaultOptions; +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerator.cs index 8274ff6f918c9..312998cb290d1 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/CodeGenerator.cs @@ -20,75 +20,75 @@ internal static class CodeGenerator /// public static readonly SyntaxAnnotation Annotation = new(nameof(CodeGenerator)); - private static ICodeGenerationService GetCodeGenerationService(SolutionServices services, string language) - => services.GetLanguageServices(language).GetRequiredService(); + private static ICodeGenerationService GetCodeGenerationService(HostWorkspaceServices services, string language) + => services.GetExtendedLanguageServices(language).GetRequiredService(); /// /// Create a new solution where the declaration of the destination symbol has an additional event of the same signature as the specified event symbol. /// Returns the document in the new solution where the destination symbol is declared. /// public static Task AddEventDeclarationAsync(CodeGenerationSolutionContext context, INamedTypeSymbol destination, IEventSymbol @event, CancellationToken cancellationToken) - => GetCodeGenerationService(context.Solution.Services, destination.Language).AddEventAsync(context, destination, @event, cancellationToken); + => GetCodeGenerationService(context.Solution.Workspace.Services, destination.Language).AddEventAsync(context, destination, @event, cancellationToken); /// /// Create a new solution where the declaration of the destination symbol has an additional field of the same signature as the specified field symbol. /// Returns the document in the new solution where the destination symbol is declared. /// public static Task AddFieldDeclarationAsync(CodeGenerationSolutionContext context, INamedTypeSymbol destination, IFieldSymbol field, CancellationToken cancellationToken) - => GetCodeGenerationService(context.Solution.Services, destination.Language).AddFieldAsync(context, destination, field, cancellationToken); + => GetCodeGenerationService(context.Solution.Workspace.Services, destination.Language).AddFieldAsync(context, destination, field, cancellationToken); /// /// Create a new solution where the declaration of the destination symbol has an additional method of the same signature as the specified method symbol. /// Returns the document in the new solution where the destination symbol is declared. /// public static Task AddMethodDeclarationAsync(CodeGenerationSolutionContext context, INamedTypeSymbol destination, IMethodSymbol method, CancellationToken cancellationToken) - => GetCodeGenerationService(context.Solution.Services, destination.Language).AddMethodAsync(context, destination, method, cancellationToken); + => GetCodeGenerationService(context.Solution.Workspace.Services, destination.Language).AddMethodAsync(context, destination, method, cancellationToken); /// /// Create a new solution where the declaration of the destination symbol has an additional property of the same signature as the specified property symbol. /// Returns the document in the new solution where the destination symbol is declared. /// public static Task AddPropertyDeclarationAsync(CodeGenerationSolutionContext context, INamedTypeSymbol destination, IPropertySymbol property, CancellationToken cancellationToken) - => GetCodeGenerationService(context.Solution.Services, destination.Language).AddPropertyAsync(context, destination, property, cancellationToken); + => GetCodeGenerationService(context.Solution.Workspace.Services, destination.Language).AddPropertyAsync(context, destination, property, cancellationToken); /// /// Create a new solution where the declaration of the destination symbol has an additional named type of the same signature as the specified named type symbol. /// Returns the document in the new solution where the destination symbol is declared. /// public static Task AddNamedTypeDeclarationAsync(CodeGenerationSolutionContext context, INamedTypeSymbol destination, INamedTypeSymbol namedType, CancellationToken cancellationToken) - => GetCodeGenerationService(context.Solution.Services, destination.Language).AddNamedTypeAsync(context, destination, namedType, cancellationToken); + => GetCodeGenerationService(context.Solution.Workspace.Services, destination.Language).AddNamedTypeAsync(context, destination, namedType, cancellationToken); /// /// Create a new solution where the declaration of the destination symbol has an additional named type of the same signature as the specified named type symbol. /// Returns the document in the new solution where the destination symbol is declared. /// public static Task AddNamedTypeDeclarationAsync(CodeGenerationSolutionContext context, INamespaceSymbol destination, INamedTypeSymbol namedType, CancellationToken cancellationToken) - => GetCodeGenerationService(context.Solution.Services, destination.Language).AddNamedTypeAsync(context, destination, namedType, cancellationToken); + => GetCodeGenerationService(context.Solution.Workspace.Services, destination.Language).AddNamedTypeAsync(context, destination, namedType, cancellationToken); /// /// Create a new solution where the declaration of the destination symbol has an additional namespace of the same signature as the specified namespace symbol. /// Returns the document in the new solution where the destination symbol is declared. /// public static Task AddNamespaceDeclarationAsync(CodeGenerationSolutionContext context, INamespaceSymbol destination, INamespaceSymbol @namespace, CancellationToken cancellationToken) - => GetCodeGenerationService(context.Solution.Services, destination.Language).AddNamespaceAsync(context, destination, @namespace, cancellationToken); + => GetCodeGenerationService(context.Solution.Workspace.Services, destination.Language).AddNamespaceAsync(context, destination, @namespace, cancellationToken); /// /// Create a new solution where the declaration of the destination symbol has an additional namespace or type of the same signature as the specified namespace or type symbol. /// Returns the document in the new solution where the destination symbol is declared. /// public static Task AddNamespaceOrTypeDeclarationAsync(CodeGenerationSolutionContext context, INamespaceSymbol destination, INamespaceOrTypeSymbol namespaceOrType, CancellationToken cancellationToken) - => GetCodeGenerationService(context.Solution.Services, destination.Language).AddNamespaceOrTypeAsync(context, destination, namespaceOrType, cancellationToken); + => GetCodeGenerationService(context.Solution.Workspace.Services, destination.Language).AddNamespaceOrTypeAsync(context, destination, namespaceOrType, cancellationToken); /// /// Create a new solution where the declaration of the destination symbol has additional members of the same signature as the specified member symbols. /// Returns the document in the new solution where the destination symbol is declared. /// public static Task AddMemberDeclarationsAsync(CodeGenerationSolutionContext context, INamedTypeSymbol destination, IEnumerable members, CancellationToken cancellationToken) - => GetCodeGenerationService(context.Solution.Services, destination.Language).AddMembersAsync(context, destination, members, cancellationToken); + => GetCodeGenerationService(context.Solution.Workspace.Services, destination.Language).AddMembersAsync(context, destination, members, cancellationToken); /// /// Returns true if additional declarations can be added to the destination symbol's declaration. /// public static bool CanAdd(Solution solution, ISymbol destination, CancellationToken cancellationToken) - => GetCodeGenerationService(solution.Services, destination.Language).CanAddTo(destination, solution, cancellationToken); + => GetCodeGenerationService(solution.Workspace.Services, destination.Language).CanAddTo(destination, solution, cancellationToken); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationArrayTypeSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationArrayTypeSymbol.cs index 812ee819a8c13..608cfae4caa33 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationArrayTypeSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationArrayTypeSymbol.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationArrayTypeSymbol(ITypeSymbol elementType, int rank, NullableAnnotation nullableAnnotation) : CodeGenerationTypeSymbol(null, null, default, Accessibility.NotApplicable, default, string.Empty, SpecialType.None, nullableAnnotation), IArrayTypeSymbol +internal sealed class CodeGenerationArrayTypeSymbol(ITypeSymbol elementType, int rank, NullableAnnotation nullableAnnotation) : CodeGenerationTypeSymbol(null, null, default, Accessibility.NotApplicable, default, string.Empty, SpecialType.None, nullableAnnotation), IArrayTypeSymbol { public ITypeSymbol ElementType { get; } = elementType; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationAttributeData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationAttributeData.cs index f0415b9e9c500..0661a730d858a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationAttributeData.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationAttributeData.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationAttributeData( +internal sealed class CodeGenerationAttributeData( INamedTypeSymbol attributeClass, ImmutableArray constructorArguments, ImmutableArray> namedArguments) : AttributeData diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs index 383216df0c13b..8f52e9fa3f04f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationConstructedMethodSymbol : CodeGenerationAbstractMethodSymbol +internal sealed class CodeGenerationConstructedMethodSymbol : CodeGenerationAbstractMethodSymbol { private readonly CodeGenerationAbstractMethodSymbol _constructedFrom; private readonly ImmutableArray _typeArguments; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedNamedTypeSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedNamedTypeSymbol.cs index 614dc1cdc54ca..820b1072c34ce 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedNamedTypeSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructedNamedTypeSymbol.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationConstructedNamedTypeSymbol : CodeGenerationAbstractNamedTypeSymbol +internal sealed class CodeGenerationConstructedNamedTypeSymbol : CodeGenerationAbstractNamedTypeSymbol { private readonly CodeGenerationNamedTypeSymbol _constructedFrom; private readonly ImmutableArray _typeArguments; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorInfo.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorInfo.cs index b5419bc7ff690..6283e6b97d72a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorInfo.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorInfo.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationConstructorInfo +internal sealed class CodeGenerationConstructorInfo { private static readonly ConditionalWeakTable s_constructorToInfoMap = new(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs index ca25e37906429..5f81a1a3fdbf7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationConstructorSymbol( +internal sealed class CodeGenerationConstructorSymbol( INamedTypeSymbol containingType, ImmutableArray attributes, Accessibility accessibility, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs index 86836a70163a2..e904c5103815c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationConversionSymbol( +internal sealed class CodeGenerationConversionSymbol( INamedTypeSymbol containingType, ImmutableArray attributes, Accessibility declaredAccessibility, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorInfo.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorInfo.cs index 4fac4273b1026..4efb6a85e9062 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorInfo.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorInfo.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationDestructorInfo +internal sealed class CodeGenerationDestructorInfo { private static readonly ConditionalWeakTable s_destructorToInfoMap = new(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs index 83169b3093bb9..419834acf4327 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationDestructorSymbol( +internal sealed class CodeGenerationDestructorSymbol( INamedTypeSymbol containingType, ImmutableArray attributes) : CodeGenerationMethodSymbol(containingType, attributes, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventInfo.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventInfo.cs index ad5a66c70af51..18c41c0c4535c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventInfo.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventInfo.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationEventInfo +internal sealed class CodeGenerationEventInfo { private static readonly ConditionalWeakTable s_eventToInfoMap = new(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs index 5a3299f7bb242..bc60a6bfd6e10 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationEventSymbol.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationEventSymbol( +internal sealed class CodeGenerationEventSymbol( INamedTypeSymbol? containingType, ImmutableArray attributes, Accessibility declaredAccessibility, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationFieldInfo.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationFieldInfo.cs index d9e2435ba26fd..0bb6754c8fbcf 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationFieldInfo.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationFieldInfo.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationFieldInfo +internal sealed class CodeGenerationFieldInfo { private static readonly ConditionalWeakTable s_fieldToInfoMap = new(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs index 6989d32f74e0e..c888a0582895d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationFieldSymbol( +internal sealed class CodeGenerationFieldSymbol( INamedTypeSymbol containingType, ImmutableArray attributes, Accessibility accessibility, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationMethodInfo.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationMethodInfo.cs index 69d96dd20662c..600279ce26914 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationMethodInfo.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationMethodInfo.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationMethodInfo +internal sealed class CodeGenerationMethodInfo { private static readonly ConditionalWeakTable s_methodToInfoMap = new(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamedTypeSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamedTypeSymbol.cs index 390e1cca6a28e..3b16804a7844d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamedTypeSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamedTypeSymbol.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationNamedTypeSymbol : CodeGenerationAbstractNamedTypeSymbol +internal sealed class CodeGenerationNamedTypeSymbol : CodeGenerationAbstractNamedTypeSymbol { private readonly ImmutableArray _typeParameters; private readonly ImmutableArray _interfaces; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceInfo.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceInfo.cs index 5b61c1cca86ff..663ecc773475d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceInfo.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceInfo.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationNamespaceInfo +internal sealed class CodeGenerationNamespaceInfo { private static readonly ConditionalWeakTable s_namespaceToInfoMap = new(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceSymbol.cs index d30143b13f760..f8d0224f0f4bd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationNamespaceSymbol.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationNamespaceSymbol(string name, IList members) : CodeGenerationNamespaceOrTypeSymbol(null, null, default, Accessibility.NotApplicable, default, name), INamespaceSymbol +internal sealed class CodeGenerationNamespaceSymbol(string name, IList members) : CodeGenerationNamespaceOrTypeSymbol(null, null, default, Accessibility.NotApplicable, default, name), INamespaceSymbol { private readonly IList _members = members ?? SpecializedCollections.EmptyList(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs index fb1f46b4dff21..6817aed1e15c7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationOperatorSymbol( +internal sealed class CodeGenerationOperatorSymbol( INamedTypeSymbol containingType, ImmutableArray attributes, Accessibility accessibility, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationParameterSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationParameterSymbol.cs index 01b40df92c2ba..6b3d2911d8a35 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationParameterSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationParameterSymbol.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationParameterSymbol( +internal sealed class CodeGenerationParameterSymbol( INamedTypeSymbol containingType, ImmutableArray attributes, RefKind refKind, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPointerTypeSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPointerTypeSymbol.cs index 9732803c48700..6763045f6ca9d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPointerTypeSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPointerTypeSymbol.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationPointerTypeSymbol(ITypeSymbol pointedAtType) : CodeGenerationTypeSymbol(null, null, default, Accessibility.NotApplicable, default, string.Empty, SpecialType.None, NullableAnnotation.None), IPointerTypeSymbol +internal sealed class CodeGenerationPointerTypeSymbol(ITypeSymbol pointedAtType) : CodeGenerationTypeSymbol(null, null, default, Accessibility.NotApplicable, default, string.Empty, SpecialType.None, NullableAnnotation.None), IPointerTypeSymbol { public ITypeSymbol PointedAtType { get; } = pointedAtType; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPropertyInfo.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPropertyInfo.cs index db9c073443d6f..e5ff16a00f310 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPropertyInfo.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPropertyInfo.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationPropertyInfo +internal sealed class CodeGenerationPropertyInfo { private static readonly ConditionalWeakTable s_propertyToInfoMap = new(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs index 361647a0027d9..4f013a06b8a4e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs @@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationPropertySymbol( +internal sealed class CodeGenerationPropertySymbol( INamedTypeSymbol containingType, ImmutableArray attributes, Accessibility declaredAccessibility, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationTypeParameterSymbol.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationTypeParameterSymbol.cs index b97e71d3c3ac5..0a5941bbd6564 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationTypeParameterSymbol.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/Symbols/CodeGenerationTypeParameterSymbol.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class CodeGenerationTypeParameterSymbol( +internal sealed class CodeGenerationTypeParameterSymbol( INamedTypeSymbol containingType, ImmutableArray attributes, VarianceKind varianceKind, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/TypeGenerator.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/TypeGenerator.cs index 9e04c0e0a80e5..25b232e7cba32 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/TypeGenerator.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeGeneration/TypeGenerator.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration; -internal class TypeGenerator : ITypeGenerator +internal sealed class TypeGenerator : ITypeGenerator { public TypeGenerator() { diff --git a/src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/AbstractRefactoringHelpersService.cs similarity index 99% rename from src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/AbstractRefactoringHelpersService.cs index 193ef0fcbb8ed..2372d41935977 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AbstractRefactoringHelpersService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/AbstractRefactoringHelpersService.cs @@ -523,7 +523,7 @@ private static void AddNodesDeepIn( // -> can simply FindToken -> proceed testing its ancestors var root = document.Root; if (root is null) - throw new NotSupportedException(WorkspacesResources.Document_does_not_support_syntax_trees); + throw new NotSupportedException(WorkspaceExtensionsResources.Document_does_not_support_syntax_trees); var token = root.FindTokenOnRightOfPosition(position, true); diff --git a/src/Features/Core/Portable/CodeRefactoringHelpers.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/CodeRefactoringHelpers.cs similarity index 100% rename from src/Features/Core/Portable/CodeRefactoringHelpers.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/CodeRefactoringHelpers.cs diff --git a/src/Features/Core/Portable/CodeRefactorings/IRefactoringHelpersService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/IRefactoringHelpersService.cs similarity index 100% rename from src/Features/Core/Portable/CodeRefactorings/IRefactoringHelpersService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/CodeRefactorings/IRefactoringHelpersService.cs diff --git a/src/Workspaces/Core/Portable/Editing/ImportAdderService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Editing/ImportAdderService.cs similarity index 98% rename from src/Workspaces/Core/Portable/Editing/ImportAdderService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Editing/ImportAdderService.cs index 5b13036e05388..b836a2d0d8f01 100644 --- a/src/Workspaces/Core/Portable/Editing/ImportAdderService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Editing/ImportAdderService.cs @@ -174,7 +174,12 @@ private async Task AddImportDirectivesFromSymbolAnnotationsAsync( using var _ = PooledDictionary.GetInstance(out var importToSyntax); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + +#if CODE_STYLE + var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); +#else var model = await document.GetRequiredNullableDisabledSemanticModelAsync(cancellationToken).ConfigureAwait(false); +#endif SyntaxNode? first = null, last = null; var annotatedNodes = syntaxNodes.Where(x => x.HasAnnotations(SymbolAnnotation.Kind)); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/DocumentExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/DocumentExtensions.cs index d7d5fa8da2911..5373096393005 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/DocumentExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/DocumentExtensions.cs @@ -15,6 +15,9 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; +using Microsoft.CodeAnalysis.CodeStyle; #if DEBUG using System.Collections.Immutable; @@ -222,10 +225,10 @@ public static IEnumerable GetLinkedDocuments(this Document document) } #if CODE_STYLE - public static async ValueTask GetAnalyzerConfigOptionsAsync(this Document document, CancellationToken cancellationToken) + public static async ValueTask GetAnalyzerConfigOptionsAsync(this Document document, CancellationToken cancellationToken) { var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - return document.Project.AnalyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree); + return document.Project.AnalyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree).GetOptionsReader(); } #endif } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IMethodSymbolExtensions.cs new file mode 100644 index 0000000000000..4032634ac146a --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IMethodSymbolExtensions.cs @@ -0,0 +1,178 @@ +// 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.Diagnostics.CodeAnalysis; +using System.Linq; +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.LanguageService; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Shared.Extensions; + +internal static partial class IMethodSymbolExtensions +{ + public static IMethodSymbol EnsureNonConflictingNames( + this IMethodSymbol method, INamedTypeSymbol containingType, ISyntaxFactsService syntaxFacts) + { + // The method's type parameters may conflict with the type parameters in the type + // we're generating into. In that case, rename them. + var parameterNames = NameGenerator.EnsureUniqueness( + method.Parameters.SelectAsArray(p => p.Name), isCaseSensitive: syntaxFacts.IsCaseSensitive); + + var outerTypeParameterNames = + containingType.GetAllTypeParameters() + .Select(tp => tp.Name) + .Concat(method.Name) + .Concat(containingType.Name); + + var unusableNames = parameterNames.Concat(outerTypeParameterNames).ToSet( + syntaxFacts.IsCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase); + + var newTypeParameterNames = NameGenerator.EnsureUniqueness( + method.TypeParameters.SelectAsArray(tp => tp.Name), + n => !unusableNames.Contains(n)); + + var updatedMethod = method.RenameTypeParameters(newTypeParameterNames); + return updatedMethod.RenameParameters(parameterNames); + } + + public static IMethodSymbol RenameTypeParameters(this IMethodSymbol method, ImmutableArray newNames) + { + if (method.TypeParameters.Select(t => t.Name).SequenceEqual(newNames)) + { + return method; + } + + var typeGenerator = new TypeGenerator(); + var updatedTypeParameters = RenameTypeParameters( + method.TypeParameters, newNames, typeGenerator); + + var mapping = new Dictionary(SymbolEqualityComparer.Default); + for (var i = 0; i < method.TypeParameters.Length; i++) + { + mapping[method.TypeParameters[i]] = updatedTypeParameters[i]; + } + + return CodeGenerationSymbolFactory.CreateMethodSymbol( + method.ContainingType, + method.GetAttributes(), + method.DeclaredAccessibility, + method.GetSymbolModifiers(), + method.ReturnType.SubstituteTypes(mapping, typeGenerator), + method.RefKind, + method.ExplicitInterfaceImplementations, + method.Name, + updatedTypeParameters, + method.Parameters.SelectAsArray(p => + CodeGenerationSymbolFactory.CreateParameterSymbol(p.GetAttributes(), p.RefKind, p.IsParams, p.Type.SubstituteTypes(mapping, typeGenerator), p.Name, p.IsOptional, + p.HasExplicitDefaultValue, p.HasExplicitDefaultValue ? p.ExplicitDefaultValue : null))); + } + + public static IMethodSymbol RenameParameters( + this IMethodSymbol method, ImmutableArray parameterNames) + { + var parameterList = method.Parameters; + if (parameterList.Select(p => p.Name).SequenceEqual(parameterNames)) + { + return method; + } + + var parameters = parameterList.RenameParameters(parameterNames); + + return CodeGenerationSymbolFactory.CreateMethodSymbol( + method.ContainingType, + method.GetAttributes(), + method.DeclaredAccessibility, + method.GetSymbolModifiers(), + method.ReturnType, + method.RefKind, + method.ExplicitInterfaceImplementations, + method.Name, + method.TypeParameters, + parameters); + } + + private static ImmutableArray RenameTypeParameters( + ImmutableArray typeParameters, + ImmutableArray newNames, + ITypeGenerator typeGenerator) + { + // We generate the type parameter in two passes. The first creates the new type + // parameter. The second updates the constraints to point at this new type parameter. + var newTypeParameters = new List(); + + var mapping = new Dictionary(SymbolEqualityComparer.Default); + for (var i = 0; i < typeParameters.Length; i++) + { + var typeParameter = typeParameters[i]; + + var newTypeParameter = new CodeGenerationTypeParameterSymbol( + typeParameter.ContainingType, + typeParameter.GetAttributes(), + typeParameter.Variance, + newNames[i], + typeParameter.NullableAnnotation, + typeParameter.ConstraintTypes, + typeParameter.HasConstructorConstraint, + typeParameter.HasReferenceTypeConstraint, + typeParameter.HasValueTypeConstraint, + typeParameter.HasUnmanagedTypeConstraint, + typeParameter.HasNotNullConstraint, + typeParameter.AllowsRefLikeType, + typeParameter.Ordinal); + + newTypeParameters.Add(newTypeParameter); + mapping[typeParameter] = newTypeParameter; + } + + // Now we update the constraints. + foreach (var newTypeParameter in newTypeParameters) + { + newTypeParameter.ConstraintTypes = ImmutableArray.CreateRange(newTypeParameter.ConstraintTypes, t => t.SubstituteTypes(mapping, typeGenerator)); + } + + return newTypeParameters.Cast().ToImmutableArray(); + } + + public static IMethodSymbol RemoveInaccessibleAttributesAndAttributesOfTypes( + this IMethodSymbol method, ISymbol accessibleWithin, + params INamedTypeSymbol[] removeAttributeTypes) + { + // Many static predicates use the same state argument in this method + var arg = (removeAttributeTypes, accessibleWithin); + + var methodHasAttribute = method.GetAttributes().Any(shouldRemoveAttribute, arg); + + var someParameterHasAttribute = method.Parameters + .Any(static (m, arg) => m.GetAttributes().Any(shouldRemoveAttribute, arg), arg); + + var returnTypeHasAttribute = method.GetReturnTypeAttributes().Any(shouldRemoveAttribute, arg); + + if (!methodHasAttribute && !someParameterHasAttribute && !returnTypeHasAttribute) + { + return method; + } + + return CodeGenerationSymbolFactory.CreateMethodSymbol( + method, + containingType: method.ContainingType, + explicitInterfaceImplementations: method.ExplicitInterfaceImplementations, + attributes: method.GetAttributes().WhereAsArray(static (a, arg) => !shouldRemoveAttribute(a, arg), arg), + parameters: method.Parameters.SelectAsArray(static (p, arg) => + CodeGenerationSymbolFactory.CreateParameterSymbol( + p.GetAttributes().WhereAsArray(static (a, arg) => !shouldRemoveAttribute(a, arg), arg), + p.RefKind, p.IsParams, p.Type, p.Name, p.IsOptional, + p.HasExplicitDefaultValue, p.HasExplicitDefaultValue ? p.ExplicitDefaultValue : null), arg), + returnTypeAttributes: method.GetReturnTypeAttributes().WhereAsArray(static (a, arg) => !shouldRemoveAttribute(a, arg), arg)); + + static bool shouldRemoveAttribute(AttributeData a, (INamedTypeSymbol[] removeAttributeTypes, ISymbol accessibleWithin) arg) + => arg.removeAttributeTypes.Any(attr => attr.Equals(a.AttributeClass)) || + a.AttributeClass?.IsAccessibleWithin(arg.accessibleWithin) == false; + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IParameterSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IParameterSymbolExtensions.cs new file mode 100644 index 0000000000000..0e1873f9f9fbb --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IParameterSymbolExtensions.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.CodeGeneration; + +namespace Microsoft.CodeAnalysis.Shared.Extensions; + +internal static partial class IParameterSymbolExtensions +{ + public static ImmutableArray RenameParameters(this IList parameters, ImmutableArray parameterNames) + { + var result = new FixedSizeArrayBuilder(parameters.Count); + for (var i = 0; i < parameterNames.Length; i++) + result.Add(parameters[i].RenameParameter(parameterNames[i])); + + return result.MoveToImmutable(); + } + + public static IParameterSymbol RenameParameter(this IParameterSymbol parameter, string parameterName) + { + return parameter.Name == parameterName + ? parameter + : CodeGenerationSymbolFactory.CreateParameterSymbol( + parameter.GetAttributes(), + parameter.RefKind, + parameter.IsParams, + parameter.Type, + parameterName, + parameter.IsOptional, + parameter.HasExplicitDefaultValue, + parameter.HasExplicitDefaultValue ? parameter.ExplicitDefaultValue : null); + } +} diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/IPropertySymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IPropertySymbolExtensions.cs similarity index 100% rename from src/Workspaces/Core/Portable/Shared/Extensions/IPropertySymbolExtensions.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/IPropertySymbolExtensions.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ITypeSymbolExtensions.cs deleted file mode 100644 index 33a03578e4007..0000000000000 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ITypeSymbolExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; - -namespace Microsoft.CodeAnalysis.Shared.Extensions; - -internal static partial class ITypeSymbolExtensions -{ - public static IList GetReferencedMethodTypeParameters( - this ITypeSymbol? type, IList? result = null) - { - result ??= []; - type?.Accept(new CollectTypeParameterSymbolsVisitor(result, onlyMethodTypeParameters: true)); - return result; - } - - public static IList GetReferencedTypeParameters( - this ITypeSymbol? type, IList? result = null) - { - result ??= []; - type?.Accept(new CollectTypeParameterSymbolsVisitor(result, onlyMethodTypeParameters: false)); - return result; - } -} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ProjectExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ProjectExtensions.cs index 2c00001dec6de..13a9669003389 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ProjectExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ProjectExtensions.cs @@ -39,6 +39,7 @@ public static HostLanguageServices GetExtendedLanguageServices(this Project proj #else => project.Solution.Services.GetExtendedLanguageServices(project.Language); #endif + #pragma warning restore RS0030 // Do not used banned APIs public static string? TryGetAnalyzerConfigPathForProjectConfiguration(this Project project) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs index 224eef7fde58f..e1dd24c448120 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions.cs @@ -2,14 +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. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.Shared.Extensions; internal static partial class SyntaxGeneratorExtensions @@ -86,4 +94,360 @@ private static ITypeSymbol GetType(Compilation compilation, ISymbol symbol) public static SyntaxNode IsPatternExpression(this SyntaxGeneratorInternal generator, SyntaxNode expression, SyntaxNode pattern) => generator.IsPatternExpression(expression, isToken: default, pattern); + + /// + /// Generates a call to a method *through* an existing field or property symbol. + /// + /// + public static SyntaxNode GenerateDelegateThroughMemberStatement( + this SyntaxGenerator generator, IMethodSymbol method, ISymbol throughMember) + { + var through = generator.MemberAccessExpression( + CreateDelegateThroughExpression(generator, method, throughMember), + method.IsGenericMethod + ? generator.GenericName(method.Name, method.TypeArguments) + : generator.IdentifierName(method.Name)); + + var invocationExpression = generator.InvocationExpression(through, generator.CreateArguments(method.Parameters)); + return method.ReturnsVoid + ? generator.ExpressionStatement(invocationExpression) + : generator.ReturnStatement(invocationExpression); + } + + public static SyntaxNode CreateDelegateThroughExpression( + this SyntaxGenerator generator, ISymbol member, ISymbol throughMember) + { + var name = generator.IdentifierName(throughMember.Name); + var through = throughMember.IsStatic + ? GenerateContainerName(generator, throughMember) + // If we're delegating through a primary constructor parameter, we cannot qualify the name at all. + : throughMember is IParameterSymbol + ? null + : generator.ThisExpression(); + + through = through is null ? name : generator.MemberAccessExpression(through, name); + + var throughMemberType = throughMember.GetMemberType(); + if (throughMemberType != null && + member.ContainingType is { TypeKind: TypeKind.Interface } interfaceBeingImplemented) + { + // In the case of 'implement interface through field / property', we need to know what + // interface we are implementing so that we can insert casts to this interface on every + // usage of the field in the generated code. Without these casts we would end up generating + // code that fails compilation in certain situations. + // + // For example consider the following code. + // class C : IReadOnlyList { int[] field; } + // When applying the 'implement interface through field' code fix in the above example, + // we need to generate the following code to implement the Count property on IReadOnlyList + // class C : IReadOnlyList { int[] field; int Count { get { ((IReadOnlyList)field).Count; } ...} + // as opposed to the following code which will fail to compile (because the array field + // doesn't have a property named .Count) - + // class C : IReadOnlyList { int[] field; int Count { get { field.Count; } ...} + // + // The 'InterfaceTypes' property on the state object always contains only one item + // in the case of C# i.e. it will contain exactly the interface we are trying to implement. + // This is also the case most of the time in the case of VB, except in certain error conditions + // (recursive / circular cases) where the span of the squiggle for the corresponding + // diagnostic (BC30149) changes and 'InterfaceTypes' ends up including all interfaces + // in the Implements clause. For the purposes of inserting the above cast, we ignore the + // uncommon case and optimize for the common one - in other words, we only apply the cast + // in cases where we can unambiguously figure out which interface we are trying to implement. + if (!throughMemberType.Equals(interfaceBeingImplemented)) + { + through = generator.CastExpression(interfaceBeingImplemented, + through.WithAdditionalAnnotations(Simplifier.Annotation)); + } + else if (throughMember is IPropertySymbol { IsStatic: false, ExplicitInterfaceImplementations: [var explicitlyImplementedProperty, ..] }) + { + // If we are implementing through an explicitly implemented property, we need to cast 'this' to + // the explicitly implemented interface type before calling the member, as in: + // ((IA)this).Prop.Member(); + // + var explicitImplementationCast = generator.CastExpression( + explicitlyImplementedProperty.ContainingType, + generator.ThisExpression()); + + through = generator.MemberAccessExpression(explicitImplementationCast, + generator.IdentifierName(explicitlyImplementedProperty.Name)); + + through = through.WithAdditionalAnnotations(Simplifier.Annotation); + } + } + + return through.WithAdditionalAnnotations(Simplifier.Annotation); + + // local functions + + static SyntaxNode GenerateContainerName(SyntaxGenerator factory, ISymbol throughMember) + { + var classOrStructType = throughMember.ContainingType; + return classOrStructType.IsGenericType + ? factory.GenericName(classOrStructType.Name, classOrStructType.TypeArguments) + : factory.IdentifierName(classOrStructType.Name); + } + } + + public static ImmutableArray GetGetAccessorStatements( + this SyntaxGenerator generator, Compilation compilation, + IPropertySymbol property, ISymbol? throughMember, bool preferAutoProperties) + { + if (throughMember != null) + { + var throughExpression = CreateDelegateThroughExpression(generator, property, throughMember); + var expression = property.IsIndexer + ? throughExpression + : generator.MemberAccessExpression( + throughExpression, generator.IdentifierName(property.Name)); + + if (property.Parameters.Length > 0) + { + var arguments = generator.CreateArguments(property.Parameters); + expression = generator.ElementAccessExpression(expression, arguments); + } + + return [generator.ReturnStatement(expression)]; + } + + return preferAutoProperties ? default : generator.CreateThrowNotImplementedStatementBlock(compilation); + } + + public static ImmutableArray GetSetAccessorStatements( + this SyntaxGenerator generator, Compilation compilation, + IPropertySymbol property, ISymbol? throughMember, bool preferAutoProperties) + { + if (throughMember != null) + { + var throughExpression = CreateDelegateThroughExpression(generator, property, throughMember); + var expression = property.IsIndexer + ? throughExpression + : generator.MemberAccessExpression( + throughExpression, generator.IdentifierName(property.Name)); + + if (property.Parameters.Length > 0) + { + var arguments = generator.CreateArguments(property.Parameters); + expression = generator.ElementAccessExpression(expression, arguments); + } + + expression = generator.AssignmentStatement(expression, generator.IdentifierName("value")); + + return [generator.ExpressionStatement(expression)]; + } + + return preferAutoProperties + ? default + : generator.CreateThrowNotImplementedStatementBlock(compilation); + } + + private static bool TryGetValue(IDictionary? dictionary, string key, [NotNullWhen(true)] out string? value) + { + value = null; + return + dictionary != null && + dictionary.TryGetValue(key, out value); + } + + private static bool TryGetValue(IDictionary? dictionary, string key, [NotNullWhen(true)] out string? value) + { + value = null; + if (dictionary != null && dictionary.TryGetValue(key, out var symbol)) + { + value = symbol.Name; + return true; + } + + return false; + } + + public static ImmutableArray CreateFieldsForParameters( + ImmutableArray parameters, ImmutableDictionary? parameterToNewFieldMap, bool isContainedInUnsafeType) + { + using var _ = ArrayBuilder.GetInstance(out var result); + foreach (var parameter in parameters) + { + // For non-out parameters, create a field and assign the parameter to it. + if (parameter.RefKind != RefKind.Out && + TryGetValue(parameterToNewFieldMap, parameter.Name, out var fieldName)) + { + result.Add(CodeGenerationSymbolFactory.CreateFieldSymbol( + attributes: default, + accessibility: Accessibility.Private, + modifiers: new DeclarationModifiers(isUnsafe: !isContainedInUnsafeType && parameter.RequiresUnsafeModifier()), + type: parameter.Type, + name: fieldName)); + } + } + + return result.ToImmutableAndClear(); + } + + public static ImmutableArray CreatePropertiesForParameters( + ImmutableArray parameters, ImmutableDictionary? parameterToNewPropertyMap, bool isContainedInUnsafeType) + { + using var _ = ArrayBuilder.GetInstance(out var result); + foreach (var parameter in parameters) + { + // For non-out parameters, create a property and assign the parameter to it. + if (parameter.RefKind != RefKind.Out && + TryGetValue(parameterToNewPropertyMap, parameter.Name, out var propertyName)) + { + result.Add(CodeGenerationSymbolFactory.CreatePropertySymbol( + attributes: default, + accessibility: Accessibility.Public, + modifiers: new DeclarationModifiers(isUnsafe: !isContainedInUnsafeType && parameter.RequiresUnsafeModifier()), + type: parameter.Type, + refKind: RefKind.None, + explicitInterfaceImplementations: [], + name: propertyName, + parameters: [], + getMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol( + attributes: default, + accessibility: default, + statements: default), + setMethod: null)); + } + } + + return result.ToImmutableAndClear(); + } + + public static ImmutableArray CreateAssignmentStatements( + this SyntaxGenerator factory, + SyntaxGeneratorInternal generatorInternal, + SemanticModel semanticModel, + ImmutableArray parameters, + IDictionary? parameterToExistingFieldMap, + IDictionary? parameterToNewFieldMap, + bool addNullChecks, + bool preferThrowExpression) + { + var nullCheckStatements = ArrayBuilder.GetInstance(); + var assignStatements = ArrayBuilder.GetInstance(); + + foreach (var parameter in parameters) + { + var refKind = parameter.RefKind; + var parameterType = parameter.Type; + var parameterName = parameter.Name; + + if (refKind == RefKind.Out) + { + // If it's an out param, then don't create a field for it. Instead, assign + // the default value for that type (i.e. "default(...)") to it. + var assignExpression = factory.AssignmentStatement( + factory.IdentifierName(parameterName), + factory.DefaultExpression(parameterType)); + var statement = factory.ExpressionStatement(assignExpression); + assignStatements.Add(statement); + } + else + { + // For non-out parameters, create a field and assign the parameter to it. + // TODO: I'm not sure that's what we really want for ref parameters. + if (TryGetValue(parameterToExistingFieldMap, parameterName, out var fieldName) || + TryGetValue(parameterToNewFieldMap, parameterName, out fieldName)) + { + var fieldAccess = factory.MemberAccessExpression(factory.ThisExpression(), factory.IdentifierName(fieldName)) + .WithAdditionalAnnotations(Simplifier.Annotation); + + factory.AddAssignmentStatements( + generatorInternal, + semanticModel, parameter, fieldAccess, + addNullChecks, preferThrowExpression, + nullCheckStatements, assignStatements); + } + } + } + + return nullCheckStatements.ToImmutableAndFree().Concat(assignStatements.ToImmutableAndFree()); + } + + public static void AddAssignmentStatements( + this SyntaxGenerator factory, + SyntaxGeneratorInternal generatorInternal, + SemanticModel semanticModel, + IParameterSymbol parameter, + SyntaxNode fieldAccess, + bool addNullChecks, + bool preferThrowExpression, + ArrayBuilder nullCheckStatements, + ArrayBuilder assignStatements) + { + // Don't want to add a null check for something of the form `int?`. The type was + // already declared as nullable to indicate that null is ok. Adding a null check + // just disallows something that should be allowed. + var shouldAddNullCheck = addNullChecks && parameter.Type.CanAddNullCheck() && !parameter.Type.IsNullable(); + + if (shouldAddNullCheck && preferThrowExpression && generatorInternal.SupportsThrowExpression()) + { + // Generate: this.x = x ?? throw ... + assignStatements.Add(CreateAssignWithNullCheckStatement( + factory, semanticModel.Compilation, parameter, fieldAccess)); + } + else + { + if (shouldAddNullCheck) + { + // generate: if (x == null) throw ... + nullCheckStatements.Add( + factory.CreateNullCheckAndThrowStatement(generatorInternal, semanticModel, parameter)); + } + + // generate: this.x = x; + assignStatements.Add( + factory.ExpressionStatement( + factory.AssignmentStatement( + fieldAccess, + factory.IdentifierName(parameter.Name)))); + } + } + + public static SyntaxNode CreateAssignWithNullCheckStatement( + this SyntaxGenerator factory, Compilation compilation, IParameterSymbol parameter, SyntaxNode fieldAccess) + { + return factory.ExpressionStatement(factory.AssignmentStatement( + fieldAccess, + factory.CoalesceExpression( + factory.IdentifierName(parameter.Name), + factory.CreateThrowArgumentNullExpression(compilation, parameter)))); + } + + public static SyntaxNode CreateThrowArgumentNullExpression(this SyntaxGenerator factory, Compilation compilation, IParameterSymbol parameter) + => factory.ThrowExpression(CreateNewArgumentNullException(factory, compilation, parameter)); + + private static SyntaxNode CreateNewArgumentNullException(SyntaxGenerator factory, Compilation compilation, IParameterSymbol parameter) + { + var type = compilation.GetTypeByMetadataName(typeof(ArgumentNullException).FullName!); + Contract.ThrowIfNull(type); + return factory.ObjectCreationExpression(type, + factory.NameOfExpression( + factory.IdentifierName(parameter.Name))).WithAdditionalAnnotations(Simplifier.AddImportsAnnotation); + } + + public static SyntaxNode CreateNullCheckAndThrowStatement( + this SyntaxGenerator factory, + SyntaxGeneratorInternal generatorInternal, + SemanticModel semanticModel, + IParameterSymbol parameter) + { + var condition = factory.CreateNullCheckExpression(generatorInternal, semanticModel, parameter.Name); + var throwStatement = factory.CreateThrowArgumentNullExceptionStatement(semanticModel.Compilation, parameter); + + // generates: if (s is null) { throw new ArgumentNullException(nameof(s)); } + return factory.IfStatement(condition, [throwStatement]); + } + public static SyntaxNode CreateNullCheckExpression( + this SyntaxGenerator factory, SyntaxGeneratorInternal generatorInternal, SemanticModel semanticModel, string identifierName) + { + var identifier = factory.IdentifierName(identifierName); + var nullExpr = factory.NullLiteralExpression(); + var condition = generatorInternal.SupportsPatterns(semanticModel.SyntaxTree.Options) + ? generatorInternal.IsPatternExpression(identifier, generatorInternal.ConstantPattern(nullExpr)) + : factory.ReferenceEqualsExpression(identifier, nullExpr); + return condition; + } + + public static SyntaxNode CreateThrowArgumentNullExceptionStatement(this SyntaxGenerator factory, Compilation compilation, IParameterSymbol parameter) + => factory.ThrowStatement(CreateNewArgumentNullException(factory, compilation, parameter)); } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs similarity index 80% rename from src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs index 6ebbbe5063f0c..3919fc0d6a83b 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs @@ -5,6 +5,7 @@ #nullable disable using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -14,9 +15,16 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; +#if CODE_STYLE +using DeclarationModifiers = Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers; +#else +using DeclarationModifiers = Microsoft.CodeAnalysis.Editing.DeclarationModifiers; +#endif + namespace Microsoft.CodeAnalysis.Shared.Extensions; internal static partial class SyntaxGeneratorExtensions @@ -79,7 +87,7 @@ public static IMethodSymbol CreateIEquatableEqualsMethod( type: constructedEquatableType.GetTypeArguments()[0], attributes: ImmutableArray.Empty)); - if (factory.RequiresExplicitImplementationForInterfaceMembers) + if (generatorInternal.RequiresExplicitImplementationForInterfaceMembers) { return CodeGenerationSymbolFactory.CreateMethodSymbol( methodSymbol, @@ -132,12 +140,12 @@ private static ImmutableArray CreateEqualsMethodStatements( // return statement of 'Equals'. using var _2 = ArrayBuilder.GetInstance(out var expressions); - if (factory.SyntaxGeneratorInternal.SupportsPatterns(parseOptions)) + if (generatorInternal.SupportsPatterns(parseOptions)) { // If we support patterns then we can do "return obj is MyType myType && ..." expressions.Add( - factory.SyntaxGeneratorInternal.IsPatternExpression(objNameExpression, - factory.SyntaxGeneratorInternal.DeclarationPattern(containingType, localName))); + generatorInternal.IsPatternExpression(objNameExpression, + generatorInternal.DeclarationPattern(containingType, localName))); } else if (containingType.IsValueType) { @@ -159,7 +167,7 @@ private static ImmutableArray CreateEqualsMethodStatements( // // var myType = (MyType)obj; - var localDeclaration = factory.SimpleLocalDeclarationStatement(factory.SyntaxGeneratorInternal, + var localDeclaration = factory.SimpleLocalDeclarationStatement(generatorInternal, containingType, localName, factory.CastExpression(containingType, objNameExpression)); statements.Add(ifStatement); @@ -171,13 +179,14 @@ private static ImmutableArray CreateEqualsMethodStatements( // // var myType = obj as MyType; - var localDeclaration = factory.SimpleLocalDeclarationStatement(factory.SyntaxGeneratorInternal, + var localDeclaration = factory.SimpleLocalDeclarationStatement(generatorInternal, containingType, localName, factory.TryCastExpression(objNameExpression, containingType)); statements.Add(localDeclaration); // Ensure that the parameter we got was not null (which also ensures the 'as' test succeeded): - AddReferenceNotNullCheck(factory, compilation, parseOptions, localNameExpression, expressions); + AddReferenceNotNullCheck( + factory, generatorInternal, compilation, parseOptions, localNameExpression, expressions); } if (!containingType.IsValueType && HasExistingBaseEqualsMethod(containingType)) @@ -280,7 +289,8 @@ private static ImmutableArray CreateIEquatableEqualsMethodStatements // It's not a value type. Ensure that the parameter we got was not null. // if we support patterns, we can do `x is not null` - AddReferenceNotNullCheck(factory, compilation, parseOptions, otherNameExpression, expressions); + AddReferenceNotNullCheck( + factory, generatorInternal, compilation, parseOptions, otherNameExpression, expressions); if (HasExistingBaseEqualsMethod(containingType)) { @@ -310,7 +320,7 @@ private static ImmutableArray CreateIEquatableEqualsMethodStatements } private static void AddReferenceNotNullCheck( - SyntaxGenerator factory, Compilation compilation, ParseOptions parseOptions, SyntaxNode otherNameExpression, ArrayBuilder expressions) + SyntaxGenerator factory, SyntaxGeneratorInternal generatorInternal, Compilation compilation, ParseOptions parseOptions, SyntaxNode otherNameExpression, ArrayBuilder expressions) { var nullLiteral = factory.NullLiteralExpression(); if (compilation.Language == LanguageNames.VisualBasic) @@ -320,22 +330,21 @@ private static void AddReferenceNotNullCheck( return; } - var generator = factory.SyntaxGeneratorInternal; - if (generator.SyntaxFacts.SupportsNotPattern(parseOptions)) + if (generatorInternal.SyntaxFacts.SupportsNotPattern(parseOptions)) { // If we support not patterns then we can do "obj is not null && ..." expressions.Add( - generator.IsPatternExpression(otherNameExpression, - generator.NotPattern( - generator.ConstantPattern(nullLiteral)))); + generatorInternal.IsPatternExpression(otherNameExpression, + generatorInternal.NotPattern( + generatorInternal.ConstantPattern(nullLiteral)))); } - else if (generator.SupportsPatterns(parseOptions)) + else if (generatorInternal.SupportsPatterns(parseOptions)) { // if we support patterns then we can do `!(obj is null)` expressions.Add( factory.LogicalNotExpression( - generator.IsPatternExpression(otherNameExpression, - generator.ConstantPattern(nullLiteral)))); + generatorInternal.IsPatternExpression(otherNameExpression, + generatorInternal.ConstantPattern(nullLiteral)))); } else { @@ -443,4 +452,64 @@ where method.IsOverride && return existingMethods.Any(); } + + public static ImmutableArray CreateMemberDelegatingConstructor( + this SyntaxGenerator factory, + SyntaxGeneratorInternal generatorInternal, + SemanticModel semanticModel, + string typeName, + INamedTypeSymbol? containingType, + ImmutableArray parameters, + Accessibility accessibility, + ImmutableDictionary? parameterToExistingMemberMap, + ImmutableDictionary? parameterToNewMemberMap, + bool addNullChecks, + bool preferThrowExpression, + bool generateProperties, + bool isContainedInUnsafeType) + { + var newMembers = generateProperties + ? CreatePropertiesForParameters(parameters, parameterToNewMemberMap, isContainedInUnsafeType) + : CreateFieldsForParameters(parameters, parameterToNewMemberMap, isContainedInUnsafeType); + var statements = factory.CreateAssignmentStatements( + generatorInternal, semanticModel, + parameters, parameterToExistingMemberMap, parameterToNewMemberMap, + addNullChecks, preferThrowExpression).SelectAsArray( + s => s.WithAdditionalAnnotations(Simplifier.Annotation)); + + var constructor = CodeGenerationSymbolFactory.CreateConstructorSymbol( + attributes: default, + accessibility: accessibility, + modifiers: new DeclarationModifiers(isUnsafe: !isContainedInUnsafeType && parameters.Any(static p => p.RequiresUnsafeModifier())), + typeName: typeName, + parameters: parameters, + statements: statements, + thisConstructorArguments: ShouldGenerateThisConstructorCall(containingType, parameterToExistingMemberMap) + ? [] + : default); + + return newMembers.Concat(constructor); + } + + private static bool ShouldGenerateThisConstructorCall( + INamedTypeSymbol? containingType, + IDictionary? parameterToExistingFieldMap) + { + if (containingType?.TypeKind == TypeKind.Struct) + { + // Special case. If we're generating a struct constructor, then we'll need + // to initialize all fields in the struct, not just the ones we're creating. + // If there is any field or auto-property not being set by a parameter, we + // call the default constructor. + + return containingType.GetMembers() + .OfType() + .Where(field => !field.IsStatic) + .Select(field => field.AssociatedSymbol ?? field) + .Except(parameterToExistingFieldMap?.Values ?? []) + .Any(); + } + + return false; + } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Formatting/DocumentFormattingOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Formatting/DocumentFormattingOptionsProviders.cs new file mode 100644 index 0000000000000..b3c9b701e2228 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Formatting/DocumentFormattingOptionsProviders.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Formatting; + +internal static class DocumentFormattingOptionsProviders +{ + public static DocumentFormattingOptions GetDocumentFormattingOptions(this IOptionsReader options) + => new() + { + FileHeaderTemplate = options.GetOption(CodeStyleOptions2.FileHeaderTemplate), + InsertFinalNewLine = options.GetOption(FormattingOptions2.InsertFinalNewLine) + }; + + public static async ValueTask GetDocumentFormattingOptionsAsync(this Document document, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + return configOptions.GetDocumentFormattingOptions(); + } +} diff --git a/src/Workspaces/Core/Portable/Formatting/ISyntaxFormattingService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Formatting/ISyntaxFormattingService.cs similarity index 100% rename from src/Workspaces/Core/Portable/Formatting/ISyntaxFormattingService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Formatting/ISyntaxFormattingService.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Formatting/LineFormattingOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Formatting/LineFormattingOptionsProviders.cs new file mode 100644 index 0000000000000..04c840f43ede5 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Formatting/LineFormattingOptionsProviders.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Formatting; + +internal static class LineFormattingOptionsProviders +{ + public static LineFormattingOptions GetLineFormattingOptions(this IOptionsReader options, string language) + => new(options, language); + + public static async ValueTask GetLineFormattingOptionsAsync(this Document document, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + return configOptions.GetLineFormattingOptions(document.Project.Language); + } +} + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Formatting/SyntaxFormattingOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Formatting/SyntaxFormattingOptionsProviders.cs new file mode 100644 index 0000000000000..8e5e5c41e1530 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Formatting/SyntaxFormattingOptionsProviders.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Formatting; + +internal static class SyntaxFormattingOptionsProviders +{ + public static SyntaxFormattingOptions GetSyntaxFormattingOptions(this IOptionsReader options, Host.LanguageServices languageServices) + => languageServices.GetRequiredService().GetFormattingOptions(options); + + public static ValueTask GetSyntaxFormattingOptionsAsync(this Document document, CancellationToken cancellationToken) + => GetSyntaxFormattingOptionsAsync(document, document.GetRequiredLanguageService(), cancellationToken); + + public static async ValueTask GetSyntaxFormattingOptionsAsync(this Document document, ISyntaxFormatting formatting, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + return formatting.GetFormattingOptions(configOptions); + } + + public static SyntaxFormattingOptions GetDefault(Host.LanguageServices languageServices) + => languageServices.GetRequiredService().DefaultOptions; +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/AbstractIndentationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/AbstractIndentationService.cs index 4d626031f3069..e89266c0d77c2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/AbstractIndentationService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/AbstractIndentationService.cs @@ -59,6 +59,6 @@ private Indenter GetIndenter(ParsedDocument document, int lineNumber, Indentatio var smartTokenFormatter = CreateSmartTokenFormatter( (TSyntaxRoot)document.Root, document.Text, lineToBeIndented, options, baseIndentationRule); - return new Indenter(this, document.SyntaxTree, formattingRules, options, lineToBeIndented, smartTokenFormatter, cancellationToken); + return new Indenter(this, document.SyntaxTree, document.Text, formattingRules, options, lineToBeIndented, smartTokenFormatter, cancellationToken); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/IndentationOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/IndentationOptionsProviders.cs new file mode 100644 index 0000000000000..099000384fa1e --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Indentation/IndentationOptionsProviders.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.Indentation; + +internal static class IndentationOptionsProviders +{ + public static IndentationOptions GetDefault(LanguageServices languageServices) + => new(SyntaxFormattingOptionsProviders.GetDefault(languageServices)); +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.State.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.State.cs index d0664d83ca817..f5362c5b6f439 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.State.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.State.cs @@ -16,13 +16,13 @@ namespace Microsoft.CodeAnalysis.MoveDeclarationNearReference; -internal partial class AbstractMoveDeclarationNearReferenceService< +internal abstract partial class AbstractMoveDeclarationNearReferenceService< TService, TStatementSyntax, TLocalDeclarationStatementSyntax, TVariableDeclaratorSyntax> { - private class State + private sealed class State { public TLocalDeclarationStatementSyntax DeclarationStatement { get; private set; } public TVariableDeclaratorSyntax VariableDeclarator { get; private set; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsService.cs index a9ae9a3bcd3d1..be6a0da6fe3b4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsService.cs @@ -20,10 +20,10 @@ internal abstract class AbstractRemoveUnnecessaryImportsService : { protected abstract IUnnecessaryImportsProvider UnnecessaryImportsProvider { get; } - public Task RemoveUnnecessaryImportsAsync(Document document, SyntaxFormattingOptions? formattingOptions, CancellationToken cancellationToken) - => RemoveUnnecessaryImportsAsync(document, predicate: null, formattingOptions, cancellationToken); + public Task RemoveUnnecessaryImportsAsync(Document document, CancellationToken cancellationToken) + => RemoveUnnecessaryImportsAsync(document, predicate: null, cancellationToken: cancellationToken); - public abstract Task RemoveUnnecessaryImportsAsync(Document fromDocument, Func? predicate, SyntaxFormattingOptions? formattingOptions, CancellationToken cancellationToken); + public abstract Task RemoveUnnecessaryImportsAsync(Document fromDocument, Func? predicate, CancellationToken cancellationToken); protected async Task> GetCommonUnnecessaryImportsOfAllContextAsync( Document document, Func predicate, CancellationToken cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/IRemoveUnnecessaryImportsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/IRemoveUnnecessaryImportsService.cs index 8793966fef14e..76752273fe457 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/IRemoveUnnecessaryImportsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/RemoveUnnecessaryImports/IRemoveUnnecessaryImportsService.cs @@ -5,16 +5,13 @@ using System; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.RemoveUnnecessaryImports; internal interface IRemoveUnnecessaryImportsService : ILanguageService { - /// Null if the document does not support syntax trees. - Task RemoveUnnecessaryImportsAsync(Document document, SyntaxFormattingOptions? formattingOptions, CancellationToken cancellationToken); + Task RemoveUnnecessaryImportsAsync(Document document, CancellationToken cancellationToken); - /// Null if the document does not support syntax trees. - Task RemoveUnnecessaryImportsAsync(Document fromDocument, Func? predicate, SyntaxFormattingOptions? formattingOptions, CancellationToken cancellationToken); + Task RemoveUnnecessaryImportsAsync(Document fromDocument, Func? predicate, CancellationToken cancellationToken); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs index 99e1123316d71..b87a79832bdf4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SyntaxGeneratorInternalExtensions/SyntaxGeneratorInternal.cs @@ -20,7 +20,15 @@ internal abstract class SyntaxGeneratorInternal : ILanguageService { public abstract ISyntaxFacts SyntaxFacts { get; } + public abstract SyntaxTrivia CarriageReturnLineFeed { get; } + public abstract SyntaxTrivia ElasticCarriageReturnLineFeed { get; } + public abstract SyntaxTrivia EndOfLine(string text); + public abstract SyntaxTrivia SingleLineComment(string text); + + public abstract bool RequiresExplicitImplementationForInterfaceMembers { get; } + + public abstract bool SupportsThrowExpression(); /// /// Creates a statement that declares a single local variable with an optional initializer. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs index 4dc1aa16c05c2..ff11d0acf11fd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/TypeInferenceService/AbstractTypeInferenceService.AbstractTypeInferrer.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.LanguageService.TypeInferenceService; -internal partial class AbstractTypeInferenceService : ITypeInferenceService +internal abstract partial class AbstractTypeInferenceService : ITypeInferenceService { protected abstract class AbstractTypeInferrer { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/NamingStyles/NamingStylePreferencesProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/NamingStyles/NamingStylePreferencesProviders.cs new file mode 100644 index 0000000000000..852f353f856fb --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/NamingStyles/NamingStylePreferencesProviders.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.CodeStyle; + +internal static class NamingStylePreferencesProviders +{ + public static async ValueTask GetNamingStylePreferencesAsync(this Document document, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + return configOptions.GetOption(NamingStyleOptions.NamingPreferences, document.Project.Language); + } +} diff --git a/src/Features/Core/Portable/Options/MemberDisplayOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Options/MemberDisplayOptions.cs similarity index 88% rename from src/Features/Core/Portable/Options/MemberDisplayOptions.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Options/MemberDisplayOptions.cs index fcdfb9064660a..9fad0c04e94c7 100644 --- a/src/Features/Core/Portable/Options/MemberDisplayOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Options/MemberDisplayOptions.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis; @@ -24,8 +25,7 @@ internal readonly record struct MemberDisplayOptions() /// internal static class MemberDisplayOptionsStorage { - public static readonly OptionGroup CodeActionsGroup = new(name: "code_actions", description: FeaturesResources.NET_Code_Actions, priority: 3); - public static readonly OptionGroup TypeMemberGroup = new(name: "type_members", description: FeaturesResources.Type_members, priority: 3, parent: CodeActionsGroup); + public static readonly OptionGroup TypeMemberGroup = new(name: "type_members", description: WorkspaceExtensionsResources.Type_members, priority: 3, parent: null); public static readonly PerLanguageOption2 HideAdvancedMembers = new( "dotnet_hide_advanced_members", diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameActionAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameActionAnnotation.cs index 3ad0ef66c36f8..470faf912bc49 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameActionAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameActionAnnotation.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Rename.ConflictEngine; /// check if the semantics have been changes (conflict detection). /// /// This annotation should be put on tokens only. -internal class RenameActionAnnotation( +internal sealed class RenameActionAnnotation( TextSpan originalSpan, bool isRenameLocation, string prefix, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameDeclarationLocationReference.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameDeclarationLocationReference.cs index 392d26c2bce4f..f96ac9a7a9c04 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameDeclarationLocationReference.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameDeclarationLocationReference.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Rename.ConflictEngine; /// This class is used to refer to a Symbol definition which could be in source or metadata /// it has a metadata name. /// -internal class RenameDeclarationLocationReference +internal sealed class RenameDeclarationLocationReference { // The DocumentId and the TextSpan of the First Symbol Location public readonly DocumentId DocumentId; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameInvalidIdentifierAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameInvalidIdentifierAnnotation.cs index 9177b9e3cde26..fd4aa97c58179 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameInvalidIdentifierAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameInvalidIdentifierAnnotation.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Rename.ConflictEngine; -internal class RenameInvalidIdentifierAnnotation : RenameAnnotation +internal sealed class RenameInvalidIdentifierAnnotation : RenameAnnotation { public static RenameInvalidIdentifierAnnotation Instance = new(); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameNodeSimplificationAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameNodeSimplificationAnnotation.cs index 3874cc572ddc8..6be479a030147 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameNodeSimplificationAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameNodeSimplificationAnnotation.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Rename.ConflictEngine; -internal class RenameNodeSimplificationAnnotation : RenameAnnotation +internal sealed class RenameNodeSimplificationAnnotation : RenameAnnotation { public TextSpan OriginalTextSpan { get; set; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameTokenSimplificationAnnotation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameTokenSimplificationAnnotation.cs index 1e1de4c59fe61..04972ca54a80a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameTokenSimplificationAnnotation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Rename/Annotations/RenameTokenSimplificationAnnotation.cs @@ -6,7 +6,7 @@ namespace Microsoft.CodeAnalysis.Rename.ConflictEngine; -internal class RenameTokenSimplificationAnnotation : RenameAnnotation +internal sealed class RenameTokenSimplificationAnnotation : RenameAnnotation { public TextSpan OriginalTextSpan { get; set; } } diff --git a/src/Workspaces/Core/Portable/Simplification/AbstractReducer.IExpressionRewriter.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.IExpressionRewriter.cs similarity index 100% rename from src/Workspaces/Core/Portable/Simplification/AbstractReducer.IExpressionRewriter.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.IExpressionRewriter.cs diff --git a/src/Workspaces/Core/Portable/Simplification/AbstractReducer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.cs similarity index 100% rename from src/Workspaces/Core/Portable/Simplification/AbstractReducer.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractReducer.cs diff --git a/src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractSimplificationService.cs similarity index 100% rename from src/Workspaces/Core/Portable/Simplification/AbstractSimplificationService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/AbstractSimplificationService.cs diff --git a/src/Workspaces/Core/Portable/Simplification/ISimplificationService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/ISimplificationService.cs similarity index 100% rename from src/Workspaces/Core/Portable/Simplification/ISimplificationService.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/ISimplificationService.cs diff --git a/src/Workspaces/Core/Portable/Simplification/NodeOrTokenToReduce.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/NodeOrTokenToReduce.cs similarity index 100% rename from src/Workspaces/Core/Portable/Simplification/NodeOrTokenToReduce.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/NodeOrTokenToReduce.cs diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/SimplifierOptionsProviders.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/SimplifierOptionsProviders.cs new file mode 100644 index 0000000000000..2ed19877fdcc3 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/SimplifierOptionsProviders.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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Simplification; + +internal static class SimplifierOptionsProviders +{ + public static SimplifierOptions GetSimplifierOptions(this IOptionsReader options, Host.LanguageServices languageServices) + => languageServices.GetService()?.GetSimplifierOptions(options) ?? SimplifierOptions.CommonDefaults; + + public static ValueTask GetSimplifierOptionsAsync(this Document document, CancellationToken cancellationToken) + => GetSimplifierOptionsAsync(document, document.GetRequiredLanguageService(), cancellationToken); + + public static async ValueTask GetSimplifierOptionsAsync(this Document document, ISimplification simplification, CancellationToken cancellationToken) + { + var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); + return simplification.GetSimplifierOptions(configOptions); + } + + public static SimplifierOptions GetDefault(Host.LanguageServices languageServices) + => languageServices.GetRequiredService().DefaultOptions; +} + diff --git a/src/Workspaces/Core/Portable/Simplification/Simplifiers/AbstractMemberAccessExpressionSimplifier.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/Simplifiers/AbstractMemberAccessExpressionSimplifier.cs similarity index 100% rename from src/Workspaces/Core/Portable/Simplification/Simplifiers/AbstractMemberAccessExpressionSimplifier.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/Simplifiers/AbstractMemberAccessExpressionSimplifier.cs diff --git a/src/Workspaces/Core/Portable/Simplification/Simplifiers/AbstractSimplifier.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/Simplifiers/AbstractSimplifier.cs similarity index 87% rename from src/Workspaces/Core/Portable/Simplification/Simplifiers/AbstractSimplifier.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/Simplifiers/AbstractSimplifier.cs index 57c4a0677b710..ff3c2faf492e3 100644 --- a/src/Workspaces/Core/Portable/Simplification/Simplifiers/AbstractSimplifier.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Simplification/Simplifiers/AbstractSimplifier.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.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis.Text; @@ -18,7 +17,7 @@ public abstract bool TrySimplify( TSyntax syntax, SemanticModel semanticModel, TSimplifierOptions options, - out TSimplifiedSyntax replacementNode, + [NotNullWhen(true)] out TSimplifiedSyntax? replacementNode, out TextSpan issueSpan, CancellationToken cancellationToken); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/TextReaderWithLength.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/TextReaderWithLength.cs index d9df0f3f7d3a2..efc7455e2279c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/TextReaderWithLength.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Utilities/TextReaderWithLength.cs @@ -12,7 +12,7 @@ internal abstract class TextReaderWithLength(int length) : TextReader public override string ReadToEnd() { -#if NETCOREAPP +#if NET return string.Create(Length, this, static (chars, state) => state.Read(chars)); #else var chars = new char[Length]; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/CodeChangeProviderMetadata.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/CodeChangeProviderMetadata.cs index 3b61403c03278..fe051bf5a5ba5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/CodeChangeProviderMetadata.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/CodeChangeProviderMetadata.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Host.Mef; -internal class CodeChangeProviderMetadata : OrderableMetadata, ILanguagesMetadata +internal sealed class CodeChangeProviderMetadata : OrderableMetadata, ILanguagesMetadata { public IEnumerable Languages { get; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/FileExtensionsMetadata.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/FileExtensionsMetadata.cs index e8c3f33f55c82..e1e9d88784807 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/FileExtensionsMetadata.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/FileExtensionsMetadata.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Host.Mef; /// /// MEF metadata class used to find exports declared for a specific file extensions. /// -internal class FileExtensionsMetadata +internal sealed class FileExtensionsMetadata { public IEnumerable Extensions { get; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LanguageMetadata.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LanguageMetadata.cs index 18515a160bbae..0e413fa8216af 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LanguageMetadata.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LanguageMetadata.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Host.Mef; /// /// MEF metadata class used to find exports declared for a specific language. /// -internal class LanguageMetadata(IDictionary data) : ILanguageMetadata +internal sealed class LanguageMetadata(IDictionary data) : ILanguageMetadata { public string Language { get; } = (string)data[nameof(Language)]; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LanguageServiceMetadata.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LanguageServiceMetadata.cs index a924e71101407..d6468a066b044 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LanguageServiceMetadata.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LanguageServiceMetadata.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Host.Mef /// /// MEF metadata class used for finding and exports. /// - internal class LanguageServiceMetadata(IDictionary data) : ILanguageMetadata, ILayeredServiceMetadata + internal sealed class LanguageServiceMetadata(IDictionary data) : ILanguageMetadata, ILayeredServiceMetadata { public string Language { get; } = (string)data[nameof(ExportLanguageServiceAttribute.Language)]; public string ServiceType { get; } = (string)data[nameof(ExportLanguageServiceAttribute.ServiceType)]; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LayeredServiceUtilities.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LayeredServiceUtilities.cs index be3224fcedd88..b614df6eec4ec 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LayeredServiceUtilities.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/LayeredServiceUtilities.cs @@ -20,21 +20,21 @@ internal static class LayeredServiceUtilities public static string GetAssemblyQualifiedServiceTypeName(Type type, string argName) => (type ?? throw new ArgumentNullException(argName)).AssemblyQualifiedName ?? throw new ArgumentException("Invalid service type", argName); - public static Lazy? PickService( + public static (Lazy? lazyService, bool usesFactory) PickService( Type serviceType, string? workspaceKind, - IEnumerable> services) + IEnumerable<(Lazy? lazyService, bool usesFactory)> services) where TMetadata : ILayeredServiceMetadata { - Lazy? service; - TemporaryArray> servicesOfMatchingType = new(); + (Lazy? lazyService, bool usesFactory) service; + TemporaryArray<(Lazy? lazyService, bool usesFactory)> servicesOfMatchingType = new(); // PERF: Hoist AssemblyQualifiedName out of the loop to avoid repeated string allocations. var assemblyQualifiedName = serviceType.AssemblyQualifiedName; foreach (var entry in services) { - if (entry.Metadata.ServiceType == assemblyQualifiedName) + if (entry.lazyService?.Metadata.ServiceType == assemblyQualifiedName) { servicesOfMatchingType.Add(entry); } @@ -42,8 +42,8 @@ public static string GetAssemblyQualifiedServiceTypeName(Type type, string argNa #if !CODE_STYLE // test layer overrides all other layers and workspace kinds: - service = servicesOfMatchingType.SingleOrDefault(static lz => lz.Metadata.Layer == ServiceLayer.Test); - if (service != null) + service = servicesOfMatchingType.SingleOrDefault(static lz => lz.lazyService?.Metadata.Layer == ServiceLayer.Test); + if (service.lazyService != null) { return service; } @@ -51,8 +51,8 @@ public static string GetAssemblyQualifiedServiceTypeName(Type type, string argNa // If a service is exported for specific workspace kinds and the current workspace kind is among them, use it. if (workspaceKind != null) { - service = servicesOfMatchingType.SingleOrDefault(static (lz, workspaceKind) => lz.Metadata.WorkspaceKinds.Contains(workspaceKind), workspaceKind); - if (service != null) + service = servicesOfMatchingType.SingleOrDefault(static (lz, workspaceKind) => lz.lazyService?.Metadata.WorkspaceKinds.Contains(workspaceKind) ?? false, workspaceKind); + if (service.lazyService != null) { return service; } @@ -60,7 +60,7 @@ public static string GetAssemblyQualifiedServiceTypeName(Type type, string argNa // For backward compat check workspace kind specific service. // Workspace kind specific service should specify supported kinds in WorkspaceKinds. service = TryGetServiceByLayer(workspaceKind); - if (service != null) + if (service.lazyService != null) { return service; } @@ -69,16 +69,16 @@ public static string GetAssemblyQualifiedServiceTypeName(Type type, string argNa foreach (var layer in s_orderedProductLayers) { service = TryGetServiceByLayer(layer); - if (service != null) + if (service.lazyService != null) { return service; } } // no service. - return null; + return default; - Lazy? TryGetServiceByLayer(string layer) - => servicesOfMatchingType.SingleOrDefault(static (lz, layer) => lz.Metadata.WorkspaceKinds is [] && lz.Metadata.Layer == layer, layer); + (Lazy? lazyService, bool usesFactory) TryGetServiceByLayer(string layer) + => servicesOfMatchingType.SingleOrDefault(static (lz, layer) => lz.lazyService?.Metadata.WorkspaceKinds is [] && lz.lazyService.Metadata.Layer == layer, layer); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefLanguageServices.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefLanguageServices.cs index 6359ab73b455e..79cf67540bea4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefLanguageServices.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefLanguageServices.cs @@ -3,12 +3,15 @@ // 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.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; +using Roslyn.Utilities; +using ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer; [assembly: DebuggerTypeProxy(typeof(MefLanguageServices.LazyServiceMetadataDebuggerProxy), Target = typeof(ImmutableArray>))] @@ -18,10 +21,13 @@ internal sealed class MefLanguageServices : HostLanguageServices { private readonly MefWorkspaceServices _workspaceServices; private readonly string _language; - private readonly ImmutableArray> _services; + private readonly ImmutableArray<(Lazy lazyService, bool usesFactory)> _services; - private ImmutableDictionary?> _serviceMap - = ImmutableDictionary?>.Empty; + private ImmutableDictionary? lazyService, bool usesFactory)> _serviceMap + = ImmutableDictionary? lazyService, bool usesFactory)>.Empty; + + private readonly object _gate = new(); + private readonly HashSet _ownedDisposableServices = new(ReferenceEqualityComparer.Instance); public MefLanguageServices( MefWorkspaceServices workspaceServices, @@ -32,11 +38,12 @@ public MefLanguageServices( var hostServices = workspaceServices.HostExportProvider; - var services = hostServices.GetExports(); + var services = hostServices.GetExports() + .Select(lz => (lazyService: lz, usesFactory: false)); var factories = hostServices.GetExports() - .Select(lz => new Lazy(() => lz.Value.CreateLanguageService(this), lz.Metadata)); + .Select(lz => (lazyService: new Lazy(() => lz.Value.CreateLanguageService(this), lz.Metadata), usesFactory: true)); - _services = services.Concat(factories).Where(lz => lz.Metadata.Language == language).ToImmutableArray(); + _services = services.Concat(factories).Where(lz => lz.lazyService.Metadata.Language == language).ToImmutableArray(); } public override HostWorkspaceServices WorkspaceServices => _workspaceServices; @@ -48,11 +55,35 @@ public bool HasServices get { return _services.Length > 0; } } + public override void Dispose() + { + ImmutableArray disposableServices; + lock (_gate) + { + disposableServices = _ownedDisposableServices.ToImmutableArray(); + _ownedDisposableServices.Clear(); + } + + // Take care to give all disposal parts a chance to dispose even if some parts throw exceptions. + List? exceptions = null; + foreach (var service in disposableServices) + { + MefUtilities.DisposeWithExceptionTracking(service, ref exceptions); + } + + if (exceptions is not null) + { + throw new AggregateException(CompilerExtensionsResources.Instantiated_parts_threw_exceptions_from_IDisposable_Dispose, exceptions); + } + + base.Dispose(); + } + public override TLanguageService GetService() { - if (TryGetService(typeof(TLanguageService), out var service)) + if (TryGetService(static _ => true, out var service)) { - return (TLanguageService)service.Value; + return service; } else { @@ -60,14 +91,50 @@ public override TLanguageService GetService() } } - internal bool TryGetService(Type serviceType, [NotNullWhen(true)] out Lazy? service) + internal bool TryGetService(HostWorkspaceServices.MetadataFilter filter, [MaybeNullWhen(false)] out TLanguageService languageService) + { + if (TryGetService(typeof(TLanguageService), out var lazyService, out var usesFactory) + && filter(lazyService.Metadata.Data)) + { + // MEF language service instances created by a factory are not owned by the MEF catalog or disposed + // when the MEF catalog is disposed. Whenever we are potentially going to create an instance of a + // service provided by a factory, we need to check if the resulting service implements IDisposable. The + // specific conditions here are: + // + // * usesFactory: This is true when the language service is provided by a factory. Services provided + // directly are owned by the MEF catalog so they do not need to be tracked by the workspace. + // * IsValueCreated: This will be false at least once prior to accessing the lazy value. Once the value + // is known to be created, we no longer need to try adding it to _ownedDisposableServices, so we use a + // lock-free fast path. + var checkAddDisposable = usesFactory && !lazyService.IsValueCreated; + + languageService = (TLanguageService)lazyService.Value; + if (checkAddDisposable && languageService is IDisposable disposable) + { + lock (_gate) + { + _ownedDisposableServices.Add(disposable); + } + } + + return true; + } + else + { + languageService = default; + return false; + } + } + + private bool TryGetService(Type serviceType, [NotNullWhen(true)] out Lazy? lazyService, out bool usesFactory) { - if (!_serviceMap.TryGetValue(serviceType, out service)) + if (!_serviceMap.TryGetValue(serviceType, out var service)) { service = ImmutableInterlocked.GetOrAdd(ref _serviceMap, serviceType, serviceType => LayeredServiceUtilities.PickService(serviceType, _workspaceServices.WorkspaceKind, _services)); } - return service != null; + (lazyService, usesFactory) = (service.lazyService, service.usesFactory); + return lazyService != null; } internal sealed class LazyServiceMetadataDebuggerProxy(ImmutableArray> services) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefUtilities.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefUtilities.cs new file mode 100644 index 0000000000000..415744ff25cc2 --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefUtilities.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.ErrorReporting; + +namespace Microsoft.CodeAnalysis.Host.Mef +{ + internal static class MefUtilities + { + public static void DisposeWithExceptionTracking(T instance, [NotNullIfNotNull("exceptions")] ref List? exceptions) + where T : IDisposable + { + try + { + instance.Dispose(); + } + catch (Exception ex) when (FatalError.ReportAndCatch(ex)) + { + exceptions ??= new List(); + exceptions.Add(ex); + } + } + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefWorkspaceServices.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefWorkspaceServices.cs index 4f6dfda3663c8..edb6c31002036 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefWorkspaceServices.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Workspace/Mef/MefWorkspaceServices.cs @@ -8,9 +8,11 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Threading; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Roslyn.Utilities; +using ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer; [assembly: DebuggerTypeProxy(typeof(MefWorkspaceServices.LazyServiceMetadataDebuggerProxy), Target = typeof(ImmutableArray>))] @@ -18,14 +20,16 @@ namespace Microsoft.CodeAnalysis.Host.Mef { internal sealed class MefWorkspaceServices : HostWorkspaceServices { - private readonly IMefHostExportProvider _exportProvider; private readonly Workspace _workspace; - private readonly ImmutableArray> _services; + private readonly ImmutableArray<(Lazy lazyService, bool usesFactory)> _services; // map of type name to workspace service - private ImmutableDictionary?> _serviceMap - = ImmutableDictionary?>.Empty; + private ImmutableDictionary? lazyService, bool usesFactory)> _serviceMap + = ImmutableDictionary? lazyService, bool usesFactory)>.Empty; + + private readonly object _gate = new(); + private readonly HashSet _ownedDisposableServices = new(ReferenceEqualityComparer.Instance); // accumulated cache for language services private ImmutableDictionary _languageServicesMap @@ -35,22 +39,23 @@ private ImmutableDictionary _languageServicesMap public MefWorkspaceServices(IMefHostExportProvider host, Workspace workspace) { - _exportProvider = host; + HostExportProvider = host; _workspace = workspace; - var services = host.GetExports(); + var services = host.GetExports() + .Select(lz => (lz, usesFactory: false)); var factories = host.GetExports() - .Select(lz => new Lazy(() => lz.Value.CreateService(this), lz.Metadata)); + .Select(lz => (new Lazy(() => lz.Value.CreateService(this), lz.Metadata), usesFactory: true)); _services = services.Concat(factories).ToImmutableArray(); } public override HostServices HostServices { - get { return (HostServices)_exportProvider; } + get { return (HostServices)HostExportProvider; } } - internal IMefHostExportProvider HostExportProvider => _exportProvider; + internal IMefHostExportProvider HostExportProvider { get; } internal string? WorkspaceKind => _workspace.Kind; @@ -65,11 +70,64 @@ public override Workspace Workspace } } + public override void Dispose() + { + var allLanguageServices = Interlocked.Exchange(ref _languageServicesMap, _languageServicesMap.Clear()); + + ImmutableArray disposableServices; + lock (_gate) + { + disposableServices = _ownedDisposableServices.ToImmutableArray(); + _ownedDisposableServices.Clear(); + } + + // Take care to give all disposal parts a chance to dispose even if some parts throw exceptions. + List? exceptions = null; + + foreach (var (_, languageServices) in allLanguageServices) + { + MefUtilities.DisposeWithExceptionTracking(languageServices, ref exceptions); + } + + foreach (var service in disposableServices) + { + MefUtilities.DisposeWithExceptionTracking(service, ref exceptions); + } + + if (exceptions is not null) + { + throw new AggregateException(CompilerExtensionsResources.Instantiated_parts_threw_exceptions_from_IDisposable_Dispose, exceptions); + } + + base.Dispose(); + } + public override TWorkspaceService GetService() { - if (TryGetService(typeof(TWorkspaceService), out var service)) + if (TryGetService(typeof(TWorkspaceService), out var lazyService, out var usesFactory)) { - return (TWorkspaceService)service.Value; + // MEF workspace service instances created by a factory are not owned by the MEF catalog or disposed + // when the MEF catalog is disposed. Whenever we are potentially going to create an instance of a + // service provided by a factory, we need to check if the resulting service implements IDisposable. The + // specific conditions here are: + // + // * usesFactory: This is true when the workspace service is provided by a factory. Services provided + // directly are owned by the MEF catalog so they do not need to be tracked by the workspace. + // * IsValueCreated: This will be false at least once prior to accessing the lazy value. Once the value + // is known to be created, we no longer need to try adding it to _ownedDisposableServices, so we use a + // lock-free fast path. + var checkAddDisposable = usesFactory && !lazyService.IsValueCreated; + + var serviceInstance = (TWorkspaceService)lazyService.Value; + if (checkAddDisposable && serviceInstance is IDisposable disposable) + { + lock (_gate) + { + _ownedDisposableServices.Add(disposable); + } + } + + return serviceInstance; } else { @@ -77,14 +135,15 @@ public override TWorkspaceService GetService() } } - private bool TryGetService(Type serviceType, [NotNullWhen(true)] out Lazy? service) + private bool TryGetService(Type serviceType, [NotNullWhen(true)] out Lazy? lazyService, out bool usesFactory) { - if (!_serviceMap.TryGetValue(serviceType, out service)) + if (!_serviceMap.TryGetValue(serviceType, out var service)) { service = ImmutableInterlocked.GetOrAdd(ref _serviceMap, serviceType, serviceType => LayeredServiceUtilities.PickService(serviceType, _workspace.Kind, _services)); } - return service != null; + (lazyService, usesFactory) = (service.lazyService, service.usesFactory); + return lazyService != null; } private ImmutableArray ComputeSupportedLanguages() @@ -92,8 +151,8 @@ private ImmutableArray ComputeSupportedLanguages() var localLanguages = _languages; if (localLanguages.IsDefault) { - var list = _exportProvider.GetExports().Select(lz => lz.Metadata.Language).Concat( - _exportProvider.GetExports().Select(lz => lz.Metadata.Language)) + var list = HostExportProvider.GetExports().Select(lz => lz.Metadata.Language).Concat( + HostExportProvider.GetExports().Select(lz => lz.Metadata.Language)) .Distinct() .ToImmutableArray(); @@ -142,12 +201,9 @@ public override IEnumerable FindLanguageServices(filter, out var service)) { - if (filter(service.Metadata.Data)) - { - yield return (TLanguageService)service.Value; - } + yield return service; } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems index c99af6a5983c7..32a4686da39e5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensions.projitems @@ -9,12 +9,27 @@ Microsoft.CodeAnalysis.Shared + + + + + + + + + + + + + + + + + - - @@ -28,7 +43,6 @@ - @@ -72,14 +86,17 @@ - - + + + + + @@ -119,6 +136,8 @@ + + @@ -142,10 +161,14 @@ + + + + @@ -156,4 +179,7 @@ + + + \ No newline at end of file diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensionsResources.resx b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensionsResources.resx index 4ca939845df3e..db238f2195b38 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensionsResources.resx +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceExtensionsResources.resx @@ -192,4 +192,10 @@ Namespace can not be added in this destination. + + Type members + + + Document does not support syntax trees + \ No newline at end of file diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs index ca917d21deda1..562598812ed69 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/WorkspaceServices/SemanticModelReuse/SemanticModelReuseWorkspaceServiceFactory.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.SemanticModelReuse; [ExportWorkspaceServiceFactory(typeof(ISemanticModelReuseWorkspaceService), ServiceLayer.Default), Shared] -internal partial class SemanticModelReuseWorkspaceServiceFactory : IWorkspaceServiceFactory +internal sealed partial class SemanticModelReuseWorkspaceServiceFactory : IWorkspaceServiceFactory { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.cs.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.cs.xlf index fbabe19a86657..81dc239c4cc91 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.cs.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.cs.xlf @@ -47,6 +47,11 @@ Cílový typ musí být {0} nebo {1}, ale zadaný typ je {2}. + + Document does not support syntax trees + Dokument nepodporuje stromy syntaxe. + + Fix all '{0}' Opravit vše ({0}) @@ -122,6 +127,11 @@ Řešení neobsahuje zadaný dokument. + + Type members + Členy typů + + Warning: Declaration changes scope and may change meaning. Upozornění: Deklarace mění rozsah a může změnit význam. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.de.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.de.xlf index cffd3da698896..40777c886e1dd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.de.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.de.xlf @@ -47,6 +47,11 @@ Zieltyp muss {0} oder {1} sein. Es wurde jedoch {2} angegeben. + + Document does not support syntax trees + Das Dokument unterstützt keine Syntaxstrukturen. + + Fix all '{0}' Alle '{0}' reparieren @@ -122,6 +127,11 @@ Die Lösung enthält nicht das angegebene Dokument. + + Type members + Typmitglied + + Warning: Declaration changes scope and may change meaning. Warnung: Die Deklaration ändert den Bereich und möglicherweise die Bedeutung. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.es.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.es.xlf index 07164c7c23837..25ad67acb755f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.es.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.es.xlf @@ -47,6 +47,11 @@ El tipo de destino debe ser un {0} o un {1}, pero el proporcionado es {2}. + + Document does not support syntax trees + El documento no admite árboles de sintaxis + + Fix all '{0}' Corregir todo '{0}' @@ -122,6 +127,11 @@ La solución no contiene el documento especificado. + + Type members + Miembros de tipo + + Warning: Declaration changes scope and may change meaning. Advertencia: La declaración cambia el ámbito y puede cambiar el significado. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.fr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.fr.xlf index dbddeb1912b98..2cdca8fbc7835 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.fr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.fr.xlf @@ -47,6 +47,11 @@ Le type de destination doit être un {0} ou un {1}, mais le type donné est {2}. + + Document does not support syntax trees + Le document ne prend pas en charge les arborescences de syntaxe + + Fix all '{0}' Corriger tous les '{0}' @@ -122,6 +127,11 @@ La solution ne contient pas le document spécifié. + + Type members + Membres du type + + Warning: Declaration changes scope and may change meaning. Avertissement : La déclaration change la portée et éventuellement la signification. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.it.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.it.xlf index a2c78b22b50ab..c7295581b091b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.it.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.it.xlf @@ -47,6 +47,11 @@ Il tipo di destinazione deve essere {0} o {1}, ma quello specificato è {2}. + + Document does not support syntax trees + Il documento non supporta alberi di sintassi + + Fix all '{0}' Correggi tutti '{0}' @@ -122,6 +127,11 @@ La soluzione non contiene il documento specificato. + + Type members + Membri tipo + + Warning: Declaration changes scope and may change meaning. Avviso: la dichiarazione implica la modifica dell'ambito e potrebbe modificare il significato. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ja.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ja.xlf index 47ac48e3daa75..2aed3706ef64c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ja.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ja.xlf @@ -47,6 +47,11 @@ ターゲットの型は {0} または {1} である必要がありますが、{2} が指定されています。 + + Document does not support syntax trees + ドキュメントでは構文ツリーがサポートされません + + Fix all '{0}' すべての '{0}' を修正します @@ -122,6 +127,11 @@ ソリューションには、指定されたドキュメントがありません。 + + Type members + 型メンバー + + Warning: Declaration changes scope and may change meaning. 警告: 宣言によりスコープが変更され、意味が変わる可能性があります。 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ko.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ko.xlf index 9206614edb5a7..c35c4bcea6262 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ko.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ko.xlf @@ -47,6 +47,11 @@ 대상 형식은 {0} 또는 {1}이어야 하지만 지정된 형식은 {2}입니다. + + Document does not support syntax trees + 문서가 구문 트리를 지원하지 않음 + + Fix all '{0}' 모든 '{0}' 수정 @@ -122,6 +127,11 @@ 솔루션에 지정한 문서가 포함되어 있지 않습니다. + + Type members + 멤버 입력 + + Warning: Declaration changes scope and may change meaning. 경고: 선언 시 범위가 변경되고 의미가 변경될 수 있습니다. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.pl.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.pl.xlf index eab56886bbe3e..ce378dda3233d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.pl.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.pl.xlf @@ -47,6 +47,11 @@ Typ docelowy musi być elementem {0} lub {1}, ale podano element {2}. + + Document does not support syntax trees + Dokument nie obsługuje drzew składni + + Fix all '{0}' Napraw wszystkie wystąpienia elementu „{0}” @@ -122,6 +127,11 @@ Rozwiązanie nie zawiera określonego dokumentu. + + Type members + Składowe typu + + Warning: Declaration changes scope and may change meaning. Ostrzeżenie: deklaracja zmienia zakres i może zmienić znaczenie. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.pt-BR.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.pt-BR.xlf index 4d335c670f6d8..bf32983799e15 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.pt-BR.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.pt-BR.xlf @@ -47,6 +47,11 @@ O tipo de destino deve ser um {0} ou um {1}, mas o tipo fornecido é {2}. + + Document does not support syntax trees + O documento não dá suporte a árvores de sintaxe + + Fix all '{0}' Corrigir todos os '{0}' @@ -122,6 +127,11 @@ A solução não contém o documento especificado. + + Type members + Digitar membros + + Warning: Declaration changes scope and may change meaning. Aviso: a declaração altera e escopo e pode alterar o significado. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ru.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ru.xlf index 5222a6f599619..9165b56bade5a 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ru.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.ru.xlf @@ -47,6 +47,11 @@ Конечный тип должен быть {0} или {1}, но указан {2}. + + Document does not support syntax trees + Документ не поддерживает синтаксические деревья. + + Fix all '{0}' Исправить все "{0}" @@ -122,6 +127,11 @@ Указанный документ отсутствует в решении. + + Type members + Члены типа + + Warning: Declaration changes scope and may change meaning. Предупреждение. Объявление изменяет область и может изменить значение. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.tr.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.tr.xlf index d9c8984990dc5..0fc721676f026 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.tr.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.tr.xlf @@ -47,6 +47,11 @@ Hedef tür bir {0} veya {1} olmalı, ancak {2} belirtildi. + + Document does not support syntax trees + Belge, söz dizimi ağaçlarını desteklemiyor + + Fix all '{0}' Geçtiği her yerde '{0}' ifadesini düzelt @@ -122,6 +127,11 @@ Çözüm belirtilen belgeyi içermiyor. + + Type members + Tür üyeleri + + Warning: Declaration changes scope and may change meaning. Uyarı: Bildirim, kapsamı değiştiriyor ve anlamı da değiştirebilir. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.zh-Hans.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.zh-Hans.xlf index 5fe06e2b21b63..92ccfe8cf0873 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.zh-Hans.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.zh-Hans.xlf @@ -47,6 +47,11 @@ 目标类型必须是 {0} 或 {1},但给定类型是 {2}。 + + Document does not support syntax trees + 文档不支持语法树 + + Fix all '{0}' 修复所有“{0}” @@ -122,6 +127,11 @@ 解决方案不包含指定的文档。 + + Type members + 类型成员 + + Warning: Declaration changes scope and may change meaning. 警告: 声明更改了作用域,并且可能更改含义。 diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.zh-Hant.xlf b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.zh-Hant.xlf index 38c4ef5ba363d..07c2d69afe585 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.zh-Hant.xlf +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/xlf/WorkspaceExtensionsResources.zh-Hant.xlf @@ -47,6 +47,11 @@ 目的地類型必須是 {0} 或 {1},但提供的是 {2}。 + + Document does not support syntax trees + 文件不支援語法樹 + + Fix all '{0}' 修正所有 '{0}' @@ -122,6 +127,11 @@ 此方案不包含指定的文件。 + + Type members + 類型成員 + + Warning: Declaration changes scope and may change meaning. 警告: 宣告會變更範圍,且可能會變更意義。 diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/ArgumentGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ArgumentGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/ArgumentGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ArgumentGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/AttributeGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/AttributeGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/AttributeGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/AttributeGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/ConstructorGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ConstructorGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/ConstructorGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ConstructorGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/ConversionGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ConversionGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/ConversionGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ConversionGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/EnumMemberGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/EnumMemberGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/EnumMemberGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/EnumMemberGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/EventGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/EventGenerator.vb similarity index 84% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/EventGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/EventGenerator.vb index 8c42db193a173..9056e0381f15d 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/EventGenerator.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/EventGenerator.vb @@ -44,10 +44,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return FirstMethod(members) End Function - Friend Function AddEventTo(destination As TypeBlockSyntax, - [event] As IEventSymbol, - options As CodeGenerationContextInfo, - availableIndices As IList(Of Boolean)) As TypeBlockSyntax + Friend Function AddEventTo( + destination As TypeBlockSyntax, + [event] As IEventSymbol, + options As CodeGenerationContextInfo, + availableIndices As IList(Of Boolean)) As TypeBlockSyntax Dim eventDeclaration = GenerateEventDeclaration([event], GetDestination(destination), options) Dim members = Insert(destination.Members, eventDeclaration, options, availableIndices, @@ -59,9 +60,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return FixTerminators(destination.WithMembers(members)) End Function - Public Function GenerateEventDeclaration([event] As IEventSymbol, - destination As CodeGenerationDestination, - options As CodeGenerationContextInfo) As DeclarationStatementSyntax + Public Function GenerateEventDeclaration( + [event] As IEventSymbol, + destination As CodeGenerationDestination, + options As CodeGenerationContextInfo) As DeclarationStatementSyntax Dim reusableSyntax = GetReuseableSyntaxNodeForSymbol(Of DeclarationStatementSyntax)([event], options) If reusableSyntax IsNot Nothing Then Return reusableSyntax @@ -72,9 +74,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return AddFormatterAndCodeGeneratorAnnotationsTo(ConditionallyAddDocumentationCommentTo(declaration, [event], options)) End Function - Private Function GenerateEventDeclarationWorker([event] As IEventSymbol, - destination As CodeGenerationDestination, - options As CodeGenerationContextInfo) As DeclarationStatementSyntax + Private Function GenerateEventDeclarationWorker( + [event] As IEventSymbol, + destination As CodeGenerationDestination, + options As CodeGenerationContextInfo) As DeclarationStatementSyntax If options.Context.GenerateMethodBodies AndAlso ([event].AddMethod IsNot Nothing OrElse [event].RemoveMethod IsNot Nothing OrElse [event].RaiseMethod IsNot Nothing) Then @@ -101,29 +104,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration New SyntaxList(Of StatementSyntax), GenerateStatements([event].RaiseMethod)) - Dim generator As VisualBasicSyntaxGenerator = New VisualBasicSyntaxGenerator() - + Dim generator = options.Generator Dim invoke = DirectCast([event].Type, INamedTypeSymbol)?.DelegateInvokeMethod Dim parameters = If( invoke IsNot Nothing, invoke.Parameters.Select(Function(p) generator.ParameterDeclaration(p)), Nothing) - Dim result = DirectCast(generator.CustomEventDeclarationWithRaise( - [event].Name, - generator.TypeExpression([event].Type), - [event].DeclaredAccessibility, - DeclarationModifiers.From([event]), - parameters, - addStatements, - removeStatements, - raiseStatements), EventBlockSyntax) + Dim result = DirectCast(VisualBasicSyntaxGeneratorInternal.CustomEventDeclarationWithRaise( + [event].Name, + generator.TypeExpression([event].Type), + [event].DeclaredAccessibility, + DeclarationModifiers.From([event]), + parameters, + addStatements, + removeStatements, + raiseStatements), EventBlockSyntax) result = DirectCast( result.WithAttributeLists(GenerateAttributeBlocks([event].GetAttributes(), options)), EventBlockSyntax) result = DirectCast(result.WithModifiers(GenerateModifiers([event], destination, options)), EventBlockSyntax) Dim explicitInterface = [event].ExplicitInterfaceImplementations.FirstOrDefault() - If (explicitInterface IsNot Nothing) + If (explicitInterface IsNot Nothing) Then result = result.WithEventStatement( result.EventStatement.WithImplementsClause(GenerateImplementsClause(explicitInterface))) End If diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/ExpressionGenerator.StringPiece.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ExpressionGenerator.StringPiece.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/ExpressionGenerator.StringPiece.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ExpressionGenerator.StringPiece.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/ExpressionGenerator.StringPieceKind.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ExpressionGenerator.StringPieceKind.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/ExpressionGenerator.StringPieceKind.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ExpressionGenerator.StringPieceKind.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/ExpressionGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ExpressionGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/ExpressionGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ExpressionGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/FieldGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/FieldGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/FieldGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/FieldGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/MethodGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/MethodGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/MethodGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/MethodGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/NamedTypeGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/NamedTypeGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/NamedTypeGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/NamedTypeGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/NamespaceGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/NamespaceGenerator.vb similarity index 96% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/NamespaceGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/NamespaceGenerator.vb index 78ea3cacf4973..8915c423b2d56 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/NamespaceGenerator.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/NamespaceGenerator.vb @@ -19,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration cancellationToken As CancellationToken) As CompilationUnitSyntax Dim declaration = GenerateNamespaceDeclaration(service, [namespace], options, cancellationToken) If Not TypeOf declaration Is NamespaceBlockSyntax Then - Throw New ArgumentException(VBWorkspaceResources.Namespace_can_not_be_added_in_this_destination) + Throw New ArgumentException(WorkspaceExtensionsResources.Namespace_can_not_be_added_in_this_destination) End If Dim members = Insert(destination.Members, DirectCast(declaration, StatementSyntax), options, availableIndices) @@ -34,7 +34,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration cancellationToken As CancellationToken) As NamespaceBlockSyntax Dim declaration = GenerateNamespaceDeclaration(service, [namespace], options, cancellationToken) If Not TypeOf declaration Is NamespaceBlockSyntax Then - Throw New ArgumentException(VBWorkspaceResources.Namespace_can_not_be_added_in_this_destination) + Throw New ArgumentException(WorkspaceExtensionsResources.Namespace_can_not_be_added_in_this_destination) End If Dim members = Insert(destination.Members, DirectCast(declaration, StatementSyntax), options, availableIndices) diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/OperatorGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/OperatorGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/OperatorGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/OperatorGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/ParameterGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ParameterGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/ParameterGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/ParameterGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/PropertyGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/PropertyGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/PropertyGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/PropertyGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/StatementGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/StatementGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/StatementGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/StatementGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/TypeParameterGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/TypeParameterGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/TypeParameterGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/TypeParameterGenerator.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationContextInfo.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationContextInfo.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationContextInfo.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationContextInfo.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationHelpers.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationHelpers.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationHelpers.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationHelpers.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationService.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationService.vb similarity index 99% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationService.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationService.vb index b1298c0f3ed96..b01506434ada5 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationService.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationService.vb @@ -17,8 +17,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration - - Friend Class VisualBasicCodeGenerationService + Friend NotInheritable Class VisualBasicCodeGenerationService Inherits AbstractCodeGenerationService(Of VisualBasicCodeGenerationContextInfo) Public Sub New(languageServices As LanguageServices) @@ -247,7 +246,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End If End Function - Private Overloads Shared Function AddParametersToMethod(Of TDeclarationNode As SyntaxNode)( + Private Overloads Function AddParametersToMethod(Of TDeclarationNode As SyntaxNode)( methodStatement As MethodBaseSyntax, methodBlock As MethodBlockBaseSyntax, parameters As IEnumerable(Of IParameterSymbol), @@ -282,7 +281,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return DirectCast(DirectCast(result, Object), TDeclarationNode) End Function - Private Overloads Shared Function AddParametersToProperty(Of TDeclarationNode As SyntaxNode)( + Private Overloads Function AddParametersToProperty(Of TDeclarationNode As SyntaxNode)( propertyBlock As PropertyBlockSyntax, parameters As IEnumerable(Of IParameterSymbol), options As VisualBasicCodeGenerationContextInfo, @@ -293,7 +292,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return DirectCast(newPropertyBlock, TDeclarationNode) End Function - Private Overloads Shared Function AddParameterToMethodBase(Of TMethodBase As MethodBaseSyntax)( + Private Overloads Function AddParameterToMethodBase(Of TMethodBase As MethodBaseSyntax)( methodBase As TMethodBase, parameters As IEnumerable(Of IParameterSymbol), options As VisualBasicCodeGenerationContextInfo, @@ -304,7 +303,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Dim parameterCount = If(parameterList IsNot Nothing, parameterList.Parameters.Count, 0) Dim seenOptional = parameterCount > 0 AndAlso parameterList.Parameters(parameterCount - 1).Default IsNot Nothing - Dim editor = New SyntaxEditor(methodBase, VisualBasicSyntaxGenerator.Instance) + Dim editor = New SyntaxEditor(methodBase, Me.LanguageServices.SolutionServices) For Each parameter In parameters Dim parameterSyntax = ParameterGenerator.GenerateParameter(parameter, seenOptional, options) diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationServiceFactory.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationServiceFactory.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicCodeGenerationServiceFactory.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicCodeGenerationServiceFactory.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicDeclarationComparer.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicDeclarationComparer.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicDeclarationComparer.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicDeclarationComparer.vb diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicFlagsEnumGenerator.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicFlagsEnumGenerator.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicFlagsEnumGenerator.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeGeneration/VisualBasicFlagsEnumGenerator.vb diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/VisualBasicRefactoringHelpersService.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeRefactorings/VisualBasicRefactoringHelpersService.vb similarity index 98% rename from src/Features/VisualBasic/Portable/CodeRefactorings/VisualBasicRefactoringHelpersService.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeRefactorings/VisualBasicRefactoringHelpersService.vb index d28d345c993c9..0539a9d7f2ad4 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/VisualBasicRefactoringHelpersService.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/CodeRefactorings/VisualBasicRefactoringHelpersService.vb @@ -12,7 +12,7 @@ Imports Microsoft.CodeAnalysis.Text Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings - Friend Class VisualBasicRefactoringHelpersService + Friend NotInheritable Class VisualBasicRefactoringHelpersService Inherits AbstractRefactoringHelpersService(Of ExpressionSyntax, ArgumentSyntax, ExpressionStatementSyntax) diff --git a/src/Workspaces/VisualBasic/Portable/Editing/VisualBasicImportAdder.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Editing/VisualBasicImportAdder.vb similarity index 99% rename from src/Workspaces/VisualBasic/Portable/Editing/VisualBasicImportAdder.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Editing/VisualBasicImportAdder.vb index 7d3efc3941eda..48df567891d0a 100644 --- a/src/Workspaces/VisualBasic/Portable/Editing/VisualBasicImportAdder.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Editing/VisualBasicImportAdder.vb @@ -14,7 +14,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Editing - Partial Friend Class VisualBasicImportAdder + Partial Friend NotInheritable Class VisualBasicImportAdder Inherits ImportAdderService diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/SemanticModelExtensions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/SemanticModelExtensions.vb similarity index 100% rename from src/Workspaces/VisualBasic/Portable/Extensions/SemanticModelExtensions.vb rename to src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/SemanticModelExtensions.vb diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicRemoveUnnecessaryImportsService.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicRemoveUnnecessaryImportsService.vb index a27384ea397b2..078dc07fb0be5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicRemoveUnnecessaryImportsService.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicRemoveUnnecessaryImportsService.vb @@ -26,11 +26,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryImports Public Overrides Async Function RemoveUnnecessaryImportsAsync( document As Document, predicate As Func(Of SyntaxNode, Boolean), - formattingOptions As SyntaxFormattingOptions, cancellationToken As CancellationToken) As Task(Of Document) - Contract.ThrowIfNull(formattingOptions) - predicate = If(predicate, Functions(Of SyntaxNode).True) Using Logger.LogBlock(FunctionId.Refactoring_RemoveUnnecessaryImports_VisualBasic, cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSyntaxGeneratorInternal.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSyntaxGeneratorInternal.vb index de4f014b21889..c8d1a1c29926e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSyntaxGeneratorInternal.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSyntaxGeneratorInternal.vb @@ -4,6 +4,7 @@ Imports System.Composition Imports System.Diagnostics.CodeAnalysis +Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.LanguageService @@ -16,7 +17,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Friend Class VisualBasicSyntaxGeneratorInternal Inherits SyntaxGeneratorInternal - Public Shared ReadOnly Instance As SyntaxGeneratorInternal = New VisualBasicSyntaxGeneratorInternal() + Public Shared ReadOnly Instance As New VisualBasicSyntaxGeneratorInternal() + + Public Shared ReadOnly s_fieldModifiers As DeclarationModifiers = DeclarationModifiers.Const Or DeclarationModifiers.[New] Or DeclarationModifiers.ReadOnly Or DeclarationModifiers.Static Or DeclarationModifiers.WithEvents + Public Shared ReadOnly s_methodModifiers As DeclarationModifiers = DeclarationModifiers.Abstract Or DeclarationModifiers.Async Or DeclarationModifiers.[New] Or DeclarationModifiers.Override Or DeclarationModifiers.Partial Or DeclarationModifiers.Sealed Or DeclarationModifiers.Static Or DeclarationModifiers.Virtual + Public Shared ReadOnly s_constructorModifiers As DeclarationModifiers = DeclarationModifiers.Static + Public Shared ReadOnly s_propertyModifiers As DeclarationModifiers = DeclarationModifiers.Abstract Or DeclarationModifiers.[New] Or DeclarationModifiers.Override Or DeclarationModifiers.ReadOnly Or DeclarationModifiers.WriteOnly Or DeclarationModifiers.Sealed Or DeclarationModifiers.Static Or DeclarationModifiers.Virtual + Public Shared ReadOnly s_indexerModifiers As DeclarationModifiers = DeclarationModifiers.Abstract Or DeclarationModifiers.[New] Or DeclarationModifiers.Override Or DeclarationModifiers.ReadOnly Or DeclarationModifiers.WriteOnly Or DeclarationModifiers.Sealed Or DeclarationModifiers.Static Or DeclarationModifiers.Virtual + Public Shared ReadOnly s_classModifiers As DeclarationModifiers = DeclarationModifiers.Abstract Or DeclarationModifiers.[New] Or DeclarationModifiers.Partial Or DeclarationModifiers.Sealed Or DeclarationModifiers.Static + Public Shared ReadOnly s_structModifiers As DeclarationModifiers = DeclarationModifiers.[New] Or DeclarationModifiers.Partial + Public Shared ReadOnly s_interfaceModifiers As DeclarationModifiers = DeclarationModifiers.[New] Or DeclarationModifiers.Partial + Public Shared ReadOnly s_accessorModifiers As DeclarationModifiers = DeclarationModifiers.Abstract Or DeclarationModifiers.[New] Or DeclarationModifiers.Override Or DeclarationModifiers.Virtual @@ -25,10 +36,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Public Overrides ReadOnly Property SyntaxFacts As ISyntaxFacts = VisualBasicSyntaxFacts.Instance + Public Overrides ReadOnly Property CarriageReturnLineFeed As SyntaxTrivia = SyntaxFactory.CarriageReturnLineFeed + + Public Overrides ReadOnly Property ElasticCarriageReturnLineFeed As SyntaxTrivia = SyntaxFactory.ElasticCarriageReturnLineFeed + + Public Overrides Function SupportsThrowExpression() As Boolean + Return False + End Function + + Public Overrides ReadOnly Property RequiresExplicitImplementationForInterfaceMembers As Boolean = True + Public Overrides Function EndOfLine(text As String) As SyntaxTrivia Return SyntaxFactory.EndOfLine(text) End Function + Public Overrides Function SingleLineComment(text As String) As SyntaxTrivia + Return SyntaxFactory.CommentTrivia("'" + text) + End Function + Public Overloads Overrides Function LocalDeclarationStatement(type As SyntaxNode, identifier As SyntaxToken, Optional initializer As SyntaxNode = Nothing, Optional isConst As Boolean = False) As SyntaxNode Return SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.TokenList(SyntaxFactory.Token(If(isConst, SyntaxKind.ConstKeyword, SyntaxKind.DimKeyword))), @@ -146,6 +171,291 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return SyntaxFactory.TypeOfIsNotExpression(DirectCast(expression, ExpressionSyntax), DirectCast(type, TypeSyntax)) End Function + Public Shared Function CustomEventDeclarationWithRaise( + name As String, + type As SyntaxNode, + Optional accessibility As Accessibility = Accessibility.NotApplicable, + Optional modifiers As DeclarationModifiers = Nothing, + Optional parameters As IEnumerable(Of SyntaxNode) = Nothing, + Optional addAccessorStatements As IEnumerable(Of SyntaxNode) = Nothing, + Optional removeAccessorStatements As IEnumerable(Of SyntaxNode) = Nothing, + Optional raiseAccessorStatements As IEnumerable(Of SyntaxNode) = Nothing) As SyntaxNode + + Dim accessors = New List(Of AccessorBlockSyntax)() + + If modifiers.IsAbstract Then + addAccessorStatements = Nothing + removeAccessorStatements = Nothing + raiseAccessorStatements = Nothing + Else + If addAccessorStatements Is Nothing Then + addAccessorStatements = SpecializedCollections.EmptyEnumerable(Of SyntaxNode)() + End If + + If removeAccessorStatements Is Nothing Then + removeAccessorStatements = SpecializedCollections.EmptyEnumerable(Of SyntaxNode)() + End If + + If raiseAccessorStatements Is Nothing Then + raiseAccessorStatements = SpecializedCollections.EmptyEnumerable(Of SyntaxNode)() + End If + End If + + accessors.Add(CreateAddHandlerAccessorBlock(type, addAccessorStatements)) + accessors.Add(CreateRemoveHandlerAccessorBlock(type, removeAccessorStatements)) + accessors.Add(CreateRaiseEventAccessorBlock(parameters, raiseAccessorStatements)) + + Dim evStatement = SyntaxFactory.EventStatement( + attributeLists:=Nothing, + modifiers:=GetModifierList(accessibility, modifiers And GetAllowedModifiers(SyntaxKind.EventStatement), declaration:=Nothing, DeclarationKind.Event), + customKeyword:=SyntaxFactory.Token(SyntaxKind.CustomKeyword), + eventKeyword:=SyntaxFactory.Token(SyntaxKind.EventKeyword), + identifier:=name.ToIdentifierToken(), + parameterList:=Nothing, + asClause:=SyntaxFactory.SimpleAsClause(DirectCast(type, TypeSyntax)), + implementsClause:=Nothing) + + Return SyntaxFactory.EventBlock( + eventStatement:=evStatement, + accessors:=SyntaxFactory.List(accessors), + endEventStatement:=SyntaxFactory.EndEventStatement()) + End Function + + Friend Shared Function CreateAddHandlerAccessorBlock(delegateType As SyntaxNode, statements As IEnumerable(Of SyntaxNode)) As AccessorBlockSyntax + Dim asClause = SyntaxFactory.SimpleAsClause(DirectCast(delegateType, TypeSyntax)) + + Dim valueParameter = SyntaxFactory.Parameter( + attributeLists:=Nothing, + modifiers:=Nothing, + identifier:=SyntaxFactory.ModifiedIdentifier("value"), + asClause:=asClause, + [default]:=Nothing) + + Return SyntaxFactory.AccessorBlock( + SyntaxKind.AddHandlerAccessorBlock, + SyntaxFactory.AccessorStatement( + kind:=SyntaxKind.AddHandlerAccessorStatement, + attributeLists:=Nothing, + modifiers:=Nothing, + accessorKeyword:=SyntaxFactory.Token(SyntaxKind.AddHandlerKeyword), + parameterList:=SyntaxFactory.ParameterList(SyntaxFactory.SingletonSeparatedList(valueParameter))), + GetStatementList(statements), + SyntaxFactory.EndAddHandlerStatement()) + End Function + + Friend Shared Function CreateRemoveHandlerAccessorBlock(delegateType As SyntaxNode, statements As IEnumerable(Of SyntaxNode)) As AccessorBlockSyntax + Dim asClause = SyntaxFactory.SimpleAsClause(DirectCast(delegateType, TypeSyntax)) + + Dim valueParameter = SyntaxFactory.Parameter( + attributeLists:=Nothing, + modifiers:=Nothing, + identifier:=SyntaxFactory.ModifiedIdentifier("value"), + asClause:=asClause, + [default]:=Nothing) + + Return SyntaxFactory.AccessorBlock( + SyntaxKind.RemoveHandlerAccessorBlock, + SyntaxFactory.AccessorStatement( + kind:=SyntaxKind.RemoveHandlerAccessorStatement, + attributeLists:=Nothing, + modifiers:=Nothing, + accessorKeyword:=SyntaxFactory.Token(SyntaxKind.RemoveHandlerKeyword), + parameterList:=SyntaxFactory.ParameterList(SyntaxFactory.SingletonSeparatedList(valueParameter))), + GetStatementList(statements), + SyntaxFactory.EndRemoveHandlerStatement()) + End Function + + Friend Shared Function CreateRaiseEventAccessorBlock(parameters As IEnumerable(Of SyntaxNode), statements As IEnumerable(Of SyntaxNode)) As AccessorBlockSyntax + Dim parameterList = GetParameterList(parameters) + + Return SyntaxFactory.AccessorBlock( + SyntaxKind.RaiseEventAccessorBlock, + SyntaxFactory.AccessorStatement( + kind:=SyntaxKind.RaiseEventAccessorStatement, + attributeLists:=Nothing, + modifiers:=Nothing, + accessorKeyword:=SyntaxFactory.Token(SyntaxKind.RaiseEventKeyword), + parameterList:=parameterList), + GetStatementList(statements), + SyntaxFactory.EndRaiseEventStatement()) + End Function + + Friend Shared Function GetStatementList(nodes As IEnumerable(Of SyntaxNode)) As SyntaxList(Of StatementSyntax) + If nodes Is Nothing Then + Return Nothing + Else + Return SyntaxFactory.List(nodes.Select(AddressOf AsStatement)) + End If + End Function + + Friend Shared Function AsStatement(node As SyntaxNode) As StatementSyntax + Dim expr = TryCast(node, ExpressionSyntax) + If expr IsNot Nothing Then + Return SyntaxFactory.ExpressionStatement(expr) + Else + Return DirectCast(node, StatementSyntax) + End If + End Function + + Friend Shared Function GetAllowedModifiers(kind As SyntaxKind) As DeclarationModifiers + Select Case kind + Case SyntaxKind.ClassBlock, SyntaxKind.ClassStatement + Return s_classModifiers + + Case SyntaxKind.EnumBlock, SyntaxKind.EnumStatement + Return DeclarationModifiers.[New] + + Case SyntaxKind.DelegateFunctionStatement, SyntaxKind.DelegateSubStatement + Return DeclarationModifiers.[New] + + Case SyntaxKind.InterfaceBlock, SyntaxKind.InterfaceStatement + Return s_interfaceModifiers + + Case SyntaxKind.StructureBlock, SyntaxKind.StructureStatement + Return s_structModifiers + + Case SyntaxKind.FunctionBlock, + SyntaxKind.FunctionStatement, + SyntaxKind.SubBlock, + SyntaxKind.SubStatement, + SyntaxKind.OperatorBlock, + SyntaxKind.OperatorStatement + Return s_methodModifiers + + Case SyntaxKind.ConstructorBlock, + SyntaxKind.SubNewStatement + Return s_constructorModifiers + + Case SyntaxKind.FieldDeclaration + Return s_fieldModifiers + + Case SyntaxKind.PropertyBlock, + SyntaxKind.PropertyStatement + Return s_propertyModifiers + + Case SyntaxKind.EventBlock, + SyntaxKind.EventStatement + Return s_propertyModifiers + + Case SyntaxKind.GetAccessorBlock, + SyntaxKind.GetAccessorStatement, + SyntaxKind.SetAccessorBlock, + SyntaxKind.SetAccessorStatement, + SyntaxKind.AddHandlerAccessorBlock, + SyntaxKind.AddHandlerAccessorStatement, + SyntaxKind.RemoveHandlerAccessorBlock, + SyntaxKind.RemoveHandlerAccessorStatement, + SyntaxKind.RaiseEventAccessorBlock, + SyntaxKind.RaiseEventAccessorStatement + Return s_accessorModifiers + + Case SyntaxKind.EnumMemberDeclaration + Case SyntaxKind.Parameter + Case SyntaxKind.LocalDeclarationStatement + Case Else + Return DeclarationModifiers.None + End Select + End Function + + Friend Shared Function GetParameterList(parameters As IEnumerable(Of SyntaxNode)) As ParameterListSyntax + Return If(parameters IsNot Nothing, SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters.Cast(Of ParameterSyntax)())), SyntaxFactory.ParameterList()) + End Function + + Friend Shared Function GetModifierList(accessibility As Accessibility, modifiers As DeclarationModifiers, declaration As SyntaxNode, kind As DeclarationKind, Optional isDefault As Boolean = False) As SyntaxTokenList + Dim _list = SyntaxFactory.TokenList() + + ' While partial must always be last in C#, its preferred position in VB is to be first, + ' even before accessibility modifiers. This order is enforced by line commit. + If modifiers.IsPartial Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.PartialKeyword)) + End If + + If isDefault Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.DefaultKeyword)) + End If + + Select Case (accessibility) + Case Accessibility.Internal + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.FriendKeyword)) + Case Accessibility.Public + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) + Case Accessibility.Private + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)) + Case Accessibility.Protected + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)) + Case Accessibility.ProtectedOrInternal + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.FriendKeyword)).Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)) + Case Accessibility.ProtectedAndInternal + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)).Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)) + Case Accessibility.NotApplicable + Case Else + Throw New NotSupportedException(String.Format("Accessibility '{0}' not supported.", accessibility)) + End Select + + Dim isClass = kind = DeclarationKind.Class OrElse declaration.IsKind(SyntaxKind.ClassStatement) + If modifiers.IsAbstract Then + If isClass Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.MustInheritKeyword)) + Else + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.MustOverrideKeyword)) + End If + End If + + If modifiers.IsNew Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.ShadowsKeyword)) + End If + + If modifiers.IsSealed Then + If isClass Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.NotInheritableKeyword)) + Else + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.NotOverridableKeyword)) + End If + End If + + If modifiers.IsOverride Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.OverridesKeyword)) + End If + + If modifiers.IsVirtual Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.OverridableKeyword)) + End If + + If modifiers.IsStatic Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.SharedKeyword)) + End If + + If modifiers.IsAsync Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.AsyncKeyword)) + End If + + If modifiers.IsConst Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.ConstKeyword)) + End If + + If modifiers.IsReadOnly Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)) + End If + + If modifiers.IsWriteOnly Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.WriteOnlyKeyword)) + End If + + If modifiers.IsUnsafe Then + Throw New NotSupportedException("Unsupported modifier") + ''''_list = _list.Add(SyntaxFactory.Token(SyntaxKind.UnsafeKeyword)) + End If + + If modifiers.IsWithEvents Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.WithEventsKeyword)) + End If + + If (kind = DeclarationKind.Field AndAlso _list.Count = 0) Then + _list = _list.Add(SyntaxFactory.Token(SyntaxKind.DimKeyword)) + End If + + Return _list + End Function #Region "Patterns" Public Overrides Function SupportsPatterns(options As ParseOptions) As Boolean diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems index aeb2f1557f279..d886374b01356 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/VisualBasicWorkspaceExtensions.projitems @@ -9,6 +9,32 @@ Microsoft.CodeAnalysis.VisualBasic.Shared + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -29,6 +55,7 @@ + diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb index 25ad7483d6050..0631af24ca037 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb @@ -25,22 +25,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Public Sub New() End Sub - Friend Overrides ReadOnly Property ElasticCarriageReturnLineFeed As SyntaxTrivia = SyntaxFactory.ElasticCarriageReturnLineFeed - Friend Overrides ReadOnly Property CarriageReturnLineFeed As SyntaxTrivia = SyntaxFactory.CarriageReturnLineFeed Friend Overrides ReadOnly Property ElasticMarker As SyntaxTrivia = SyntaxFactory.ElasticMarker - Friend Overrides ReadOnly Property RequiresExplicitImplementationForInterfaceMembers As Boolean = True - Friend Overrides ReadOnly Property SyntaxGeneratorInternal As SyntaxGeneratorInternal = VisualBasicSyntaxGeneratorInternal.Instance Friend Overrides Function Whitespace(text As String) As SyntaxTrivia Return SyntaxFactory.Whitespace(text) End Function - Friend Overrides Function SingleLineComment(text As String) As SyntaxTrivia - Return SyntaxFactory.CommentTrivia("'" + text) - End Function - Friend Overrides Function SeparatedList(Of TElement As SyntaxNode)(list As SyntaxNodeOrTokenList) As SeparatedSyntaxList(Of TElement) Return SyntaxFactory.SeparatedList(Of TElement)(list) End Function @@ -249,21 +241,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration ) End Function - Private Function GetStatementList(nodes As IEnumerable(Of SyntaxNode)) As SyntaxList(Of StatementSyntax) - If nodes Is Nothing Then - Return Nothing - Else - Return SyntaxFactory.List(nodes.Select(AddressOf AsStatement)) - End If + Private Shared Function GetStatementList(nodes As IEnumerable(Of SyntaxNode)) As SyntaxList(Of StatementSyntax) + Return VisualBasicSyntaxGeneratorInternal.GetStatementList(nodes) End Function - Private Function AsStatement(node As SyntaxNode) As StatementSyntax - Dim expr = TryCast(node, ExpressionSyntax) - If expr IsNot Nothing Then - Return SyntaxFactory.ExpressionStatement(expr) - Else - Return DirectCast(node, StatementSyntax) - End If + Private Shared Function AsStatement(node As SyntaxNode) As StatementSyntax + Return VisualBasicSyntaxGeneratorInternal.AsStatement(node) End Function Public Overloads Overrides Function InvocationExpression(expression As SyntaxNode, arguments As IEnumerable(Of SyntaxNode)) As SyntaxNode @@ -396,10 +379,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Throw New NotSupportedException("ThrowExpressions are not supported in Visual Basic") End Function - Friend Overrides Function SupportsThrowExpression() As Boolean - Return False - End Function - Public Overrides Function NameExpression(namespaceOrTypeSymbol As INamespaceOrTypeSymbol) As SyntaxNode Return namespaceOrTypeSymbol.GenerateTypeSyntax() End Function @@ -691,81 +670,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration #Region "Declarations" - Private Shared ReadOnly s_fieldModifiers As DeclarationModifiers = DeclarationModifiers.Const Or DeclarationModifiers.[New] Or DeclarationModifiers.ReadOnly Or DeclarationModifiers.Static Or DeclarationModifiers.WithEvents - Private Shared ReadOnly s_methodModifiers As DeclarationModifiers = DeclarationModifiers.Abstract Or DeclarationModifiers.Async Or DeclarationModifiers.[New] Or DeclarationModifiers.Override Or DeclarationModifiers.Partial Or DeclarationModifiers.Sealed Or DeclarationModifiers.Static Or DeclarationModifiers.Virtual - Private Shared ReadOnly s_constructorModifiers As DeclarationModifiers = DeclarationModifiers.Static - Private Shared ReadOnly s_propertyModifiers As DeclarationModifiers = DeclarationModifiers.Abstract Or DeclarationModifiers.[New] Or DeclarationModifiers.Override Or DeclarationModifiers.ReadOnly Or DeclarationModifiers.WriteOnly Or DeclarationModifiers.Sealed Or DeclarationModifiers.Static Or DeclarationModifiers.Virtual - Private Shared ReadOnly s_indexerModifiers As DeclarationModifiers = DeclarationModifiers.Abstract Or DeclarationModifiers.[New] Or DeclarationModifiers.Override Or DeclarationModifiers.ReadOnly Or DeclarationModifiers.WriteOnly Or DeclarationModifiers.Sealed Or DeclarationModifiers.Static Or DeclarationModifiers.Virtual - Private Shared ReadOnly s_classModifiers As DeclarationModifiers = DeclarationModifiers.Abstract Or DeclarationModifiers.[New] Or DeclarationModifiers.Partial Or DeclarationModifiers.Sealed Or DeclarationModifiers.Static - Private Shared ReadOnly s_structModifiers As DeclarationModifiers = DeclarationModifiers.[New] Or DeclarationModifiers.Partial - Private Shared ReadOnly s_interfaceModifiers As DeclarationModifiers = DeclarationModifiers.[New] Or DeclarationModifiers.Partial - Private Shared ReadOnly s_accessorModifiers As DeclarationModifiers = DeclarationModifiers.Abstract Or DeclarationModifiers.[New] Or DeclarationModifiers.Override Or DeclarationModifiers.Virtual - - Private Shared Function GetAllowedModifiers(kind As SyntaxKind) As DeclarationModifiers - Select Case kind - Case SyntaxKind.ClassBlock, SyntaxKind.ClassStatement - Return s_classModifiers - - Case SyntaxKind.EnumBlock, SyntaxKind.EnumStatement - Return DeclarationModifiers.[New] - - Case SyntaxKind.DelegateFunctionStatement, SyntaxKind.DelegateSubStatement - Return DeclarationModifiers.[New] - - Case SyntaxKind.InterfaceBlock, SyntaxKind.InterfaceStatement - Return s_interfaceModifiers - - Case SyntaxKind.StructureBlock, SyntaxKind.StructureStatement - Return s_structModifiers - - Case SyntaxKind.FunctionBlock, - SyntaxKind.FunctionStatement, - SyntaxKind.SubBlock, - SyntaxKind.SubStatement, - SyntaxKind.OperatorBlock, - SyntaxKind.OperatorStatement - Return s_methodModifiers - - Case SyntaxKind.ConstructorBlock, - SyntaxKind.SubNewStatement - Return s_constructorModifiers - - Case SyntaxKind.FieldDeclaration - Return s_fieldModifiers - - Case SyntaxKind.PropertyBlock, - SyntaxKind.PropertyStatement - Return s_propertyModifiers - - Case SyntaxKind.EventBlock, - SyntaxKind.EventStatement - Return s_propertyModifiers - - Case SyntaxKind.GetAccessorBlock, - SyntaxKind.GetAccessorStatement, - SyntaxKind.SetAccessorBlock, - SyntaxKind.SetAccessorStatement, - SyntaxKind.AddHandlerAccessorBlock, - SyntaxKind.AddHandlerAccessorStatement, - SyntaxKind.RemoveHandlerAccessorBlock, - SyntaxKind.RemoveHandlerAccessorStatement, - SyntaxKind.RaiseEventAccessorBlock, - SyntaxKind.RaiseEventAccessorStatement - Return s_accessorModifiers - - Case SyntaxKind.EnumMemberDeclaration - Case SyntaxKind.Parameter - Case SyntaxKind.LocalDeclarationStatement - Case Else - Return DeclarationModifiers.None - End Select + Friend Shared Function GetAllowedModifiers(kind As SyntaxKind) As DeclarationModifiers + Return VisualBasicSyntaxGeneratorInternal.GetAllowedModifiers(kind) End Function Public Overrides Function FieldDeclaration(name As String, type As SyntaxNode, Optional accessibility As Accessibility = Nothing, Optional modifiers As DeclarationModifiers = Nothing, Optional initializer As SyntaxNode = Nothing) As SyntaxNode modifiers = If(modifiers.IsConst(), modifiers.WithIsReadOnly(False), modifiers) Return SyntaxFactory.FieldDeclaration( attributeLists:=Nothing, - modifiers:=GetModifierList(accessibility, modifiers And s_fieldModifiers, declaration:=Nothing, DeclarationKind.Field), + modifiers:=GetModifierList(accessibility, modifiers And VisualBasicSyntaxGeneratorInternal.s_fieldModifiers, declaration:=Nothing, DeclarationKind.Field), declarators:=SyntaxFactory.SingletonSeparatedList(VisualBasicSyntaxGeneratorInternal.VariableDeclarator(type, name.ToModifiedIdentifier, initializer))) End Function @@ -781,7 +694,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Dim statement = SyntaxFactory.MethodStatement( kind:=If(returnType Is Nothing, SyntaxKind.SubStatement, SyntaxKind.FunctionStatement), attributeLists:=Nothing, - modifiers:=GetModifierList(accessibility, modifiers And s_methodModifiers, declaration:=Nothing, DeclarationKind.Method), + modifiers:=GetModifierList(accessibility, modifiers And VisualBasicSyntaxGeneratorInternal.s_methodModifiers, declaration:=Nothing, DeclarationKind.Method), subOrFunctionKeyword:=If(returnType Is Nothing, SyntaxFactory.Token(SyntaxKind.SubKeyword), SyntaxFactory.Token(SyntaxKind.FunctionKeyword)), identifier:=identifier.ToIdentifierToken(), typeParameterList:=GetTypeParameters(typeParameters), @@ -817,7 +730,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Dim parameterList = GetParameterList(parameters) Dim vbSyntaxKind As SyntaxKind = VisualBasic.SyntaxFacts.GetOperatorKind(operatorName) Dim operatorToken = SyntaxFactory.Token(vbSyntaxKind) - Dim modifierList As SyntaxTokenList = GetModifierList(accessibility, modifiers And s_methodModifiers, declaration:=Nothing, DeclarationKind.Operator) + Dim modifierList As SyntaxTokenList = GetModifierList(accessibility, modifiers And VisualBasicSyntaxGeneratorInternal.s_methodModifiers, declaration:=Nothing, DeclarationKind.Operator) If vbSyntaxKind = SyntaxKind.CTypeKeyword Then modifierList = modifierList.Add(SyntaxFactory.Token( @@ -896,7 +809,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End Function Private Shared Function GetParameterList(parameters As IEnumerable(Of SyntaxNode)) As ParameterListSyntax - Return If(parameters IsNot Nothing, SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters.Cast(Of ParameterSyntax)())), SyntaxFactory.ParameterList()) + Return VisualBasicSyntaxGeneratorInternal.GetParameterList(parameters) End Function Private Protected Overrides Function ParameterDeclaration( @@ -1015,7 +928,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Dim asClause = SyntaxFactory.SimpleAsClause(DirectCast(type, TypeSyntax)) Dim statement = SyntaxFactory.PropertyStatement( attributeLists:=Nothing, - modifiers:=GetModifierList(accessibility, modifiers And s_propertyModifiers, declaration:=Nothing, DeclarationKind.Property), + modifiers:=GetModifierList(accessibility, modifiers And VisualBasicSyntaxGeneratorInternal.s_propertyModifiers, declaration:=Nothing, DeclarationKind.Property), identifier:=name.ToIdentifierToken(), parameterList:=Nothing, asClause:=asClause, @@ -1048,7 +961,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Dim asClause = SyntaxFactory.SimpleAsClause(DirectCast(type, TypeSyntax)) Dim statement = SyntaxFactory.PropertyStatement( attributeLists:=Nothing, - modifiers:=GetModifierList(accessibility, modifiers And s_indexerModifiers, declaration:=Nothing, DeclarationKind.Indexer, isDefault:=True), + modifiers:=GetModifierList(accessibility, modifiers And VisualBasicSyntaxGeneratorInternal.s_indexerModifiers, declaration:=Nothing, DeclarationKind.Indexer, isDefault:=True), identifier:=SyntaxFactory.Identifier("Item"), parameterList:=SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters.Cast(Of ParameterSyntax))), asClause:=asClause, @@ -1075,22 +988,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End If End Function - Private Function AccessorBlock(kind As SyntaxKind, statements As IEnumerable(Of SyntaxNode), type As SyntaxNode) As AccessorBlockSyntax + Private Shared Function AccessorBlock(kind As SyntaxKind, statements As IEnumerable(Of SyntaxNode), type As SyntaxNode) As AccessorBlockSyntax Select Case kind Case SyntaxKind.GetAccessorBlock Return CreateGetAccessorBlock(statements) Case SyntaxKind.SetAccessorBlock Return CreateSetAccessorBlock(type, statements) Case SyntaxKind.AddHandlerAccessorBlock - Return CreateAddHandlerAccessorBlock(type, statements) + Return VisualBasicSyntaxGeneratorInternal.CreateAddHandlerAccessorBlock(type, statements) Case SyntaxKind.RemoveHandlerAccessorBlock - Return CreateRemoveHandlerAccessorBlock(type, statements) + Return VisualBasicSyntaxGeneratorInternal.CreateRemoveHandlerAccessorBlock(type, statements) Case Else Return Nothing End Select End Function - Private Function CreateGetAccessorBlock(statements As IEnumerable(Of SyntaxNode)) As AccessorBlockSyntax + Private Shared Function CreateGetAccessorBlock(statements As IEnumerable(Of SyntaxNode)) As AccessorBlockSyntax Return SyntaxFactory.AccessorBlock( SyntaxKind.GetAccessorBlock, SyntaxFactory.AccessorStatement(SyntaxKind.GetAccessorStatement, SyntaxFactory.Token(SyntaxKind.GetKeyword)), @@ -1098,7 +1011,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration SyntaxFactory.EndGetStatement()) End Function - Private Function CreateSetAccessorBlock(type As SyntaxNode, statements As IEnumerable(Of SyntaxNode)) As AccessorBlockSyntax + Private Shared Function CreateSetAccessorBlock(type As SyntaxNode, statements As IEnumerable(Of SyntaxNode)) As AccessorBlockSyntax Dim asClause = SyntaxFactory.SimpleAsClause(DirectCast(type, TypeSyntax)) Dim valueParameter = SyntaxFactory.Parameter( @@ -1120,65 +1033,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration SyntaxFactory.EndSetStatement()) End Function - Private Function CreateAddHandlerAccessorBlock(delegateType As SyntaxNode, statements As IEnumerable(Of SyntaxNode)) As AccessorBlockSyntax - Dim asClause = SyntaxFactory.SimpleAsClause(DirectCast(delegateType, TypeSyntax)) - - Dim valueParameter = SyntaxFactory.Parameter( - attributeLists:=Nothing, - modifiers:=Nothing, - identifier:=SyntaxFactory.ModifiedIdentifier("value"), - asClause:=asClause, - [default]:=Nothing) - - Return SyntaxFactory.AccessorBlock( - SyntaxKind.AddHandlerAccessorBlock, - SyntaxFactory.AccessorStatement( - kind:=SyntaxKind.AddHandlerAccessorStatement, - attributeLists:=Nothing, - modifiers:=Nothing, - accessorKeyword:=SyntaxFactory.Token(SyntaxKind.AddHandlerKeyword), - parameterList:=SyntaxFactory.ParameterList(SyntaxFactory.SingletonSeparatedList(valueParameter))), - GetStatementList(statements), - SyntaxFactory.EndAddHandlerStatement()) - End Function - - Private Function CreateRemoveHandlerAccessorBlock(delegateType As SyntaxNode, statements As IEnumerable(Of SyntaxNode)) As AccessorBlockSyntax - Dim asClause = SyntaxFactory.SimpleAsClause(DirectCast(delegateType, TypeSyntax)) - - Dim valueParameter = SyntaxFactory.Parameter( - attributeLists:=Nothing, - modifiers:=Nothing, - identifier:=SyntaxFactory.ModifiedIdentifier("value"), - asClause:=asClause, - [default]:=Nothing) - - Return SyntaxFactory.AccessorBlock( - SyntaxKind.RemoveHandlerAccessorBlock, - SyntaxFactory.AccessorStatement( - kind:=SyntaxKind.RemoveHandlerAccessorStatement, - attributeLists:=Nothing, - modifiers:=Nothing, - accessorKeyword:=SyntaxFactory.Token(SyntaxKind.RemoveHandlerKeyword), - parameterList:=SyntaxFactory.ParameterList(SyntaxFactory.SingletonSeparatedList(valueParameter))), - GetStatementList(statements), - SyntaxFactory.EndRemoveHandlerStatement()) - End Function - - Private Function CreateRaiseEventAccessorBlock(parameters As IEnumerable(Of SyntaxNode), statements As IEnumerable(Of SyntaxNode)) As AccessorBlockSyntax - Dim parameterList = GetParameterList(parameters) - - Return SyntaxFactory.AccessorBlock( - SyntaxKind.RaiseEventAccessorBlock, - SyntaxFactory.AccessorStatement( - kind:=SyntaxKind.RaiseEventAccessorStatement, - attributeLists:=Nothing, - modifiers:=Nothing, - accessorKeyword:=SyntaxFactory.Token(SyntaxKind.RaiseEventKeyword), - parameterList:=parameterList), - GetStatementList(statements), - SyntaxFactory.EndRaiseEventStatement()) - End Function - Public Overrides Function AsPublicInterfaceImplementation(declaration As SyntaxNode, interfaceTypeName As SyntaxNode, interfaceMemberName As String) As SyntaxNode Return Isolate(declaration, Function(decl) AsPublicInterfaceImplementationInternal(decl, interfaceTypeName, interfaceMemberName)) End Function @@ -1354,7 +1208,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return SyntaxFactory.ConstructorBlock( subNewStatement:=SyntaxFactory.SubNewStatement( attributeLists:=Nothing, - modifiers:=GetModifierList(accessibility, modifiers And s_constructorModifiers, declaration:=Nothing, DeclarationKind.Constructor), + modifiers:=GetModifierList(accessibility, modifiers And VisualBasicSyntaxGeneratorInternal.s_constructorModifiers, declaration:=Nothing, DeclarationKind.Constructor), parameterList:=If(parameters IsNot Nothing, SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters.Cast(Of ParameterSyntax)())), SyntaxFactory.ParameterList())), statements:=stats) End Function @@ -1391,7 +1245,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return SyntaxFactory.ClassBlock( classStatement:=SyntaxFactory.ClassStatement( attributeLists:=Nothing, - modifiers:=GetModifierList(accessibility, modifiers And s_classModifiers, declaration:=Nothing, DeclarationKind.Class), + modifiers:=GetModifierList(accessibility, modifiers And VisualBasicSyntaxGeneratorInternal.s_classModifiers, declaration:=Nothing, DeclarationKind.Class), identifier:=name.ToIdentifierToken(), typeParameterList:=GetTypeParameters(typeParameters)), [inherits]:=If(baseType IsNot Nothing, SyntaxFactory.SingletonList(SyntaxFactory.InheritsStatement(DirectCast(baseType, TypeSyntax))), Nothing), @@ -1428,7 +1282,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return SyntaxFactory.StructureBlock( structureStatement:=SyntaxFactory.StructureStatement( attributeLists:=Nothing, - modifiers:=GetModifierList(accessibility, modifiers And s_structModifiers, declaration:=Nothing, DeclarationKind.Struct), + modifiers:=GetModifierList(accessibility, modifiers And VisualBasicSyntaxGeneratorInternal.s_structModifiers, declaration:=Nothing, DeclarationKind.Struct), identifier:=name.ToIdentifierToken(), typeParameterList:=GetTypeParameters(typeParameters)), [inherits]:=Nothing, @@ -1707,6 +1561,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return compilationUnit.Attributes(0).AttributeLists End If End If + Return Flatten(declaration.GetAttributeLists()) End Function @@ -1752,6 +1607,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration If Not declaration.IsKind(SyntaxKind.CompilationUnit) Then Return attributes End If + Return SyntaxFactory.List(attributes.Select(AddressOf WithAssemblyTargets)) End Function @@ -2692,100 +2548,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return WithModifierTokens(declaration, Merge(tokens, newTokens)) End Function - Private Shared Function GetModifierList(accessibility As Accessibility, modifiers As DeclarationModifiers, declaration As SyntaxNode, kind As DeclarationKind, Optional isDefault As Boolean = False) As SyntaxTokenList - Dim _list = SyntaxFactory.TokenList() - - ' While partial must always be last in C#, its preferred position in VB is to be first, - ' even before accessibility modifiers. This order is enforced by line commit. - If modifiers.IsPartial Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.PartialKeyword)) - End If - - If isDefault Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.DefaultKeyword)) - End If - - Select Case (accessibility) - Case Accessibility.Internal - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.FriendKeyword)) - Case Accessibility.Public - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) - Case Accessibility.Private - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)) - Case Accessibility.Protected - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)) - Case Accessibility.ProtectedOrInternal - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.FriendKeyword)).Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)) - Case Accessibility.ProtectedAndInternal - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)).Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)) - Case Accessibility.NotApplicable - Case Else - Throw New NotSupportedException(String.Format("Accessibility '{0}' not supported.", accessibility)) - End Select - - Dim isClass = kind = DeclarationKind.Class OrElse declaration.IsKind(SyntaxKind.ClassStatement) - If modifiers.IsAbstract Then - If isClass Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.MustInheritKeyword)) - Else - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.MustOverrideKeyword)) - End If - End If - - If modifiers.IsNew Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.ShadowsKeyword)) - End If - - If modifiers.IsSealed Then - If isClass Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.NotInheritableKeyword)) - Else - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.NotOverridableKeyword)) - End If - End If - - If modifiers.IsOverride Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.OverridesKeyword)) - End If - - If modifiers.IsVirtual Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.OverridableKeyword)) - End If - - If modifiers.IsStatic Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.SharedKeyword)) - End If - - If modifiers.IsAsync Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.AsyncKeyword)) - End If - - If modifiers.IsConst Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.ConstKeyword)) - End If - - If modifiers.IsReadOnly Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)) - End If - - If modifiers.IsWriteOnly Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.WriteOnlyKeyword)) - End If - - If modifiers.IsUnsafe Then - Throw New NotSupportedException("Unsupported modifier") - ''''_list = _list.Add(SyntaxFactory.Token(SyntaxKind.UnsafeKeyword)) - End If - - If modifiers.IsWithEvents Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.WithEventsKeyword)) - End If - - If (kind = DeclarationKind.Field AndAlso _list.Count = 0) Then - _list = _list.Add(SyntaxFactory.Token(SyntaxKind.DimKeyword)) - End If - - Return _list + Friend Shared Function GetModifierList(accessibility As Accessibility, modifiers As DeclarationModifiers, declaration As SyntaxNode, kind As DeclarationKind, Optional isDefault As Boolean = False) As SyntaxTokenList + Return VisualBasicSyntaxGeneratorInternal.GetModifierList(accessibility, modifiers, declaration, kind, isDefault) End Function Private Protected Overrides Function TypeParameter(name As String) As SyntaxNode @@ -3045,7 +2809,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return Isolate(declaration, Function(d) WithExpressionInternal(d, expression)) End Function - Private Function WithExpressionInternal(declaration As SyntaxNode, expression As SyntaxNode) As SyntaxNode + Private Shared Function WithExpressionInternal(declaration As SyntaxNode, expression As SyntaxNode) As SyntaxNode Dim expr = DirectCast(expression, ExpressionSyntax) Select Case declaration.Kind @@ -3267,7 +3031,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Return Isolate(declaration, Function(d) WithStatementsInternal(d, statements)) End Function - Private Function WithStatementsInternal(declaration As SyntaxNode, statements As IEnumerable(Of SyntaxNode)) As SyntaxNode + Private Shared Function WithStatementsInternal(declaration As SyntaxNode, statements As IEnumerable(Of SyntaxNode)) As SyntaxNode Dim list = GetStatementList(statements) Select Case declaration.Kind Case SyntaxKind.FunctionBlock, @@ -3407,7 +3171,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration accessor = DirectCast(Me.WithStatements(accessor, statements), AccessorBlockSyntax) Return Me.WithAccessorBlock(declaration, kind, accessor) ElseIf CanHaveAccessors(declaration.Kind) Then - accessor = Me.AccessorBlock(kind, statements, Me.ClearTrivia(Me.GetType(declaration))) + accessor = AccessorBlock(kind, statements, Me.ClearTrivia(Me.GetType(declaration))) Return Me.WithAccessorBlock(declaration, kind, accessor) Else Return declaration @@ -3464,57 +3228,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Optional addAccessorStatements As IEnumerable(Of SyntaxNode) = Nothing, Optional removeAccessorStatements As IEnumerable(Of SyntaxNode) = Nothing) As SyntaxNode - Return CustomEventDeclarationWithRaise(name, type, accessibility, modifiers, parameters, addAccessorStatements, removeAccessorStatements) - End Function - - Public Function CustomEventDeclarationWithRaise( - name As String, - type As SyntaxNode, - Optional accessibility As Accessibility = Accessibility.NotApplicable, - Optional modifiers As DeclarationModifiers = Nothing, - Optional parameters As IEnumerable(Of SyntaxNode) = Nothing, - Optional addAccessorStatements As IEnumerable(Of SyntaxNode) = Nothing, - Optional removeAccessorStatements As IEnumerable(Of SyntaxNode) = Nothing, - Optional raiseAccessorStatements As IEnumerable(Of SyntaxNode) = Nothing) As SyntaxNode - - Dim accessors = New List(Of AccessorBlockSyntax)() - - If modifiers.IsAbstract Then - addAccessorStatements = Nothing - removeAccessorStatements = Nothing - raiseAccessorStatements = Nothing - Else - If addAccessorStatements Is Nothing Then - addAccessorStatements = SpecializedCollections.EmptyEnumerable(Of SyntaxNode)() - End If - - If removeAccessorStatements Is Nothing Then - removeAccessorStatements = SpecializedCollections.EmptyEnumerable(Of SyntaxNode)() - End If - - If raiseAccessorStatements Is Nothing Then - raiseAccessorStatements = SpecializedCollections.EmptyEnumerable(Of SyntaxNode)() - End If - End If - - accessors.Add(CreateAddHandlerAccessorBlock(type, addAccessorStatements)) - accessors.Add(CreateRemoveHandlerAccessorBlock(type, removeAccessorStatements)) - accessors.Add(CreateRaiseEventAccessorBlock(parameters, raiseAccessorStatements)) - - Dim evStatement = SyntaxFactory.EventStatement( - attributeLists:=Nothing, - modifiers:=GetModifierList(accessibility, modifiers And GetAllowedModifiers(SyntaxKind.EventStatement), declaration:=Nothing, DeclarationKind.Event), - customKeyword:=SyntaxFactory.Token(SyntaxKind.CustomKeyword), - eventKeyword:=SyntaxFactory.Token(SyntaxKind.EventKeyword), - identifier:=name.ToIdentifierToken(), - parameterList:=Nothing, - asClause:=SyntaxFactory.SimpleAsClause(DirectCast(type, TypeSyntax)), - implementsClause:=Nothing) - - Return SyntaxFactory.EventBlock( - eventStatement:=evStatement, - accessors:=SyntaxFactory.List(accessors), - endEventStatement:=SyntaxFactory.EndEventStatement()) + Return VisualBasicSyntaxGeneratorInternal.CustomEventDeclarationWithRaise( + name, type, accessibility, modifiers, parameters, addAccessorStatements, removeAccessorStatements) End Function Public Overrides Function GetAttributeArguments(attributeDeclaration As SyntaxNode) As IReadOnlyList(Of SyntaxNode) diff --git a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/VisualBasicTriviaFormatter.vb b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/VisualBasicTriviaFormatter.vb index 0119c9972c42d..bf97184586cc0 100644 --- a/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/VisualBasicTriviaFormatter.vb +++ b/src/Workspaces/VisualBasic/Portable/Formatting/Engine/Trivia/VisualBasicTriviaFormatter.vb @@ -271,7 +271,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Formatting ' If the doc comment was parsed from a text fragment, there may not be ' an end-of-line at all. We need to trim the end before we check the ' number of line breaks in the text. -#If NETCOREAPP Then +#If NET Then Dim textWithoutFinalNewLine = text.TrimEnd() #Else Dim textWithoutFinalNewLine = text.TrimEnd(Nothing) diff --git a/src/Workspaces/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.Workspaces.vbproj b/src/Workspaces/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.Workspaces.vbproj index 94e93344d4e42..43aeb17ae3230 100644 --- a/src/Workspaces/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.Workspaces.vbproj +++ b/src/Workspaces/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.Workspaces.vbproj @@ -13,10 +13,6 @@ .NET Compiler Platform ("Roslyn") support for analyzing Visual Basic projects and solutions. - - - - diff --git a/src/Workspaces/VisualBasic/Portable/VBWorkspaceResources.resx b/src/Workspaces/VisualBasic/Portable/VBWorkspaceResources.resx index b040162d4149e..43f8dc0e878d5 100644 --- a/src/Workspaces/VisualBasic/Portable/VBWorkspaceResources.resx +++ b/src/Workspaces/VisualBasic/Portable/VBWorkspaceResources.resx @@ -117,9 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Namespace can not be added in this destination. - Only attributes, expressions or statements can be made explicit diff --git a/src/Workspaces/VisualBasic/Portable/Workspace/LanguageServices/VisualBasicSyntaxTreeFactoryService.vb b/src/Workspaces/VisualBasic/Portable/Workspace/LanguageServices/VisualBasicSyntaxTreeFactoryService.vb index 97b8341d7aae7..6b810e4587f7a 100644 --- a/src/Workspaces/VisualBasic/Portable/Workspace/LanguageServices/VisualBasicSyntaxTreeFactoryService.vb +++ b/src/Workspaces/VisualBasic/Portable/Workspace/LanguageServices/VisualBasicSyntaxTreeFactoryService.vb @@ -70,12 +70,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return SyntaxFactory.ParseSyntaxTree(text, options, filePath, cancellationToken) End Function - Public Overrides Function CreateSyntaxTree(filePath As String, options As ParseOptions, encoding As Encoding, checksumAlgorithm As SourceHashAlgorithm, root As SyntaxNode) As SyntaxTree + Public Overrides Function CreateSyntaxTree(filePath As String, options As ParseOptions, text As SourceText, encoding As Encoding, checksumAlgorithm As SourceHashAlgorithm, root As SyntaxNode) As SyntaxTree If options Is Nothing Then options = GetDefaultParseOptions() End If - Return New ParsedSyntaxTree(lazyText:=Nothing, DirectCast(root, VisualBasicSyntaxNode), DirectCast(options, VisualBasicParseOptions), filePath, encoding, checksumAlgorithm) + Return New ParsedSyntaxTree(text, DirectCast(root, VisualBasicSyntaxNode), DirectCast(options, VisualBasicParseOptions), filePath, encoding, checksumAlgorithm) End Function End Class End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.cs.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.cs.xlf index a5bb92f2b56b6..8f1c14134a046 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.cs.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.cs.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - Obor názvů nejde přidat do tohoto cílového umístění. - - Only attributes, expressions or statements can be made explicit Jako explicitní jde nastavit jenom atributy, výrazy nebo příkazy. diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.de.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.de.xlf index b7655c60b9bec..3b85f06265d2b 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.de.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.de.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - Namespace kann zu diesem Ziel nicht hinzugefügt werden. - - Only attributes, expressions or statements can be made explicit Nur Attribute, Ausdrücke oder Anweisungen können explizit gemacht werden diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.es.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.es.xlf index a828ee4730b1d..f8f920679f207 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.es.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.es.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - El espacio de nombres no se puede agregar en este destino. - - Only attributes, expressions or statements can be made explicit Solo atributos, expresiones o instrucciones pueden hacerse explícitos diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.fr.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.fr.xlf index 104e111a3c795..cba9986390434 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.fr.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.fr.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - L'espace de noms ne peut pas être ajouté dans cette destination. - - Only attributes, expressions or statements can be made explicit Seuls les attributs, les expressions ou les déclarations peuvent être rendus explicites diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.it.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.it.xlf index 23926ea56983d..0668a338c5f4e 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.it.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.it.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - Non è possibile aggiungere lo spazio dei nomi in questa destinazione. - - Only attributes, expressions or statements can be made explicit È possibile rendere espliciti solo attributi, espressioni o istruzioni diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ja.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ja.xlf index 01aa95869062d..5924be0c13286 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ja.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ja.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - 名前空間は、このターゲットでは追加できません。 - - Only attributes, expressions or statements can be made explicit 属性、式、またはステートメントのみを明示的にすることができます diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ko.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ko.xlf index 8f7664f22d652..cc645230fa24d 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ko.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ko.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - 이 대상에는 네임스페이스를 추가할 수 없습니다. - - Only attributes, expressions or statements can be made explicit 특성, 식 또는 문만 명시적일 수 있습니다. diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.pl.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.pl.xlf index 13b56c6a55309..70bdac61bff28 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.pl.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.pl.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - Do tego miejsca docelowego nie można dodać przestrzeni nazw. - - Only attributes, expressions or statements can be made explicit Jako jawne można ustawić tylko atrybuty, wyrażenia lub instrukcje diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.pt-BR.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.pt-BR.xlf index 8ee104e3ab603..07d03ccdfcdf8 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.pt-BR.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.pt-BR.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - Namespace não pode ser adicionado nesse destino. - - Only attributes, expressions or statements can be made explicit Somente atributos, expressões ou instruções podem ser tornados explícitos diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ru.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ru.xlf index 1b577679dc3f9..79fca3c4d8de2 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ru.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.ru.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - Не удается добавить пространство имен в этот конечный объект. - - Only attributes, expressions or statements can be made explicit Явными могут стать только атрибуты, выражения или операторы diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.tr.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.tr.xlf index aac21f16029bd..e257b03cd0866 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.tr.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.tr.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - Ad alanı bu hedefe eklenemez. - - Only attributes, expressions or statements can be made explicit Yalnızca öznitelikler, ifadeler veya deyimler açık hale getirilebilir diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.zh-Hans.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.zh-Hans.xlf index 1fd78caf06402..2227c1d84eb5e 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.zh-Hans.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.zh-Hans.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - 不能在此目标中添加命名空间。 - - Only attributes, expressions or statements can be made explicit 只有属性、表达式或语句可以变得明显 diff --git a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.zh-Hant.xlf b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.zh-Hant.xlf index 44960fcd0ace1..458c31aa88bbc 100644 --- a/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.zh-Hant.xlf +++ b/src/Workspaces/VisualBasic/Portable/xlf/VBWorkspaceResources.zh-Hant.xlf @@ -2,11 +2,6 @@ - - Namespace can not be added in this destination. - 無法將命名空間加入此目的地。 - - Only attributes, expressions or statements can be made explicit 只有屬性、運算式或陳述式可以設為明確 diff --git a/src/Workspaces/VisualBasicTest/CodeGeneration/AddImportsTests.vb b/src/Workspaces/VisualBasicTest/CodeGeneration/AddImportsTests.vb index 030030707be9b..e28c0e358f468 100644 --- a/src/Workspaces/VisualBasicTest/CodeGeneration/AddImportsTests.vb +++ b/src/Workspaces/VisualBasicTest/CodeGeneration/AddImportsTests.vb @@ -36,7 +36,7 @@ End NameSpace" "test", "test.dll", LanguageNames.VisualBasic, - metadataReferences:={TestMetadata.Net451.mscorlib})) + metadataReferences:={NetFramework.mscorlib})) If globalImports IsNot Nothing Then Dim gi = GlobalImport.Parse(globalImports) diff --git a/src/Workspaces/VisualBasicTest/CodeGeneration/SyntaxGeneratorTests.vb b/src/Workspaces/VisualBasicTest/CodeGeneration/SyntaxGeneratorTests.vb index 97ab3a5e94c6e..540d27ed70c97 100644 --- a/src/Workspaces/VisualBasicTest/CodeGeneration/SyntaxGeneratorTests.vb +++ b/src/Workspaces/VisualBasicTest/CodeGeneration/SyntaxGeneratorTests.vb @@ -16,7 +16,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Editing Public Class SyntaxGeneratorTests Private _g As SyntaxGenerator - Private ReadOnly _emptyCompilation As VisualBasicCompilation = VisualBasicCompilation.Create("empty", references:={TestMetadata.Net451.mscorlib, TestMetadata.Net451.System}) + Private ReadOnly _emptyCompilation As VisualBasicCompilation = VisualBasicCompilation.Create("empty", references:={NetFramework.mscorlib, NetFramework.System}) Private ReadOnly _ienumerableInt As INamedTypeSymbol @@ -35,7 +35,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Editing End Property Public Shared Function Compile(code As String) As Compilation - Return VisualBasicCompilation.Create("test").AddReferences(TestMetadata.Net451.mscorlib).AddSyntaxTrees(SyntaxFactory.ParseSyntaxTree(code)) + Return VisualBasicCompilation.Create("test").AddReferences(NetFramework.mscorlib).AddSyntaxTrees(SyntaxFactory.ParseSyntaxTree(code)) End Function Private Shared Sub VerifySyntax(Of TSyntax As SyntaxNode)(type As SyntaxNode, expectedText As String)